@eventra_dev/eventra-sdk 1.0.7 → 1.1.1
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 +131 -246
- package/dist/index.cjs +172 -165
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -17
- package/dist/index.d.ts +18 -17
- package/dist/index.mjs +175 -168
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -25,133 +25,164 @@ __export(index_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(index_exports);
|
|
26
26
|
|
|
27
27
|
// src/client.ts
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
44
|
-
if (typeof crypto !== "undefined" &&
|
|
36
|
+
function uuid() {
|
|
37
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
45
38
|
return crypto.randomUUID();
|
|
46
39
|
}
|
|
47
|
-
|
|
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
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
JSON.stringify({ ts: now })
|
|
68
|
-
);
|
|
69
|
-
return true;
|
|
45
|
+
var Storage = class {
|
|
46
|
+
constructor() {
|
|
47
|
+
this.enabled = false;
|
|
48
|
+
try {
|
|
49
|
+
if (typeof localStorage !== "undefined") {
|
|
50
|
+
localStorage.setItem("__t", "1");
|
|
51
|
+
localStorage.removeItem("__t");
|
|
52
|
+
this.enabled = true;
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
70
55
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return
|
|
56
|
+
}
|
|
57
|
+
get(key) {
|
|
58
|
+
if (!this.enabled) return null;
|
|
59
|
+
try {
|
|
60
|
+
return JSON.parse(localStorage.getItem(key) || "null");
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
78
63
|
}
|
|
79
|
-
return false;
|
|
80
|
-
} catch {
|
|
81
|
-
return true;
|
|
82
64
|
}
|
|
83
|
-
|
|
65
|
+
set(key, value) {
|
|
66
|
+
if (!this.enabled) return;
|
|
67
|
+
try {
|
|
68
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var Leader = class {
|
|
74
|
+
constructor(enabled) {
|
|
75
|
+
this.isLeader = true;
|
|
76
|
+
if (!enabled) return;
|
|
77
|
+
if (typeof BroadcastChannel !== "undefined") {
|
|
78
|
+
this.channel = new BroadcastChannel("eventra");
|
|
79
|
+
this.channel.onmessage = (e) => {
|
|
80
|
+
if (e.data === "leader") this.isLeader = false;
|
|
81
|
+
};
|
|
82
|
+
this.channel.postMessage("leader");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
canSend() {
|
|
86
|
+
return this.isLeader;
|
|
87
|
+
}
|
|
88
|
+
destroy() {
|
|
89
|
+
this.channel?.close();
|
|
90
|
+
}
|
|
91
|
+
};
|
|
84
92
|
var Eventra = class {
|
|
85
93
|
constructor(options) {
|
|
86
94
|
this.queue = [];
|
|
87
95
|
this.inFlight = false;
|
|
88
96
|
this.destroyed = false;
|
|
89
|
-
this.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
this.storage = new Storage();
|
|
98
|
+
this.leader = null;
|
|
99
|
+
this.failureCount = 0;
|
|
100
|
+
this.circuitOpenUntil = 0;
|
|
101
|
+
this.exitHandlers = [];
|
|
102
|
+
if (!options.apiKey) throw new Error("apiKey required");
|
|
103
|
+
if (!options.endpoint) throw new Error("endpoint required");
|
|
104
|
+
this.options = options;
|
|
93
105
|
this.apiKey = options.apiKey;
|
|
94
|
-
this.endpoint = options.endpoint
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
);
|
|
106
|
+
this.endpoint = options.endpoint;
|
|
107
|
+
this.runtime = detectRuntime();
|
|
108
|
+
this.fetch = options.fetchImpl ?? globalThis.fetch;
|
|
109
|
+
if (!this.fetch) {
|
|
110
|
+
throw new Error("fetch not available \u2014 provide fetchImpl");
|
|
109
111
|
}
|
|
112
|
+
this.maxBatch = options.maxBatchSize ?? 50;
|
|
113
|
+
this.maxQueue = options.maxQueueSize ?? 1e4;
|
|
114
|
+
this.flushInterval = options.flushInterval ?? 2e3;
|
|
115
|
+
this.retries = options.maxRetries ?? 3;
|
|
116
|
+
this.retryDelay = options.retryBaseDelayMs ?? 300;
|
|
110
117
|
this.sdkInfo = {
|
|
111
118
|
name: "@eventra_dev/eventra-sdk",
|
|
112
|
-
version:
|
|
113
|
-
runtime: this.
|
|
119
|
+
version: "1.0.0",
|
|
120
|
+
runtime: this.runtime
|
|
114
121
|
};
|
|
122
|
+
if (this.runtime === "browser") {
|
|
123
|
+
const saved = this.storage.get("__eventra_q__");
|
|
124
|
+
if (Array.isArray(saved)) this.queue = saved;
|
|
125
|
+
}
|
|
126
|
+
if (this.runtime === "browser" && options.multiTabMode === "leader") {
|
|
127
|
+
this.leader = new Leader(true);
|
|
128
|
+
}
|
|
115
129
|
if (!options.disableTimer) {
|
|
116
130
|
this.startTimer();
|
|
117
131
|
}
|
|
118
|
-
if (
|
|
119
|
-
this.
|
|
132
|
+
if (this.runtime === "browser") {
|
|
133
|
+
this.setupBrowserExit();
|
|
134
|
+
}
|
|
135
|
+
if (options.autoFlushOnExit !== false && this.runtime !== "browser") {
|
|
136
|
+
this.setupProcessExit();
|
|
120
137
|
}
|
|
121
|
-
this.onEventsDropped = options.onEventsDropped;
|
|
122
138
|
}
|
|
123
|
-
|
|
139
|
+
// ================= PUBLIC =================
|
|
124
140
|
track(name, options) {
|
|
125
141
|
if (this.destroyed) return;
|
|
126
|
-
if (this.queue.length >= this.
|
|
127
|
-
this.
|
|
128
|
-
this.onEventsDropped?.(this.droppedEvents);
|
|
142
|
+
if (this.queue.length >= this.maxQueue) {
|
|
143
|
+
this.options.onEventsDropped?.(1);
|
|
129
144
|
return;
|
|
130
145
|
}
|
|
131
|
-
|
|
132
|
-
idempotencyKey:
|
|
146
|
+
const event = {
|
|
147
|
+
idempotencyKey: uuid(),
|
|
133
148
|
name,
|
|
134
149
|
userId: options?.userId,
|
|
135
150
|
properties: options?.properties ?? {},
|
|
136
151
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
137
|
-
}
|
|
138
|
-
|
|
152
|
+
};
|
|
153
|
+
this.queue.push(event);
|
|
154
|
+
if (this.runtime === "browser") {
|
|
155
|
+
this.persist();
|
|
156
|
+
}
|
|
157
|
+
if (this.queue.length >= this.maxBatch) {
|
|
158
|
+
void this.flush();
|
|
159
|
+
}
|
|
160
|
+
if (this.runtime === "serverless") {
|
|
139
161
|
void this.flush();
|
|
140
162
|
}
|
|
141
163
|
}
|
|
142
164
|
async flush() {
|
|
143
|
-
if (this.destroyed) return;
|
|
144
|
-
if (this.
|
|
145
|
-
if (this.
|
|
146
|
-
if (
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
165
|
+
if (this.inFlight || this.destroyed) return;
|
|
166
|
+
if (!this.queue.length) return;
|
|
167
|
+
if (this.leader && !this.leader.canSend()) return;
|
|
168
|
+
if (Date.now() < this.circuitOpenUntil) return;
|
|
149
169
|
this.inFlight = true;
|
|
150
|
-
const batch = this.queue.splice(0, this.
|
|
170
|
+
const batch = this.queue.splice(0, this.maxBatch);
|
|
171
|
+
if (this.runtime === "browser") {
|
|
172
|
+
this.persist();
|
|
173
|
+
}
|
|
151
174
|
try {
|
|
152
175
|
await this.send(batch);
|
|
176
|
+
this.failureCount = 0;
|
|
153
177
|
} catch {
|
|
154
|
-
this.queue
|
|
178
|
+
this.queue = [...batch, ...this.queue];
|
|
179
|
+
if (this.runtime === "browser") {
|
|
180
|
+
this.persist();
|
|
181
|
+
}
|
|
182
|
+
this.failureCount++;
|
|
183
|
+
if (this.failureCount >= 5) {
|
|
184
|
+
this.circuitOpenUntil = Date.now() + 5e3;
|
|
185
|
+
}
|
|
155
186
|
} finally {
|
|
156
187
|
this.inFlight = false;
|
|
157
188
|
}
|
|
@@ -159,113 +190,89 @@ var Eventra = class {
|
|
|
159
190
|
destroy() {
|
|
160
191
|
this.destroyed = true;
|
|
161
192
|
if (this.timer) clearInterval(this.timer);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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 {
|
|
193
|
+
this.leader?.destroy();
|
|
194
|
+
for (const off of this.exitHandlers) {
|
|
195
|
+
off();
|
|
174
196
|
}
|
|
175
|
-
return false;
|
|
176
197
|
}
|
|
198
|
+
// ================= SEND =================
|
|
177
199
|
async send(events) {
|
|
178
200
|
const payload = JSON.stringify({
|
|
179
201
|
sentAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
180
202
|
sdk: this.sdkInfo,
|
|
181
203
|
events
|
|
182
204
|
});
|
|
183
|
-
if (
|
|
184
|
-
|
|
205
|
+
if (this.runtime === "browser" && typeof navigator !== "undefined" && navigator.sendBeacon && payload.length < 6e4 && document.visibilityState === "hidden") {
|
|
206
|
+
navigator.sendBeacon(this.endpoint, payload);
|
|
207
|
+
return;
|
|
185
208
|
}
|
|
186
209
|
let attempt = 0;
|
|
187
|
-
while (attempt <= this.
|
|
210
|
+
while (attempt <= this.retries) {
|
|
188
211
|
try {
|
|
189
|
-
const
|
|
212
|
+
const controller = new AbortController();
|
|
213
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
214
|
+
const res = await this.fetch(this.endpoint, {
|
|
190
215
|
method: "POST",
|
|
191
216
|
headers: {
|
|
192
217
|
"Content-Type": "application/json",
|
|
193
218
|
"x-api-key": this.apiKey
|
|
194
219
|
},
|
|
195
|
-
body: payload
|
|
220
|
+
body: payload,
|
|
221
|
+
signal: controller.signal
|
|
196
222
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
if (!res.ok) {
|
|
204
|
-
throw new Error(`HTTP ${res.status}`);
|
|
205
|
-
}
|
|
223
|
+
clearTimeout(timeout);
|
|
224
|
+
if (res.status >= 400 && res.status < 500) return;
|
|
225
|
+
if (!res.ok) throw new Error();
|
|
206
226
|
return;
|
|
207
|
-
} catch
|
|
227
|
+
} catch {
|
|
208
228
|
attempt++;
|
|
209
|
-
if (attempt > this.
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
const jitter = 0.5 + Math.random();
|
|
213
|
-
const delay = this.retryBaseDelay * 2 ** (attempt - 1) * jitter;
|
|
214
|
-
await sleep(delay);
|
|
229
|
+
if (attempt > this.retries) throw new Error();
|
|
230
|
+
await sleep(this.retryDelay * 2 ** attempt);
|
|
215
231
|
}
|
|
216
232
|
}
|
|
217
233
|
}
|
|
218
|
-
|
|
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 ---------------- */
|
|
234
|
+
// ================= INTERNAL =================
|
|
242
235
|
startTimer() {
|
|
243
236
|
this.timer = setInterval(() => {
|
|
244
237
|
void this.flush();
|
|
245
238
|
}, this.flushInterval);
|
|
246
239
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
240
|
+
setupBrowserExit() {
|
|
241
|
+
const handler = () => {
|
|
242
|
+
if (document.visibilityState === "hidden") {
|
|
243
|
+
void this.flush();
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
window.addEventListener("visibilitychange", handler);
|
|
247
|
+
this.exitHandlers.push(() => {
|
|
248
|
+
window.removeEventListener("visibilitychange", handler);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
setupProcessExit() {
|
|
256
252
|
const g = globalThis;
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
253
|
+
const flushSafe = async () => {
|
|
254
|
+
try {
|
|
255
|
+
await this.flush();
|
|
256
|
+
} catch {
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
const beforeExit = () => {
|
|
260
|
+
void flushSafe();
|
|
261
|
+
};
|
|
262
|
+
const sigint = async () => {
|
|
263
|
+
await flushSafe();
|
|
264
|
+
g.exit();
|
|
265
|
+
};
|
|
266
|
+
g?.on?.("beforeExit", beforeExit);
|
|
267
|
+
g?.on?.("SIGINT", sigint);
|
|
268
|
+
this.exitHandlers.push(() => {
|
|
269
|
+
g?.off?.("beforeExit", beforeExit);
|
|
270
|
+
g?.off?.("SIGINT", sigint);
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
persist() {
|
|
274
|
+
if (this.runtime !== "browser") return;
|
|
275
|
+
this.storage.set("__eventra_q__", this.queue);
|
|
269
276
|
}
|
|
270
277
|
};
|
|
271
278
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.cjs.map
CHANGED
|
@@ -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 =================\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\n// ================= STORAGE =================\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 =================\nclass Leader {\n private channel?: BroadcastChannel;\n private isLeader = true;\n\n constructor(enabled: boolean) {\n if (!enabled) return;\n\n if (typeof BroadcastChannel !== \"undefined\") {\n this.channel = new BroadcastChannel(\"eventra\");\n\n this.channel.onmessage = (e) => {\n if (e.data === \"leader\") this.isLeader = false;\n };\n\n this.channel.postMessage(\"leader\");\n }\n }\n\n canSend() {\n return this.isLeader;\n }\n\n destroy() {\n this.channel?.close();\n }\n}\n\n// ================= SDK =================\nexport class Eventra {\n private apiKey: string;\n private endpoint: string;\n private runtime: Runtime;\n private fetch: typeof fetch;\n\n private queue: TrackEvent[] = [];\n private inFlight = false;\n private destroyed = false;\n\n private maxBatch: number;\n private maxQueue: number;\n private flushInterval: number;\n private retries: number;\n private retryDelay: number;\n\n private timer?: any;\n\n private storage = new Storage();\n private leader: Leader | null = null;\n\n private failureCount = 0;\n private circuitOpenUntil = 0;\n\n private sdkInfo: SdkInfo;\n private options: TrackerOptions;\n\n private exitHandlers: Array<() => void> = [];\n\n constructor(options: TrackerOptions) {\n if (!options.apiKey) throw new Error(\"apiKey required\");\n if (!options.endpoint) throw new Error(\"endpoint required\");\n\n this.options = options;\n this.apiKey = options.apiKey;\n this.endpoint = options.endpoint;\n this.runtime = detectRuntime();\n\n this.fetch = options.fetchImpl ?? globalThis.fetch;\n if (!this.fetch) {\n throw new Error(\"fetch not available — provide fetchImpl\");\n }\n\n this.maxBatch = options.maxBatchSize ?? 50;\n this.maxQueue = options.maxQueueSize ?? 10000;\n this.flushInterval = options.flushInterval ?? 2000;\n this.retries = options.maxRetries ?? 3;\n this.retryDelay = options.retryBaseDelayMs ?? 300;\n\n this.sdkInfo = {\n name: \"@eventra_dev/eventra-sdk\",\n version: \"1.0.0\",\n runtime: this.runtime,\n };\n\n // restore browser queue\n if (this.runtime === \"browser\") {\n const saved = this.storage.get(\"__eventra_q__\");\n if (Array.isArray(saved)) this.queue = saved;\n }\n\n // leader (browser only)\n if (this.runtime === \"browser\" && options.multiTabMode === \"leader\") {\n this.leader = new Leader(true);\n }\n\n // timer\n if (!options.disableTimer) {\n this.startTimer();\n }\n\n // browser exit\n if (this.runtime === \"browser\") {\n this.setupBrowserExit();\n }\n\n // node / serverless exit\n if (options.autoFlushOnExit !== false && this.runtime !== \"browser\") {\n this.setupProcessExit();\n }\n }\n\n // ================= PUBLIC =================\n track(name: string, options?: any) {\n if (this.destroyed) return;\n\n if (this.queue.length >= this.maxQueue) {\n this.options.onEventsDropped?.(1);\n return;\n }\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 this.queue.push(event);\n\n if (this.runtime === \"browser\") {\n this.persist();\n }\n\n if (this.queue.length >= this.maxBatch) {\n void this.flush();\n }\n\n if (this.runtime === \"serverless\") {\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 && !this.leader.canSend()) return;\n if (Date.now() < this.circuitOpenUntil) return;\n\n this.inFlight = true;\n\n const batch = this.queue.splice(0, this.maxBatch);\n\n if (this.runtime === \"browser\") {\n this.persist();\n }\n\n try {\n await this.send(batch);\n this.failureCount = 0;\n } catch {\n // возвращаем батч назад (без dedupe — это задача backend)\n this.queue = [...batch, ...this.queue];\n\n if (this.runtime === \"browser\") {\n this.persist();\n }\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\n if (this.timer) clearInterval(this.timer);\n\n this.leader?.destroy();\n\n // remove process listeners\n for (const off of this.exitHandlers) {\n off();\n }\n }\n\n // ================= SEND =================\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 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 if (!res.ok) throw new Error();\n\n return;\n } catch {\n attempt++;\n if (attempt > this.retries) throw new Error();\n await sleep(this.retryDelay * 2 ** attempt);\n }\n }\n }\n\n // ================= INTERNAL =================\n private startTimer() {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.flushInterval);\n }\n\n private setupBrowserExit() {\n const handler = () => {\n if (document.visibilityState === \"hidden\") {\n void this.flush();\n }\n };\n\n window.addEventListener(\"visibilitychange\", handler);\n\n this.exitHandlers.push(() => {\n window.removeEventListener(\"visibilitychange\", handler);\n });\n }\n\n private setupProcessExit() {\n\n const g = globalThis as any;\n\n const flushSafe = async () => {\n try {\n await this.flush();\n } catch {}\n };\n\n const beforeExit = () => {\n void flushSafe();\n };\n\n const sigint = async () => {\n await flushSafe();\n g.exit();\n };\n\n g?.on?.(\"beforeExit\", beforeExit);\n g?.on?.(\"SIGINT\", sigint);\n\n this.exitHandlers.push(() => {\n g?.off?.(\"beforeExit\", beforeExit);\n g?.off?.(\"SIGINT\", sigint);\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,33 @@ interface SdkInfo {
|
|
|
30
30
|
declare class Eventra {
|
|
31
31
|
private apiKey;
|
|
32
32
|
private endpoint;
|
|
33
|
-
private
|
|
34
|
-
private
|
|
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
|
|
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;
|
|
49
|
+
private options;
|
|
50
|
+
private exitHandlers;
|
|
46
51
|
constructor(options: TrackerOptions);
|
|
47
|
-
|
|
48
|
-
track(name: string, options?: {
|
|
49
|
-
userId?: string;
|
|
50
|
-
properties?: Record<string, unknown>;
|
|
51
|
-
}): void;
|
|
52
|
+
track(name: string, options?: any): void;
|
|
52
53
|
flush(): Promise<void>;
|
|
53
54
|
destroy(): void;
|
|
54
|
-
private trySendBeacon;
|
|
55
55
|
private send;
|
|
56
|
-
private detectRuntime;
|
|
57
56
|
private startTimer;
|
|
58
|
-
private
|
|
57
|
+
private setupBrowserExit;
|
|
58
|
+
private setupProcessExit;
|
|
59
|
+
private persist;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
export { Eventra, type SdkInfo, type TrackEvent, type TrackerOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -30,32 +30,33 @@ interface SdkInfo {
|
|
|
30
30
|
declare class Eventra {
|
|
31
31
|
private apiKey;
|
|
32
32
|
private endpoint;
|
|
33
|
-
private
|
|
34
|
-
private
|
|
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
|
|
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;
|
|
49
|
+
private options;
|
|
50
|
+
private exitHandlers;
|
|
46
51
|
constructor(options: TrackerOptions);
|
|
47
|
-
|
|
48
|
-
track(name: string, options?: {
|
|
49
|
-
userId?: string;
|
|
50
|
-
properties?: Record<string, unknown>;
|
|
51
|
-
}): void;
|
|
52
|
+
track(name: string, options?: any): void;
|
|
52
53
|
flush(): Promise<void>;
|
|
53
54
|
destroy(): void;
|
|
54
|
-
private trySendBeacon;
|
|
55
55
|
private send;
|
|
56
|
-
private detectRuntime;
|
|
57
56
|
private startTimer;
|
|
58
|
-
private
|
|
57
|
+
private setupBrowserExit;
|
|
58
|
+
private setupProcessExit;
|
|
59
|
+
private persist;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
export { Eventra, type SdkInfo, type TrackEvent, type TrackerOptions };
|