@scoperat/tracker 0.1.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 ADDED
@@ -0,0 +1,75 @@
1
+ # @scoperat/tracker
2
+
3
+ Browser analytics SDK.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @scoperat/tracker
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import scoperat from "@scoperat/tracker";
15
+
16
+ // Initialize once at app startup (endpoint defaults to window.location.origin)
17
+ scoperat.init("tk_live_your_write_key");
18
+
19
+ // Identify the current user after login
20
+ scoperat.identify("user_123", { email: "user@example.com", orgId: "org_456" });
21
+
22
+ // Track events
23
+ scoperat.track("button_clicked", { buttonId: "signup-cta", page: "/pricing" });
24
+
25
+ // Reset on logout
26
+ scoperat.reset();
27
+ ```
28
+
29
+ ## API
30
+
31
+ ### `scoperat.init(writeKey, options?)`
32
+
33
+ Initialize the tracker. Must be called before any other method.
34
+
35
+ | Option | Type | Default | Description |
36
+ | --------------- | ------------------------- | ------------------------ | ---------------------------- |
37
+ | `endpoint` | `string` | `window.location.origin` | API base URL |
38
+ | `flushAt` | `number` | `10` | Flush after this many events |
39
+ | `flushInterval` | `number` | `3000` | Auto-flush interval in ms |
40
+ | `timeout` | `number` | `10000` | Request timeout in ms |
41
+ | `onError` | `(error, events) => void` | — | Error callback |
42
+
43
+ ### `scoperat.identify(userId, traits?)`
44
+
45
+ Associate events with a user. Traits are merged into every event's context.
46
+
47
+ ### `scoperat.track(event, properties?)`
48
+
49
+ Enqueue a tracking event. Events are batched and flushed automatically.
50
+
51
+ ### `scoperat.reset()`
52
+
53
+ Clear user identity and generate a new anonymous ID. Call on logout.
54
+
55
+ ### `scoperat.flush()`
56
+
57
+ Manually flush the event buffer. Returns a `Promise<FlushResult>`.
58
+
59
+ ### `scoperat.shutdown()`
60
+
61
+ Flush remaining events and stop the auto-flush timer. Call before app teardown.
62
+
63
+ ## Features
64
+
65
+ - **Auto-batching** — events are buffered and sent in batches for efficiency
66
+ - **Anonymous IDs** — persistent anonymous ID via `localStorage`, auto-generated on first visit
67
+ - **sendBeacon fallback** — uses `navigator.sendBeacon` on page hide for reliable delivery
68
+ - **Retry on failure** — failed batches are re-queued for the next flush
69
+ - **Zero dependencies** — no runtime dependencies
70
+ - **Tree-shakeable** — marked as side-effect-free for optimal bundling
71
+ - **ESM-only** — ships as pure ES modules
72
+
73
+ ## License
74
+
75
+ MIT
@@ -0,0 +1,27 @@
1
+ import type { FlushResult, IdentifyTraits, InitOptions, TrackEvent } from "./types.js";
2
+ declare class TrackerImpl {
3
+ private writeKey;
4
+ private endpoint;
5
+ private flushAt;
6
+ private flushInterval;
7
+ private timeout;
8
+ private onError?;
9
+ private buffer;
10
+ private timer;
11
+ private visibilityHandler;
12
+ private userId;
13
+ private orgId;
14
+ private traits;
15
+ private anonymousId;
16
+ init(writeKey: string, options?: InitOptions): void;
17
+ identify(userId: string, traits?: IdentifyTraits): void;
18
+ reset(): void;
19
+ track(event: string, properties?: Record<string, unknown>): void;
20
+ track(event: TrackEvent): void;
21
+ flush(): Promise<FlushResult>;
22
+ private flushSync;
23
+ shutdown(): Promise<void>;
24
+ }
25
+ declare const scoperat: TrackerImpl;
26
+ export default scoperat;
27
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,WAAW,EACX,UAAU,EACX,MAAM,YAAY,CAAC;AAoCpB,cAAM,WAAW;IACf,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,OAAO,CAAC,CAA+C;IAE/D,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,WAAW,CAAqB;IAExC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,IAAI;IAkCvD,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI;IAQvD,KAAK,IAAI,IAAI;IAOb,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAChE,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAoCxB,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAiCnC,OAAO,CAAC,SAAS;IAiBX,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAehC;AAED,QAAA,MAAM,QAAQ,aAAoB,CAAC;AACnC,eAAe,QAAQ,CAAC"}
package/dist/client.js ADDED
@@ -0,0 +1,178 @@
1
+ import { getBrowserContext } from "./context.js";
2
+ const DEFAULT_FLUSH_AT = 10;
3
+ const DEFAULT_FLUSH_INTERVAL = 3_000;
4
+ const DEFAULT_TIMEOUT = 10_000;
5
+ const MAX_BATCH_SIZE = 100;
6
+ const ANON_ID_KEY = "__scoperat_anon_id";
7
+ function generateAnonId() {
8
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
9
+ return crypto.randomUUID();
10
+ }
11
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
12
+ const r = (Math.random() * 16) | 0;
13
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
14
+ return v.toString(16);
15
+ });
16
+ }
17
+ function getOrCreateAnonId() {
18
+ if (typeof window === "undefined" || typeof localStorage === "undefined") {
19
+ return undefined;
20
+ }
21
+ try {
22
+ let id = localStorage.getItem(ANON_ID_KEY);
23
+ if (!id) {
24
+ id = generateAnonId();
25
+ localStorage.setItem(ANON_ID_KEY, id);
26
+ }
27
+ return id;
28
+ }
29
+ catch {
30
+ return generateAnonId();
31
+ }
32
+ }
33
+ class TrackerImpl {
34
+ writeKey = null;
35
+ endpoint = "";
36
+ flushAt = DEFAULT_FLUSH_AT;
37
+ flushInterval = DEFAULT_FLUSH_INTERVAL;
38
+ timeout = DEFAULT_TIMEOUT;
39
+ onError;
40
+ buffer = [];
41
+ timer = null;
42
+ visibilityHandler = null;
43
+ userId;
44
+ orgId;
45
+ traits = {};
46
+ anonymousId;
47
+ init(writeKey, options = {}) {
48
+ this.writeKey = writeKey;
49
+ this.endpoint = (options.endpoint ??
50
+ globalThis.location?.origin ??
51
+ "").replace(/\/+$/, "");
52
+ this.flushAt = options.flushAt ?? DEFAULT_FLUSH_AT;
53
+ this.flushInterval = options.flushInterval ?? DEFAULT_FLUSH_INTERVAL;
54
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
55
+ this.onError = options.onError;
56
+ this.anonymousId = getOrCreateAnonId();
57
+ if (this.timer)
58
+ clearInterval(this.timer);
59
+ this.timer = setInterval(() => {
60
+ if (this.buffer.length > 0) {
61
+ this.flush().catch(() => { });
62
+ }
63
+ }, this.flushInterval);
64
+ if (typeof window !== "undefined") {
65
+ if (this.visibilityHandler) {
66
+ window.removeEventListener("visibilitychange", this.visibilityHandler);
67
+ }
68
+ this.visibilityHandler = () => {
69
+ if (document.visibilityState === "hidden" && this.buffer.length > 0) {
70
+ this.flushSync();
71
+ }
72
+ };
73
+ window.addEventListener("visibilitychange", this.visibilityHandler);
74
+ }
75
+ }
76
+ identify(userId, traits) {
77
+ this.userId = userId;
78
+ if (traits) {
79
+ this.traits = { ...traits };
80
+ if (traits.orgId)
81
+ this.orgId = traits.orgId;
82
+ }
83
+ }
84
+ reset() {
85
+ this.userId = undefined;
86
+ this.orgId = undefined;
87
+ this.traits = {};
88
+ this.anonymousId = getOrCreateAnonId();
89
+ }
90
+ track(eventOrName, properties) {
91
+ if (!this.writeKey)
92
+ return;
93
+ const evt = typeof eventOrName === "string"
94
+ ? { event: eventOrName, properties }
95
+ : eventOrName;
96
+ const traitsContext = Object.keys(this.traits).length > 0 ? { traits: this.traits } : {};
97
+ const enriched = {
98
+ ...evt,
99
+ occurred_at: evt.occurred_at ?? new Date().toISOString(),
100
+ source: evt.source ?? "browser",
101
+ org_id: evt.org_id ?? this.orgId,
102
+ user_id: evt.user_id ?? this.userId,
103
+ anonymous_id: evt.anonymous_id ?? this.anonymousId,
104
+ context: {
105
+ ...getBrowserContext(),
106
+ ...traitsContext,
107
+ ...evt.context,
108
+ },
109
+ };
110
+ this.buffer.push(enriched);
111
+ if (this.buffer.length >= this.flushAt) {
112
+ this.flush().catch(() => { });
113
+ }
114
+ }
115
+ async flush() {
116
+ if (!this.writeKey || this.buffer.length === 0) {
117
+ return { success: true, ingested: 0 };
118
+ }
119
+ const batch = this.buffer.splice(0, MAX_BATCH_SIZE);
120
+ try {
121
+ const res = await fetch(`${this.endpoint}/api/ingest/track`, {
122
+ method: "POST",
123
+ headers: {
124
+ "Content-Type": "application/json",
125
+ Authorization: `Bearer ${this.writeKey}`,
126
+ },
127
+ body: JSON.stringify({ events: batch }),
128
+ signal: AbortSignal.timeout(this.timeout),
129
+ });
130
+ if (!res.ok) {
131
+ const body = await res.text().catch(() => "");
132
+ throw new Error(`API returned ${res.status}: ${body}`);
133
+ }
134
+ const json = (await res.json());
135
+ return { success: true, ingested: json.ingested };
136
+ }
137
+ catch (error) {
138
+ this.buffer.unshift(...batch);
139
+ const err = error instanceof Error ? error : new Error(String(error));
140
+ this.onError?.(err, batch);
141
+ return { success: false, ingested: 0 };
142
+ }
143
+ }
144
+ flushSync() {
145
+ if (!this.writeKey)
146
+ return;
147
+ if (typeof navigator === "undefined" || !navigator.sendBeacon)
148
+ return;
149
+ if (this.buffer.length === 0)
150
+ return;
151
+ const batch = this.buffer.splice(0, MAX_BATCH_SIZE);
152
+ const payload = JSON.stringify({ events: batch });
153
+ const url = `${this.endpoint}/api/ingest/track?key=${encodeURIComponent(this.writeKey)}`;
154
+ try {
155
+ const blob = new Blob([payload], { type: "application/json" });
156
+ navigator.sendBeacon(url, blob);
157
+ }
158
+ catch {
159
+ // Best effort on unload
160
+ }
161
+ }
162
+ async shutdown() {
163
+ if (this.timer) {
164
+ clearInterval(this.timer);
165
+ this.timer = null;
166
+ }
167
+ if (typeof window !== "undefined" && this.visibilityHandler) {
168
+ window.removeEventListener("visibilitychange", this.visibilityHandler);
169
+ this.visibilityHandler = null;
170
+ }
171
+ while (this.buffer.length > 0) {
172
+ await this.flush();
173
+ }
174
+ }
175
+ }
176
+ const scoperat = new TrackerImpl();
177
+ export default scoperat;
178
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Auto-capture browser context: page, referrer, screen, locale, user agent.
3
+ */
4
+ export declare function getBrowserContext(): Record<string, unknown>;
5
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoB3D"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Auto-capture browser context: page, referrer, screen, locale, user agent.
3
+ */
4
+ export function getBrowserContext() {
5
+ if (typeof window === "undefined") {
6
+ return {};
7
+ }
8
+ return {
9
+ page: {
10
+ url: window.location.href,
11
+ path: window.location.pathname,
12
+ title: document.title,
13
+ referrer: document.referrer || undefined,
14
+ },
15
+ screen: {
16
+ width: window.screen.width,
17
+ height: window.screen.height,
18
+ },
19
+ locale: navigator.language,
20
+ userAgent: navigator.userAgent,
21
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
22
+ };
23
+ }
24
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO;QACL,IAAI,EAAE;YACJ,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI;YACzB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ;YAC9B,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,QAAQ,EAAE,QAAQ,CAAC,QAAQ,IAAI,SAAS;SACzC;QACD,MAAM,EAAE;YACN,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK;YAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM;SAC7B;QACD,MAAM,EAAE,SAAS,CAAC,QAAQ;QAC1B,SAAS,EAAE,SAAS,CAAC,SAAS;QAC9B,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,eAAe,EAAE,CAAC,QAAQ;KAC3D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import scoperat from "./client.js";
2
+ export default scoperat;
3
+ export type { EventSource, FlushResult, IdentifyTraits, InitOptions, TrackEvent, } from "./types.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,aAAa,CAAC;AAEnC,eAAe,QAAQ,CAAC;AACxB,YAAY,EACV,WAAW,EACX,WAAW,EACX,cAAc,EACd,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import scoperat from "./client.js";
2
+ export default scoperat;
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,aAAa,CAAC;AAEnC,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,30 @@
1
+ export type EventSource = "browser" | "server" | "worker";
2
+ export interface TrackEvent {
3
+ event: string;
4
+ properties?: Record<string, unknown>;
5
+ context?: Record<string, unknown>;
6
+ source?: EventSource;
7
+ occurred_at?: Date | string;
8
+ org_id?: string;
9
+ user_id?: string;
10
+ anonymous_id?: string;
11
+ }
12
+ export interface IdentifyTraits {
13
+ orgId?: string;
14
+ orgName?: string;
15
+ email?: string;
16
+ name?: string;
17
+ [key: string]: unknown;
18
+ }
19
+ export interface InitOptions {
20
+ endpoint?: string;
21
+ flushAt?: number;
22
+ flushInterval?: number;
23
+ timeout?: number;
24
+ onError?: (error: Error, events: TrackEvent[]) => void;
25
+ }
26
+ export interface FlushResult {
27
+ success: boolean;
28
+ ingested: number;
29
+ }
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@scoperat/tracker",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Browser analytics SDK",
6
+ "license": "MIT",
7
+ "sideEffects": false,
8
+ "engines": {
9
+ "node": ">=18"
10
+ },
11
+ "keywords": [
12
+ "analytics",
13
+ "tracking",
14
+ "events",
15
+ "telemetry",
16
+ "browser",
17
+ "scoperat"
18
+ ],
19
+ "main": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md"
30
+ ],
31
+ "devDependencies": {
32
+ "typescript": "^5"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "clean": "rm -rf dist",
37
+ "type-check": "tsc --noEmit"
38
+ }
39
+ }