@loggerjs/browser 0.5.6 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -16
- package/dist/chunks/http-capture-utils-DbhpUirh.cjs +83 -0
- package/dist/chunks/http-capture-utils-DbhpUirh.cjs.map +1 -0
- package/dist/chunks/http-capture-utils-_hG5wepA.js +48 -0
- package/dist/chunks/http-capture-utils-_hG5wepA.js.map +1 -0
- package/dist/context-propagation-integration.cjs +5 -4
- package/dist/context-propagation-integration.cjs.map +1 -1
- package/dist/context-propagation-integration.d.ts +2 -1
- package/dist/context-propagation-integration.d.ts.map +1 -1
- package/dist/context-propagation-integration.js +2 -1
- package/dist/context-propagation-integration.js.map +1 -1
- package/dist/fetch-integration.cjs +8 -52
- package/dist/fetch-integration.cjs.map +1 -1
- package/dist/fetch-integration.js +1 -45
- package/dist/fetch-integration.js.map +1 -1
- package/dist/http-transport.cjs +121 -29
- package/dist/http-transport.cjs.map +1 -1
- package/dist/http-transport.d.ts +18 -0
- package/dist/http-transport.d.ts.map +1 -1
- package/dist/http-transport.js +121 -29
- package/dist/http-transport.js.map +1 -1
- package/dist/index.cjs +58 -4148
- package/dist/index.d.ts +243 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -4116
- package/dist/indexeddb-offline-queue.cjs +8 -1
- package/dist/indexeddb-offline-queue.cjs.map +1 -1
- package/dist/indexeddb-offline-queue.d.ts.map +1 -1
- package/dist/indexeddb-offline-queue.js +8 -1
- package/dist/indexeddb-offline-queue.js.map +1 -1
- package/dist/indexeddb-transport.cjs +24 -4
- package/dist/indexeddb-transport.cjs.map +1 -1
- package/dist/indexeddb-transport.d.ts.map +1 -1
- package/dist/indexeddb-transport.js +24 -4
- package/dist/indexeddb-transport.js.map +1 -1
- package/dist/offline-first-transport.cjs +3 -1029
- package/dist/offline-first-transport.cjs.map +1 -1
- package/dist/offline-first-transport.d.ts.map +1 -1
- package/dist/offline-first-transport.js +3 -1029
- package/dist/offline-first-transport.js.map +1 -1
- package/dist/payload-transforms.cjs +3 -3
- package/dist/payload-transforms.cjs.map +1 -1
- package/dist/payload-transforms.d.ts.map +1 -1
- package/dist/payload-transforms.js +1 -1
- package/dist/payload-transforms.js.map +1 -1
- package/dist/websocket-integration.cjs +5 -32
- package/dist/websocket-integration.cjs.map +1 -1
- package/dist/websocket-integration.js +1 -28
- package/dist/websocket-integration.js.map +1 -1
- package/dist/websocket-transport.cjs +1 -1
- package/dist/websocket-transport.cjs.map +1 -1
- package/dist/websocket-transport.js +2 -2
- package/dist/websocket-transport.js.map +1 -1
- package/dist/xhr-integration.cjs +6 -33
- package/dist/xhr-integration.cjs.map +1 -1
- package/dist/xhr-integration.js +1 -28
- package/dist/xhr-integration.js.map +1 -1
- package/package.json +5 -2
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/http-transport.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
+
let _loggerjs_core_payload_transforms = require("@loggerjs/core/payload-transforms");
|
|
3
4
|
//#region src/http-transport.ts
|
|
4
5
|
const DEFAULT_BEACON_MAX_BYTES = 60 * 1024;
|
|
5
6
|
const sleep = (delayMs) => delayMs <= 0 ? Promise.resolve() : new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
@@ -57,13 +58,30 @@ function remainingEvents(chunks, startIndex) {
|
|
|
57
58
|
}
|
|
58
59
|
return events;
|
|
59
60
|
}
|
|
61
|
+
function idempotencyKeyHeaders(header) {
|
|
62
|
+
if (!header) return () => void 0;
|
|
63
|
+
new Headers().append(header, "");
|
|
64
|
+
const prefix = Array.from(crypto.getRandomValues(new Uint32Array(2)), (word) => word.toString(36)).join("");
|
|
65
|
+
const keys = /* @__PURE__ */ new WeakMap();
|
|
66
|
+
let next = 0;
|
|
67
|
+
return (events) => {
|
|
68
|
+
const last = events[events.length - 1];
|
|
69
|
+
let key = keys.get(last);
|
|
70
|
+
if (key === void 0) {
|
|
71
|
+
key = `${prefix}-${(next++).toString(36)}`;
|
|
72
|
+
keys.set(last, key);
|
|
73
|
+
}
|
|
74
|
+
return { [header]: key };
|
|
75
|
+
};
|
|
76
|
+
}
|
|
60
77
|
function browserHttpTransport(options) {
|
|
61
|
-
const codec = options.codec ?? (0, _loggerjs_core.
|
|
78
|
+
const codec = options.codec ?? (0, _loggerjs_core.safeJsonEncoder)();
|
|
62
79
|
const beaconCodec = options.beaconCodec ?? codec;
|
|
63
80
|
const queue = [];
|
|
64
81
|
const maxBatchSize = options.maxBatchSize ?? 50;
|
|
65
82
|
if (!Number.isSafeInteger(maxBatchSize) || maxBatchSize <= 0) throw new RangeError("maxBatchSize must be a positive safe integer");
|
|
66
83
|
const flushIntervalMs = options.flushIntervalMs ?? 2e3;
|
|
84
|
+
const keyHeaders = idempotencyKeyHeaders(options.idempotencyKeyHeader);
|
|
67
85
|
const maxQueueSize = options.maxQueueSize ?? 1e3;
|
|
68
86
|
const dropPolicy = options.dropPolicy ?? "drop-oldest";
|
|
69
87
|
const beaconMaxBytes = options.beaconMaxBytes ?? DEFAULT_BEACON_MAX_BYTES;
|
|
@@ -73,11 +91,16 @@ function browserHttpTransport(options) {
|
|
|
73
91
|
const offlineReplayMaxDelayMs = options.offlineReplayMaxDelayMs ?? 5e3;
|
|
74
92
|
const random = options.random ?? Math.random;
|
|
75
93
|
const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);
|
|
94
|
+
const timeoutMs = options.timeoutMs ?? 1e4;
|
|
76
95
|
let offlineEntrySeq = 0;
|
|
96
|
+
let closed = false;
|
|
97
|
+
let retryNotBefore = 0;
|
|
98
|
+
let replayTimer;
|
|
77
99
|
let timer;
|
|
78
100
|
let activeFlush;
|
|
79
101
|
let flushingBeacon = false;
|
|
80
|
-
let
|
|
102
|
+
let replayPromise;
|
|
103
|
+
let heldBatchSize = 0;
|
|
81
104
|
let lastContext;
|
|
82
105
|
const headers = (payloadHeaders, contentType = codec.contentType) => ({
|
|
83
106
|
"content-type": contentType,
|
|
@@ -149,13 +172,18 @@ function browserHttpTransport(options) {
|
|
|
149
172
|
const chunk = chunks[index];
|
|
150
173
|
if (!chunk) continue;
|
|
151
174
|
try {
|
|
152
|
-
if (!navigator.sendBeacon(options.url, payloadToBeaconBody(chunk.payload, beaconCodec.contentType)))
|
|
175
|
+
if (!navigator.sendBeacon(options.url, payloadToBeaconBody(chunk.payload, beaconCodec.contentType))) {
|
|
176
|
+
(0, _loggerjs_core.incrementLoggerMetaCounter)("transport.beacon.rejected", chunk.events.length);
|
|
177
|
+
return { remaining: remainingEvents(chunks, index) };
|
|
178
|
+
}
|
|
153
179
|
} catch (error) {
|
|
180
|
+
(0, _loggerjs_core.incrementLoggerMetaCounter)("transport.beacon.rejected", chunk.events.length);
|
|
154
181
|
return {
|
|
155
182
|
remaining: remainingEvents(chunks, index),
|
|
156
183
|
failure: { error }
|
|
157
184
|
};
|
|
158
185
|
}
|
|
186
|
+
(0, _loggerjs_core.incrementLoggerMetaCounter)("transport.beacon.accepted", chunk.events.length);
|
|
159
187
|
}
|
|
160
188
|
return { remaining: [] };
|
|
161
189
|
};
|
|
@@ -166,12 +194,13 @@ function browserHttpTransport(options) {
|
|
|
166
194
|
headers: entry.headers,
|
|
167
195
|
body: payloadToBody(entry.body),
|
|
168
196
|
credentials: entry.credentials,
|
|
169
|
-
keepalive: entry.keepalive
|
|
197
|
+
keepalive: entry.keepalive,
|
|
198
|
+
signal: timeoutMs > 0 && typeof AbortSignal?.timeout === "function" ? AbortSignal.timeout(timeoutMs) : void 0
|
|
170
199
|
});
|
|
171
|
-
if (!response.ok) throw
|
|
200
|
+
if (!response.ok) throw (0, _loggerjs_core.httpStatusError)("browserHttpTransport", response);
|
|
172
201
|
};
|
|
173
202
|
const encodeTransformedPayload = async (batch) => {
|
|
174
|
-
return (0,
|
|
203
|
+
return (0, _loggerjs_core_payload_transforms.applyPayloadTransforms)(codec.encode(batch), {
|
|
175
204
|
contentType: codec.contentType,
|
|
176
205
|
events: batch,
|
|
177
206
|
transport: options.name ?? "browser-http"
|
|
@@ -193,20 +222,33 @@ function browserHttpTransport(options) {
|
|
|
193
222
|
(0, _loggerjs_core.incrementLoggerMetaCounter)("transport.offline.queued");
|
|
194
223
|
return true;
|
|
195
224
|
};
|
|
225
|
+
const isOnline = () => typeof navigator === "undefined" || navigator.onLine !== false;
|
|
196
226
|
const sendFetchBatch = async (batch) => {
|
|
197
|
-
if (batch.length === 0) return;
|
|
198
227
|
const transformed = await encodeTransformedPayload(batch);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
228
|
+
const payloadHeaders = {
|
|
229
|
+
...transformed.headers,
|
|
230
|
+
...keyHeaders(batch)
|
|
231
|
+
};
|
|
232
|
+
if (offlineQueue && !isOnline()) {
|
|
233
|
+
await enqueueOfflinePayload(transformed.payload, payloadHeaders, transformed.contentType);
|
|
234
|
+
return "queued";
|
|
202
235
|
}
|
|
203
236
|
try {
|
|
204
|
-
await sendPayload(createOfflineEntry(transformed.payload,
|
|
237
|
+
await sendPayload(createOfflineEntry(transformed.payload, payloadHeaders, transformed.contentType));
|
|
238
|
+
return "sent";
|
|
205
239
|
} catch (error) {
|
|
206
|
-
|
|
240
|
+
noteRetryAfter(error);
|
|
241
|
+
if (await enqueueOfflinePayload(transformed.payload, payloadHeaders, transformed.contentType)) return "queued";
|
|
207
242
|
throw error;
|
|
208
243
|
}
|
|
209
244
|
};
|
|
245
|
+
const retryWaitMs = () => Math.max(0, retryNotBefore - Date.now());
|
|
246
|
+
const noteRetryAfter = (error) => {
|
|
247
|
+
const retryAfterMs = error?.retryAfterMs;
|
|
248
|
+
if (typeof retryAfterMs !== "number" || !(retryAfterMs >= 0)) return void 0;
|
|
249
|
+
retryNotBefore = Math.max(retryNotBefore, Date.now() + retryAfterMs);
|
|
250
|
+
return retryAfterMs;
|
|
251
|
+
};
|
|
210
252
|
const replayRetryDelay = (attempt) => {
|
|
211
253
|
const cap = Math.min(offlineReplayMaxDelayMs, offlineReplayBaseDelayMs * 2 ** attempt);
|
|
212
254
|
return cap <= 0 ? 0 : random() * cap;
|
|
@@ -217,33 +259,54 @@ function browserHttpTransport(options) {
|
|
|
217
259
|
(0, _loggerjs_core.incrementLoggerMetaCounter)("transport.offline.replayed");
|
|
218
260
|
return;
|
|
219
261
|
} catch (error) {
|
|
220
|
-
|
|
262
|
+
const retryAfterMs = noteRetryAfter(error);
|
|
263
|
+
if (attempt >= offlineReplayMaxRetries || (retryAfterMs ?? 0) > offlineReplayMaxDelayMs) {
|
|
221
264
|
(0, _loggerjs_core.incrementLoggerMetaCounter)("transport.offline.replay.failed");
|
|
222
265
|
throw error;
|
|
223
266
|
}
|
|
224
267
|
(0, _loggerjs_core.incrementLoggerMetaCounter)("transport.offline.retry");
|
|
225
|
-
await sleep(replayRetryDelay(attempt));
|
|
268
|
+
await sleep(Math.max(replayRetryDelay(attempt), retryAfterMs ?? 0));
|
|
226
269
|
}
|
|
227
270
|
};
|
|
228
|
-
const replayOfflineQueue =
|
|
229
|
-
if (!offlineQueue
|
|
230
|
-
|
|
271
|
+
const replayOfflineQueue = () => {
|
|
272
|
+
if (!offlineQueue) return Promise.resolve();
|
|
273
|
+
replayPromise ??= (async () => {
|
|
274
|
+
try {
|
|
275
|
+
await offlineQueue.replay(sendOfflineEntryWithRetry);
|
|
276
|
+
} finally {
|
|
277
|
+
replayPromise = void 0;
|
|
278
|
+
}
|
|
279
|
+
})();
|
|
280
|
+
return replayPromise;
|
|
281
|
+
};
|
|
282
|
+
const replayOfflineQueueSafely = async (operation) => {
|
|
283
|
+
if (!offlineQueue || !isOnline()) return;
|
|
284
|
+
const waitMs = retryWaitMs();
|
|
285
|
+
if (waitMs > 0) {
|
|
286
|
+
if (!closed && replayTimer === void 0) replayTimer = setTimeout(() => {
|
|
287
|
+
replayTimer = void 0;
|
|
288
|
+
replayOfflineQueueSafely(operation);
|
|
289
|
+
}, waitMs);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
231
292
|
try {
|
|
232
|
-
await
|
|
233
|
-
}
|
|
234
|
-
|
|
293
|
+
await replayOfflineQueue();
|
|
294
|
+
} catch (error) {
|
|
295
|
+
reportInternalError(error, operation);
|
|
235
296
|
}
|
|
236
297
|
};
|
|
237
298
|
const flushBeaconQueue = () => {
|
|
238
299
|
if (flushingBeacon || options.transformPayload || queue.length === 0) return;
|
|
239
300
|
flushingBeacon = true;
|
|
240
|
-
|
|
301
|
+
const taken = queue.length;
|
|
302
|
+
let pending = queue.splice(0, taken);
|
|
241
303
|
try {
|
|
242
304
|
const result = sendBeaconBatch(pending);
|
|
243
305
|
pending = result.remaining;
|
|
244
306
|
if (result.failure) throw result.failure.error;
|
|
245
307
|
} finally {
|
|
246
308
|
if (pending.length > 0) queue.unshift(...pending);
|
|
309
|
+
heldBatchSize = Math.max(0, heldBatchSize - (taken - pending.length));
|
|
247
310
|
flushingBeacon = false;
|
|
248
311
|
}
|
|
249
312
|
};
|
|
@@ -258,7 +321,11 @@ function browserHttpTransport(options) {
|
|
|
258
321
|
}
|
|
259
322
|
return activeFlush;
|
|
260
323
|
}
|
|
261
|
-
if (queue.length === 0) return Promise.resolve();
|
|
324
|
+
if (queue.length === 0) return preferBeacon ? Promise.resolve() : replayOfflineQueueSafely("replay");
|
|
325
|
+
if (!preferBeacon && retryWaitMs() > 0) {
|
|
326
|
+
schedule();
|
|
327
|
+
return Promise.resolve();
|
|
328
|
+
}
|
|
262
329
|
clearTimer();
|
|
263
330
|
let resolve;
|
|
264
331
|
let reject;
|
|
@@ -270,15 +337,21 @@ function browserHttpTransport(options) {
|
|
|
270
337
|
(async () => {
|
|
271
338
|
try {
|
|
272
339
|
if (preferBeacon) flushBeaconQueue();
|
|
340
|
+
let sent = false;
|
|
341
|
+
let queued = false;
|
|
273
342
|
while (queue.length > 0) {
|
|
274
|
-
const batch = queue.splice(0, maxBatchSize);
|
|
343
|
+
const batch = queue.splice(0, heldBatchSize || maxBatchSize);
|
|
344
|
+
heldBatchSize = 0;
|
|
275
345
|
try {
|
|
276
|
-
await sendFetchBatch(batch);
|
|
346
|
+
if (await sendFetchBatch(batch) === "sent") sent = true;
|
|
347
|
+
else queued = true;
|
|
277
348
|
} catch (error) {
|
|
278
349
|
queue.unshift(...batch);
|
|
350
|
+
heldBatchSize = batch.length;
|
|
279
351
|
throw error;
|
|
280
352
|
}
|
|
281
353
|
}
|
|
354
|
+
if (!preferBeacon && sent && !queued) await replayOfflineQueueSafely("replay");
|
|
282
355
|
resolve();
|
|
283
356
|
} catch (error) {
|
|
284
357
|
reject(error);
|
|
@@ -290,11 +363,13 @@ function browserHttpTransport(options) {
|
|
|
290
363
|
return task;
|
|
291
364
|
};
|
|
292
365
|
const schedule = () => {
|
|
293
|
-
if (
|
|
366
|
+
if (closed || activeFlush || timer) return;
|
|
367
|
+
const delayMs = Math.max(flushIntervalMs, retryWaitMs());
|
|
368
|
+
if (delayMs <= 0) return;
|
|
294
369
|
timer = setTimeout(() => {
|
|
295
370
|
timer = void 0;
|
|
296
371
|
flush(false).catch((error) => reportInternalError(error, "flush"));
|
|
297
|
-
},
|
|
372
|
+
}, delayMs);
|
|
298
373
|
};
|
|
299
374
|
const onPageHide = () => {
|
|
300
375
|
flush(true).catch((error) => reportInternalError(error, "pagehide-flush"));
|
|
@@ -303,25 +378,33 @@ function browserHttpTransport(options) {
|
|
|
303
378
|
if (typeof document !== "undefined" && document.visibilityState === "hidden") flush(true).catch((error) => reportInternalError(error, "visibility-flush"));
|
|
304
379
|
};
|
|
305
380
|
const onOnline = () => {
|
|
306
|
-
|
|
381
|
+
replayOfflineQueueSafely("replay");
|
|
307
382
|
};
|
|
308
383
|
if (options.useBeaconOnPageHide ?? true) {
|
|
309
384
|
globalThis.addEventListener?.("pagehide", onPageHide);
|
|
310
385
|
globalThis.addEventListener?.("visibilitychange", onVisibilityChange);
|
|
311
386
|
}
|
|
312
|
-
if (offlineQueue)
|
|
387
|
+
if (offlineQueue) {
|
|
388
|
+
globalThis.addEventListener?.("online", onOnline);
|
|
389
|
+
if (options.offlineReplayOnStart ?? true) setTimeout(() => void replayOfflineQueueSafely("startup-replay"), 0);
|
|
390
|
+
}
|
|
313
391
|
return {
|
|
314
392
|
name: options.name ?? "browser-http",
|
|
315
393
|
minLevel: options.minLevel,
|
|
316
394
|
log(event, context) {
|
|
317
395
|
if (options.minLevel !== void 0 && event.level < (0, _loggerjs_core.toLevelValue)(options.minLevel)) return;
|
|
318
396
|
lastContext = context;
|
|
397
|
+
if (closed) {
|
|
398
|
+
reportDrop(event, "closed");
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
319
401
|
if (queue.length >= maxQueueSize) {
|
|
320
402
|
if (dropPolicy === "drop-newest") {
|
|
321
403
|
reportDrop(event, "queue-full");
|
|
322
404
|
return;
|
|
323
405
|
}
|
|
324
406
|
const dropped = queue.shift();
|
|
407
|
+
if (heldBatchSize > 0) heldBatchSize -= 1;
|
|
325
408
|
if (dropped) reportDrop(dropped, "queue-full");
|
|
326
409
|
}
|
|
327
410
|
queue.push(event);
|
|
@@ -336,7 +419,16 @@ function browserHttpTransport(options) {
|
|
|
336
419
|
globalThis.removeEventListener?.("pagehide", onPageHide);
|
|
337
420
|
globalThis.removeEventListener?.("visibilitychange", onVisibilityChange);
|
|
338
421
|
globalThis.removeEventListener?.("online", onOnline);
|
|
339
|
-
|
|
422
|
+
closed = true;
|
|
423
|
+
clearTimer();
|
|
424
|
+
if (replayTimer !== void 0) clearTimeout(replayTimer);
|
|
425
|
+
const dropUndelivered = () => {
|
|
426
|
+
for (const event of queue.splice(0)) reportDrop(event, "closed");
|
|
427
|
+
};
|
|
428
|
+
return flush(true).then(dropUndelivered, (error) => {
|
|
429
|
+
dropUndelivered();
|
|
430
|
+
throw error;
|
|
431
|
+
});
|
|
340
432
|
}
|
|
341
433
|
};
|
|
342
434
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-transport.cjs","names":[],"sources":["../src/http-transport.ts"],"sourcesContent":["import {\n applyPayloadTransforms,\n incrementLoggerMetaCounter,\n safeJsonCodec,\n toLevelValue,\n type Codec,\n type EncodedPayload,\n type LogEvent,\n type LoggerLevel,\n type PayloadTransform,\n type Transport,\n type TransportContext,\n} from \"@loggerjs/core\";\n\nexport type BrowserHttpDropPolicy = \"drop-oldest\" | \"drop-newest\";\n\nconst DEFAULT_BEACON_MAX_BYTES = 60 * 1024;\n\nconst sleep = (delayMs: number) =>\n delayMs <= 0 ? Promise.resolve() : new Promise<void>((resolve) => setTimeout(resolve, delayMs));\n\nexport interface BrowserHttpOfflineEntry {\n id: string;\n url: string;\n method: \"POST\" | \"PUT\";\n headers: Record<string, string>;\n body: string | Uint8Array;\n credentials?: RequestCredentials;\n keepalive: boolean;\n createdAt: number;\n}\n\nexport interface BrowserHttpOfflineQueue {\n enqueue: (entry: BrowserHttpOfflineEntry) => void | Promise<void>;\n replay: (send: (entry: BrowserHttpOfflineEntry) => Promise<void>) => void | Promise<void>;\n}\n\nexport interface MemoryBrowserHttpOfflineQueueOptions {\n maxEntries?: number;\n dropPolicy?: BrowserHttpDropPolicy;\n onDrop?: (entry: BrowserHttpOfflineEntry, reason: string) => void;\n}\n\nexport interface BrowserHttpTransportOptions {\n url: string;\n name?: string;\n method?: \"POST\" | \"PUT\";\n headers?: Record<string, string>;\n credentials?: RequestCredentials;\n keepalive?: boolean;\n codec?: Codec<string | Uint8Array>;\n beaconCodec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n maxBatchSize?: number;\n flushIntervalMs?: number;\n maxQueueSize?: number;\n dropPolicy?: BrowserHttpDropPolicy;\n useBeaconOnPageHide?: boolean;\n beaconMaxBytes?: number;\n offlineQueue?: BrowserHttpOfflineQueue;\n offlineReplayMaxRetries?: number;\n offlineReplayBaseDelayMs?: number;\n offlineReplayMaxDelayMs?: number;\n random?: () => number;\n fetchFn?: typeof fetch;\n transformPayload?: PayloadTransform | readonly PayloadTransform[];\n onDrop?: (event: LogEvent, reason: string) => void;\n}\n\nexport function memoryBrowserHttpOfflineQueue(\n options: MemoryBrowserHttpOfflineQueueOptions = {},\n): BrowserHttpOfflineQueue & { size: () => number } {\n const entries: BrowserHttpOfflineEntry[] = [];\n const maxEntries = options.maxEntries ?? 1000;\n const dropPolicy = options.dropPolicy ?? \"drop-oldest\";\n\n const drop = (entry: BrowserHttpOfflineEntry, reason: string) => {\n incrementLoggerMetaCounter(\"transport.offline.dropped\");\n incrementLoggerMetaCounter(`transport.offline.dropped.${reason}`);\n options.onDrop?.(entry, reason);\n };\n\n return {\n enqueue(entry) {\n if (entries.length >= maxEntries) {\n if (dropPolicy === \"drop-newest\") {\n drop(entry, \"queue-full\");\n return;\n }\n const dropped = entries.shift();\n if (dropped) drop(dropped, \"queue-full\");\n }\n entries.push(entry);\n },\n async replay(send) {\n while (entries.length > 0) {\n const entry = entries[0];\n if (!entry) return;\n // oxlint-disable-next-line no-await-in-loop -- Replay must remove entries only after each send succeeds.\n await send(entry);\n entries.shift();\n }\n },\n size() {\n return entries.length;\n },\n };\n}\n\nfunction payloadToBody(payload: EncodedPayload): BodyInit {\n if (typeof payload === \"string\") return payload;\n return Uint8Array.from(payload);\n}\n\nfunction payloadByteLength(payload: EncodedPayload): number {\n if (typeof payload !== \"string\") return payload.byteLength;\n if (typeof TextEncoder !== \"undefined\") return new TextEncoder().encode(payload).byteLength;\n return new Blob([payload]).size;\n}\n\nfunction payloadToBeaconBody(payload: EncodedPayload, contentType: string): BodyInit {\n return new Blob([typeof payload === \"string\" ? payload : Uint8Array.from(payload)], {\n type: contentType,\n });\n}\n\ninterface BeaconChunk {\n events: LogEvent[];\n payload: string | Uint8Array;\n}\n\nfunction remainingEvents(chunks: BeaconChunk[], startIndex: number): LogEvent[] {\n const events: LogEvent[] = [];\n for (let index = startIndex; index < chunks.length; index++) {\n const chunk = chunks[index];\n if (chunk) events.push(...chunk.events);\n }\n return events;\n}\n\nexport function browserHttpTransport(options: BrowserHttpTransportOptions): Transport {\n const codec = options.codec ?? safeJsonCodec();\n const beaconCodec = options.beaconCodec ?? codec;\n const queue: LogEvent[] = [];\n const maxBatchSize = options.maxBatchSize ?? 50;\n if (!Number.isSafeInteger(maxBatchSize) || maxBatchSize <= 0) {\n throw new RangeError(\"maxBatchSize must be a positive safe integer\");\n }\n const flushIntervalMs = options.flushIntervalMs ?? 2000;\n const maxQueueSize = options.maxQueueSize ?? 1000;\n const dropPolicy = options.dropPolicy ?? \"drop-oldest\";\n const beaconMaxBytes = options.beaconMaxBytes ?? DEFAULT_BEACON_MAX_BYTES;\n const offlineQueue = options.offlineQueue;\n const offlineReplayMaxRetries = options.offlineReplayMaxRetries ?? 3;\n const offlineReplayBaseDelayMs = options.offlineReplayBaseDelayMs ?? 250;\n const offlineReplayMaxDelayMs = options.offlineReplayMaxDelayMs ?? 5000;\n const random = options.random ?? Math.random;\n const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);\n let offlineEntrySeq = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let activeFlush: Promise<void> | undefined;\n let flushingBeacon = false;\n let replayingOffline = false;\n let lastContext: TransportContext | undefined;\n\n const headers = (payloadHeaders?: Record<string, string>, contentType = codec.contentType) => ({\n \"content-type\": contentType,\n ...payloadHeaders,\n ...options.headers,\n });\n\n const clearTimer = () => {\n if (timer) clearTimeout(timer);\n timer = undefined;\n };\n\n const reportDrop = (event: LogEvent, reason: string) => {\n incrementLoggerMetaCounter(\"transport.dropped\");\n incrementLoggerMetaCounter(`transport.dropped.${reason}`);\n options.onDrop?.(event, reason);\n };\n\n const reportInternalError = (error: unknown, operation: string) => {\n lastContext?.reportInternalError(error, {\n phase: \"transport\",\n transport: options.name ?? \"browser-http\",\n operation,\n });\n };\n\n const createBeaconChunks = (batch: LogEvent[]): BeaconChunk[] => {\n const chunks: BeaconChunk[] = [];\n const oversized: LogEvent[] = [];\n let currentEvents: LogEvent[] = [];\n let currentPayload: string | Uint8Array | undefined;\n\n for (const event of batch) {\n if (currentEvents.length === maxBatchSize && currentPayload !== undefined) {\n chunks.push({ events: currentEvents, payload: currentPayload });\n currentEvents = [];\n currentPayload = undefined;\n }\n const candidateEvents = [...currentEvents, event];\n const candidatePayload = beaconCodec.encode(candidateEvents);\n if (payloadByteLength(candidatePayload) <= beaconMaxBytes) {\n currentEvents = candidateEvents;\n currentPayload = candidatePayload;\n continue;\n }\n\n if (currentEvents.length > 0 && currentPayload !== undefined) {\n chunks.push({ events: currentEvents, payload: currentPayload });\n }\n\n const singlePayload = beaconCodec.encode([event]);\n if (payloadByteLength(singlePayload) <= beaconMaxBytes) {\n currentEvents = [event];\n currentPayload = singlePayload;\n } else {\n currentEvents = [];\n currentPayload = undefined;\n oversized.push(event);\n }\n }\n\n if (currentEvents.length > 0 && currentPayload !== undefined) {\n chunks.push({ events: currentEvents, payload: currentPayload });\n }\n\n for (const event of oversized) reportDrop(event, \"beacon-too-large\");\n return chunks;\n };\n\n const sendBeaconBatch = (\n batch: LogEvent[],\n ): { remaining: LogEvent[]; failure?: { error: unknown } } => {\n if (typeof navigator === \"undefined\" || !navigator.sendBeacon) {\n return { remaining: batch };\n }\n\n const chunks = createBeaconChunks(batch);\n for (let index = 0; index < chunks.length; index++) {\n const chunk = chunks[index];\n if (!chunk) continue;\n try {\n const ok = navigator.sendBeacon(\n options.url,\n payloadToBeaconBody(chunk.payload, beaconCodec.contentType),\n );\n if (!ok) return { remaining: remainingEvents(chunks, index) };\n } catch (error) {\n return { remaining: remainingEvents(chunks, index), failure: { error } };\n }\n }\n\n return { remaining: [] };\n };\n\n const sendPayload = async (entry: BrowserHttpOfflineEntry) => {\n if (!fetchFn) throw new Error(\"fetch is not available for browserHttpTransport\");\n const response = await fetchFn(entry.url, {\n method: entry.method,\n headers: entry.headers,\n body: payloadToBody(entry.body),\n credentials: entry.credentials,\n keepalive: entry.keepalive,\n });\n if (!response.ok) throw new Error(`browserHttpTransport failed with status ${response.status}`);\n };\n\n const encodeTransformedPayload = async (batch: LogEvent[]) => {\n const encoded = codec.encode(batch);\n return applyPayloadTransforms(\n encoded,\n {\n contentType: codec.contentType,\n events: batch,\n transport: options.name ?? \"browser-http\",\n },\n options.transformPayload,\n );\n };\n\n const createOfflineEntry = (\n payload: string | Uint8Array,\n payloadHeaders?: Record<string, string>,\n contentType?: string,\n ): BrowserHttpOfflineEntry => ({\n id: `${Date.now().toString(36)}-${(offlineEntrySeq++).toString(36)}`,\n url: options.url,\n method: options.method ?? \"POST\",\n headers: headers(payloadHeaders, contentType),\n body: payload,\n credentials: options.credentials,\n keepalive: options.keepalive ?? true,\n createdAt: Date.now(),\n });\n\n const enqueueOfflinePayload = async (\n payload: string | Uint8Array,\n payloadHeaders?: Record<string, string>,\n contentType?: string,\n ) => {\n if (!offlineQueue) return false;\n await offlineQueue.enqueue(createOfflineEntry(payload, payloadHeaders, contentType));\n incrementLoggerMetaCounter(\"transport.offline.queued\");\n return true;\n };\n\n const sendFetchBatch = async (batch: LogEvent[]) => {\n if (batch.length === 0) return;\n const transformed = await encodeTransformedPayload(batch);\n if (offlineQueue && typeof navigator !== \"undefined\" && navigator.onLine === false) {\n await enqueueOfflinePayload(\n transformed.payload,\n transformed.headers,\n transformed.contentType,\n );\n return;\n }\n try {\n await sendPayload(\n createOfflineEntry(transformed.payload, transformed.headers, transformed.contentType),\n );\n } catch (error) {\n if (\n await enqueueOfflinePayload(\n transformed.payload,\n transformed.headers,\n transformed.contentType,\n )\n ) {\n return;\n }\n throw error;\n }\n };\n\n const replayRetryDelay = (attempt: number): number => {\n const cap = Math.min(offlineReplayMaxDelayMs, offlineReplayBaseDelayMs * 2 ** attempt);\n return cap <= 0 ? 0 : random() * cap;\n };\n\n const sendOfflineEntryWithRetry = async (entry: BrowserHttpOfflineEntry) => {\n for (let attempt = 0; ; attempt++) {\n try {\n // oxlint-disable-next-line no-await-in-loop -- Retry attempts must run sequentially.\n await sendPayload(entry);\n incrementLoggerMetaCounter(\"transport.offline.replayed\");\n return;\n } catch (error) {\n if (attempt >= offlineReplayMaxRetries) {\n incrementLoggerMetaCounter(\"transport.offline.replay.failed\");\n throw error;\n }\n incrementLoggerMetaCounter(\"transport.offline.retry\");\n // oxlint-disable-next-line no-await-in-loop -- Backoff must complete before the next retry.\n await sleep(replayRetryDelay(attempt));\n }\n }\n };\n\n const replayOfflineQueue = async () => {\n if (!offlineQueue || replayingOffline) return;\n replayingOffline = true;\n try {\n await offlineQueue.replay(sendOfflineEntryWithRetry);\n } finally {\n replayingOffline = false;\n }\n };\n\n // Beacon submission is synchronous, even while an earlier Fetch is pending.\n // Only queued events are eligible; the active Fetch batch keeps its ownership.\n const flushBeaconQueue = () => {\n if (flushingBeacon || options.transformPayload || queue.length === 0) return;\n flushingBeacon = true;\n let pending = queue.splice(0, queue.length);\n try {\n const result = sendBeaconBatch(pending);\n pending = result.remaining;\n if (result.failure) throw result.failure.error;\n } finally {\n if (pending.length > 0) queue.unshift(...pending);\n flushingBeacon = false;\n }\n };\n\n const flush = (preferBeacon = false): Promise<void> => {\n if (activeFlush) {\n if (preferBeacon) {\n try {\n flushBeaconQueue();\n } catch (error) {\n // close() must still wait for the active delivery before reporting a Beacon error.\n return activeFlush.then(() => {\n throw error;\n });\n }\n }\n return activeFlush;\n }\n if (queue.length === 0) return Promise.resolve();\n clearTimer();\n\n // Publish the task before invoking user codecs/transforms, which may reenter log().\n let resolve!: () => void;\n let reject!: (error: unknown) => void;\n const task = new Promise<void>((onResolve, onReject) => {\n resolve = onResolve;\n reject = onReject;\n });\n activeFlush = task;\n void (async () => {\n try {\n if (preferBeacon) flushBeaconQueue();\n while (queue.length > 0) {\n const batch = queue.splice(0, maxBatchSize);\n try {\n // oxlint-disable-next-line no-await-in-loop -- Preserve batch order and stop on the first unhandled failure.\n await sendFetchBatch(batch);\n } catch (error) {\n queue.unshift(...batch);\n throw error;\n }\n }\n resolve();\n } catch (error) {\n reject(error);\n } finally {\n activeFlush = undefined;\n if (queue.length > 0) schedule();\n }\n })();\n return task;\n };\n\n const schedule = () => {\n if (activeFlush || timer || flushIntervalMs <= 0) return;\n timer = setTimeout(() => {\n timer = undefined;\n void flush(false).catch((error: unknown) => reportInternalError(error, \"flush\"));\n }, flushIntervalMs);\n };\n\n const onPageHide = () => {\n void flush(true).catch((error: unknown) => reportInternalError(error, \"pagehide-flush\"));\n };\n const onVisibilityChange = () => {\n if (typeof document !== \"undefined\" && document.visibilityState === \"hidden\") {\n void flush(true).catch((error: unknown) => reportInternalError(error, \"visibility-flush\"));\n }\n };\n const onOnline = () => {\n void replayOfflineQueue().catch((error: unknown) => reportInternalError(error, \"replay\"));\n };\n\n if (options.useBeaconOnPageHide ?? true) {\n globalThis.addEventListener?.(\"pagehide\", onPageHide);\n globalThis.addEventListener?.(\"visibilitychange\", onVisibilityChange);\n }\n if (offlineQueue) globalThis.addEventListener?.(\"online\", onOnline);\n\n return {\n name: options.name ?? \"browser-http\",\n minLevel: options.minLevel,\n log(event, context) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel)) return;\n lastContext = context;\n if (queue.length >= maxQueueSize) {\n if (dropPolicy === \"drop-newest\") {\n reportDrop(event, \"queue-full\");\n return;\n }\n const dropped = queue.shift();\n if (dropped) reportDrop(dropped, \"queue-full\");\n }\n queue.push(event);\n if (activeFlush) return;\n if (queue.length >= maxBatchSize) {\n void flush(false).catch((error: unknown) => reportInternalError(error, \"flush\"));\n } else schedule();\n },\n flush() {\n return flush(false);\n },\n close() {\n globalThis.removeEventListener?.(\"pagehide\", onPageHide);\n globalThis.removeEventListener?.(\"visibilitychange\", onVisibilityChange);\n globalThis.removeEventListener?.(\"online\", onOnline);\n return flush(true);\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"http-transport.cjs","names":[],"sources":["../src/http-transport.ts"],"sourcesContent":["import {\n httpStatusError,\n incrementLoggerMetaCounter,\n safeJsonEncoder,\n toLevelValue,\n type Codec,\n type EncodedPayload,\n type LogEvent,\n type LoggerLevel,\n type PayloadTransform,\n type Transport,\n type TransportContext,\n type HttpStatusError,\n} from \"@loggerjs/core\";\nimport { applyPayloadTransforms } from \"@loggerjs/core/payload-transforms\";\n\nexport type BrowserHttpDropPolicy = \"drop-oldest\" | \"drop-newest\";\n\nconst DEFAULT_BEACON_MAX_BYTES = 60 * 1024;\n\nconst sleep = (delayMs: number) =>\n delayMs <= 0 ? Promise.resolve() : new Promise<void>((resolve) => setTimeout(resolve, delayMs));\n\nexport interface BrowserHttpOfflineEntry {\n id: string;\n url: string;\n method: \"POST\" | \"PUT\";\n headers: Record<string, string>;\n body: string | Uint8Array;\n credentials?: RequestCredentials;\n keepalive: boolean;\n createdAt: number;\n}\n\nexport interface BrowserHttpOfflineQueue {\n enqueue: (entry: BrowserHttpOfflineEntry) => void | Promise<void>;\n replay: (send: (entry: BrowserHttpOfflineEntry) => Promise<void>) => void | Promise<void>;\n}\n\nexport interface MemoryBrowserHttpOfflineQueueOptions {\n maxEntries?: number;\n dropPolicy?: BrowserHttpDropPolicy;\n onDrop?: (entry: BrowserHttpOfflineEntry, reason: string) => void;\n}\n\nexport interface BrowserHttpTransportOptions {\n url: string;\n name?: string;\n method?: \"POST\" | \"PUT\";\n headers?: Record<string, string>;\n credentials?: RequestCredentials;\n keepalive?: boolean;\n codec?: Codec<string | Uint8Array>;\n beaconCodec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n maxBatchSize?: number;\n flushIntervalMs?: number;\n maxQueueSize?: number;\n dropPolicy?: BrowserHttpDropPolicy;\n useBeaconOnPageHide?: boolean;\n beaconMaxBytes?: number;\n offlineQueue?: BrowserHttpOfflineQueue;\n offlineReplayMaxRetries?: number;\n offlineReplayBaseDelayMs?: number;\n offlineReplayMaxDelayMs?: number;\n offlineReplayOnStart?: boolean;\n random?: () => number;\n fetchFn?: typeof fetch;\n transformPayload?: PayloadTransform | readonly PayloadTransform[];\n onDrop?: (event: LogEvent, reason: string) => void;\n /**\n * Abort a Fetch delivery after this many milliseconds. Browsers never time\n * out a request on their own, so one stalled request would otherwise hold\n * every later flush and close(). A timed-out batch falls back to the\n * offline queue when one is configured. Set to 0 to disable. Defaults to\n * 10000.\n */\n timeoutMs?: number;\n /**\n * Header that carries an idempotency key for each Fetch request, for\n * example \"Idempotency-Key\". Every resend of a batch repeats its key, and\n * offline-queue entries store it, so the collector can drop duplicates.\n * Keys start with a random per-transport prefix, so senders never share\n * one. Off by default because a cross-origin collector must allow the\n * header in Access-Control-Allow-Headers. Beacon requests cannot carry it.\n */\n idempotencyKeyHeader?: string;\n}\n\nexport function memoryBrowserHttpOfflineQueue(\n options: MemoryBrowserHttpOfflineQueueOptions = {},\n): BrowserHttpOfflineQueue & { size: () => number } {\n const entries: BrowserHttpOfflineEntry[] = [];\n const maxEntries = options.maxEntries ?? 1000;\n const dropPolicy = options.dropPolicy ?? \"drop-oldest\";\n\n const drop = (entry: BrowserHttpOfflineEntry, reason: string) => {\n incrementLoggerMetaCounter(\"transport.offline.dropped\");\n incrementLoggerMetaCounter(`transport.offline.dropped.${reason}`);\n options.onDrop?.(entry, reason);\n };\n\n return {\n enqueue(entry) {\n if (entries.length >= maxEntries) {\n if (dropPolicy === \"drop-newest\") {\n drop(entry, \"queue-full\");\n return;\n }\n const dropped = entries.shift();\n if (dropped) drop(dropped, \"queue-full\");\n }\n entries.push(entry);\n },\n async replay(send) {\n while (entries.length > 0) {\n const entry = entries[0];\n if (!entry) return;\n // oxlint-disable-next-line no-await-in-loop -- Replay must remove entries only after each send succeeds.\n await send(entry);\n entries.shift();\n }\n },\n size() {\n return entries.length;\n },\n };\n}\n\nfunction payloadToBody(payload: EncodedPayload): BodyInit {\n if (typeof payload === \"string\") return payload;\n return Uint8Array.from(payload);\n}\n\nfunction payloadByteLength(payload: EncodedPayload): number {\n if (typeof payload !== \"string\") return payload.byteLength;\n if (typeof TextEncoder !== \"undefined\") return new TextEncoder().encode(payload).byteLength;\n return new Blob([payload]).size;\n}\n\nfunction payloadToBeaconBody(payload: EncodedPayload, contentType: string): BodyInit {\n return new Blob([typeof payload === \"string\" ? payload : Uint8Array.from(payload)], {\n type: contentType,\n });\n}\n\ninterface BeaconChunk {\n events: LogEvent[];\n payload: string | Uint8Array;\n}\n\nfunction remainingEvents(chunks: BeaconChunk[], startIndex: number): LogEvent[] {\n const events: LogEvent[] = [];\n for (let index = startIndex; index < chunks.length; index++) {\n const chunk = chunks[index];\n if (chunk) events.push(...chunk.events);\n }\n return events;\n}\n\n// Keys are a random per-transport prefix, which keeps senders apart, and a\n// batch number. A batch's key is stored under its last event: resends of a\n// held batch keep that event, because a full queue and Beacon delivery only\n// remove events from the front. Mirrors @loggerjs/node.\nfunction idempotencyKeyHeaders(\n header: string | undefined,\n): (events: readonly LogEvent[]) => Record<string, string> | undefined {\n if (!header) return () => undefined;\n // Throws a TypeError for an invalid header name now instead of on every send.\n new Headers().append(header, \"\");\n const prefix = Array.from(crypto.getRandomValues(new Uint32Array(2)), (word) =>\n word.toString(36),\n ).join(\"\");\n const keys = new WeakMap<LogEvent, string>();\n let next = 0;\n return (events) => {\n const last = events[events.length - 1]!;\n let key = keys.get(last);\n if (key === undefined) {\n key = `${prefix}-${(next++).toString(36)}`;\n keys.set(last, key);\n }\n return { [header]: key };\n };\n}\n\nexport function browserHttpTransport(options: BrowserHttpTransportOptions): Transport {\n const codec = options.codec ?? safeJsonEncoder();\n const beaconCodec = options.beaconCodec ?? codec;\n const queue: LogEvent[] = [];\n const maxBatchSize = options.maxBatchSize ?? 50;\n if (!Number.isSafeInteger(maxBatchSize) || maxBatchSize <= 0) {\n throw new RangeError(\"maxBatchSize must be a positive safe integer\");\n }\n const flushIntervalMs = options.flushIntervalMs ?? 2000;\n const keyHeaders = idempotencyKeyHeaders(options.idempotencyKeyHeader);\n const maxQueueSize = options.maxQueueSize ?? 1000;\n const dropPolicy = options.dropPolicy ?? \"drop-oldest\";\n const beaconMaxBytes = options.beaconMaxBytes ?? DEFAULT_BEACON_MAX_BYTES;\n const offlineQueue = options.offlineQueue;\n const offlineReplayMaxRetries = options.offlineReplayMaxRetries ?? 3;\n const offlineReplayBaseDelayMs = options.offlineReplayBaseDelayMs ?? 250;\n const offlineReplayMaxDelayMs = options.offlineReplayMaxDelayMs ?? 5000;\n const random = options.random ?? Math.random;\n const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);\n const timeoutMs = options.timeoutMs ?? 10_000;\n let offlineEntrySeq = 0;\n let closed = false;\n // Set from a Retry-After response: automatic sends and replays wait until then.\n let retryNotBefore = 0;\n let replayTimer: ReturnType<typeof setTimeout> | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let activeFlush: Promise<void> | undefined;\n let flushingBeacon = false;\n let replayPromise: Promise<void> | undefined;\n // Events at the front of the queue that a failed send handed back. They are\n // resent as the same batch, so its idempotency key repeats.\n let heldBatchSize = 0;\n let lastContext: TransportContext | undefined;\n\n const headers = (payloadHeaders?: Record<string, string>, contentType = codec.contentType) => ({\n \"content-type\": contentType,\n ...payloadHeaders,\n ...options.headers,\n });\n\n const clearTimer = () => {\n if (timer) clearTimeout(timer);\n timer = undefined;\n };\n\n const reportDrop = (event: LogEvent, reason: string) => {\n incrementLoggerMetaCounter(\"transport.dropped\");\n incrementLoggerMetaCounter(`transport.dropped.${reason}`);\n options.onDrop?.(event, reason);\n };\n\n const reportInternalError = (error: unknown, operation: string) => {\n lastContext?.reportInternalError(error, {\n phase: \"transport\",\n transport: options.name ?? \"browser-http\",\n operation,\n });\n };\n\n const createBeaconChunks = (batch: LogEvent[]): BeaconChunk[] => {\n const chunks: BeaconChunk[] = [];\n const oversized: LogEvent[] = [];\n let currentEvents: LogEvent[] = [];\n let currentPayload: string | Uint8Array | undefined;\n\n for (const event of batch) {\n if (currentEvents.length === maxBatchSize && currentPayload !== undefined) {\n chunks.push({ events: currentEvents, payload: currentPayload });\n currentEvents = [];\n currentPayload = undefined;\n }\n const candidateEvents = [...currentEvents, event];\n const candidatePayload = beaconCodec.encode(candidateEvents);\n if (payloadByteLength(candidatePayload) <= beaconMaxBytes) {\n currentEvents = candidateEvents;\n currentPayload = candidatePayload;\n continue;\n }\n\n if (currentEvents.length > 0 && currentPayload !== undefined) {\n chunks.push({ events: currentEvents, payload: currentPayload });\n }\n\n const singlePayload = beaconCodec.encode([event]);\n if (payloadByteLength(singlePayload) <= beaconMaxBytes) {\n currentEvents = [event];\n currentPayload = singlePayload;\n } else {\n currentEvents = [];\n currentPayload = undefined;\n oversized.push(event);\n }\n }\n\n if (currentEvents.length > 0 && currentPayload !== undefined) {\n chunks.push({ events: currentEvents, payload: currentPayload });\n }\n\n for (const event of oversized) reportDrop(event, \"beacon-too-large\");\n return chunks;\n };\n\n const sendBeaconBatch = (\n batch: LogEvent[],\n ): { remaining: LogEvent[]; failure?: { error: unknown } } => {\n if (typeof navigator === \"undefined\" || !navigator.sendBeacon) {\n return { remaining: batch };\n }\n\n const chunks = createBeaconChunks(batch);\n for (let index = 0; index < chunks.length; index++) {\n const chunk = chunks[index];\n if (!chunk) continue;\n try {\n const ok = navigator.sendBeacon(\n options.url,\n payloadToBeaconBody(chunk.payload, beaconCodec.contentType),\n );\n if (!ok) {\n incrementLoggerMetaCounter(\"transport.beacon.rejected\", chunk.events.length);\n return { remaining: remainingEvents(chunks, index) };\n }\n } catch (error) {\n incrementLoggerMetaCounter(\"transport.beacon.rejected\", chunk.events.length);\n return { remaining: remainingEvents(chunks, index), failure: { error } };\n }\n // Accepted only means the browser queued the request: nothing reports\n // whether it reaches the collector, so these events are never dropped.\n incrementLoggerMetaCounter(\"transport.beacon.accepted\", chunk.events.length);\n }\n\n return { remaining: [] };\n };\n\n const sendPayload = async (entry: BrowserHttpOfflineEntry) => {\n if (!fetchFn) throw new Error(\"fetch is not available for browserHttpTransport\");\n const response = await fetchFn(entry.url, {\n method: entry.method,\n headers: entry.headers,\n body: payloadToBody(entry.body),\n credentials: entry.credentials,\n keepalive: entry.keepalive,\n signal:\n timeoutMs > 0 && typeof AbortSignal?.timeout === \"function\"\n ? AbortSignal.timeout(timeoutMs)\n : undefined,\n });\n if (!response.ok) throw httpStatusError(\"browserHttpTransport\", response);\n };\n\n const encodeTransformedPayload = async (batch: LogEvent[]) => {\n const encoded = codec.encode(batch);\n return applyPayloadTransforms(\n encoded,\n {\n contentType: codec.contentType,\n events: batch,\n transport: options.name ?? \"browser-http\",\n },\n options.transformPayload,\n );\n };\n\n const createOfflineEntry = (\n payload: string | Uint8Array,\n payloadHeaders?: Record<string, string>,\n contentType?: string,\n ): BrowserHttpOfflineEntry => ({\n id: `${Date.now().toString(36)}-${(offlineEntrySeq++).toString(36)}`,\n url: options.url,\n method: options.method ?? \"POST\",\n headers: headers(payloadHeaders, contentType),\n body: payload,\n credentials: options.credentials,\n keepalive: options.keepalive ?? true,\n createdAt: Date.now(),\n });\n\n const enqueueOfflinePayload = async (\n payload: string | Uint8Array,\n payloadHeaders?: Record<string, string>,\n contentType?: string,\n ) => {\n if (!offlineQueue) return false;\n await offlineQueue.enqueue(createOfflineEntry(payload, payloadHeaders, contentType));\n incrementLoggerMetaCounter(\"transport.offline.queued\");\n return true;\n };\n\n const isOnline = () => typeof navigator === \"undefined\" || navigator.onLine !== false;\n\n // Resolves to \"sent\" when the collector accepted the batch and \"queued\" when\n // the offline queue took it instead.\n const sendFetchBatch = async (batch: LogEvent[]): Promise<\"sent\" | \"queued\"> => {\n const transformed = await encodeTransformedPayload(batch);\n // The key travels in the stored headers, so replays repeat it.\n const payloadHeaders = { ...transformed.headers, ...keyHeaders(batch) };\n if (offlineQueue && !isOnline()) {\n await enqueueOfflinePayload(transformed.payload, payloadHeaders, transformed.contentType);\n return \"queued\";\n }\n try {\n await sendPayload(\n createOfflineEntry(transformed.payload, payloadHeaders, transformed.contentType),\n );\n return \"sent\";\n } catch (error) {\n noteRetryAfter(error);\n if (\n await enqueueOfflinePayload(transformed.payload, payloadHeaders, transformed.contentType)\n ) {\n return \"queued\";\n }\n throw error;\n }\n };\n\n const retryWaitMs = () => Math.max(0, retryNotBefore - Date.now());\n\n // Cross-origin collectors must expose Retry-After through\n // Access-Control-Expose-Headers for the browser to read it.\n const noteRetryAfter = (error: unknown): number | undefined => {\n const retryAfterMs = (error as Partial<HttpStatusError> | null)?.retryAfterMs;\n if (typeof retryAfterMs !== \"number\" || !(retryAfterMs >= 0)) return undefined;\n retryNotBefore = Math.max(retryNotBefore, Date.now() + retryAfterMs);\n return retryAfterMs;\n };\n\n const replayRetryDelay = (attempt: number): number => {\n const cap = Math.min(offlineReplayMaxDelayMs, offlineReplayBaseDelayMs * 2 ** attempt);\n return cap <= 0 ? 0 : random() * cap;\n };\n\n const sendOfflineEntryWithRetry = async (entry: BrowserHttpOfflineEntry) => {\n for (let attempt = 0; ; attempt++) {\n try {\n // oxlint-disable-next-line no-await-in-loop -- Retry attempts must run sequentially.\n await sendPayload(entry);\n incrementLoggerMetaCounter(\"transport.offline.replayed\");\n return;\n } catch (error) {\n const retryAfterMs = noteRetryAfter(error);\n // A longer server-requested wait ends this replay round; the entry\n // stays queued and replays after the wait.\n if (attempt >= offlineReplayMaxRetries || (retryAfterMs ?? 0) > offlineReplayMaxDelayMs) {\n incrementLoggerMetaCounter(\"transport.offline.replay.failed\");\n throw error;\n }\n incrementLoggerMetaCounter(\"transport.offline.retry\");\n // oxlint-disable-next-line no-await-in-loop -- Backoff must complete before the next retry.\n await sleep(Math.max(replayRetryDelay(attempt), retryAfterMs ?? 0));\n }\n }\n };\n\n const replayOfflineQueue = (): Promise<void> => {\n if (!offlineQueue) return Promise.resolve();\n replayPromise ??= (async () => {\n try {\n await offlineQueue.replay(sendOfflineEntryWithRetry);\n } finally {\n replayPromise = undefined;\n }\n })();\n return replayPromise;\n };\n\n // Stored entries stay in the offline queue when replay fails, so a failed\n // replay is reported instead of failing the flush that triggered it.\n const replayOfflineQueueSafely = async (operation: string): Promise<void> => {\n if (!offlineQueue || !isOnline()) return;\n const waitMs = retryWaitMs();\n if (waitMs > 0) {\n if (!closed && replayTimer === undefined) {\n replayTimer = setTimeout(() => {\n replayTimer = undefined;\n void replayOfflineQueueSafely(operation);\n }, waitMs);\n }\n return;\n }\n try {\n await replayOfflineQueue();\n } catch (error) {\n reportInternalError(error, operation);\n }\n };\n\n // Beacon submission is synchronous, even while an earlier Fetch is pending.\n // Only queued events are eligible; the active Fetch batch keeps its ownership.\n const flushBeaconQueue = () => {\n if (flushingBeacon || options.transformPayload || queue.length === 0) return;\n flushingBeacon = true;\n const taken = queue.length;\n let pending = queue.splice(0, taken);\n try {\n const result = sendBeaconBatch(pending);\n pending = result.remaining;\n if (result.failure) throw result.failure.error;\n } finally {\n if (pending.length > 0) queue.unshift(...pending);\n heldBatchSize = Math.max(0, heldBatchSize - (taken - pending.length));\n flushingBeacon = false;\n }\n };\n\n const flush = (preferBeacon = false): Promise<void> => {\n if (activeFlush) {\n if (preferBeacon) {\n try {\n flushBeaconQueue();\n } catch (error) {\n // close() must still wait for the active delivery before reporting a Beacon error.\n return activeFlush.then(() => {\n throw error;\n });\n }\n }\n return activeFlush;\n }\n if (queue.length === 0) {\n // An explicit flush with nothing live still retries stored payloads, so\n // entries queued during a server outage do not wait for an `online` event.\n return preferBeacon ? Promise.resolve() : replayOfflineQueueSafely(\"replay\");\n }\n // While the collector's Retry-After runs, keep events queued; the\n // scheduler sends them when it ends. Page-exit Beacon flushes still go out.\n if (!preferBeacon && retryWaitMs() > 0) {\n schedule();\n return Promise.resolve();\n }\n clearTimer();\n\n // Publish the task before invoking user codecs/transforms, which may reenter log().\n let resolve!: () => void;\n let reject!: (error: unknown) => void;\n const task = new Promise<void>((onResolve, onReject) => {\n resolve = onResolve;\n reject = onReject;\n });\n activeFlush = task;\n void (async () => {\n try {\n if (preferBeacon) flushBeaconQueue();\n let sent = false;\n let queued = false;\n while (queue.length > 0) {\n const batch = queue.splice(0, heldBatchSize || maxBatchSize);\n heldBatchSize = 0;\n try {\n // oxlint-disable-next-line no-await-in-loop -- Preserve batch order and stop on the first unhandled failure.\n const outcome = await sendFetchBatch(batch);\n if (outcome === \"sent\") sent = true;\n else queued = true;\n } catch (error) {\n queue.unshift(...batch);\n heldBatchSize = batch.length;\n throw error;\n }\n }\n // A live batch reached the collector and none fell back to the offline\n // queue, so the collector is reachable again: replay stored payloads.\n if (!preferBeacon && sent && !queued) await replayOfflineQueueSafely(\"replay\");\n resolve();\n } catch (error) {\n reject(error);\n } finally {\n activeFlush = undefined;\n if (queue.length > 0) schedule();\n }\n })();\n return task;\n };\n\n const schedule = () => {\n if (closed || activeFlush || timer) return;\n const delayMs = Math.max(flushIntervalMs, retryWaitMs());\n if (delayMs <= 0) return;\n timer = setTimeout(() => {\n timer = undefined;\n void flush(false).catch((error: unknown) => reportInternalError(error, \"flush\"));\n }, delayMs);\n };\n\n const onPageHide = () => {\n void flush(true).catch((error: unknown) => reportInternalError(error, \"pagehide-flush\"));\n };\n const onVisibilityChange = () => {\n if (typeof document !== \"undefined\" && document.visibilityState === \"hidden\") {\n void flush(true).catch((error: unknown) => reportInternalError(error, \"visibility-flush\"));\n }\n };\n const onOnline = () => {\n void replayOfflineQueueSafely(\"replay\");\n };\n\n if (options.useBeaconOnPageHide ?? true) {\n globalThis.addEventListener?.(\"pagehide\", onPageHide);\n globalThis.addEventListener?.(\"visibilitychange\", onVisibilityChange);\n }\n if (offlineQueue) {\n globalThis.addEventListener?.(\"online\", onOnline);\n // Payloads persisted by an earlier page load (for example in IndexedDB)\n // would otherwise wait for an `online` event that may never fire.\n if (options.offlineReplayOnStart ?? true) {\n setTimeout(() => void replayOfflineQueueSafely(\"startup-replay\"), 0);\n }\n }\n\n return {\n name: options.name ?? \"browser-http\",\n minLevel: options.minLevel,\n log(event, context) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel)) return;\n lastContext = context;\n if (closed) {\n reportDrop(event, \"closed\");\n return;\n }\n if (queue.length >= maxQueueSize) {\n if (dropPolicy === \"drop-newest\") {\n reportDrop(event, \"queue-full\");\n return;\n }\n const dropped = queue.shift();\n if (heldBatchSize > 0) heldBatchSize -= 1;\n if (dropped) reportDrop(dropped, \"queue-full\");\n }\n queue.push(event);\n if (activeFlush) return;\n if (queue.length >= maxBatchSize) {\n void flush(false).catch((error: unknown) => reportInternalError(error, \"flush\"));\n } else schedule();\n },\n flush() {\n return flush(false);\n },\n close() {\n globalThis.removeEventListener?.(\"pagehide\", onPageHide);\n globalThis.removeEventListener?.(\"visibilitychange\", onVisibilityChange);\n globalThis.removeEventListener?.(\"online\", onOnline);\n closed = true;\n clearTimer();\n if (replayTimer !== undefined) clearTimeout(replayTimer);\n // Events the final flush could not deliver or store are accounted for\n // as dropped instead of disappearing with the transport.\n const dropUndelivered = () => {\n for (const event of queue.splice(0)) reportDrop(event, \"closed\");\n };\n return flush(true).then(dropUndelivered, (error: unknown) => {\n dropUndelivered();\n throw error;\n });\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/http-transport.d.ts
CHANGED
|
@@ -39,10 +39,28 @@ export interface BrowserHttpTransportOptions {
|
|
|
39
39
|
offlineReplayMaxRetries?: number;
|
|
40
40
|
offlineReplayBaseDelayMs?: number;
|
|
41
41
|
offlineReplayMaxDelayMs?: number;
|
|
42
|
+
offlineReplayOnStart?: boolean;
|
|
42
43
|
random?: () => number;
|
|
43
44
|
fetchFn?: typeof fetch;
|
|
44
45
|
transformPayload?: PayloadTransform | readonly PayloadTransform[];
|
|
45
46
|
onDrop?: (event: LogEvent, reason: string) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Abort a Fetch delivery after this many milliseconds. Browsers never time
|
|
49
|
+
* out a request on their own, so one stalled request would otherwise hold
|
|
50
|
+
* every later flush and close(). A timed-out batch falls back to the
|
|
51
|
+
* offline queue when one is configured. Set to 0 to disable. Defaults to
|
|
52
|
+
* 10000.
|
|
53
|
+
*/
|
|
54
|
+
timeoutMs?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Header that carries an idempotency key for each Fetch request, for
|
|
57
|
+
* example "Idempotency-Key". Every resend of a batch repeats its key, and
|
|
58
|
+
* offline-queue entries store it, so the collector can drop duplicates.
|
|
59
|
+
* Keys start with a random per-transport prefix, so senders never share
|
|
60
|
+
* one. Off by default because a cross-origin collector must allow the
|
|
61
|
+
* header in Access-Control-Allow-Headers. Beacon requests cannot carry it.
|
|
62
|
+
*/
|
|
63
|
+
idempotencyKeyHeader?: string;
|
|
46
64
|
}
|
|
47
65
|
export declare function memoryBrowserHttpOfflineQueue(options?: MemoryBrowserHttpOfflineQueueOptions): BrowserHttpOfflineQueue & {
|
|
48
66
|
size: () => number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-transport.d.ts","sourceRoot":"","sources":["../src/http-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,KAAK,EAEV,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"http-transport.d.ts","sourceRoot":"","sources":["../src/http-transport.ts"],"names":[],"mappings":"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"}
|