@eventra_dev/eventra-sdk 1.0.7 → 1.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/dist/index.cjs CHANGED
@@ -25,133 +25,146 @@ __export(index_exports, {
25
25
  module.exports = __toCommonJS(index_exports);
26
26
 
27
27
  // src/client.ts
28
- var SDK_VERSION = "1.0.7";
29
- var DEFAULTS = {
30
- endpoint: "https://api.eventra.dev/api/v1/ingest/batch",
31
- flushInterval: 2e3,
32
- maxBatchSize: 50,
33
- maxQueueSize: 1e4,
34
- maxRetries: 3,
35
- retryBaseDelay: 300
36
- };
37
- function getGlobalFetch() {
38
- if (typeof fetch !== "undefined") {
39
- return fetch.bind(globalThis);
40
- }
41
- return void 0;
28
+ function detectRuntime() {
29
+ const g = globalThis;
30
+ if (typeof window !== "undefined") return "browser";
31
+ if (g.EdgeRuntime) return "edge";
32
+ if (g.process?.env?.AWS_LAMBDA_FUNCTION_NAME) return "serverless";
33
+ if (g.process?.versions?.node) return "node";
34
+ return "unknown";
42
35
  }
43
- function generateUUIDv4() {
44
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
36
+ function uuid() {
37
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
45
38
  return crypto.randomUUID();
46
39
  }
47
- const rnd = Math.random().toString(16).slice(2);
48
- const ts = Date.now().toString(16);
49
- return `${ts}-${rnd}`;
50
- }
51
- function isBrowser() {
52
- return typeof window !== "undefined";
40
+ return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
53
41
  }
54
42
  function sleep(ms) {
55
43
  return new Promise((r) => setTimeout(r, ms));
56
44
  }
57
- var LEADER_KEY = "__eventra_sdk_leader__";
58
- var LEADER_TTL = 4e3;
59
- function tryBecomeLeader() {
60
- if (!isBrowser()) return true;
61
- try {
62
- const now = Date.now();
63
- const raw = localStorage.getItem(LEADER_KEY);
64
- if (!raw) {
65
- localStorage.setItem(
66
- LEADER_KEY,
67
- JSON.stringify({ ts: now })
68
- );
69
- return true;
45
+ function getFetch() {
46
+ if (typeof fetch !== "undefined") return fetch.bind(globalThis);
47
+ throw new Error("fetch not available");
48
+ }
49
+ var Storage = class {
50
+ constructor() {
51
+ this.enabled = false;
52
+ try {
53
+ if (typeof localStorage !== "undefined") {
54
+ localStorage.setItem("__t", "1");
55
+ localStorage.removeItem("__t");
56
+ this.enabled = true;
57
+ }
58
+ } catch {
70
59
  }
71
- const parsed = JSON.parse(raw);
72
- if (now - parsed.ts > LEADER_TTL) {
73
- localStorage.setItem(
74
- LEADER_KEY,
75
- JSON.stringify({ ts: now })
76
- );
77
- return true;
60
+ }
61
+ get(key) {
62
+ if (!this.enabled) return null;
63
+ try {
64
+ return JSON.parse(localStorage.getItem(key) || "null");
65
+ } catch {
66
+ return null;
78
67
  }
79
- return false;
80
- } catch {
81
- return true;
82
68
  }
83
- }
69
+ set(key, value) {
70
+ if (!this.enabled) return;
71
+ try {
72
+ localStorage.setItem(key, JSON.stringify(value));
73
+ } catch {
74
+ }
75
+ }
76
+ };
77
+ var Leader = class {
78
+ constructor() {
79
+ this.isLeader = true;
80
+ if (typeof BroadcastChannel !== "undefined") {
81
+ this.channel = new BroadcastChannel("eventra");
82
+ this.channel.onmessage = (e) => {
83
+ if (e.data === "leader") {
84
+ this.isLeader = false;
85
+ }
86
+ };
87
+ this.channel.postMessage("leader");
88
+ }
89
+ }
90
+ canSend() {
91
+ return this.isLeader;
92
+ }
93
+ };
84
94
  var Eventra = class {
85
95
  constructor(options) {
96
+ this.fetch = getFetch();
86
97
  this.queue = [];
87
98
  this.inFlight = false;
88
99
  this.destroyed = false;
89
- this.droppedEvents = 0;
90
- if (!options.apiKey) {
91
- throw new Error("Eventra: apiKey is required");
92
- }
100
+ this.maxBatch = 50;
101
+ this.maxQueue = 1e4;
102
+ this.flushInterval = 2e3;
103
+ this.retries = 3;
104
+ this.retryDelay = 300;
105
+ this.storage = new Storage();
106
+ this.leader = new Leader();
107
+ this.failureCount = 0;
108
+ this.circuitOpenUntil = 0;
109
+ if (!options.apiKey) throw new Error("apiKey required");
93
110
  this.apiKey = options.apiKey;
94
- this.endpoint = options.endpoint ?? DEFAULTS.endpoint ?? "";
95
- if (!this.endpoint) {
96
- throw new Error("Eventra: endpoint is not configured");
97
- }
98
- this.flushInterval = options.flushInterval ?? DEFAULTS.flushInterval;
99
- this.maxBatchSize = options.maxBatchSize ?? DEFAULTS.maxBatchSize;
100
- this.maxQueueSize = options.maxQueueSize ?? DEFAULTS.maxQueueSize;
101
- this.maxRetries = options.maxRetries ?? DEFAULTS.maxRetries;
102
- this.retryBaseDelay = options.retryBaseDelayMs ?? DEFAULTS.retryBaseDelay;
103
- this.multiTabMode = options.multiTabMode ?? "independent";
104
- this.fetchImpl = options.fetchImpl ?? getGlobalFetch();
105
- if (!this.fetchImpl) {
106
- throw new Error(
107
- "Eventra: fetch is not available. Provide fetchImpl."
108
- );
109
- }
111
+ this.endpoint = options.endpoint ?? "";
112
+ if (!this.endpoint) throw new Error("endpoint required");
113
+ this.runtime = detectRuntime();
114
+ this.maxBatch = options.maxBatchSize ?? this.maxBatch;
115
+ this.maxQueue = options.maxQueueSize ?? this.maxQueue;
116
+ this.flushInterval = options.flushInterval ?? this.flushInterval;
110
117
  this.sdkInfo = {
111
118
  name: "@eventra_dev/eventra-sdk",
112
- version: SDK_VERSION,
113
- runtime: this.detectRuntime()
119
+ version: "ultra",
120
+ runtime: this.runtime
114
121
  };
115
- if (!options.disableTimer) {
122
+ if (this.runtime === "browser") {
123
+ const saved = this.storage.get("__eventra_q__");
124
+ if (saved) this.queue = saved;
116
125
  this.startTimer();
126
+ this.setupBrowserExit();
117
127
  }
118
- if (options.autoFlushOnExit !== false) {
119
- this.setupExitHandlers();
120
- }
121
- this.onEventsDropped = options.onEventsDropped;
122
128
  }
123
- /* ---------------- Public API ---------------- */
129
+ // PUBLIC
124
130
  track(name, options) {
125
131
  if (this.destroyed) return;
126
- if (this.queue.length >= this.maxQueueSize) {
127
- this.droppedEvents++;
128
- this.onEventsDropped?.(this.droppedEvents);
129
- return;
130
- }
131
- this.queue.push({
132
- idempotencyKey: generateUUIDv4(),
132
+ const event = {
133
+ idempotencyKey: uuid(),
133
134
  name,
134
135
  userId: options?.userId,
135
136
  properties: options?.properties ?? {},
136
137
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
137
- });
138
- if (this.queue.length >= this.maxBatchSize) {
138
+ };
139
+ if (this.runtime !== "browser") {
140
+ void this.send([event]);
141
+ return;
142
+ }
143
+ if (this.queue.length >= this.maxQueue) return;
144
+ this.queue.push(event);
145
+ this.persist();
146
+ if (this.queue.length >= this.maxBatch) {
139
147
  void this.flush();
140
148
  }
141
149
  }
142
150
  async flush() {
143
- if (this.destroyed) return;
144
- if (this.inFlight) return;
145
- if (this.queue.length === 0) return;
146
- if (this.multiTabMode === "leader" && !tryBecomeLeader()) {
147
- return;
148
- }
151
+ if (this.inFlight || this.destroyed) return;
152
+ if (!this.queue.length) return;
153
+ if (!this.leader.canSend()) return;
154
+ if (Date.now() < this.circuitOpenUntil) return;
149
155
  this.inFlight = true;
150
- const batch = this.queue.splice(0, this.queue.length);
156
+ const batch = this.queue.splice(0, this.maxBatch);
157
+ this.persist();
151
158
  try {
152
159
  await this.send(batch);
160
+ this.failureCount = 0;
153
161
  } catch {
154
- this.queue.unshift(...batch);
162
+ this.queue = [...batch, ...this.queue];
163
+ this.persist();
164
+ this.failureCount++;
165
+ if (this.failureCount >= 5) {
166
+ this.circuitOpenUntil = Date.now() + 5e3;
167
+ }
155
168
  } finally {
156
169
  this.inFlight = false;
157
170
  }
@@ -160,112 +173,58 @@ var Eventra = class {
160
173
  this.destroyed = true;
161
174
  if (this.timer) clearInterval(this.timer);
162
175
  }
163
- /* ---------------- Transport ---------------- */
164
- trySendBeacon(payload) {
165
- if (!isBrowser()) return false;
166
- try {
167
- if (navigator.sendBeacon) {
168
- const blob = new Blob([payload], {
169
- type: "application/json"
170
- });
171
- return navigator.sendBeacon(this.endpoint, blob);
172
- }
173
- } catch {
174
- }
175
- return false;
176
- }
176
+ // SEND (CORE)
177
177
  async send(events) {
178
178
  const payload = JSON.stringify({
179
179
  sentAt: (/* @__PURE__ */ new Date()).toISOString(),
180
180
  sdk: this.sdkInfo,
181
181
  events
182
182
  });
183
- if (isBrowser() && payload.length < 6e4 && document.visibilityState === "hidden") {
184
- if (this.trySendBeacon(payload)) return;
183
+ if (this.runtime === "browser" && typeof navigator !== "undefined" && navigator.sendBeacon && payload.length < 6e4 && document.visibilityState === "hidden") {
184
+ navigator.sendBeacon(this.endpoint, payload);
185
+ return;
185
186
  }
186
187
  let attempt = 0;
187
- while (attempt <= this.maxRetries) {
188
+ while (attempt <= this.retries) {
188
189
  try {
189
- const res = await this.fetchImpl(this.endpoint, {
190
+ const controller = new AbortController();
191
+ const timeout = setTimeout(() => controller.abort(), 5e3);
192
+ const res = await this.fetch(this.endpoint, {
190
193
  method: "POST",
191
194
  headers: {
192
195
  "Content-Type": "application/json",
193
196
  "x-api-key": this.apiKey
194
197
  },
195
- body: payload
198
+ body: payload,
199
+ signal: controller.signal
196
200
  });
197
- if (res.status >= 400 && res.status < 500) {
198
- if (res.status === 401 || res.status === 403) {
199
- console.error("Eventra: Invalid API key");
200
- }
201
- return;
202
- }
203
- if (!res.ok) {
204
- throw new Error(`HTTP ${res.status}`);
205
- }
201
+ clearTimeout(timeout);
202
+ if (res.status >= 400 && res.status < 500) return;
203
+ if (!res.ok) throw new Error();
206
204
  return;
207
- } catch (err) {
205
+ } catch {
208
206
  attempt++;
209
- if (attempt > this.maxRetries) {
210
- throw err;
211
- }
212
- const jitter = 0.5 + Math.random();
213
- const delay = this.retryBaseDelay * 2 ** (attempt - 1) * jitter;
214
- await sleep(delay);
207
+ if (attempt > this.retries) throw new Error();
208
+ await sleep(this.retryDelay * 2 ** attempt);
215
209
  }
216
210
  }
217
211
  }
218
- /* ---------------- Runtime ---------------- */
219
- detectRuntime() {
220
- const g = globalThis;
221
- if (typeof g["EdgeRuntime"] !== "undefined") {
222
- return "edge-vercel";
223
- }
224
- if (typeof g["WebSocketPair"] !== "undefined" && typeof g["caches"] !== "undefined") {
225
- return "edge-cloudflare";
226
- }
227
- if (g["Deno"]) return "deno";
228
- if (g["Bun"]) return "bun";
229
- if (typeof window !== "undefined") {
230
- return "browser";
231
- }
232
- if (typeof self !== "undefined" && typeof window === "undefined") {
233
- return "worker";
234
- }
235
- const maybeProcess = g["process"];
236
- if (maybeProcess?.versions?.node) {
237
- return "node";
238
- }
239
- return "unknown";
240
- }
241
- /* ---------------- Timer ---------------- */
212
+ // BROWSER
242
213
  startTimer() {
243
214
  this.timer = setInterval(() => {
244
215
  void this.flush();
245
216
  }, this.flushInterval);
246
217
  }
247
- /* ---------------- Exit handling ---------------- */
248
- setupExitHandlers() {
249
- if (typeof window !== "undefined") {
250
- window.addEventListener("visibilitychange", () => {
251
- if (document.visibilityState === "hidden") {
252
- void this.flush();
253
- }
254
- });
255
- }
256
- const g = globalThis;
257
- const maybeProcess = g["process"];
258
- if (typeof maybeProcess?.once === "function") {
259
- const shutdown = async () => {
260
- try {
261
- await this.flush();
262
- } catch {
263
- }
264
- };
265
- maybeProcess.once("SIGINT", shutdown);
266
- maybeProcess.once("SIGTERM", shutdown);
267
- maybeProcess.once("beforeExit", shutdown);
268
- }
218
+ setupBrowserExit() {
219
+ window.addEventListener("visibilitychange", () => {
220
+ if (document.visibilityState === "hidden") {
221
+ void this.flush();
222
+ }
223
+ });
224
+ }
225
+ persist() {
226
+ if (this.runtime !== "browser") return;
227
+ this.storage.set("__eventra_q__", this.queue);
269
228
  }
270
229
  };
271
230
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["export * from \"./client\";\nexport * from \"./types\";\n","import {\n TrackerOptions,\n TrackEvent,\n SdkInfo,\n} from \"./types\";\n\n/* ---------------- Constants ---------------- */\n\n\ndeclare const __SDK_VERSION__: string;\ndeclare const __EVENTRA_ENDPOINT__: string | undefined;\n\nconst SDK_VERSION = __SDK_VERSION__;\n\nconst DEFAULTS = {\n endpoint: __EVENTRA_ENDPOINT__ ?? \"\",\n flushInterval: 2000,\n maxBatchSize: 50,\n maxQueueSize: 10_000,\n maxRetries: 3,\n retryBaseDelay: 300,\n};\n\n/* ---------------- Helpers ---------------- */\n\nfunction getGlobalFetch(): typeof fetch | undefined {\n if (typeof fetch !== \"undefined\") {\n return fetch.bind(globalThis);\n }\n return undefined;\n}\n\nfunction generateUUIDv4(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID();\n }\n\n // ultra-rare fallback\n const rnd = Math.random().toString(16).slice(2);\n const ts = Date.now().toString(16);\n return `${ts}-${rnd}`;\n}\n\nfunction isBrowser(): boolean {\n return typeof window !== \"undefined\";\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\n/* ---------------- Leader Election (minimal) ---------------- */\n\nconst LEADER_KEY = \"__eventra_sdk_leader__\";\nconst LEADER_TTL = 4000;\n\nfunction tryBecomeLeader(): boolean {\n if (!isBrowser()) return true;\n\n try {\n const now = Date.now();\n const raw = localStorage.getItem(LEADER_KEY);\n\n if (!raw) {\n localStorage.setItem(\n LEADER_KEY,\n JSON.stringify({ ts: now })\n );\n return true;\n }\n\n const parsed = JSON.parse(raw) as { ts: number };\n\n if (now - parsed.ts > LEADER_TTL) {\n localStorage.setItem(\n LEADER_KEY,\n JSON.stringify({ ts: now })\n );\n return true;\n }\n\n return false;\n } catch {\n return true; // fail-open\n }\n}\n\n/* ============================================================ */\n\nexport class Eventra {\n private apiKey: string;\n private endpoint: string;\n private flushInterval: number;\n private maxBatchSize: number;\n private maxQueueSize: number;\n private maxRetries: number;\n private retryBaseDelay: number;\n private multiTabMode: \"independent\" | \"leader\";\n\n private fetchImpl?: typeof fetch;\n private queue: TrackEvent[] = [];\n private timer?: ReturnType<typeof setInterval>;\n private inFlight = false;\n private destroyed = false;\n private droppedEvents = 0;\n\n private sdkInfo: SdkInfo;\n\n constructor(options: TrackerOptions) {\n if (!options.apiKey) {\n throw new Error(\"Eventra: apiKey is required\");\n }\n\n this.apiKey = options.apiKey;\n\n this.endpoint = options.endpoint ?? DEFAULTS.endpoint ?? \"\";\n if (!this.endpoint) {\n throw new Error(\"Eventra: endpoint is not configured\");\n }\n\n this.flushInterval =\n options.flushInterval ?? DEFAULTS.flushInterval;\n\n this.maxBatchSize =\n options.maxBatchSize ?? DEFAULTS.maxBatchSize;\n\n this.maxQueueSize =\n options.maxQueueSize ?? DEFAULTS.maxQueueSize;\n\n this.maxRetries =\n options.maxRetries ?? DEFAULTS.maxRetries;\n\n this.retryBaseDelay =\n options.retryBaseDelayMs ?? DEFAULTS.retryBaseDelay;\n\n this.multiTabMode =\n options.multiTabMode ?? \"independent\";\n\n this.fetchImpl =\n options.fetchImpl ?? getGlobalFetch();\n\n if (!this.fetchImpl) {\n throw new Error(\n \"Eventra: fetch is not available. Provide fetchImpl.\"\n );\n }\n\n this.sdkInfo = {\n name: \"@eventra_dev/eventra-sdk\",\n version: SDK_VERSION,\n runtime: this.detectRuntime(),\n };\n\n if (!options.disableTimer) {\n this.startTimer();\n }\n\n if (options.autoFlushOnExit !== false) {\n this.setupExitHandlers();\n }\n\n this.onEventsDropped = options.onEventsDropped;\n }\n\n private onEventsDropped?: (count: number) => void;\n\n /* ---------------- Public API ---------------- */\n\n track(\n name: string,\n options?: {\n userId?: string;\n properties?: Record<string, unknown>;\n }\n ) {\n if (this.destroyed) return;\n\n if (this.queue.length >= this.maxQueueSize) {\n this.droppedEvents++;\n this.onEventsDropped?.(this.droppedEvents);\n return;\n }\n\n this.queue.push({\n idempotencyKey: generateUUIDv4(),\n name,\n userId: options?.userId,\n properties: options?.properties ?? {},\n timestamp: new Date().toISOString(),\n });\n\n if (this.queue.length >= this.maxBatchSize) {\n void this.flush();\n }\n }\n\n async flush(): Promise<void> {\n if (this.destroyed) return;\n if (this.inFlight) return;\n if (this.queue.length === 0) return;\n\n if (\n this.multiTabMode === \"leader\" &&\n !tryBecomeLeader()\n ) {\n return;\n }\n\n this.inFlight = true;\n\n const batch = this.queue.splice(0, this.queue.length);\n\n try {\n await this.send(batch);\n } catch {\n this.queue.unshift(...batch);\n } finally {\n this.inFlight = false;\n }\n }\n\n destroy() {\n this.destroyed = true;\n if (this.timer) clearInterval(this.timer);\n }\n\n /* ---------------- Transport ---------------- */\n\n private trySendBeacon(payload: string): boolean {\n if (!isBrowser()) return false;\n\n try {\n if (navigator.sendBeacon) {\n const blob = new Blob([payload], {\n type: \"application/json\",\n });\n return navigator.sendBeacon(this.endpoint, blob);\n }\n } catch {\n // ignore\n }\n\n return false;\n }\n\n private async send(events: TrackEvent[]) {\n const payload = JSON.stringify({\n sentAt: new Date().toISOString(),\n sdk: this.sdkInfo,\n events,\n });\n\n // beacon fast-path (browser only)\n if (\n isBrowser() &&\n payload.length < 60_000 &&\n document.visibilityState === \"hidden\"\n ) {\n if (this.trySendBeacon(payload)) return;\n }\n\n let attempt = 0;\n\n while (attempt <= this.maxRetries) {\n try {\n const res = await this.fetchImpl!(this.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n },\n body: payload,\n });\n\n // ❗ DO NOT retry client errors\n if (res.status >= 400 && res.status < 500) {\n if (res.status === 401 || res.status === 403) {\n console.error(\"Eventra: Invalid API key\");\n }\n return;\n }\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n return;\n } catch (err) {\n attempt++;\n\n if (attempt > this.maxRetries) {\n throw err;\n }\n\n const jitter = 0.5 + Math.random(); // 0.5–1.5\n const delay =\n this.retryBaseDelay *\n 2 ** (attempt - 1) *\n jitter;\n\n await sleep(delay);\n }\n }\n }\n\n /* ---------------- Runtime ---------------- */\n\n private detectRuntime(): string {\n const g = globalThis as Record<string, unknown>;\n\n // Edge (Vercel)\n if (typeof g[\"EdgeRuntime\"] !== \"undefined\") {\n return \"edge-vercel\";\n }\n\n // Cloudflare Workers\n if (\n typeof g[\"WebSocketPair\"] !== \"undefined\" &&\n typeof g[\"caches\"] !== \"undefined\"\n ) {\n return \"edge-cloudflare\";\n }\n\n // Deno\n if (g[\"Deno\"]) return \"deno\";\n\n // Bun\n if (g[\"Bun\"]) return \"bun\";\n\n // Browser (window)\n if (typeof window !== \"undefined\") {\n return \"browser\";\n }\n\n // Web Worker / Service Worker\n if (\n typeof self !== \"undefined\" &&\n typeof window === \"undefined\"\n ) {\n return \"worker\";\n }\n\n // Node\n const maybeProcess = g[\"process\"] as\n | { versions?: { node?: string } }\n | undefined;\n\n if (maybeProcess?.versions?.node) {\n return \"node\";\n }\n\n return \"unknown\";\n }\n\n /* ---------------- Timer ---------------- */\n\n private startTimer() {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.flushInterval);\n }\n\n /* ---------------- Exit handling ---------------- */\n\n private setupExitHandlers() {\n // browser\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n void this.flush();\n }\n });\n }\n\n // node\n const g = globalThis as Record<string, unknown>;\n\n const maybeProcess = g[\"process\"] as\n | { once?: (event: string, cb: () => void) => void }\n | undefined;\n\n if (typeof maybeProcess?.once === \"function\") {\n const shutdown = async () => {\n try {\n await this.flush();\n } catch {}\n };\n\n maybeProcess.once(\"SIGINT\", shutdown);\n maybeProcess.once(\"SIGTERM\", shutdown);\n maybeProcess.once(\"beforeExit\", shutdown);\n }\n }\n}\n\nexport * from \"./types\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["export * from \"./client\";\nexport * from \"./types\";\n","import { TrackerOptions, TrackEvent, SdkInfo } from \"./types\";\n\n// RUNTIME DETECTION\ntype Runtime = \"browser\" | \"node\" | \"edge\" | \"serverless\" | \"unknown\";\n\nfunction detectRuntime(): Runtime {\n const g = globalThis as any;\n\n if (typeof window !== \"undefined\") return \"browser\";\n if (g.EdgeRuntime) return \"edge\";\n if (g.process?.env?.AWS_LAMBDA_FUNCTION_NAME) return \"serverless\";\n if (g.process?.versions?.node) return \"node\";\n\n return \"unknown\";\n}\n\n// HELPERS\nfunction uuid(): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(16).slice(2)}`;\n}\n\nfunction sleep(ms: number) {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction getFetch(): typeof fetch {\n if (typeof fetch !== \"undefined\") return fetch.bind(globalThis);\n throw new Error(\"fetch not available\");\n}\n\n// SAFE STORAGE (browser only)\nclass Storage {\n private enabled = false;\n\n constructor() {\n try {\n if (typeof localStorage !== \"undefined\") {\n localStorage.setItem(\"__t\", \"1\");\n localStorage.removeItem(\"__t\");\n this.enabled = true;\n }\n } catch {}\n }\n\n get(key: string): any {\n if (!this.enabled) return null;\n try {\n return JSON.parse(localStorage.getItem(key) || \"null\");\n } catch {\n return null;\n }\n }\n\n set(key: string, value: any) {\n if (!this.enabled) return;\n try {\n localStorage.setItem(key, JSON.stringify(value));\n } catch {}\n }\n}\n\n// LEADER ELECTION (browser)\nclass Leader {\n private channel?: BroadcastChannel;\n private isLeader = true;\n\n constructor() {\n if (typeof BroadcastChannel !== \"undefined\") {\n this.channel = new BroadcastChannel(\"eventra\");\n\n this.channel.onmessage = (e) => {\n if (e.data === \"leader\") {\n this.isLeader = false;\n }\n };\n\n this.channel.postMessage(\"leader\");\n }\n }\n\n canSend() {\n return this.isLeader;\n }\n}\n\n// SDK\nexport class Eventra {\n private apiKey: string;\n private endpoint: string;\n private runtime: Runtime;\n private fetch = getFetch();\n\n private queue: TrackEvent[] = [];\n private inFlight = false;\n private destroyed = false;\n\n private maxBatch = 50;\n private maxQueue = 10000;\n private flushInterval = 2000;\n private retries = 3;\n private retryDelay = 300;\n\n private timer?: any;\n\n private storage = new Storage();\n private leader = new Leader();\n\n private failureCount = 0;\n private circuitOpenUntil = 0;\n\n private sdkInfo: SdkInfo;\n\n constructor(options: TrackerOptions) {\n if (!options.apiKey) throw new Error(\"apiKey required\");\n\n this.apiKey = options.apiKey;\n this.endpoint = options.endpoint ?? \"\";\n\n if (!this.endpoint) throw new Error(\"endpoint required\");\n\n this.runtime = detectRuntime();\n\n this.maxBatch = options.maxBatchSize ?? this.maxBatch;\n this.maxQueue = options.maxQueueSize ?? this.maxQueue;\n this.flushInterval = options.flushInterval ?? this.flushInterval;\n\n this.sdkInfo = {\n name: \"@eventra_dev/eventra-sdk\",\n version: \"ultra\",\n runtime: this.runtime,\n };\n\n if (this.runtime === \"browser\") {\n const saved = this.storage.get(\"__eventra_q__\");\n if (saved) this.queue = saved;\n\n this.startTimer();\n this.setupBrowserExit();\n }\n }\n\n // PUBLIC\n track(name: string, options?: any) {\n if (this.destroyed) return;\n\n const event: TrackEvent = {\n idempotencyKey: uuid(),\n name,\n userId: options?.userId,\n properties: options?.properties ?? {},\n timestamp: new Date().toISOString(),\n };\n\n // server environments → instant send\n if (this.runtime !== \"browser\") {\n void this.send([event]);\n return;\n }\n\n // browser → queue\n if (this.queue.length >= this.maxQueue) return;\n\n this.queue.push(event);\n this.persist();\n\n if (this.queue.length >= this.maxBatch) {\n void this.flush();\n }\n }\n\n async flush() {\n if (this.inFlight || this.destroyed) return;\n if (!this.queue.length) return;\n\n if (!this.leader.canSend()) return;\n\n if (Date.now() < this.circuitOpenUntil) return;\n\n this.inFlight = true;\n\n const batch = this.queue.splice(0, this.maxBatch);\n this.persist();\n\n try {\n await this.send(batch);\n\n this.failureCount = 0;\n } catch {\n this.queue = [...batch, ...this.queue];\n this.persist();\n\n this.failureCount++;\n\n if (this.failureCount >= 5) {\n this.circuitOpenUntil = Date.now() + 5000;\n }\n } finally {\n this.inFlight = false;\n }\n }\n\n destroy() {\n this.destroyed = true;\n if (this.timer) clearInterval(this.timer);\n }\n\n // SEND (CORE)\n private async send(events: TrackEvent[]) {\n const payload = JSON.stringify({\n sentAt: new Date().toISOString(),\n sdk: this.sdkInfo,\n events,\n });\n\n // sendBeacon fast path\n if (\n this.runtime === \"browser\" &&\n typeof navigator !== \"undefined\" &&\n navigator.sendBeacon &&\n payload.length < 60000 &&\n document.visibilityState === \"hidden\"\n ) {\n navigator.sendBeacon(this.endpoint, payload);\n return;\n }\n\n let attempt = 0;\n\n while (attempt <= this.retries) {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n\n const res = await this.fetch(this.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n },\n body: payload,\n signal: controller.signal,\n });\n\n clearTimeout(timeout);\n\n if (res.status >= 400 && res.status < 500) return;\n\n if (!res.ok) throw new Error();\n\n return;\n } catch {\n attempt++;\n\n if (attempt > this.retries) throw new Error();\n\n await sleep(this.retryDelay * 2 ** attempt);\n }\n }\n }\n\n // BROWSER\n private startTimer() {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.flushInterval);\n }\n\n private setupBrowserExit() {\n window.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n void this.flush();\n }\n });\n }\n\n private persist() {\n if (this.runtime !== \"browser\") return;\n this.storage.set(\"__eventra_q__\", this.queue);\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -30,32 +30,30 @@ interface SdkInfo {
30
30
  declare class Eventra {
31
31
  private apiKey;
32
32
  private endpoint;
33
- private flushInterval;
34
- private maxBatchSize;
35
- private maxQueueSize;
36
- private maxRetries;
37
- private retryBaseDelay;
38
- private multiTabMode;
39
- private fetchImpl?;
33
+ private runtime;
34
+ private fetch;
40
35
  private queue;
41
- private timer?;
42
36
  private inFlight;
43
37
  private destroyed;
44
- private droppedEvents;
38
+ private maxBatch;
39
+ private maxQueue;
40
+ private flushInterval;
41
+ private retries;
42
+ private retryDelay;
43
+ private timer?;
44
+ private storage;
45
+ private leader;
46
+ private failureCount;
47
+ private circuitOpenUntil;
45
48
  private sdkInfo;
46
49
  constructor(options: TrackerOptions);
47
- private onEventsDropped?;
48
- track(name: string, options?: {
49
- userId?: string;
50
- properties?: Record<string, unknown>;
51
- }): void;
50
+ track(name: string, options?: any): void;
52
51
  flush(): Promise<void>;
53
52
  destroy(): void;
54
- private trySendBeacon;
55
53
  private send;
56
- private detectRuntime;
57
54
  private startTimer;
58
- private setupExitHandlers;
55
+ private setupBrowserExit;
56
+ private persist;
59
57
  }
60
58
 
61
59
  export { Eventra, type SdkInfo, type TrackEvent, type TrackerOptions };
package/dist/index.d.ts CHANGED
@@ -30,32 +30,30 @@ interface SdkInfo {
30
30
  declare class Eventra {
31
31
  private apiKey;
32
32
  private endpoint;
33
- private flushInterval;
34
- private maxBatchSize;
35
- private maxQueueSize;
36
- private maxRetries;
37
- private retryBaseDelay;
38
- private multiTabMode;
39
- private fetchImpl?;
33
+ private runtime;
34
+ private fetch;
40
35
  private queue;
41
- private timer?;
42
36
  private inFlight;
43
37
  private destroyed;
44
- private droppedEvents;
38
+ private maxBatch;
39
+ private maxQueue;
40
+ private flushInterval;
41
+ private retries;
42
+ private retryDelay;
43
+ private timer?;
44
+ private storage;
45
+ private leader;
46
+ private failureCount;
47
+ private circuitOpenUntil;
45
48
  private sdkInfo;
46
49
  constructor(options: TrackerOptions);
47
- private onEventsDropped?;
48
- track(name: string, options?: {
49
- userId?: string;
50
- properties?: Record<string, unknown>;
51
- }): void;
50
+ track(name: string, options?: any): void;
52
51
  flush(): Promise<void>;
53
52
  destroy(): void;
54
- private trySendBeacon;
55
53
  private send;
56
- private detectRuntime;
57
54
  private startTimer;
58
- private setupExitHandlers;
55
+ private setupBrowserExit;
56
+ private persist;
59
57
  }
60
58
 
61
59
  export { Eventra, type SdkInfo, type TrackEvent, type TrackerOptions };