@loggerjs/browser 0.5.2 → 0.5.4
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 +40 -2
- package/dist/index.cjs +641 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +641 -41
- package/dist/index.js.map +1 -1
- package/dist/indexeddb-transport.cjs +529 -27
- package/dist/indexeddb-transport.cjs.map +1 -1
- package/dist/indexeddb-transport.d.ts +41 -0
- package/dist/indexeddb-transport.d.ts.map +1 -1
- package/dist/indexeddb-transport.js +530 -28
- package/dist/indexeddb-transport.js.map +1 -1
- package/dist/offline-first-transport.cjs +532 -28
- 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 +533 -29
- package/dist/offline-first-transport.js.map +1 -1
- package/dist/zip-export.cjs +109 -13
- package/dist/zip-export.cjs.map +1 -1
- package/dist/zip-export.d.ts +24 -0
- package/dist/zip-export.d.ts.map +1 -1
- package/dist/zip-export.js +109 -13
- package/dist/zip-export.js.map +1 -1
- package/package.json +2 -2
|
@@ -3,12 +3,98 @@ let _loggerjs_core = require("@loggerjs/core");
|
|
|
3
3
|
//#region src/indexeddb-transport.ts
|
|
4
4
|
const DEFAULT_DB_NAME = "loggerjs";
|
|
5
5
|
const DEFAULT_STORE_NAME = "logs";
|
|
6
|
-
const
|
|
6
|
+
const DEFAULT_SESSION_CONTEXT_KEY = "sessionId";
|
|
7
|
+
const DEFAULT_SPILL_MAX_ENTRIES = 200;
|
|
8
|
+
const DEFAULT_SPILL_MAX_BYTES = 512 * 1024;
|
|
9
|
+
const DEFAULT_SPILL_MAX_ORIGIN_BYTES = 5 * 1024 * 1024;
|
|
10
|
+
const DB_VERSION = 4;
|
|
7
11
|
const ORDER_INDEX_NAME = "createdAtSeq";
|
|
12
|
+
const SESSION_INDEX_NAME = "sessionId";
|
|
13
|
+
const SESSION_ORDER_INDEX_NAME = "sessionIdCreatedAtSeq";
|
|
14
|
+
const SESSION_STORE_SUFFIX = "__sessions";
|
|
15
|
+
const SESSION_LAST_SEEN_INDEX_NAME = "lastSeenSessionId";
|
|
16
|
+
const SPILL_SCHEMA = "loggerjs.indexeddb-spill.v1";
|
|
8
17
|
function normalizePositiveInteger(value, fallback) {
|
|
9
18
|
if (value === void 0 || !Number.isFinite(value)) return fallback;
|
|
10
19
|
return Math.max(0, Math.floor(value));
|
|
11
20
|
}
|
|
21
|
+
let fallbackSessionSeq = 0;
|
|
22
|
+
function defaultPageSessionId() {
|
|
23
|
+
const randomUUID = globalThis.crypto?.randomUUID;
|
|
24
|
+
if (randomUUID) return randomUUID.call(globalThis.crypto);
|
|
25
|
+
return `${Date.now().toString(36)}-${(fallbackSessionSeq++).toString(36)}`;
|
|
26
|
+
}
|
|
27
|
+
function normalizeSessionId(value) {
|
|
28
|
+
if (typeof value !== "string") return void 0;
|
|
29
|
+
const normalized = value.trim();
|
|
30
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
31
|
+
}
|
|
32
|
+
function normalizeSessionOptions(session) {
|
|
33
|
+
if (session === false) return void 0;
|
|
34
|
+
if (typeof session === "string") return {
|
|
35
|
+
contextKey: DEFAULT_SESSION_CONTEXT_KEY,
|
|
36
|
+
id: normalizeSessionId(session) ?? defaultPageSessionId()
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
contextKey: session?.contextKey ?? DEFAULT_SESSION_CONTEXT_KEY,
|
|
40
|
+
getId: session?.getId,
|
|
41
|
+
id: normalizeSessionId(session?.id) ?? defaultPageSessionId()
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function resolveLocalStorage(storage) {
|
|
45
|
+
if (storage) return storage;
|
|
46
|
+
try {
|
|
47
|
+
return globalThis.localStorage;
|
|
48
|
+
} catch {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function normalizeLocalStorageSpillOptions(spill, dbName, storeName) {
|
|
53
|
+
if (!spill) return void 0;
|
|
54
|
+
const storage = resolveLocalStorage(spill.storage);
|
|
55
|
+
if (!storage) return void 0;
|
|
56
|
+
const namespace = spill.namespace ?? `${dbName}:${storeName}`;
|
|
57
|
+
return {
|
|
58
|
+
drainOnCreate: spill.drainOnCreate ?? true,
|
|
59
|
+
key: `loggerjs:spill:v1:${namespace}`,
|
|
60
|
+
maxBytes: normalizePositiveInteger(spill.maxBytes, DEFAULT_SPILL_MAX_BYTES),
|
|
61
|
+
maxEntries: normalizePositiveInteger(spill.maxEntries, DEFAULT_SPILL_MAX_ENTRIES),
|
|
62
|
+
maxOriginBytes: normalizePositiveInteger(spill.maxOriginBytes, DEFAULT_SPILL_MAX_ORIGIN_BYTES),
|
|
63
|
+
minLevelValue: spill.minLevel === void 0 ? void 0 : (0, _loggerjs_core.toLevelValue)(spill.minLevel),
|
|
64
|
+
onDrop: spill.onDrop,
|
|
65
|
+
spillOnPageHide: spill.spillOnPageHide ?? true,
|
|
66
|
+
storage
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function storageByteLength(key, value) {
|
|
70
|
+
return 2 * (key.length + value.length);
|
|
71
|
+
}
|
|
72
|
+
function estimateLocalStorageBytes(storage) {
|
|
73
|
+
try {
|
|
74
|
+
let total = 0;
|
|
75
|
+
for (let index = 0; index < storage.length; index += 1) {
|
|
76
|
+
const key = storage.key(index);
|
|
77
|
+
if (key === null) continue;
|
|
78
|
+
total += storageByteLength(key, storage.getItem(key) ?? "");
|
|
79
|
+
}
|
|
80
|
+
return total;
|
|
81
|
+
} catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function isQuotaExceededError(error) {
|
|
86
|
+
return typeof DOMException !== "undefined" && error instanceof DOMException && (error.name === "QuotaExceededError" || error.name === "NS_ERROR_DOM_QUOTA_REACHED");
|
|
87
|
+
}
|
|
88
|
+
function isSpillLogEvent(value) {
|
|
89
|
+
if (!value || typeof value !== "object") return false;
|
|
90
|
+
const event = value;
|
|
91
|
+
return typeof event.id === "string" && typeof event.time === "number" && typeof event.seq === "number" && typeof event.level === "number" && typeof event.levelName === "string" && typeof event.logger === "string" && typeof event.message === "string";
|
|
92
|
+
}
|
|
93
|
+
function parseSpillPayload(raw) {
|
|
94
|
+
const parsed = JSON.parse(raw);
|
|
95
|
+
if (parsed.schema !== SPILL_SCHEMA || !Array.isArray(parsed.entries)) return void 0;
|
|
96
|
+
return parsed.entries.filter(isSpillLogEvent);
|
|
97
|
+
}
|
|
12
98
|
function nowMs() {
|
|
13
99
|
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
14
100
|
}
|
|
@@ -51,6 +137,9 @@ function indexExists(store, name) {
|
|
|
51
137
|
function ensureIndex(store, name, keyPath) {
|
|
52
138
|
if (!indexExists(store, name)) store.createIndex(name, keyPath);
|
|
53
139
|
}
|
|
140
|
+
function sessionStoreNameFor(storeName) {
|
|
141
|
+
return `${storeName}${SESSION_STORE_SUFFIX}`;
|
|
142
|
+
}
|
|
54
143
|
function getStoreIndex(store, name) {
|
|
55
144
|
const maybeStore = store;
|
|
56
145
|
if (typeof maybeStore.index !== "function" || !indexExists(store, name)) return void 0;
|
|
@@ -74,13 +163,67 @@ function decodeEntry(entry, codec) {
|
|
|
74
163
|
function shouldKeepEntry(entry, options) {
|
|
75
164
|
if (options.from !== void 0 && entry.createdAt < options.from) return false;
|
|
76
165
|
if (options.to !== void 0 && entry.createdAt > options.to) return false;
|
|
166
|
+
if (options.sessionId !== void 0 && entry.sessionId !== options.sessionId) return false;
|
|
77
167
|
if (options.minLevel !== void 0 && entry.level < (0, _loggerjs_core.toLevelValue)(options.minLevel)) return false;
|
|
78
168
|
if (options.logger !== void 0 && entry.logger !== options.logger) return false;
|
|
79
169
|
if (options.type !== void 0 && entry.type !== options.type) return false;
|
|
80
170
|
return true;
|
|
81
171
|
}
|
|
172
|
+
function addSessionSummary(sessions, entry) {
|
|
173
|
+
if (!entry.sessionId) return;
|
|
174
|
+
const current = sessions.get(entry.sessionId);
|
|
175
|
+
if (current) {
|
|
176
|
+
current.firstSeen = Math.min(current.firstSeen, entry.createdAt);
|
|
177
|
+
current.lastSeen = Math.max(current.lastSeen, entry.createdAt);
|
|
178
|
+
current.count += 1;
|
|
179
|
+
current.byteLength += entry.byteLength;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
sessions.set(entry.sessionId, {
|
|
183
|
+
byteLength: entry.byteLength,
|
|
184
|
+
count: 1,
|
|
185
|
+
firstSeen: entry.createdAt,
|
|
186
|
+
lastSeen: entry.createdAt,
|
|
187
|
+
sessionId: entry.sessionId
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
function mergeSessionSummary(current, incoming) {
|
|
191
|
+
if (!current) return incoming;
|
|
192
|
+
return {
|
|
193
|
+
byteLength: current.byteLength + incoming.byteLength,
|
|
194
|
+
count: current.count + incoming.count,
|
|
195
|
+
firstSeen: Math.min(current.firstSeen, incoming.firstSeen),
|
|
196
|
+
lastSeen: Math.max(current.lastSeen, incoming.lastSeen),
|
|
197
|
+
sessionId: incoming.sessionId
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function orderSessions(sessions, order = "desc") {
|
|
201
|
+
const sorted = [...sessions].sort((left, right) => {
|
|
202
|
+
if (left.lastSeen !== right.lastSeen) return left.lastSeen - right.lastSeen;
|
|
203
|
+
return left.sessionId < right.sessionId ? -1 : left.sessionId > right.sessionId ? 1 : 0;
|
|
204
|
+
});
|
|
205
|
+
if (order === "asc") return sorted;
|
|
206
|
+
const reversed = [];
|
|
207
|
+
for (let index = sorted.length - 1; index >= 0; index -= 1) reversed.push(sorted[index]);
|
|
208
|
+
return reversed;
|
|
209
|
+
}
|
|
82
210
|
function orderRangeForQuery(options) {
|
|
83
211
|
if (typeof IDBKeyRange === "undefined") return void 0;
|
|
212
|
+
if (options.sessionId !== void 0) {
|
|
213
|
+
const lower = [
|
|
214
|
+
options.sessionId,
|
|
215
|
+
options.from ?? Number.MIN_SAFE_INTEGER,
|
|
216
|
+
Number.MIN_SAFE_INTEGER,
|
|
217
|
+
""
|
|
218
|
+
];
|
|
219
|
+
const upper = [
|
|
220
|
+
options.sessionId,
|
|
221
|
+
options.to ?? Number.MAX_SAFE_INTEGER,
|
|
222
|
+
Number.MAX_SAFE_INTEGER,
|
|
223
|
+
""
|
|
224
|
+
];
|
|
225
|
+
return IDBKeyRange.bound(lower, upper);
|
|
226
|
+
}
|
|
84
227
|
const lower = options.from === void 0 ? void 0 : [
|
|
85
228
|
options.from,
|
|
86
229
|
Number.MIN_SAFE_INTEGER,
|
|
@@ -95,6 +238,33 @@ function orderRangeForQuery(options) {
|
|
|
95
238
|
if (lower) return IDBKeyRange.lowerBound(lower);
|
|
96
239
|
if (upper) return IDBKeyRange.upperBound(upper);
|
|
97
240
|
}
|
|
241
|
+
function orderRangeForSessionId(sessionId) {
|
|
242
|
+
if (typeof IDBKeyRange === "undefined") return void 0;
|
|
243
|
+
return IDBKeyRange.bound([
|
|
244
|
+
sessionId,
|
|
245
|
+
Number.MIN_SAFE_INTEGER,
|
|
246
|
+
Number.MIN_SAFE_INTEGER,
|
|
247
|
+
""
|
|
248
|
+
], [
|
|
249
|
+
sessionId,
|
|
250
|
+
Number.MAX_SAFE_INTEGER,
|
|
251
|
+
Number.MAX_SAFE_INTEGER,
|
|
252
|
+
""
|
|
253
|
+
]);
|
|
254
|
+
}
|
|
255
|
+
function migrateSessionSummaries(logStore, sessionStore) {
|
|
256
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
257
|
+
const request = logStore.openCursor();
|
|
258
|
+
request.addEventListener("success", () => {
|
|
259
|
+
const cursor = request.result;
|
|
260
|
+
if (!cursor) {
|
|
261
|
+
for (const summary of summaries.values()) sessionStore.put(summary);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
addSessionSummary(summaries, cursor.value);
|
|
265
|
+
cursor.continue();
|
|
266
|
+
});
|
|
267
|
+
}
|
|
98
268
|
function iterateCursor(request, visit) {
|
|
99
269
|
return new Promise((resolve, reject) => {
|
|
100
270
|
request.addEventListener("success", () => {
|
|
@@ -119,6 +289,7 @@ function iterateCursor(request, visit) {
|
|
|
119
289
|
function indexedDbTransport(options = {}) {
|
|
120
290
|
const dbName = options.dbName ?? DEFAULT_DB_NAME;
|
|
121
291
|
const storeName = options.storeName ?? DEFAULT_STORE_NAME;
|
|
292
|
+
const sessionStoreName = sessionStoreNameFor(storeName);
|
|
122
293
|
const codec = options.codec ?? (0, _loggerjs_core.safeJsonCodec)();
|
|
123
294
|
const batchSize = normalizePositiveInteger(options.batchSize, 100);
|
|
124
295
|
const flushIntervalMs = normalizePositiveInteger(options.flushIntervalMs, 1e3);
|
|
@@ -129,12 +300,18 @@ function indexedDbTransport(options = {}) {
|
|
|
129
300
|
const flushOnPageHide = options.flushOnPageHide ?? true;
|
|
130
301
|
const durability = options.durability ?? "default";
|
|
131
302
|
const rootIndexedDB = options.indexedDB ?? globalThis.indexedDB;
|
|
303
|
+
const sessionOptions = normalizeSessionOptions(options.session);
|
|
304
|
+
const spillOptions = normalizeLocalStorageSpillOptions(options.localStorageSpill, dbName, storeName);
|
|
132
305
|
const transactionOptions = durability === "default" ? void 0 : { durability };
|
|
133
306
|
const buffer = [];
|
|
134
307
|
let dbPromise;
|
|
135
308
|
let indexedDBFactoryPromise;
|
|
136
309
|
let timer;
|
|
137
310
|
let flushPromise;
|
|
311
|
+
let clearPromise;
|
|
312
|
+
let pendingFlushBatch;
|
|
313
|
+
let spillDrainPromise;
|
|
314
|
+
let localStorageSpillClearCandidate;
|
|
138
315
|
let lastContext;
|
|
139
316
|
let closed = false;
|
|
140
317
|
const statsState = {
|
|
@@ -161,13 +338,23 @@ function indexedDbTransport(options = {}) {
|
|
|
161
338
|
storageBucketFallbacks: 0,
|
|
162
339
|
transactionOptionFallbacks: 0,
|
|
163
340
|
errors: 0,
|
|
164
|
-
errorsByOperation: {}
|
|
341
|
+
errorsByOperation: {},
|
|
342
|
+
localStorageSpillWrites: 0,
|
|
343
|
+
localStorageSpillEntries: 0,
|
|
344
|
+
localStorageSpillDrains: 0,
|
|
345
|
+
localStorageSpillDrainedEntries: 0,
|
|
346
|
+
localStorageSpillDropped: 0,
|
|
347
|
+
localStorageSpillDroppedByReason: {},
|
|
348
|
+
localStorageSpillErrors: 0,
|
|
349
|
+
localStorageSpillErrorsByOperation: {}
|
|
165
350
|
};
|
|
166
351
|
const snapshotStats = () => ({
|
|
167
352
|
...statsState,
|
|
168
353
|
bufferDepth: buffer.length,
|
|
169
354
|
droppedByReason: { ...statsState.droppedByReason },
|
|
170
355
|
errorsByOperation: { ...statsState.errorsByOperation },
|
|
356
|
+
localStorageSpillDroppedByReason: { ...statsState.localStorageSpillDroppedByReason },
|
|
357
|
+
localStorageSpillErrorsByOperation: { ...statsState.localStorageSpillErrorsByOperation },
|
|
171
358
|
pendingFlush: flushPromise !== void 0,
|
|
172
359
|
persistedDroppedByReason: { ...statsState.persistedDroppedByReason }
|
|
173
360
|
});
|
|
@@ -194,6 +381,18 @@ function indexedDbTransport(options = {}) {
|
|
|
194
381
|
(0, _loggerjs_core.incrementLoggerMetaCounter)(`transport.indexeddb.persisted.dropped.${reason}`);
|
|
195
382
|
options.onPersistedDrop?.(entry, reason);
|
|
196
383
|
};
|
|
384
|
+
const reportSpillError = (error, operation) => {
|
|
385
|
+
statsState.localStorageSpillErrors += 1;
|
|
386
|
+
incrementRecord(statsState.localStorageSpillErrorsByOperation, operation);
|
|
387
|
+
reportInternalError(error, `localstorage-spill-${operation}`);
|
|
388
|
+
};
|
|
389
|
+
const dropSpillEvent = (event, reason) => {
|
|
390
|
+
statsState.localStorageSpillDropped += 1;
|
|
391
|
+
incrementRecord(statsState.localStorageSpillDroppedByReason, reason);
|
|
392
|
+
(0, _loggerjs_core.incrementLoggerMetaCounter)("transport.indexeddb.localstorage_spill.dropped");
|
|
393
|
+
(0, _loggerjs_core.incrementLoggerMetaCounter)(`transport.indexeddb.localstorage_spill.dropped.${reason}`);
|
|
394
|
+
spillOptions?.onDrop?.(event, reason);
|
|
395
|
+
};
|
|
197
396
|
const resolveIndexedDBFactory = async () => {
|
|
198
397
|
if (options.indexedDB || !options.storageBucketName) return rootIndexedDB;
|
|
199
398
|
indexedDBFactoryPromise ??= (async () => {
|
|
@@ -220,7 +419,7 @@ function indexedDbTransport(options = {}) {
|
|
|
220
419
|
if (!idb) throw new Error("IndexedDB is not available for indexedDbTransport");
|
|
221
420
|
return new Promise((resolve, reject) => {
|
|
222
421
|
const request = idb.open(dbName, DB_VERSION);
|
|
223
|
-
request.addEventListener("upgradeneeded", () => {
|
|
422
|
+
request.addEventListener("upgradeneeded", (event) => {
|
|
224
423
|
const db = request.result;
|
|
225
424
|
const store = db.objectStoreNames.contains(storeName) ? request.transaction?.objectStore(storeName) : db.createObjectStore(storeName, { keyPath: "id" });
|
|
226
425
|
if (!store) return;
|
|
@@ -233,6 +432,17 @@ function indexedDbTransport(options = {}) {
|
|
|
233
432
|
"seq",
|
|
234
433
|
"id"
|
|
235
434
|
]);
|
|
435
|
+
ensureIndex(store, SESSION_INDEX_NAME, "sessionId");
|
|
436
|
+
ensureIndex(store, SESSION_ORDER_INDEX_NAME, [
|
|
437
|
+
"sessionId",
|
|
438
|
+
"createdAt",
|
|
439
|
+
"seq",
|
|
440
|
+
"id"
|
|
441
|
+
]);
|
|
442
|
+
const sessionStore = db.objectStoreNames.contains(sessionStoreName) ? request.transaction?.objectStore(sessionStoreName) : db.createObjectStore(sessionStoreName, { keyPath: "sessionId" });
|
|
443
|
+
if (!sessionStore) return;
|
|
444
|
+
ensureIndex(sessionStore, SESSION_LAST_SEEN_INDEX_NAME, ["lastSeen", "sessionId"]);
|
|
445
|
+
if (event.oldVersion < 4) migrateSessionSummaries(store, sessionStore);
|
|
236
446
|
});
|
|
237
447
|
request.addEventListener("success", () => {
|
|
238
448
|
statsState.databaseOpenCount += 1;
|
|
@@ -243,13 +453,13 @@ function indexedDbTransport(options = {}) {
|
|
|
243
453
|
});
|
|
244
454
|
return dbPromise;
|
|
245
455
|
};
|
|
246
|
-
const createTransaction = (db, mode) => {
|
|
247
|
-
if (mode !== "readwrite" || !transactionOptions) return db.transaction(
|
|
456
|
+
const createTransaction = (db, mode, stores = storeName) => {
|
|
457
|
+
if (mode !== "readwrite" || !transactionOptions) return db.transaction(stores, mode);
|
|
248
458
|
try {
|
|
249
|
-
return db.transaction(
|
|
459
|
+
return db.transaction(stores, mode, transactionOptions);
|
|
250
460
|
} catch {
|
|
251
461
|
statsState.transactionOptionFallbacks += 1;
|
|
252
|
-
return db.transaction(
|
|
462
|
+
return db.transaction(stores, mode);
|
|
253
463
|
}
|
|
254
464
|
};
|
|
255
465
|
const withStore = async (mode, run) => {
|
|
@@ -266,6 +476,57 @@ function indexedDbTransport(options = {}) {
|
|
|
266
476
|
throw error;
|
|
267
477
|
}
|
|
268
478
|
};
|
|
479
|
+
const withLogAndSessionStores = async (mode, run) => {
|
|
480
|
+
const tx = createTransaction(await openDb(), mode, [storeName, sessionStoreName]);
|
|
481
|
+
const settled = transactionToPromise(tx);
|
|
482
|
+
try {
|
|
483
|
+
const result = await run(tx.objectStore(storeName), tx.objectStore(sessionStoreName), tx);
|
|
484
|
+
await settled;
|
|
485
|
+
return result;
|
|
486
|
+
} catch (error) {
|
|
487
|
+
if (tx.error === null) try {
|
|
488
|
+
tx.abort();
|
|
489
|
+
} catch {}
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
const withSessionStore = async (mode, run) => {
|
|
494
|
+
const tx = createTransaction(await openDb(), mode, sessionStoreName);
|
|
495
|
+
const settled = transactionToPromise(tx);
|
|
496
|
+
try {
|
|
497
|
+
const result = await run(tx.objectStore(sessionStoreName), tx);
|
|
498
|
+
await settled;
|
|
499
|
+
return result;
|
|
500
|
+
} catch (error) {
|
|
501
|
+
if (tx.error === null) try {
|
|
502
|
+
tx.abort();
|
|
503
|
+
} catch {}
|
|
504
|
+
throw error;
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
const mergeSessionSummaries = async (sessionStore, entries) => {
|
|
508
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
509
|
+
for (const entry of entries) addSessionSummary(summaries, entry);
|
|
510
|
+
for (const summary of summaries.values()) {
|
|
511
|
+
const current = await requestToPromise(sessionStore.get(summary.sessionId));
|
|
512
|
+
await requestToPromise(sessionStore.put(mergeSessionSummary(current, summary)));
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
const rebuildSessionSummaries = async (store, sessionStore, sessionIds) => {
|
|
516
|
+
if (sessionIds.size === 0) return;
|
|
517
|
+
const index = getStoreIndex(store, SESSION_ORDER_INDEX_NAME);
|
|
518
|
+
for (const sessionId of sessionIds) {
|
|
519
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
520
|
+
const range = orderRangeForSessionId(sessionId);
|
|
521
|
+
await iterateCursor(index && range ? index.openCursor(range) : store.openCursor(), (cursor) => {
|
|
522
|
+
const entry = cursor.value;
|
|
523
|
+
if (entry.sessionId === sessionId) addSessionSummary(summaries, entry);
|
|
524
|
+
});
|
|
525
|
+
const summary = summaries.get(sessionId);
|
|
526
|
+
if (summary) await requestToPromise(sessionStore.put(summary));
|
|
527
|
+
else await requestToPromise(sessionStore.delete(sessionId));
|
|
528
|
+
}
|
|
529
|
+
};
|
|
269
530
|
const getEntries = async () => orderEntries(await withStore("readonly", (store) => requestToPromise(store.getAll())));
|
|
270
531
|
const countEntries = async () => withStore("readonly", (store) => {
|
|
271
532
|
const maybeStore = store;
|
|
@@ -274,25 +535,31 @@ function indexedDbTransport(options = {}) {
|
|
|
274
535
|
});
|
|
275
536
|
const deleteEntries = async (entries, reason) => {
|
|
276
537
|
if (entries.length === 0) return;
|
|
277
|
-
await
|
|
538
|
+
await withLogAndSessionStores("readwrite", async (store, sessionStore) => {
|
|
539
|
+
const affectedSessionIds = /* @__PURE__ */ new Set();
|
|
278
540
|
for (const entry of entries) {
|
|
279
541
|
await requestToPromise(store.delete(entry.id));
|
|
542
|
+
if (entry.sessionId) affectedSessionIds.add(entry.sessionId);
|
|
280
543
|
dropPersistedEntry(entry, reason);
|
|
281
544
|
}
|
|
545
|
+
await rebuildSessionSummaries(store, sessionStore, affectedSessionIds);
|
|
282
546
|
});
|
|
283
547
|
};
|
|
284
|
-
const deleteByCursor = async (reason, openCursor, shouldDelete) =>
|
|
548
|
+
const deleteByCursor = async (reason, openCursor, shouldDelete) => withLogAndSessionStores("readwrite", async (store, sessionStore) => {
|
|
285
549
|
const request = openCursor(store);
|
|
286
550
|
if (!request) return void 0;
|
|
287
551
|
let deleted = 0;
|
|
552
|
+
const affectedSessionIds = /* @__PURE__ */ new Set();
|
|
288
553
|
await iterateCursor(request, (cursor) => {
|
|
289
554
|
const entry = cursor.value;
|
|
290
555
|
if (!shouldDelete(entry, deleted)) return false;
|
|
291
556
|
cursor.delete();
|
|
292
557
|
deleted += 1;
|
|
558
|
+
if (entry.sessionId) affectedSessionIds.add(entry.sessionId);
|
|
293
559
|
dropPersistedEntry(entry, reason);
|
|
294
560
|
return true;
|
|
295
561
|
});
|
|
562
|
+
await rebuildSessionSummaries(store, sessionStore, affectedSessionIds);
|
|
296
563
|
return deleted;
|
|
297
564
|
});
|
|
298
565
|
const deleteExpiredByCursor = async (cutoff) => {
|
|
@@ -323,7 +590,7 @@ function indexedDbTransport(options = {}) {
|
|
|
323
590
|
return total;
|
|
324
591
|
});
|
|
325
592
|
const queryEntriesByCursor = async (queryOptions) => withStore("readonly", async (store) => {
|
|
326
|
-
const index = getStoreIndex(store, ORDER_INDEX_NAME);
|
|
593
|
+
const index = getStoreIndex(store, queryOptions.sessionId === void 0 ? ORDER_INDEX_NAME : SESSION_ORDER_INDEX_NAME);
|
|
327
594
|
if (!index) return void 0;
|
|
328
595
|
const entries = [];
|
|
329
596
|
const limit = queryOptions.limit;
|
|
@@ -336,6 +603,20 @@ function indexedDbTransport(options = {}) {
|
|
|
336
603
|
});
|
|
337
604
|
return entries;
|
|
338
605
|
});
|
|
606
|
+
const listSessions = async (sessionQueryOptions = {}) => {
|
|
607
|
+
const limit = sessionQueryOptions.limit;
|
|
608
|
+
if (limit !== void 0 && limit <= 0) return [];
|
|
609
|
+
return withSessionStore("readonly", async (sessionStore) => {
|
|
610
|
+
const sessions = [];
|
|
611
|
+
const index = getStoreIndex(sessionStore, SESSION_LAST_SEEN_INDEX_NAME);
|
|
612
|
+
if (!index) return orderSessions(await requestToPromise(sessionStore.getAll()), sessionQueryOptions.order).slice(0, limit);
|
|
613
|
+
await iterateCursor(index.openCursor(void 0, sessionQueryOptions.order === "asc" ? "next" : "prev"), (cursor) => {
|
|
614
|
+
sessions.push(cursor.value);
|
|
615
|
+
return limit === void 0 || sessions.length < limit;
|
|
616
|
+
});
|
|
617
|
+
return sessions;
|
|
618
|
+
});
|
|
619
|
+
};
|
|
339
620
|
const pruneWithEntries = async () => {
|
|
340
621
|
const now = Date.now();
|
|
341
622
|
let entries = await getEntries();
|
|
@@ -391,10 +672,34 @@ function indexedDbTransport(options = {}) {
|
|
|
391
672
|
statsState.lastPruneDurationMs = nowMs() - startedAt;
|
|
392
673
|
}
|
|
393
674
|
};
|
|
675
|
+
const sessionIdForEvent = (event) => {
|
|
676
|
+
if (!sessionOptions) return void 0;
|
|
677
|
+
return normalizeSessionId(sessionOptions.getId?.(event)) ?? normalizeSessionId(event.context?.[sessionOptions.contextKey]) ?? sessionOptions.id;
|
|
678
|
+
};
|
|
679
|
+
const eventWithSessionContext = (event, sessionId) => {
|
|
680
|
+
if (!sessionId || !sessionOptions?.contextKey) return event;
|
|
681
|
+
if (event.context?.[sessionOptions.contextKey] === sessionId) return event;
|
|
682
|
+
return {
|
|
683
|
+
...event,
|
|
684
|
+
context: {
|
|
685
|
+
...event.context,
|
|
686
|
+
[sessionOptions.contextKey]: sessionId
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
};
|
|
690
|
+
const eventWithResolvedSession = (event) => {
|
|
691
|
+
const sessionId = sessionIdForEvent(event);
|
|
692
|
+
return {
|
|
693
|
+
event: eventWithSessionContext(event, sessionId),
|
|
694
|
+
sessionId
|
|
695
|
+
};
|
|
696
|
+
};
|
|
394
697
|
const eventToEntry = (event) => {
|
|
395
|
-
const
|
|
698
|
+
const resolved = eventWithResolvedSession(event);
|
|
699
|
+
const payload = codec.encode(resolved.event);
|
|
396
700
|
return {
|
|
397
701
|
id: event.id,
|
|
702
|
+
sessionId: resolved.sessionId,
|
|
398
703
|
seq: event.seq,
|
|
399
704
|
createdAt: event.time,
|
|
400
705
|
level: event.level,
|
|
@@ -405,17 +710,50 @@ function indexedDbTransport(options = {}) {
|
|
|
405
710
|
payload
|
|
406
711
|
};
|
|
407
712
|
};
|
|
713
|
+
const clearLocalStorageSpill = (expectedValue) => {
|
|
714
|
+
if (!spillOptions) return false;
|
|
715
|
+
try {
|
|
716
|
+
if (expectedValue !== void 0 && spillOptions.storage.getItem(spillOptions.key) !== expectedValue) return false;
|
|
717
|
+
spillOptions.storage.removeItem(spillOptions.key);
|
|
718
|
+
if (expectedValue === void 0 || localStorageSpillClearCandidate?.value === expectedValue) localStorageSpillClearCandidate = void 0;
|
|
719
|
+
return true;
|
|
720
|
+
} catch (error) {
|
|
721
|
+
reportSpillError(error, "clear");
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
const rememberLocalStorageSpill = (value, events) => {
|
|
726
|
+
localStorageSpillClearCandidate = {
|
|
727
|
+
pendingIds: new Set(events.map((event) => event.id)),
|
|
728
|
+
value
|
|
729
|
+
};
|
|
730
|
+
};
|
|
731
|
+
const markLocalStorageSpillPersisted = (events) => {
|
|
732
|
+
const candidate = localStorageSpillClearCandidate;
|
|
733
|
+
if (!candidate || events.length === 0) return;
|
|
734
|
+
for (const event of events) candidate.pendingIds.delete(event.id);
|
|
735
|
+
if (candidate.pendingIds.size === 0) clearLocalStorageSpill(candidate.value);
|
|
736
|
+
};
|
|
408
737
|
const writeBatch = async (events) => {
|
|
409
738
|
if (events.length === 0) return;
|
|
410
739
|
const startedAt = nowMs();
|
|
411
740
|
statsState.lastFlushBatchSize = events.length;
|
|
412
741
|
const entries = events.map(eventToEntry);
|
|
413
742
|
try {
|
|
414
|
-
await
|
|
415
|
-
|
|
743
|
+
await withLogAndSessionStores("readwrite", async (store, sessionStore) => {
|
|
744
|
+
const rebuildSessionIds = /* @__PURE__ */ new Set();
|
|
745
|
+
for (const entry of entries) {
|
|
746
|
+
const existing = await requestToPromise(store.get(entry.id));
|
|
747
|
+
if (existing?.sessionId) rebuildSessionIds.add(existing.sessionId);
|
|
748
|
+
if (existing && entry.sessionId) rebuildSessionIds.add(entry.sessionId);
|
|
749
|
+
await requestToPromise(store.put(entry));
|
|
750
|
+
}
|
|
751
|
+
await rebuildSessionSummaries(store, sessionStore, rebuildSessionIds);
|
|
752
|
+
await mergeSessionSummaries(sessionStore, entries.filter((entry) => !entry.sessionId || !rebuildSessionIds.has(entry.sessionId)));
|
|
416
753
|
});
|
|
417
754
|
statsState.persisted += entries.length;
|
|
418
755
|
(0, _loggerjs_core.incrementLoggerMetaCounter)("transport.indexeddb.persisted", entries.length);
|
|
756
|
+
markLocalStorageSpillPersisted(events);
|
|
419
757
|
await prune();
|
|
420
758
|
statsState.flushes += 1;
|
|
421
759
|
} catch (error) {
|
|
@@ -425,6 +763,124 @@ function indexedDbTransport(options = {}) {
|
|
|
425
763
|
statsState.lastFlushDurationMs = nowMs() - startedAt;
|
|
426
764
|
}
|
|
427
765
|
};
|
|
766
|
+
const stringifySpillPayload = (events) => (0, _loggerjs_core.safeJsonStringify)({
|
|
767
|
+
createdAt: Date.now(),
|
|
768
|
+
entries: events,
|
|
769
|
+
schema: SPILL_SCHEMA
|
|
770
|
+
}, { maxArrayLength: spillOptions?.maxEntries ?? DEFAULT_SPILL_MAX_ENTRIES });
|
|
771
|
+
const spillStorageBudget = (currentValue) => {
|
|
772
|
+
if (!spillOptions) return 0;
|
|
773
|
+
const ownBytes = currentValue ? storageByteLength(spillOptions.key, currentValue) : 0;
|
|
774
|
+
const originBytes = estimateLocalStorageBytes(spillOptions.storage);
|
|
775
|
+
if (originBytes === void 0) return spillOptions.maxBytes;
|
|
776
|
+
return Math.max(0, Math.min(spillOptions.maxBytes, spillOptions.maxOriginBytes - originBytes + ownBytes));
|
|
777
|
+
};
|
|
778
|
+
const pendingEventsForSpill = () => {
|
|
779
|
+
const events = [...pendingFlushBatch ?? [], ...buffer];
|
|
780
|
+
const seen = /* @__PURE__ */ new Set();
|
|
781
|
+
const deduped = [];
|
|
782
|
+
for (const event of events) {
|
|
783
|
+
if (seen.has(event.id)) continue;
|
|
784
|
+
seen.add(event.id);
|
|
785
|
+
if (spillOptions?.minLevelValue !== void 0 && event.level < spillOptions.minLevelValue) continue;
|
|
786
|
+
deduped.push(eventWithResolvedSession(event).event);
|
|
787
|
+
}
|
|
788
|
+
return deduped;
|
|
789
|
+
};
|
|
790
|
+
const trimSpillEventsToBudget = (events, budget) => {
|
|
791
|
+
if (!spillOptions) return void 0;
|
|
792
|
+
while (events.length > spillOptions.maxEntries) {
|
|
793
|
+
const dropped = events.shift();
|
|
794
|
+
if (dropped) dropSpillEvent(dropped, "max-entries");
|
|
795
|
+
}
|
|
796
|
+
while (events.length > 0) {
|
|
797
|
+
const value = stringifySpillPayload(events);
|
|
798
|
+
if (storageByteLength(spillOptions.key, value) <= budget) return value;
|
|
799
|
+
const dropped = events.shift();
|
|
800
|
+
if (dropped) dropSpillEvent(dropped, "max-bytes");
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
const writeLocalStorageSpill = () => {
|
|
804
|
+
if (!spillOptions) return;
|
|
805
|
+
const pendingEvents = pendingEventsForSpill();
|
|
806
|
+
if (pendingEvents.length === 0) return;
|
|
807
|
+
try {
|
|
808
|
+
const currentValue = spillOptions.storage.getItem(spillOptions.key);
|
|
809
|
+
let events = pendingEvents;
|
|
810
|
+
if (currentValue) {
|
|
811
|
+
const merged = /* @__PURE__ */ new Map();
|
|
812
|
+
try {
|
|
813
|
+
for (const event of parseSpillPayload(currentValue) ?? []) merged.set(event.id, event);
|
|
814
|
+
} catch {}
|
|
815
|
+
for (const event of pendingEvents) merged.set(event.id, event);
|
|
816
|
+
events = [...merged.values()];
|
|
817
|
+
}
|
|
818
|
+
const budget = spillStorageBudget(currentValue);
|
|
819
|
+
const value = trimSpillEventsToBudget(events, budget);
|
|
820
|
+
if (!value) return;
|
|
821
|
+
try {
|
|
822
|
+
spillOptions.storage.setItem(spillOptions.key, value);
|
|
823
|
+
} catch (error) {
|
|
824
|
+
if (!isQuotaExceededError(error)) throw error;
|
|
825
|
+
while (events.length > 0) {
|
|
826
|
+
const dropped = events.shift();
|
|
827
|
+
if (dropped) dropSpillEvent(dropped, "quota");
|
|
828
|
+
const retryValue = trimSpillEventsToBudget(events, budget);
|
|
829
|
+
if (!retryValue) return;
|
|
830
|
+
try {
|
|
831
|
+
spillOptions.storage.setItem(spillOptions.key, retryValue);
|
|
832
|
+
rememberLocalStorageSpill(retryValue, events);
|
|
833
|
+
statsState.localStorageSpillWrites += 1;
|
|
834
|
+
statsState.localStorageSpillEntries += events.length;
|
|
835
|
+
return;
|
|
836
|
+
} catch (retryError) {
|
|
837
|
+
if (!isQuotaExceededError(retryError)) throw retryError;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
rememberLocalStorageSpill(value, events);
|
|
843
|
+
statsState.localStorageSpillWrites += 1;
|
|
844
|
+
statsState.localStorageSpillEntries += events.length;
|
|
845
|
+
} catch (error) {
|
|
846
|
+
reportSpillError(error, "write");
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
const drainLocalStorageSpill = async () => {
|
|
850
|
+
if (!spillOptions) return;
|
|
851
|
+
let raw;
|
|
852
|
+
try {
|
|
853
|
+
raw = spillOptions.storage.getItem(spillOptions.key);
|
|
854
|
+
} catch (error) {
|
|
855
|
+
reportSpillError(error, "read");
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
if (!raw) return;
|
|
859
|
+
let events;
|
|
860
|
+
try {
|
|
861
|
+
events = parseSpillPayload(raw);
|
|
862
|
+
} catch (error) {
|
|
863
|
+
reportSpillError(error, "parse");
|
|
864
|
+
clearLocalStorageSpill();
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
if (!events || events.length === 0) {
|
|
868
|
+
clearLocalStorageSpill();
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
await writeBatch(events);
|
|
872
|
+
clearLocalStorageSpill(raw);
|
|
873
|
+
statsState.localStorageSpillDrains += 1;
|
|
874
|
+
statsState.localStorageSpillDrainedEntries += events.length;
|
|
875
|
+
};
|
|
876
|
+
const ensureSpillDrained = async () => {
|
|
877
|
+
const promise = spillDrainPromise;
|
|
878
|
+
if (!promise) return;
|
|
879
|
+
await promise;
|
|
880
|
+
};
|
|
881
|
+
if (spillOptions?.drainOnCreate) spillDrainPromise = drainLocalStorageSpill().catch((error) => reportSpillError(error, "drain")).finally(() => {
|
|
882
|
+
spillDrainPromise = void 0;
|
|
883
|
+
});
|
|
428
884
|
const clearTimer = () => {
|
|
429
885
|
if (timer) clearTimeout(timer);
|
|
430
886
|
timer = void 0;
|
|
@@ -432,7 +888,15 @@ function indexedDbTransport(options = {}) {
|
|
|
432
888
|
const flushPending = async () => {
|
|
433
889
|
if (flushPromise) return flushPromise;
|
|
434
890
|
clearTimer();
|
|
435
|
-
|
|
891
|
+
const batch = buffer.splice(0, buffer.length);
|
|
892
|
+
pendingFlushBatch = batch;
|
|
893
|
+
const clearBarrier = clearPromise;
|
|
894
|
+
flushPromise = (async () => {
|
|
895
|
+
await clearBarrier;
|
|
896
|
+
await ensureSpillDrained();
|
|
897
|
+
await writeBatch(batch);
|
|
898
|
+
})().finally(() => {
|
|
899
|
+
if (pendingFlushBatch === batch) pendingFlushBatch = void 0;
|
|
436
900
|
flushPromise = void 0;
|
|
437
901
|
if (buffer.length > 0 && !closed) schedule();
|
|
438
902
|
});
|
|
@@ -445,14 +909,28 @@ function indexedDbTransport(options = {}) {
|
|
|
445
909
|
}, flushIntervalMs);
|
|
446
910
|
};
|
|
447
911
|
const onPageHide = () => {
|
|
448
|
-
|
|
912
|
+
if (spillOptions?.spillOnPageHide) writeLocalStorageSpill();
|
|
913
|
+
if (flushOnPageHide) flushPending().catch((error) => reportInternalError(error, "pagehide-flush"));
|
|
449
914
|
};
|
|
450
915
|
const onVisibilityChange = () => {
|
|
451
|
-
if (typeof document !== "undefined" && document.visibilityState === "hidden")
|
|
916
|
+
if (typeof document !== "undefined" && document.visibilityState === "hidden") {
|
|
917
|
+
if (spillOptions?.spillOnPageHide) writeLocalStorageSpill();
|
|
918
|
+
if (flushOnPageHide) flushPending().catch((error) => reportInternalError(error, "visibility-flush"));
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
const addVisibilityChangeListener = () => {
|
|
922
|
+
if (typeof document !== "undefined" && typeof document.addEventListener === "function") {
|
|
923
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
924
|
+
return () => document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
925
|
+
}
|
|
926
|
+
if (typeof globalThis.addEventListener !== "function") return void 0;
|
|
927
|
+
globalThis.addEventListener("visibilitychange", onVisibilityChange);
|
|
928
|
+
return () => globalThis.removeEventListener?.("visibilitychange", onVisibilityChange);
|
|
452
929
|
};
|
|
453
|
-
|
|
930
|
+
let removeVisibilityChangeListener;
|
|
931
|
+
if (flushOnPageHide || spillOptions?.spillOnPageHide) {
|
|
454
932
|
globalThis.addEventListener?.("pagehide", onPageHide);
|
|
455
|
-
|
|
933
|
+
removeVisibilityChangeListener = addVisibilityChangeListener();
|
|
456
934
|
}
|
|
457
935
|
return {
|
|
458
936
|
name: options.name ?? "indexeddb",
|
|
@@ -483,16 +961,36 @@ function indexedDbTransport(options = {}) {
|
|
|
483
961
|
return await countEntries() ?? (await getEntries()).length;
|
|
484
962
|
},
|
|
485
963
|
async clear() {
|
|
964
|
+
if (clearPromise) return clearPromise;
|
|
965
|
+
const inFlightFlush = flushPromise;
|
|
966
|
+
const inFlightDrain = spillDrainPromise;
|
|
486
967
|
buffer.length = 0;
|
|
487
968
|
clearTimer();
|
|
488
|
-
|
|
969
|
+
clearLocalStorageSpill();
|
|
970
|
+
clearPromise = (async () => {
|
|
971
|
+
await inFlightFlush;
|
|
972
|
+
await inFlightDrain;
|
|
973
|
+
await withLogAndSessionStores("readwrite", async (store, sessionStore) => {
|
|
974
|
+
await requestToPromise(store.clear());
|
|
975
|
+
await requestToPromise(sessionStore.clear());
|
|
976
|
+
});
|
|
977
|
+
})().finally(() => {
|
|
978
|
+
clearPromise = void 0;
|
|
979
|
+
});
|
|
980
|
+
return clearPromise;
|
|
489
981
|
},
|
|
490
982
|
async remove(ids) {
|
|
491
983
|
await flushPending();
|
|
492
984
|
const items = typeof ids === "string" ? [ids] : ids;
|
|
493
985
|
if (items.length === 0) return;
|
|
494
|
-
await
|
|
495
|
-
|
|
986
|
+
await withLogAndSessionStores("readwrite", async (store, sessionStore) => {
|
|
987
|
+
const affectedSessionIds = /* @__PURE__ */ new Set();
|
|
988
|
+
for (const id of items) {
|
|
989
|
+
const entry = await requestToPromise(store.get(id));
|
|
990
|
+
if (entry?.sessionId) affectedSessionIds.add(entry.sessionId);
|
|
991
|
+
await requestToPromise(store.delete(id));
|
|
992
|
+
}
|
|
993
|
+
await rebuildSessionSummaries(store, sessionStore, affectedSessionIds);
|
|
496
994
|
});
|
|
497
995
|
},
|
|
498
996
|
async *query(queryOptions = {}) {
|
|
@@ -508,6 +1006,10 @@ function indexedDbTransport(options = {}) {
|
|
|
508
1006
|
if (event) yield event;
|
|
509
1007
|
}
|
|
510
1008
|
},
|
|
1009
|
+
async sessions(sessionQueryOptions = {}) {
|
|
1010
|
+
await flushPending();
|
|
1011
|
+
return listSessions(sessionQueryOptions);
|
|
1012
|
+
},
|
|
511
1013
|
stats() {
|
|
512
1014
|
return snapshotStats();
|
|
513
1015
|
},
|
|
@@ -515,12 +1017,12 @@ function indexedDbTransport(options = {}) {
|
|
|
515
1017
|
closed = true;
|
|
516
1018
|
clearTimer();
|
|
517
1019
|
globalThis.removeEventListener?.("pagehide", onPageHide);
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
promise?.then((db) => db.close());
|
|
1020
|
+
removeVisibilityChangeListener?.();
|
|
1021
|
+
removeVisibilityChangeListener = void 0;
|
|
1022
|
+
return flushPending().finally(() => {
|
|
1023
|
+
const promise = dbPromise;
|
|
1024
|
+
dbPromise = void 0;
|
|
1025
|
+
return promise?.then((db) => db.close());
|
|
524
1026
|
});
|
|
525
1027
|
}
|
|
526
1028
|
};
|
|
@@ -547,12 +1049,14 @@ function isBrowserOnline(options) {
|
|
|
547
1049
|
function offlineFirstTransport(remote, options = {}) {
|
|
548
1050
|
const name = options.name ?? `offline-first(${remote.name ?? "transport"})`;
|
|
549
1051
|
const replayBatchSize = normalizeBatchSize(options.replayBatchSize);
|
|
1052
|
+
const queueOptions = options.queueOptions;
|
|
550
1053
|
const queue = options.queue ?? indexedDbTransport({
|
|
551
1054
|
dbName: "loggerjs-offline",
|
|
552
1055
|
flushIntervalMs: 0,
|
|
553
1056
|
name: `${name}:queue`,
|
|
554
1057
|
storeName: "offline-events",
|
|
555
|
-
...
|
|
1058
|
+
...queueOptions,
|
|
1059
|
+
session: queueOptions?.session ?? false
|
|
556
1060
|
});
|
|
557
1061
|
const reliableRemote = (0, _loggerjs_core.retryTransport)(remote, {
|
|
558
1062
|
maxRetries: 2,
|