@loggerjs/browser 0.1.0 → 0.3.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 CHANGED
@@ -51,7 +51,7 @@ const logger = createLogger({
51
51
  logger.info("page loaded");
52
52
  ```
53
53
 
54
- Logs batch over HTTP, queue while offline, replay with backoff when the network returns, and flush via `sendBeacon` when the tab closes.
54
+ Logs batch over HTTP, queue while offline, replay with backoff when the network returns, and attempt a last-chance best-effort `sendBeacon` flush when the tab closes.
55
55
 
56
56
  ## Transports
57
57
 
@@ -60,7 +60,7 @@ Logs batch over HTTP, queue while offline, replay with backoff when the network
60
60
  | `browserHttpTransport` | your collector — batching, offline queue, online replay with backoff, `sendBeacon` on page hide |
61
61
  | `indexedDbTransport` | a local, queryable IndexedDB store (TTL, pruning, optional Storage Buckets and durability hints) |
62
62
  | `browserWebSocketTransport` | a WebSocket (codec-encoded batches, queues while closed) |
63
- | `browserServiceWorkerTransport` | a service worker for centralized delivery |
63
+ | `browserServiceWorkerTransport` | a service worker for centralized delivery; `ready()` waits for `serviceWorker.ready` with `target: "ready"` |
64
64
  | `browserBroadcastChannelTransport` | other tabs via `BroadcastChannel` |
65
65
  | `offlineFirstTransport` | a local store first, then forwards online |
66
66
 
@@ -71,6 +71,11 @@ Logs batch over HTTP, queue while offline, replay with backoff when the network
71
71
  - `exportLogsToZip()` + `downloadBlob()` — export a persisted store as a zip containing `logs.ndjson` and `manifest.json`.
72
72
  - Call the `indexedDbTransport()` instance's `stats()` to read flush, prune, query, drop, and buffer-depth counters.
73
73
 
74
+ Browser delivery has runtime loss windows: tab close can cut off async work,
75
+ `sendBeacon` is size- and user-agent-limited, service worker delivery depends on
76
+ activation and lifetime, and IndexedDB persistence depends on quota and browser
77
+ storage policy. Use an IndexedDB offline queue when reload survival matters.
78
+
74
79
  ## Integrations (19)
75
80
 
76
81
  | Group | Integrations |
package/dist/index.cjs CHANGED
@@ -470,7 +470,7 @@ function browserServiceWorkerTransport(options = {}) {
470
470
  const mapBatch = options.mapBatch ?? defaultMapBatch;
471
471
  const queue = [];
472
472
  let readyWorker;
473
- let readyStarted = false;
473
+ let readyPromise;
474
474
  let lastContext;
475
475
  const reportError = (error, context, operation, droppedEvents = 0) => {
476
476
  try {
@@ -521,27 +521,35 @@ function browserServiceWorkerTransport(options = {}) {
521
521
  post(worker, item, context);
522
522
  }
523
523
  };
524
- const startReady = (context) => {
525
- if (target !== "ready" || readyStarted) return;
526
- readyStarted = true;
524
+ const dropQueued = (reason) => {
525
+ const pending = queue.splice(0);
526
+ for (const item of pending) reportDrop(item, reason);
527
+ return pending.reduce((total, item) => total + item.events.length, 0);
528
+ };
529
+ const waitForReady = (context) => {
530
+ if (currentWorker()) return Promise.resolve();
531
+ if (target !== "ready") return Promise.reject(/* @__PURE__ */ new Error("service worker controller is not available"));
532
+ if (readyPromise) return readyPromise;
527
533
  const container = options.serviceWorker ?? serviceWorkerContainer();
528
534
  if (!container?.ready) {
529
- reportError(/* @__PURE__ */ new Error("serviceWorker.ready is not available"), context, "ready");
530
- return;
535
+ const error = /* @__PURE__ */ new Error("serviceWorker.ready is not available");
536
+ reportError(error, context, "ready", dropQueued("ready"));
537
+ return Promise.reject(error);
531
538
  }
532
- container.ready.then((registration) => {
539
+ readyPromise = container.ready.then((registration) => {
533
540
  readyWorker = workerFromRegistration(registration);
534
- if (!readyWorker) {
535
- const pending = queue.splice(0);
536
- for (const item of pending) reportDrop(item, "unavailable");
537
- return;
538
- }
539
- drain(context);
541
+ if (!readyWorker) throw new Error("service worker registration has no active worker");
542
+ drain(context ?? lastContext);
540
543
  }).catch((error) => {
541
- const pending = queue.splice(0);
542
- for (const item of pending) reportDrop(item, "ready");
543
- reportError(error, context, "ready", pending.reduce((total, item) => total + item.events.length, 0));
544
+ readyPromise = void 0;
545
+ const droppedEvents = dropQueued("ready");
546
+ reportError(error, context ?? lastContext, "ready", droppedEvents);
547
+ throw error;
544
548
  });
549
+ return readyPromise;
550
+ };
551
+ const startReady = (context) => {
552
+ waitForReady(context).catch(() => {});
545
553
  };
546
554
  const enqueue = (item) => {
547
555
  if (queue.length >= maxQueueSize) {
@@ -575,6 +583,9 @@ function browserServiceWorkerTransport(options = {}) {
575
583
  queueSize() {
576
584
  return queue.length;
577
585
  },
586
+ ready() {
587
+ return waitForReady();
588
+ },
578
589
  log(event, context) {
579
590
  send({
580
591
  events: [event],