vedatrace 0.3.0 → 0.3.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 +53 -7
- package/dist/index-BcBZY8as.mjs +231 -0
- package/dist/index-osD28Hs0.cjs +239 -0
- package/dist/index.cjs +95 -96
- package/dist/index.d.cts +72 -20
- package/dist/index.d.mts +72 -20
- package/dist/index.mjs +95 -97
- package/dist/integrations/express.cjs +3 -4
- package/dist/integrations/express.mjs +3 -4
- package/dist/integrations/nextjs.cjs +31 -5
- package/dist/integrations/nextjs.d.cts +6 -14
- package/dist/integrations/nextjs.d.mts +6 -14
- package/dist/integrations/nextjs.mjs +31 -6
- package/dist/integrations/react.cjs +1 -1
- package/dist/integrations/react.mjs +1 -1
- package/dist/transports/index.cjs +5 -153
- package/dist/transports/index.d.cts +15 -5
- package/dist/transports/index.d.mts +15 -5
- package/dist/transports/index.mjs +1 -153
- package/package.json +150 -141
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var transports_index = require('./
|
|
5
|
+
var transports_index = require('./index-osD28Hs0.cjs');
|
|
6
6
|
|
|
7
7
|
class VedaTraceBatcher {
|
|
8
8
|
constructor(transports, config, immediateFlush = false) {
|
|
@@ -19,6 +19,12 @@ class VedaTraceBatcher {
|
|
|
19
19
|
pendingFlush = null;
|
|
20
20
|
context;
|
|
21
21
|
waitUntilFn;
|
|
22
|
+
/**
|
|
23
|
+
* Set when the ingestion endpoint rejects our credentials. Every subsequent
|
|
24
|
+
* batch would fail identically, so we stop rather than spend a request (and a
|
|
25
|
+
* retry storm) per flush for the life of the process. start() clears it.
|
|
26
|
+
*/
|
|
27
|
+
halted = false;
|
|
22
28
|
setContext(ctx) {
|
|
23
29
|
this.context = ctx;
|
|
24
30
|
}
|
|
@@ -26,6 +32,7 @@ class VedaTraceBatcher {
|
|
|
26
32
|
return this.context;
|
|
27
33
|
}
|
|
28
34
|
add(log) {
|
|
35
|
+
if (this.halted) return;
|
|
29
36
|
this.queue.push(log);
|
|
30
37
|
if (this.context || this.waitUntilFn) {
|
|
31
38
|
this.debouncedFlush();
|
|
@@ -47,23 +54,12 @@ class VedaTraceBatcher {
|
|
|
47
54
|
this.flushQueued = true;
|
|
48
55
|
queueMicrotask(() => {
|
|
49
56
|
this.flushQueued = false;
|
|
50
|
-
this.flush().catch((error) =>
|
|
51
|
-
if (this.config.onError) {
|
|
52
|
-
this.config.onError(
|
|
53
|
-
error instanceof Error ? error : new Error(String(error))
|
|
54
|
-
);
|
|
55
|
-
} else {
|
|
56
|
-
console.error(
|
|
57
|
-
"[VedaTrace] Debounced flush error:",
|
|
58
|
-
error instanceof Error ? error.message : String(error)
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
57
|
+
this.flush().catch((error) => this.reportError(error));
|
|
62
58
|
});
|
|
63
59
|
}
|
|
64
60
|
async flush() {
|
|
65
61
|
if (this.isFlushing) {
|
|
66
|
-
return this.pendingFlush ??
|
|
62
|
+
return this.pendingFlush ?? Promise.resolve();
|
|
67
63
|
}
|
|
68
64
|
if (this.queue.length === 0) {
|
|
69
65
|
return Promise.resolve();
|
|
@@ -74,6 +70,10 @@ class VedaTraceBatcher {
|
|
|
74
70
|
const flushPromise = this.sendWithRetry(logsToSend).finally(() => {
|
|
75
71
|
this.isFlushing = false;
|
|
76
72
|
this.pendingFlush = null;
|
|
73
|
+
}).then(() => {
|
|
74
|
+
if (this.queue.length > 0 && !this.halted) {
|
|
75
|
+
return this.flush();
|
|
76
|
+
}
|
|
77
77
|
});
|
|
78
78
|
this.pendingFlush = flushPromise;
|
|
79
79
|
if (this.context && typeof this.context.waitUntil === "function") {
|
|
@@ -89,26 +89,47 @@ class VedaTraceBatcher {
|
|
|
89
89
|
try {
|
|
90
90
|
await transport.send(logs);
|
|
91
91
|
} catch (error) {
|
|
92
|
-
errors.push(error
|
|
92
|
+
errors.push(error);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
-
if (errors.length
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
);
|
|
103
|
-
if (this.config.onError) {
|
|
104
|
-
this.config.onError(combinedError);
|
|
105
|
-
} else {
|
|
106
|
-
console.error("[VedaTrace]", combinedError.message);
|
|
107
|
-
}
|
|
95
|
+
if (errors.length === 0 || errors.length < this.transports.length) {
|
|
96
|
+
this.config.onSuccess?.();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const fatalError = errors.find(transports_index.isFatal);
|
|
100
|
+
if (fatalError) {
|
|
101
|
+
this.halt(fatalError);
|
|
108
102
|
return;
|
|
109
103
|
}
|
|
110
|
-
if (this.config.
|
|
111
|
-
this.config.
|
|
104
|
+
if (errors.some(transports_index.isRetryable) && attempt < this.config.maxRetries) {
|
|
105
|
+
const backoff = this.config.retryDelay * (attempt + 1);
|
|
106
|
+
await this.delay(transports_index.retryAfterMs(errors) ?? backoff);
|
|
107
|
+
return this.sendWithRetry(logs, attempt + 1);
|
|
108
|
+
}
|
|
109
|
+
const detail = errors.map(describeError).join(", ");
|
|
110
|
+
this.reportError(
|
|
111
|
+
new Error(
|
|
112
|
+
errors.some(transports_index.isRetryable) ? `Failed to send ${logs.length} logs after ${this.config.maxRetries} retries: ${detail}` : `Failed to send ${logs.length} logs: ${detail}`
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
/** Stop accepting logs after an unrecoverable authentication failure. */
|
|
117
|
+
halt(error) {
|
|
118
|
+
this.halted = true;
|
|
119
|
+
this.queue = [];
|
|
120
|
+
this.stop();
|
|
121
|
+
this.reportError(
|
|
122
|
+
new Error(
|
|
123
|
+
`VedaTrace disabled: ${describeError(error)}. Check your API key and the key's allowed origins, then call logger.start() to resume.`
|
|
124
|
+
)
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
reportError(error) {
|
|
128
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
129
|
+
if (this.config.onError) {
|
|
130
|
+
this.config.onError(normalized);
|
|
131
|
+
} else {
|
|
132
|
+
console.error("[VedaTrace]", normalized.message);
|
|
112
133
|
}
|
|
113
134
|
}
|
|
114
135
|
startFlushTimer() {
|
|
@@ -117,22 +138,11 @@ class VedaTraceBatcher {
|
|
|
117
138
|
}
|
|
118
139
|
this.flushTimer = setInterval(() => {
|
|
119
140
|
if (this.queue.length > 0) {
|
|
120
|
-
this.flush().catch((error) =>
|
|
121
|
-
if (this.config.onError) {
|
|
122
|
-
this.config.onError(
|
|
123
|
-
error instanceof Error ? error : new Error(String(error))
|
|
124
|
-
);
|
|
125
|
-
} else {
|
|
126
|
-
console.error(
|
|
127
|
-
"[VedaTrace] Flush error:",
|
|
128
|
-
error instanceof Error ? error.message : String(error)
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
});
|
|
141
|
+
this.flush().catch((error) => this.reportError(error));
|
|
132
142
|
}
|
|
133
143
|
}, this.config.flushInterval);
|
|
134
144
|
if (this.config.unrefTimer === true) {
|
|
135
|
-
this.flushTimer.unref();
|
|
145
|
+
this.flushTimer.unref?.();
|
|
136
146
|
}
|
|
137
147
|
}
|
|
138
148
|
stop() {
|
|
@@ -143,6 +153,7 @@ class VedaTraceBatcher {
|
|
|
143
153
|
this.flushQueued = false;
|
|
144
154
|
}
|
|
145
155
|
start() {
|
|
156
|
+
this.halted = false;
|
|
146
157
|
if (!this.flushTimer && !this.immediateFlush) {
|
|
147
158
|
this.startFlushTimer();
|
|
148
159
|
}
|
|
@@ -153,10 +164,17 @@ class VedaTraceBatcher {
|
|
|
153
164
|
getQueueSize() {
|
|
154
165
|
return this.queue.length;
|
|
155
166
|
}
|
|
167
|
+
/** True once an auth failure has shut the batcher down. */
|
|
168
|
+
isHalted() {
|
|
169
|
+
return this.halted;
|
|
170
|
+
}
|
|
156
171
|
setExecutionContext(ctx) {
|
|
157
172
|
this.context = ctx;
|
|
158
173
|
}
|
|
159
174
|
}
|
|
175
|
+
function describeError(error) {
|
|
176
|
+
return error instanceof Error ? error.message : String(error);
|
|
177
|
+
}
|
|
160
178
|
|
|
161
179
|
function detectRuntime() {
|
|
162
180
|
if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") {
|
|
@@ -199,7 +217,8 @@ function isBrowser() {
|
|
|
199
217
|
return detectRuntime() === "browser";
|
|
200
218
|
}
|
|
201
219
|
|
|
202
|
-
const SDK_VERSION =
|
|
220
|
+
const SDK_VERSION = "0.3.1";
|
|
221
|
+
|
|
203
222
|
class VedaTraceLogger {
|
|
204
223
|
batcher = null;
|
|
205
224
|
runtime;
|
|
@@ -352,24 +371,17 @@ class BrowserLifecycle {
|
|
|
352
371
|
this.config = config;
|
|
353
372
|
this.boundVisibilityHandler = this.handleVisibilityChange.bind(this);
|
|
354
373
|
this.boundPageHideHandler = this.handlePageHide.bind(this);
|
|
355
|
-
this.boundBeforeUnloadHandler = this.handleBeforeUnload.bind(this);
|
|
356
|
-
this.boundUnloadHandler = this.handleUnload.bind(this);
|
|
357
374
|
}
|
|
358
375
|
boundVisibilityHandler;
|
|
359
376
|
boundPageHideHandler;
|
|
360
|
-
boundBeforeUnloadHandler;
|
|
361
|
-
boundUnloadHandler;
|
|
362
377
|
isAttached = false;
|
|
363
378
|
pendingFlush = null;
|
|
364
379
|
/** Start listening for browser lifecycle events */
|
|
365
380
|
attach() {
|
|
366
381
|
if (this.isAttached) return;
|
|
367
|
-
if (typeof document
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
window.addEventListener("beforeunload", this.boundBeforeUnloadHandler);
|
|
371
|
-
window.addEventListener("unload", this.boundUnloadHandler);
|
|
372
|
-
}
|
|
382
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
383
|
+
document.addEventListener("visibilitychange", this.boundVisibilityHandler);
|
|
384
|
+
window.addEventListener("pagehide", this.boundPageHideHandler);
|
|
373
385
|
this.isAttached = true;
|
|
374
386
|
if (this.config.debug) {
|
|
375
387
|
console.log("[VedaTrace] Browser lifecycle handlers attached");
|
|
@@ -378,21 +390,25 @@ class BrowserLifecycle {
|
|
|
378
390
|
/** Stop listening for browser lifecycle events */
|
|
379
391
|
detach() {
|
|
380
392
|
if (!this.isAttached) return;
|
|
381
|
-
if (typeof document !== "undefined") {
|
|
393
|
+
if (typeof document !== "undefined" && typeof window !== "undefined") {
|
|
382
394
|
document.removeEventListener(
|
|
383
395
|
"visibilitychange",
|
|
384
396
|
this.boundVisibilityHandler
|
|
385
397
|
);
|
|
386
398
|
window.removeEventListener("pagehide", this.boundPageHideHandler);
|
|
387
|
-
window.removeEventListener("beforeunload", this.boundBeforeUnloadHandler);
|
|
388
|
-
window.removeEventListener("unload", this.boundUnloadHandler);
|
|
389
399
|
}
|
|
390
400
|
this.isAttached = false;
|
|
391
401
|
if (this.config.debug) {
|
|
392
402
|
console.log("[VedaTrace] Browser lifecycle handlers detached");
|
|
393
403
|
}
|
|
394
404
|
}
|
|
395
|
-
/**
|
|
405
|
+
/**
|
|
406
|
+
* Flush when the page becomes hidden.
|
|
407
|
+
*
|
|
408
|
+
* This is the one that actually matters: on mobile, a backgrounded tab is
|
|
409
|
+
* often discarded without ever firing pagehide, so "hidden" is the last
|
|
410
|
+
* reliable moment to ship what we have.
|
|
411
|
+
*/
|
|
396
412
|
handleVisibilityChange() {
|
|
397
413
|
if (document.visibilityState === "hidden") {
|
|
398
414
|
if (this.config.debug) {
|
|
@@ -401,7 +417,7 @@ class BrowserLifecycle {
|
|
|
401
417
|
this.scheduleFlush();
|
|
402
418
|
}
|
|
403
419
|
}
|
|
404
|
-
/**
|
|
420
|
+
/** Final flush as the page is torn down or frozen into the bfcache. */
|
|
405
421
|
handlePageHide(event) {
|
|
406
422
|
if (this.config.debug) {
|
|
407
423
|
console.log(
|
|
@@ -409,46 +425,16 @@ class BrowserLifecycle {
|
|
|
409
425
|
event.persisted ? "(cached)" : "(navigation)"
|
|
410
426
|
);
|
|
411
427
|
}
|
|
412
|
-
|
|
413
|
-
this.scheduleFlush();
|
|
414
|
-
} else {
|
|
415
|
-
this.finalFlush();
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
/** Handle beforeunload - backup flush mechanism */
|
|
419
|
-
handleBeforeUnload(event) {
|
|
420
|
-
if (this.config.debug) {
|
|
421
|
-
console.log("[VedaTrace] Before unload event");
|
|
422
|
-
}
|
|
423
|
-
this.finalFlush();
|
|
424
|
-
}
|
|
425
|
-
/** Handle unload - fallback for older browsers */
|
|
426
|
-
handleUnload() {
|
|
427
|
-
if (this.config.debug) {
|
|
428
|
-
console.log("[VedaTrace] Unload event");
|
|
429
|
-
}
|
|
430
|
-
this.finalFlush();
|
|
428
|
+
this.scheduleFlush();
|
|
431
429
|
}
|
|
432
|
-
/**
|
|
430
|
+
/** Flush at most once at a time; keepalive carries it past the document. */
|
|
433
431
|
scheduleFlush() {
|
|
434
432
|
if (this.pendingFlush) return;
|
|
435
|
-
this.pendingFlush = this.config.flush().
|
|
433
|
+
this.pendingFlush = this.config.flush().catch(() => {
|
|
434
|
+
}).finally(() => {
|
|
436
435
|
this.pendingFlush = null;
|
|
437
436
|
});
|
|
438
437
|
}
|
|
439
|
-
/**
|
|
440
|
-
* Final flush using keepalive fetch
|
|
441
|
-
* For sending logs after the page context is destroyed
|
|
442
|
-
*/
|
|
443
|
-
finalFlush() {
|
|
444
|
-
for (const transport of this.config.transports) {
|
|
445
|
-
if (transport.name === "http" && "flush" in transport) {
|
|
446
|
-
transport.flush?.();
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
this.config.flush().catch(() => {
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
438
|
/** Check if handlers are attached */
|
|
453
439
|
isActive() {
|
|
454
440
|
return this.isAttached;
|
|
@@ -529,6 +515,16 @@ function redactPii(value, mask) {
|
|
|
529
515
|
return result;
|
|
530
516
|
}
|
|
531
517
|
|
|
518
|
+
function resolveApiKey(config) {
|
|
519
|
+
if (config.apiKey) return config.apiKey;
|
|
520
|
+
try {
|
|
521
|
+
if (typeof process !== "undefined" && process.env) {
|
|
522
|
+
return process.env.VEDATRACE_API_KEY || void 0;
|
|
523
|
+
}
|
|
524
|
+
} catch {
|
|
525
|
+
}
|
|
526
|
+
return void 0;
|
|
527
|
+
}
|
|
532
528
|
const RUNTIME_FLUSH_INTERVALS = {
|
|
533
529
|
node: 3e3,
|
|
534
530
|
bun: 3e3,
|
|
@@ -539,14 +535,15 @@ const RUNTIME_FLUSH_INTERVALS = {
|
|
|
539
535
|
};
|
|
540
536
|
function vedatrace(config = {}) {
|
|
541
537
|
const runtime = detectRuntime();
|
|
542
|
-
const
|
|
543
|
-
|
|
538
|
+
const apiKey = resolveApiKey(config);
|
|
539
|
+
const logger = new VedaTraceLogger(apiKey ? { ...config, apiKey } : config);
|
|
540
|
+
if (apiKey && (!config.transports || config.transports.length === 0)) {
|
|
544
541
|
const isBrowserEnv = isBrowser();
|
|
545
542
|
const isServerlessEnv = isServerless();
|
|
546
543
|
const isLongRunningEnv = isLongRunning();
|
|
547
544
|
const HttpTransport = isBrowserEnv ? transports_index.VedaTraceHttpTransportBrowser : transports_index.VedaTraceHttpTransport;
|
|
548
545
|
const httpConfig = {
|
|
549
|
-
apiKey
|
|
546
|
+
apiKey,
|
|
550
547
|
keepalive: isBrowserEnv || isServerlessEnv
|
|
551
548
|
};
|
|
552
549
|
if (config.endpoint) httpConfig.endpoint = config.endpoint;
|
|
@@ -616,7 +613,9 @@ function devVedatrace(config = {}) {
|
|
|
616
613
|
exports.VedaTraceConsoleTransport = transports_index.VedaTraceConsoleTransport;
|
|
617
614
|
exports.VedaTraceHttpTransport = transports_index.VedaTraceHttpTransport;
|
|
618
615
|
exports.VedaTraceHttpTransportBrowser = transports_index.VedaTraceHttpTransportBrowser;
|
|
616
|
+
exports.VedaTraceTransportError = transports_index.VedaTraceTransportError;
|
|
619
617
|
exports.BrowserLifecycle = BrowserLifecycle;
|
|
618
|
+
exports.SDK_VERSION = SDK_VERSION;
|
|
620
619
|
exports.VedaTraceBatcher = VedaTraceBatcher;
|
|
621
620
|
exports.VedaTraceLogger = VedaTraceLogger;
|
|
622
621
|
exports.default = vedatrace;
|
package/dist/index.d.cts
CHANGED
|
@@ -22,6 +22,12 @@ declare class VedaTraceBatcher {
|
|
|
22
22
|
private pendingFlush;
|
|
23
23
|
private context;
|
|
24
24
|
private waitUntilFn;
|
|
25
|
+
/**
|
|
26
|
+
* Set when the ingestion endpoint rejects our credentials. Every subsequent
|
|
27
|
+
* batch would fail identically, so we stop rather than spend a request (and a
|
|
28
|
+
* retry storm) per flush for the life of the process. start() clears it.
|
|
29
|
+
*/
|
|
30
|
+
private halted;
|
|
25
31
|
constructor(transports: VedaTraceTransport[], config: BatcherConfig, immediateFlush?: boolean);
|
|
26
32
|
setContext(ctx: VedaTraceEdgeContext): void;
|
|
27
33
|
getContext(): VedaTraceEdgeContext | undefined;
|
|
@@ -29,14 +35,45 @@ declare class VedaTraceBatcher {
|
|
|
29
35
|
private debouncedFlush;
|
|
30
36
|
flush(): Promise<void>;
|
|
31
37
|
private sendWithRetry;
|
|
38
|
+
/** Stop accepting logs after an unrecoverable authentication failure. */
|
|
39
|
+
private halt;
|
|
40
|
+
private reportError;
|
|
32
41
|
private startFlushTimer;
|
|
33
42
|
stop(): void;
|
|
34
43
|
start(): void;
|
|
35
44
|
private delay;
|
|
36
45
|
getQueueSize(): number;
|
|
46
|
+
/** True once an auth failure has shut the batcher down. */
|
|
47
|
+
isHalted(): boolean;
|
|
37
48
|
setExecutionContext(ctx: VedaTraceEdgeContext): void;
|
|
38
49
|
}
|
|
39
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Transport error types
|
|
53
|
+
*
|
|
54
|
+
* The batcher needs to tell three cases apart:
|
|
55
|
+
* - retryable (network blip, timeout, 429, 5xx) — back off and try again
|
|
56
|
+
* - permanent (400 malformed batch) — retrying wastes the caller's time
|
|
57
|
+
* - fatal (401/403 bad key or blocked origin) — every future batch will
|
|
58
|
+
* fail the same way, so stop instead of burning a request per flush
|
|
59
|
+
*/
|
|
60
|
+
declare class VedaTraceTransportError extends Error {
|
|
61
|
+
readonly name = "VedaTraceTransportError";
|
|
62
|
+
readonly status: number | undefined;
|
|
63
|
+
readonly retryable: boolean;
|
|
64
|
+
readonly fatal: boolean;
|
|
65
|
+
/** Server-requested backoff from a `Retry-After` header, in milliseconds. */
|
|
66
|
+
readonly retryAfterMs: number | undefined;
|
|
67
|
+
constructor(message: string, options?: {
|
|
68
|
+
status?: number;
|
|
69
|
+
retryable?: boolean;
|
|
70
|
+
fatal?: boolean;
|
|
71
|
+
retryAfterMs?: number;
|
|
72
|
+
});
|
|
73
|
+
/** Build an error from an HTTP response status. */
|
|
74
|
+
static fromStatus(status: number, body: string, retryAfterMs?: number): VedaTraceTransportError;
|
|
75
|
+
}
|
|
76
|
+
|
|
40
77
|
/**
|
|
41
78
|
* Core VedaTrace Logger implementation
|
|
42
79
|
* Supports Cloudflare Workers / Pages via withContext() integration
|
|
@@ -73,12 +110,17 @@ declare class VedaTraceLogger implements VedaTraceLoggerInterface {
|
|
|
73
110
|
* Browser lifecycle management for VedaTrace
|
|
74
111
|
*
|
|
75
112
|
* Handles:
|
|
76
|
-
* - visibilitychange: flush when page becomes hidden
|
|
77
|
-
* - pagehide: final flush when
|
|
78
|
-
* - beforeunload: backup flush before page unload
|
|
113
|
+
* - visibilitychange: flush when the page becomes hidden
|
|
114
|
+
* - pagehide: final flush when the page goes away
|
|
79
115
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
116
|
+
* `beforeunload` and `unload` are deliberately not used. Registering either one
|
|
117
|
+
* makes Chrome and Safari ineligible for the back/forward cache, so a logging
|
|
118
|
+
* SDK that listens for them measurably slows down every back-navigation in the
|
|
119
|
+
* host app. `visibilitychange` + `pagehide` covers every case they did,
|
|
120
|
+
* including Safari, and is the pair the browsers themselves recommend.
|
|
121
|
+
*
|
|
122
|
+
* The final flush goes out through the batcher's normal HTTP transport, which
|
|
123
|
+
* sets `keepalive: true` in the browser so the request outlives the document.
|
|
82
124
|
*/
|
|
83
125
|
|
|
84
126
|
interface BrowserLifecycleConfig {
|
|
@@ -94,8 +136,6 @@ declare class BrowserLifecycle {
|
|
|
94
136
|
private config;
|
|
95
137
|
private boundVisibilityHandler;
|
|
96
138
|
private boundPageHideHandler;
|
|
97
|
-
private boundBeforeUnloadHandler;
|
|
98
|
-
private boundUnloadHandler;
|
|
99
139
|
private isAttached;
|
|
100
140
|
private pendingFlush;
|
|
101
141
|
constructor(config: BrowserLifecycleConfig);
|
|
@@ -103,21 +143,18 @@ declare class BrowserLifecycle {
|
|
|
103
143
|
attach(): void;
|
|
104
144
|
/** Stop listening for browser lifecycle events */
|
|
105
145
|
detach(): void;
|
|
106
|
-
/**
|
|
146
|
+
/**
|
|
147
|
+
* Flush when the page becomes hidden.
|
|
148
|
+
*
|
|
149
|
+
* This is the one that actually matters: on mobile, a backgrounded tab is
|
|
150
|
+
* often discarded without ever firing pagehide, so "hidden" is the last
|
|
151
|
+
* reliable moment to ship what we have.
|
|
152
|
+
*/
|
|
107
153
|
private handleVisibilityChange;
|
|
108
|
-
/**
|
|
154
|
+
/** Final flush as the page is torn down or frozen into the bfcache. */
|
|
109
155
|
private handlePageHide;
|
|
110
|
-
/**
|
|
111
|
-
private handleBeforeUnload;
|
|
112
|
-
/** Handle unload - fallback for older browsers */
|
|
113
|
-
private handleUnload;
|
|
114
|
-
/** Schedule a debounced flush (for visibility change) */
|
|
156
|
+
/** Flush at most once at a time; keepalive carries it past the document. */
|
|
115
157
|
private scheduleFlush;
|
|
116
|
-
/**
|
|
117
|
-
* Final flush using keepalive fetch
|
|
118
|
-
* For sending logs after the page context is destroyed
|
|
119
|
-
*/
|
|
120
|
-
private finalFlush;
|
|
121
158
|
/** Check if handlers are attached */
|
|
122
159
|
isActive(): boolean;
|
|
123
160
|
}
|
|
@@ -142,6 +179,21 @@ declare function isServerless(): boolean;
|
|
|
142
179
|
declare function isLongRunning(): boolean;
|
|
143
180
|
declare function isBrowser(): boolean;
|
|
144
181
|
|
|
182
|
+
/**
|
|
183
|
+
* SDK version, inlined at build time.
|
|
184
|
+
*
|
|
185
|
+
* This file is generated by `scripts/sync-version.mjs` from package.json and is
|
|
186
|
+
* checked in so type-checking and tests work without a build step. Do not edit
|
|
187
|
+
* it by hand — `bun run build` and `changeset version` both regenerate it, and
|
|
188
|
+
* a test asserts it matches package.json.
|
|
189
|
+
*
|
|
190
|
+
* It exists because the previous `process.env.npm_package_version` read was
|
|
191
|
+
* wrong twice over: npm only sets that variable for its own lifecycle scripts,
|
|
192
|
+
* so it was always undefined for consumers, and the bare `process` reference
|
|
193
|
+
* survived bundling and threw a ReferenceError in browsers.
|
|
194
|
+
*/
|
|
195
|
+
declare const SDK_VERSION = "0.3.1";
|
|
196
|
+
|
|
145
197
|
/**
|
|
146
198
|
* VedaTrace SDK - Universal JavaScript logging
|
|
147
199
|
*
|
|
@@ -182,4 +234,4 @@ declare function vedatrace(config?: VedaTraceConfig): VedaTraceLoggerInterface;
|
|
|
182
234
|
*/
|
|
183
235
|
declare function devVedatrace(config?: Omit<VedaTraceConfig, "apiKey" | "transports">): VedaTraceLoggerInterface;
|
|
184
236
|
|
|
185
|
-
export { BatcherConfig, BrowserLifecycle, InternalLogEntry, LogMetadata, RedactionConfig, RuntimeType$1 as RuntimeType, VedaTraceBatcher, VedaTraceConfig, VedaTraceEdgeContext, VedaTraceLogger, VedaTraceLoggerInterface, VedaTraceTransport, vedatrace as default, detectRuntime, devVedatrace, isBrowser, isEdgeRuntime, isLongRunning, isServerless, redact, vedatrace };
|
|
237
|
+
export { BatcherConfig, BrowserLifecycle, InternalLogEntry, LogMetadata, RedactionConfig, RuntimeType$1 as RuntimeType, SDK_VERSION, VedaTraceBatcher, VedaTraceConfig, VedaTraceEdgeContext, VedaTraceLogger, VedaTraceLoggerInterface, VedaTraceTransport, VedaTraceTransportError, vedatrace as default, detectRuntime, devVedatrace, isBrowser, isEdgeRuntime, isLongRunning, isServerless, redact, vedatrace };
|
package/dist/index.d.mts
CHANGED
|
@@ -22,6 +22,12 @@ declare class VedaTraceBatcher {
|
|
|
22
22
|
private pendingFlush;
|
|
23
23
|
private context;
|
|
24
24
|
private waitUntilFn;
|
|
25
|
+
/**
|
|
26
|
+
* Set when the ingestion endpoint rejects our credentials. Every subsequent
|
|
27
|
+
* batch would fail identically, so we stop rather than spend a request (and a
|
|
28
|
+
* retry storm) per flush for the life of the process. start() clears it.
|
|
29
|
+
*/
|
|
30
|
+
private halted;
|
|
25
31
|
constructor(transports: VedaTraceTransport[], config: BatcherConfig, immediateFlush?: boolean);
|
|
26
32
|
setContext(ctx: VedaTraceEdgeContext): void;
|
|
27
33
|
getContext(): VedaTraceEdgeContext | undefined;
|
|
@@ -29,14 +35,45 @@ declare class VedaTraceBatcher {
|
|
|
29
35
|
private debouncedFlush;
|
|
30
36
|
flush(): Promise<void>;
|
|
31
37
|
private sendWithRetry;
|
|
38
|
+
/** Stop accepting logs after an unrecoverable authentication failure. */
|
|
39
|
+
private halt;
|
|
40
|
+
private reportError;
|
|
32
41
|
private startFlushTimer;
|
|
33
42
|
stop(): void;
|
|
34
43
|
start(): void;
|
|
35
44
|
private delay;
|
|
36
45
|
getQueueSize(): number;
|
|
46
|
+
/** True once an auth failure has shut the batcher down. */
|
|
47
|
+
isHalted(): boolean;
|
|
37
48
|
setExecutionContext(ctx: VedaTraceEdgeContext): void;
|
|
38
49
|
}
|
|
39
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Transport error types
|
|
53
|
+
*
|
|
54
|
+
* The batcher needs to tell three cases apart:
|
|
55
|
+
* - retryable (network blip, timeout, 429, 5xx) — back off and try again
|
|
56
|
+
* - permanent (400 malformed batch) — retrying wastes the caller's time
|
|
57
|
+
* - fatal (401/403 bad key or blocked origin) — every future batch will
|
|
58
|
+
* fail the same way, so stop instead of burning a request per flush
|
|
59
|
+
*/
|
|
60
|
+
declare class VedaTraceTransportError extends Error {
|
|
61
|
+
readonly name = "VedaTraceTransportError";
|
|
62
|
+
readonly status: number | undefined;
|
|
63
|
+
readonly retryable: boolean;
|
|
64
|
+
readonly fatal: boolean;
|
|
65
|
+
/** Server-requested backoff from a `Retry-After` header, in milliseconds. */
|
|
66
|
+
readonly retryAfterMs: number | undefined;
|
|
67
|
+
constructor(message: string, options?: {
|
|
68
|
+
status?: number;
|
|
69
|
+
retryable?: boolean;
|
|
70
|
+
fatal?: boolean;
|
|
71
|
+
retryAfterMs?: number;
|
|
72
|
+
});
|
|
73
|
+
/** Build an error from an HTTP response status. */
|
|
74
|
+
static fromStatus(status: number, body: string, retryAfterMs?: number): VedaTraceTransportError;
|
|
75
|
+
}
|
|
76
|
+
|
|
40
77
|
/**
|
|
41
78
|
* Core VedaTrace Logger implementation
|
|
42
79
|
* Supports Cloudflare Workers / Pages via withContext() integration
|
|
@@ -73,12 +110,17 @@ declare class VedaTraceLogger implements VedaTraceLoggerInterface {
|
|
|
73
110
|
* Browser lifecycle management for VedaTrace
|
|
74
111
|
*
|
|
75
112
|
* Handles:
|
|
76
|
-
* - visibilitychange: flush when page becomes hidden
|
|
77
|
-
* - pagehide: final flush when
|
|
78
|
-
* - beforeunload: backup flush before page unload
|
|
113
|
+
* - visibilitychange: flush when the page becomes hidden
|
|
114
|
+
* - pagehide: final flush when the page goes away
|
|
79
115
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
116
|
+
* `beforeunload` and `unload` are deliberately not used. Registering either one
|
|
117
|
+
* makes Chrome and Safari ineligible for the back/forward cache, so a logging
|
|
118
|
+
* SDK that listens for them measurably slows down every back-navigation in the
|
|
119
|
+
* host app. `visibilitychange` + `pagehide` covers every case they did,
|
|
120
|
+
* including Safari, and is the pair the browsers themselves recommend.
|
|
121
|
+
*
|
|
122
|
+
* The final flush goes out through the batcher's normal HTTP transport, which
|
|
123
|
+
* sets `keepalive: true` in the browser so the request outlives the document.
|
|
82
124
|
*/
|
|
83
125
|
|
|
84
126
|
interface BrowserLifecycleConfig {
|
|
@@ -94,8 +136,6 @@ declare class BrowserLifecycle {
|
|
|
94
136
|
private config;
|
|
95
137
|
private boundVisibilityHandler;
|
|
96
138
|
private boundPageHideHandler;
|
|
97
|
-
private boundBeforeUnloadHandler;
|
|
98
|
-
private boundUnloadHandler;
|
|
99
139
|
private isAttached;
|
|
100
140
|
private pendingFlush;
|
|
101
141
|
constructor(config: BrowserLifecycleConfig);
|
|
@@ -103,21 +143,18 @@ declare class BrowserLifecycle {
|
|
|
103
143
|
attach(): void;
|
|
104
144
|
/** Stop listening for browser lifecycle events */
|
|
105
145
|
detach(): void;
|
|
106
|
-
/**
|
|
146
|
+
/**
|
|
147
|
+
* Flush when the page becomes hidden.
|
|
148
|
+
*
|
|
149
|
+
* This is the one that actually matters: on mobile, a backgrounded tab is
|
|
150
|
+
* often discarded without ever firing pagehide, so "hidden" is the last
|
|
151
|
+
* reliable moment to ship what we have.
|
|
152
|
+
*/
|
|
107
153
|
private handleVisibilityChange;
|
|
108
|
-
/**
|
|
154
|
+
/** Final flush as the page is torn down or frozen into the bfcache. */
|
|
109
155
|
private handlePageHide;
|
|
110
|
-
/**
|
|
111
|
-
private handleBeforeUnload;
|
|
112
|
-
/** Handle unload - fallback for older browsers */
|
|
113
|
-
private handleUnload;
|
|
114
|
-
/** Schedule a debounced flush (for visibility change) */
|
|
156
|
+
/** Flush at most once at a time; keepalive carries it past the document. */
|
|
115
157
|
private scheduleFlush;
|
|
116
|
-
/**
|
|
117
|
-
* Final flush using keepalive fetch
|
|
118
|
-
* For sending logs after the page context is destroyed
|
|
119
|
-
*/
|
|
120
|
-
private finalFlush;
|
|
121
158
|
/** Check if handlers are attached */
|
|
122
159
|
isActive(): boolean;
|
|
123
160
|
}
|
|
@@ -142,6 +179,21 @@ declare function isServerless(): boolean;
|
|
|
142
179
|
declare function isLongRunning(): boolean;
|
|
143
180
|
declare function isBrowser(): boolean;
|
|
144
181
|
|
|
182
|
+
/**
|
|
183
|
+
* SDK version, inlined at build time.
|
|
184
|
+
*
|
|
185
|
+
* This file is generated by `scripts/sync-version.mjs` from package.json and is
|
|
186
|
+
* checked in so type-checking and tests work without a build step. Do not edit
|
|
187
|
+
* it by hand — `bun run build` and `changeset version` both regenerate it, and
|
|
188
|
+
* a test asserts it matches package.json.
|
|
189
|
+
*
|
|
190
|
+
* It exists because the previous `process.env.npm_package_version` read was
|
|
191
|
+
* wrong twice over: npm only sets that variable for its own lifecycle scripts,
|
|
192
|
+
* so it was always undefined for consumers, and the bare `process` reference
|
|
193
|
+
* survived bundling and threw a ReferenceError in browsers.
|
|
194
|
+
*/
|
|
195
|
+
declare const SDK_VERSION = "0.3.1";
|
|
196
|
+
|
|
145
197
|
/**
|
|
146
198
|
* VedaTrace SDK - Universal JavaScript logging
|
|
147
199
|
*
|
|
@@ -182,4 +234,4 @@ declare function vedatrace(config?: VedaTraceConfig): VedaTraceLoggerInterface;
|
|
|
182
234
|
*/
|
|
183
235
|
declare function devVedatrace(config?: Omit<VedaTraceConfig, "apiKey" | "transports">): VedaTraceLoggerInterface;
|
|
184
236
|
|
|
185
|
-
export { BatcherConfig, BrowserLifecycle, InternalLogEntry, LogMetadata, RedactionConfig, RuntimeType$1 as RuntimeType, VedaTraceBatcher, VedaTraceConfig, VedaTraceEdgeContext, VedaTraceLogger, VedaTraceLoggerInterface, VedaTraceTransport, vedatrace as default, detectRuntime, devVedatrace, isBrowser, isEdgeRuntime, isLongRunning, isServerless, redact, vedatrace };
|
|
237
|
+
export { BatcherConfig, BrowserLifecycle, InternalLogEntry, LogMetadata, RedactionConfig, RuntimeType$1 as RuntimeType, SDK_VERSION, VedaTraceBatcher, VedaTraceConfig, VedaTraceEdgeContext, VedaTraceLogger, VedaTraceLoggerInterface, VedaTraceTransport, VedaTraceTransportError, vedatrace as default, detectRuntime, devVedatrace, isBrowser, isEdgeRuntime, isLongRunning, isServerless, redact, vedatrace };
|