@dasasian/firebase-structured-logger 0.8.0 → 0.9.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
@@ -17,8 +17,8 @@ Your web app crashed at `app-4f2a.js:1:98432`. This tells you it was `Checkout.t
17
17
 
18
18
  Ships a browser logger, a server logger, and the `fsl` CLI. Built for Firebase, but
19
19
  Firebase is optional: the browser half has no Firebase dependency, and the server half
20
- runs on Cloud Functions, Cloud Run, or any Node server. What it needs is a Google Cloud
21
- project — that is where the logs live.
20
+ runs on Cloud Functions, Cloud Run, or any Node server on Google Cloud, where stdout goes
21
+ to Cloud Logging. What it needs is a Google Cloud project — that is where the logs live.
22
22
 
23
23
  ## One query, both halves
24
24
 
@@ -66,7 +66,7 @@ npm install @dasasian/firebase-structured-logger
66
66
  # Cloud Functions
67
67
  cd functions && npm install @dasasian/firebase-structured-logger
68
68
 
69
- # Cloud Run, or any Node server
69
+ # Cloud Run, or any Node server on Google Cloud
70
70
  npm install @dasasian/firebase-structured-logger
71
71
  ```
72
72
 
@@ -198,7 +198,7 @@ The entry should carry `userId` without your having written it.
198
198
 
199
199
  ### If your backend is not Cloud Functions
200
200
 
201
- Cloud Run, or any Node server you already run. Two things differ from the browser
201
+ Cloud Run, or any Node server you already run on Google Cloud. Two things differ from the browser
202
202
  path above; everything else — breadcrumbs, labels, symbolication, the free fields — is
203
203
  identical, and the entries land in the same stream in the same shape.
204
204
 
@@ -279,6 +279,9 @@ initLogger({
279
279
 
280
280
  Nothing here needs a Firebase project — only a Google Cloud one. What changes:
281
281
 
282
+ - **The server has to run on Google Cloud** — Cloud Run, GKE, App Engine, or Compute
283
+ Engine with the Ops Agent. Entries are written to stdout, and only there does stdout
284
+ reach Cloud Logging. On AWS, Vercel or your own box they print and go nowhere.
282
285
  - **The browser** needs no `firebase` package. `logFunction` is the `fetch` above; send
283
286
  whatever credential your app already uses.
284
287
  - **`authorize`** checks your own session instead of a Firebase ID token — for example
@@ -439,6 +442,12 @@ logger.error(err, { orderId })
439
442
  | resolved file and line | function | your source maps — `Checkout.tsx:42`, not `app-4f2a.js:1:98432` |
440
443
  | trace context | function | request correlation in Cloud Logging |
441
444
 
445
+ **Repeats are counted, not thrown away.** The usual answer to an error that fires 200 times
446
+ is to send the first few and drop the rest. This one sends 3 in full, counts the other 197,
447
+ and tells you when it started, when it stopped, which release and which user. Close the tab
448
+ and the count waits on the device for the next visit. See
449
+ [Repeats are counted, not dropped](#repeats-are-counted-not-dropped).
450
+
442
451
  Backend logs get the same treatment: `withLogging` attaches `functionName`, `userId` from
443
452
  the verified `request.auth.uid`, and whatever else you bind.
444
453
 
@@ -622,15 +631,33 @@ or different IAM from your source maps — none of which can be arranged with a
622
631
  Nothing expires them. Add a lifecycle rule on `logAttachments/` to delete after N days, or
623
632
  they accumulate for the life of the project.
624
633
 
634
+ ## Big entries
635
+
636
+ Cloud Functions and Cloud Run both cut a stdout/stderr log line at exactly **102,400 bytes**
637
+ (100 KiB) — measured live. Past that the entry does not arrive truncated-but-valid: it arrives
638
+ as broken plain text, with no `severity`, no labels, and nothing for Error Reporting to group.
639
+
640
+ The backend logger watches for this. An entry over 90 KiB is shortened before it is written —
641
+ breadcrumb data first, then other context, then the tail of a long stack (the top frames are
642
+ what Error Reporting groups on, so those survive longest), then long text fields, and label
643
+ values only as a last resort. `severity`, labels, the trace and `serviceContext` are never
644
+ touched.
645
+
646
+ The full, unshortened entry is saved to Cloud Storage as `fsl-overflow.json`, at the same
647
+ `logAttachments/{logId}/` path an ordinary attachment would use, whenever a bucket is
648
+ available — see [Attachments](#attachments). A shortened entry carries `labels.truncated="true"`,
649
+ and `labels.hasAttachments="true"` when the full entry was saved. With no Storage configured,
650
+ the entry is still shortened; the original is lost, and the process warns once, not per entry.
651
+
625
652
  ## Volume controls
626
653
 
627
- Three separate gates decide whether a log is written. All have defaults, and the defaults
628
- drop things — so this is worth reading before you conclude something is broken.
654
+ Several gates decide whether a log is written. All have defaults, and the defaults
655
+ hold things back — so this is worth reading before you conclude something is broken.
629
656
 
630
657
  | Gate | Default | Where |
631
658
  |---|---|---|
632
- | Session limit | **50 logs**, then the client stops sending | client, per browser session |
633
- | Duplicate limit | **3 copies** of the same error, then it stops | client, per browser session |
659
+ | Log budget | **50 logs**, refilling **1 per minute**; the last **20%** for errors only | client, per browser tab |
660
+ | Duplicates | **3** full copies of the same error, then counted and sent as a summary | client, per browser tab |
634
661
  | Client severity floor | `WARNING` in production, `DEBUG` in dev | client, `minLogLevel` |
635
662
  | Server severity floor | `WARNING` in production, `DEBUG` in the emulator | function, `minSeverity` |
636
663
  | Function concurrency | `maxInstances: 1` on `createClientLogFunction` | function |
@@ -641,14 +668,18 @@ initLogger({
641
668
  releaseId,
642
669
  logFunction,
643
670
  minLogLevel: 'INFO',
644
- rateLimitOptions: { sessionLimit: 200, duplicateLimit: 5 },
671
+ rateLimitOptions: {
672
+ sessionLimit: 50, // the budget: how many logs can go at once
673
+ refillPerMinute: 1, // how fast it comes back
674
+ errorReserve: 0.2, // share of the budget only ERROR and above may spend
675
+ duplicateLimit: 3, // full copies of one error before counting starts
676
+ summaryIntervalMinutes: 60,
677
+ summaryMaxAgeDays: 7, // how long an unsent summary waits on the device
678
+ maxPendingSummaries: 50,
679
+ },
645
680
  })
646
681
  ```
647
682
 
648
- Two errors count as duplicates when the **message and the screen both match**, so the same
649
- error on two different screens is not collapsed into one. The budget lives in
650
- `sessionStorage` and resets with the session.
651
-
652
683
  The client's production default comes from `process.env.NODE_ENV`, which Vite replaces at
653
684
  build time. A `define: { 'process.env': {} }` in `vite.config` — common, to quiet a library
654
685
  that expects Node — replaces the whole object instead, `NODE_ENV` reads as undefined, and
@@ -656,13 +687,72 @@ the floor is silently `DEBUG` in production. If your config has that line, pass
656
687
  `minLogLevel` explicitly. Stating it is the safe habit either way: it is the one default
657
688
  here whose failure mode is a bill rather than a missing log.
658
689
 
690
+ ### The budget refills
691
+
692
+ Each browser tab starts with 50 logs. Every log spends one, and one comes back each minute,
693
+ up to 50. A reload does not reset it — the tab keeps its budget in `sessionStorage`.
694
+
695
+ So a burst at start-up is fine, and a user who works in the app all afternoon is never
696
+ silenced for long. A bug that logs in a loop is still held to about 60 entries an hour per
697
+ user: 1,000 users stuck in such a loop for a working month stays around the 50 GiB of
698
+ Cloud Logging that each project gets free.
699
+
700
+ The last 20% of the budget is reserved: warnings can spend it down to 10, and only
701
+ `ERROR` and above can spend the rest. A noisy warning cannot use up the room a crash needs.
702
+
703
+ ### Repeats are counted, not dropped
704
+
705
+ Two errors are the same when the **message and the screen both match**, so the same error
706
+ on two different screens is kept apart. The first 3 are sent in full, with their stack and
707
+ breadcrumbs. After that the browser only counts them, and sends one summary:
708
+
709
+ ```
710
+ WARNING Repeated 197 more times: cart sync failed
711
+ labels.repeatOf="<repeatKey of the first copy>" labels.repeatCount="197"
712
+ labels.firstSeen="…" labels.lastSeen="…"
713
+ ```
714
+
715
+ The same count and window are in the entry's body, under `context.repeat`, so a summary is
716
+ filed as JSON like every other entry and a search on `jsonPayload.message` finds it.
717
+
718
+ The browser never learns the server's `logId` for the first copy — `writeLog` assigns it
719
+ after the log has already left the tab. So each full copy instead carries its own
720
+ `labels.repeatKey`, a client-side id, and the summary's `repeatOf` points at that instead:
721
+ query `labels.repeatKey="…" OR labels.repeatOf="…"` to find a full copy and its summary
722
+ together.
723
+
724
+ A summary is sent once an hour, when the tab is hidden, and once at startup for anything
725
+ a previous visit left queued. It is keyed by the error, the `releaseId` and the `userId`,
726
+ so two releases or two people on one computer are never counted together. Its entry is
727
+ timestamped at `lastSeen`, not at the time it was sent.
728
+
729
+ The summary's own labels are `appId`, `releaseId`, `userId`, `screen` and `errorType` — from
730
+ the time the errors happened, not from whoever's tab eventually sends it — plus
731
+ `repeatOf`/`repeatCount`/`firstSeen`/`lastSeen`/`sentLate`. Everything else about the error —
732
+ browser, platform, breadcrumbs, the stack — is not repeated here; it is already on the full
733
+ copies `repeatOf` points back to.
734
+
735
+ Unsent summaries are kept in `localStorage`, so closing the tab does not lose them: the
736
+ next visit sends them, marked `labels.sentLate="true"`. A summary is only removed from that
737
+ queue once it has actually been sent — a failed attempt (offline, or the tab closing right
738
+ after it was queued) leaves it for the next flush or the next visit to retry, never twice.
739
+ At most 50 wait, and any older than 7 days are deleted rather than sent — they are error
740
+ messages, and may hold personal data.
741
+
742
+ A summary is a `WARNING` with no stack, so Cloud Error Reporting sees the 3 full copies and
743
+ not the summary. For the true count, add up `labels.repeatCount` in Cloud Logging.
744
+
745
+ Summaries do not spend the log budget. There is at most one per error, per release, per user,
746
+ per hour.
747
+
659
748
  ### What a dropped log looks like
660
749
 
661
750
  The two rate limits say so in the browser console:
662
751
 
663
752
  ```
664
- [fsl] Duplicate suppressed: TypeError: cannot read 'id'|checkout
665
- [fsl] Session log limit reached
753
+ [fsl] Duplicate counted for the next summary: TypeError: cannot read 'id' | checkout
754
+ [fsl] Log budget empty — next log in about a minute
755
+ [fsl] Log budget: only errors can use the reserve now
666
756
  ```
667
757
 
668
758
  **The severity floors are silent.** Both of them — the client's `minLogLevel` and the
@@ -697,6 +787,9 @@ Narrow it when you need to:
697
787
  | `labels.screen="checkout"` | one screen |
698
788
  | `labels.feedback="true"` | user-reported issues |
699
789
  | `labels.hasAttachments="true"` | entries with files in GCS |
790
+ | `labels.truncated="true"` | entries shortened to fit — the full copy is `fsl-overflow.json` |
791
+ | `labels.repeatKey="<key>" OR labels.repeatOf="<key>"` | one repeating error: its full copies and its summaries |
792
+ | `labels.sentLate="true"` | repeat summaries sent on a later visit |
700
793
 
701
794
  Locally, the emulator's JSONL answers the same questions. Point
702
795
  **[firebase-mcp-server](https://github.com/dasasian/firebase-mcp-server)** at either and ask
@@ -832,6 +925,9 @@ Some of what is already handled here, all of it learned the expensive way:
832
925
  disagree over a typo.
833
926
  - **Checking a rate limit and spending it as two calls double-counts**, quietly making a
834
927
  configured budget of 50 a budget of 25.
928
+ - **A fixed budget goes silent in a long session.** 50 logs per page load is spent by
929
+ mid-morning in an app someone keeps open all day, and the crash at lunch is never sent.
930
+ A budget that refills, with a share kept for errors, does not have that shape.
835
931
  - **An old stack naming a bundle that still exists** resolves against the current release's
836
932
  map, giving line numbers that are confidently wrong — worse than none, because nothing
837
933
  signals it.
@@ -46,6 +46,22 @@ export declare class Logger<AppLabels extends Record<string, string | undefined>
46
46
  */
47
47
  sendFeedback(text: string, extras?: FeedbackOptions<AppLabels>): void;
48
48
  private send;
49
+ private readonly summariesInFlight;
50
+ /** Send whatever repeat summaries are due, from this visit or an earlier one. */
51
+ sendPendingSummaries(): void;
52
+ /**
53
+ * A repeat summary: a WARNING with no stack, timestamped at `lastSeen` (see
54
+ * README, "Repeats are counted, not dropped"). It still respects the
55
+ * severity floor — only the budget and the duplicate gate are skipped, via
56
+ * `send`'s `skipBudget`.
57
+ *
58
+ * It is queued in `localStorage` precisely so a failed send does not lose
59
+ * it — offline, or the tab tearing down right after the `visibilitychange`
60
+ * that triggered this. So it is only acknowledged (removed from the queue)
61
+ * once `send` reports the entry actually reached `logFunction`; otherwise
62
+ * the next flush, or the next visit, finds it still there and retries it.
63
+ */
64
+ private sendRepeatSummary;
49
65
  }
50
66
  /**
51
67
  * Send user feedback through the configured logger.
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/client/logger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/client/logger.ts"],"names":[],"mappings":"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"}
@@ -136,33 +136,51 @@ class Logger {
136
136
  // same pipe — it is rare by nature and there is nothing to throttle. The
137
137
  // exemption keys on the record being feedback, not on its severity, so a
138
138
  // NOTICE emitted for anything else still behaves normally.
139
- bypassVolumeControls = false) {
139
+ bypassVolumeControls = false,
140
+ // A repeat summary spends no budget and is never itself a duplicate — but
141
+ // it still respects the severity floor, unlike feedback above.
142
+ skipBudget = false, timestamp) {
140
143
  if (!bypassVolumeControls && severity_1.SEVERITY_ORDER[severity] > this.minLevel)
141
- return;
144
+ return false;
145
+ const allLabels = {
146
+ appId: this.config.appId,
147
+ releaseId: this.config.releaseId,
148
+ screen: (0, breadcrumbs_1.getCurrentScreen)(),
149
+ userId: this.userId,
150
+ platform: PLATFORM,
151
+ browser: BROWSER,
152
+ ...this.userLabels,
153
+ ...labels,
154
+ };
142
155
  // One gate for every severity. Passing a signature opts this log into
143
156
  // duplicate suppression; the check and the budget spend are one operation,
144
157
  // so a log can neither be counted twice nor checked without being counted.
145
- const decision = bypassVolumeControls ? { allowed: true } : (0, rateLimiter_1.allow)(signature);
158
+ // Once a signature passes `duplicateLimit`, further occurrences are
159
+ // "counted", not refused outright — the rate limiter keeps a running
160
+ // count toward the next repeat summary.
161
+ const decision = bypassVolumeControls || skipBudget
162
+ ? { allowed: true }
163
+ : (0, rateLimiter_1.allow)({ severity, signature, labels: allLabels });
146
164
  if (!decision.allowed) {
147
165
  if (decision.reason === 'duplicate') {
148
- console.warn(`[fsl] Duplicate suppressed: ${decision.signature}`);
166
+ console.warn(`[fsl] Duplicate counted for the next summary: ${(0, rateLimiter_1.describeSignature)(decision.signature ?? '')}`);
167
+ }
168
+ else if (decision.reason === 'reserve') {
169
+ console.warn('[fsl] Log budget: only errors can use the reserve now');
149
170
  }
150
171
  else {
151
- console.warn('[fsl] Session log limit reached');
172
+ console.warn('[fsl] Log budget empty — next log in about a minute');
152
173
  }
153
- return;
174
+ return false;
175
+ }
176
+ // Ties this full copy to the summary its repeats will eventually become.
177
+ // The client has no server logId to put in the summary's `repeatOf` — see
178
+ // README, "Repeats are counted, not dropped" — so this client-side id is
179
+ // the join key instead, carried by every full copy of the signature.
180
+ if ('repeatKey' in decision && decision.repeatKey) {
181
+ allLabels.repeatKey = decision.repeatKey;
154
182
  }
155
183
  try {
156
- const allLabels = {
157
- appId: this.config.appId,
158
- releaseId: this.config.releaseId,
159
- screen: (0, breadcrumbs_1.getCurrentScreen)(),
160
- userId: this.userId,
161
- platform: PLATFORM,
162
- browser: BROWSER,
163
- ...this.userLabels,
164
- ...labels,
165
- };
166
184
  // Each attachment is converted in its own try. A Blob or File can fail to
167
185
  // read — a user picks a file from <input type="file">, moves or deletes it,
168
186
  // then submits, and the browser raises NotReadableError. Previously one
@@ -200,13 +218,65 @@ class Logger {
200
218
  error,
201
219
  },
202
220
  ...(base64Attachments ? { attachments: base64Attachments } : {}),
221
+ ...(timestamp ? { timestamp } : {}),
203
222
  };
204
223
  await this.config.logFunction(payload);
224
+ return true;
205
225
  }
206
226
  catch (err) {
207
227
  console.error('[fsl] Failed to send log:', err instanceof Error ? err.message : err);
228
+ return false;
229
+ }
230
+ }
231
+ // Guards against sending the same queued summary twice when a flush is
232
+ // triggered again (interval, visibilitychange) before a previous attempt's
233
+ // `logFunction` call has resolved — `peekPendingSummaries` does not remove
234
+ // anything, so without this a slow or slow-to-fail send could be picked up
235
+ // more than once.
236
+ summariesInFlight = new Set();
237
+ /** Send whatever repeat summaries are due, from this visit or an earlier one. */
238
+ sendPendingSummaries() {
239
+ for (const summary of (0, rateLimiter_1.peekPendingSummaries)()) {
240
+ if (this.summariesInFlight.has(summary.id))
241
+ continue;
242
+ this.summariesInFlight.add(summary.id);
243
+ void this.sendRepeatSummary(summary).finally(() => this.summariesInFlight.delete(summary.id));
208
244
  }
209
245
  }
246
+ /**
247
+ * A repeat summary: a WARNING with no stack, timestamped at `lastSeen` (see
248
+ * README, "Repeats are counted, not dropped"). It still respects the
249
+ * severity floor — only the budget and the duplicate gate are skipped, via
250
+ * `send`'s `skipBudget`.
251
+ *
252
+ * It is queued in `localStorage` precisely so a failed send does not lose
253
+ * it — offline, or the tab tearing down right after the `visibilitychange`
254
+ * that triggered this. So it is only acknowledged (removed from the queue)
255
+ * once `send` reports the entry actually reached `logFunction`; otherwise
256
+ * the next flush, or the next visit, finds it still there and retries it.
257
+ */
258
+ async sendRepeatSummary(summary) {
259
+ const labels = {
260
+ appId: this.config.appId,
261
+ releaseId: summary.releaseId ?? this.config.releaseId,
262
+ userId: summary.userId,
263
+ screen: summary.screen,
264
+ errorType: summary.errorType,
265
+ repeatOf: summary.repeatOf,
266
+ repeatCount: String(summary.repeatCount),
267
+ firstSeen: summary.firstSeen,
268
+ lastSeen: summary.lastSeen,
269
+ ...(summary.sentLate ? { sentLate: 'true' } : {}),
270
+ };
271
+ const sent = await this.send(`Repeated ${summary.repeatCount} more times: ${summary.message}`, 'WARNING', labels,
272
+ // A body besides the message. With only `message` left once the timestamp
273
+ // is promoted, Cloud Logging files the entry as textPayload, and a search on
274
+ // jsonPayload.message — /query-logs, or anyone's saved query — misses every
275
+ // summary. The smoke run found it.
276
+ { repeat: { count: summary.repeatCount, firstSeen: summary.firstSeen, lastSeen: summary.lastSeen } }, undefined, undefined, undefined, false, true, summary.lastSeen);
277
+ if (sent)
278
+ (0, rateLimiter_1.acknowledgeSummary)(summary.id);
279
+ }
210
280
  }
211
281
  exports.Logger = Logger;
212
282
  /**
@@ -243,6 +313,13 @@ function triggerTestLog() {
243
313
  let instance = null;
244
314
  function initLogger(config) {
245
315
  instance = new Logger(config);
316
+ // A previous visit's queued summaries (README, "the next visit sends
317
+ // them") would otherwise wait for the first `visibilitychange: hidden` or
318
+ // the first 60s interval tick — a short delay so init itself can finish
319
+ // first, not a wait for either of those.
320
+ if (typeof setTimeout !== 'undefined') {
321
+ setTimeout(() => instance?.sendPendingSummaries(), 0);
322
+ }
246
323
  return instance;
247
324
  }
248
325
  function getClientLogger() {
@@ -250,4 +327,32 @@ function getClientLogger() {
250
327
  throw new Error('[fsl] initLogger() not called');
251
328
  return instance;
252
329
  }
330
+ /**
331
+ * Repeat summaries are sent hourly and when the tab is hidden (README,
332
+ * "Repeats are counted, not dropped"). Neither is triggered by an ordinary
333
+ * log call — `send` does not check for due summaries itself, since doing so
334
+ * with frozen-for-testing time reliably makes an interval-based check look
335
+ * due immediately (see tests/rateLimiter.ts). So there are exactly three
336
+ * triggers for a flush: `initLogger` (a previous visit's queue, once, above),
337
+ * this `visibilitychange` listener (the tab going hidden), and the interval
338
+ * below (an app that never hides its tab and rarely reloads).
339
+ *
340
+ * Neither exists in the esbuild bundle test's sandbox (no `window`/`document`
341
+ * there — see tests/browserBundle.ts), so both are guarded.
342
+ */
343
+ if (typeof document !== 'undefined') {
344
+ document.addEventListener('visibilitychange', () => {
345
+ if (document.visibilityState !== 'hidden')
346
+ return;
347
+ (0, rateLimiter_1.flushDueSummaries)(true);
348
+ instance?.sendPendingSummaries();
349
+ });
350
+ }
351
+ if (typeof window !== 'undefined') {
352
+ const interval = setInterval(() => {
353
+ (0, rateLimiter_1.flushDueSummaries)();
354
+ instance?.sendPendingSummaries();
355
+ }, 60_000);
356
+ interval.unref?.();
357
+ }
253
358
  //# sourceMappingURL=logger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/client/logger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/client/logger.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,63 @@
1
+ import type { LogSeverity } from '../shared/types';
1
2
  export interface RateLimitConfig {
3
+ /** The budget: how many logs can go out at once. Default 50. */
2
4
  sessionLimit?: number;
5
+ /** How fast the budget comes back, per minute. Default 1. */
6
+ refillPerMinute?: number;
7
+ /** Share of `sessionLimit` only ERROR and above may spend. Default 0.2. */
8
+ errorReserve?: number;
9
+ /** Full copies of one error before it is only counted. Default 3. */
3
10
  duplicateLimit?: number;
4
11
  storageKey?: string;
12
+ /** How often a running count of repeats is sent as a summary. Default 60. */
13
+ summaryIntervalMinutes?: number;
14
+ /** How long an unsent summary is kept before it is deleted, not sent. Default 7. */
15
+ summaryMaxAgeDays?: number;
16
+ /** Most pending summaries kept at once; oldest are dropped first. Default 50. */
17
+ maxPendingSummaries?: number;
18
+ }
19
+ /**
20
+ * A repeat count waiting to be sent as a WARNING summary. Queued in
21
+ * `localStorage` so it survives the tab closing — `sessionStorage` does not.
22
+ *
23
+ * `bootId` is what `sentLate` is built from: it is the module's own load-time
24
+ * id, not anything persisted. A summary queued during an earlier page load
25
+ * carries a different `bootId` than the one currently running, so popping it
26
+ * here reveals it as "from a previous visit" without needing a server
27
+ * round-trip or a wall-clock guess.
28
+ *
29
+ * `message`/`errorType`/`screen`/`releaseId`/`userId` are short fields
30
+ * rebuilt once from the signature's key when the summary is created (see
31
+ * `parseSignatureKey`) — not a full label copy. Everything else about the
32
+ * error (browser, platform, stack, breadcrumbs…) is already in Cloud Logging
33
+ * on the full copies `repeatOf` points back to.
34
+ */
35
+ export interface PendingSummary {
36
+ id: string;
37
+ message: string;
38
+ errorType?: string;
39
+ screen?: string;
40
+ releaseId?: string;
41
+ userId?: string;
42
+ repeatOf: string;
43
+ repeatCount: number;
44
+ firstSeen: string;
45
+ lastSeen: string;
46
+ createdAt: number;
47
+ bootId: string;
48
+ }
49
+ export interface SentSummary {
50
+ id: string;
51
+ message: string;
52
+ errorType?: string;
53
+ screen?: string;
54
+ releaseId?: string;
55
+ userId?: string;
56
+ repeatOf: string;
57
+ repeatCount: number;
58
+ firstSeen: string;
59
+ lastSeen: string;
60
+ sentLate: boolean;
5
61
  }
6
62
  export declare function configureRateLimiter(options: RateLimitConfig): void;
7
63
  /**
@@ -15,25 +71,57 @@ export declare function configureRateLimiter(options: RateLimitConfig): void;
15
71
  * without the staleness of a span someone has to remember to clear.
16
72
  */
17
73
  export declare function signatureFor(error: Error | string, screen?: string): string;
74
+ /** A signature as a person reads it, for the console: `TypeError: cannot read 'id' | checkout`. */
75
+ export declare function describeSignature(signature: string): string;
18
76
  export type RateLimitDecision = {
19
77
  allowed: true;
78
+ repeatKey?: string;
20
79
  } | {
21
80
  allowed: false;
22
- reason: 'session-limit' | 'duplicate';
81
+ reason: 'session-limit' | 'reserve' | 'duplicate';
23
82
  signature?: string;
24
83
  };
84
+ export interface AllowOptions {
85
+ signature?: string;
86
+ severity: LogSeverity;
87
+ labels?: Record<string, string | undefined>;
88
+ }
89
+ export declare function allow(options: AllowOptions): RateLimitDecision;
25
90
  /**
26
- * Decide whether one log may be sent, and consume its budget if so.
91
+ * Move any signature's accumulated repeats into the pending-summary queue —
92
+ * every one whose window (`summaryIntervalMinutes`) has elapsed, or every one
93
+ * with anything to send when `force` is true (the tab going hidden).
27
94
  *
28
- * Check and consume are one operation on purpose. They used to be separate
29
- * exports called from two different layers, which meant an error was checked
30
- * against the session limit twice and counted against it twice — a configured
31
- * limit of 50 was really 25 for errors. A single call cannot double-count, and
32
- * cannot be checked without consuming.
95
+ * Only the counting resets; `count` (full copies already sent) is untouched,
96
+ * so a signature stays in "counting" mode across summary windows rather than
97
+ * sending three more full copies before the next summary.
98
+ */
99
+ export declare function flushDueSummaries(force?: boolean): void;
100
+ /**
101
+ * Look at every pending summary not past `summaryMaxAgeDays`, WITHOUT
102
+ * removing it from the queue. A summary may only leave the queue once its
103
+ * send has actually succeeded — see `acknowledgeSummary` — so a failed send
104
+ * (offline, or the tab tearing down right after the `visibilitychange` that
105
+ * triggered this) leaves it queued for the next flush or the next visit to
106
+ * retry, instead of losing it. `sentLate` is true for anything queued by an
107
+ * earlier page load (a different `bootId`): the case the README's "next
108
+ * visit sends them" describes.
33
109
  *
34
- * Pass a `signature` to opt this log into duplicate suppression. Any severity
35
- * may do so; it is not reserved for errors.
110
+ * Expired entries ARE removed here — there is no send to wait on for those.
111
+ */
112
+ export declare function peekPendingSummaries(): SentSummary[];
113
+ /**
114
+ * Remove one summary from the queue by id, once its send has resolved. A
115
+ * retry that calls this again for an id already gone is a no-op — it never
116
+ * re-adds anything, so it cannot create a second entry.
117
+ */
118
+ export declare function acknowledgeSummary(id: string): void;
119
+ /**
120
+ * Test-only reset. There is no `beforeunload` wiring any more — the budget
121
+ * lives in `sessionStorage` on purpose, so a reload keeps it — but tests still
122
+ * need a way to start a clean session, and to simulate a genuinely new visit
123
+ * (a new tab gets a new `bootId` for free, since the module reloads with it;
124
+ * a test in the same process cannot, so this rotates it explicitly).
36
125
  */
37
- export declare function allow(signature?: string): RateLimitDecision;
38
126
  export declare function resetRateLimiter(): void;
39
127
  //# sourceMappingURL=rateLimiter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rateLimiter.d.ts","sourceRoot":"","sources":["../../src/client/rateLimiter.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAeD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAEnE;AAmBD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,KAAK,GAAG,MAAM,EACrB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAGR;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,GAAG,WAAW,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEjF;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAkB3D;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAMvC"}
1
+ {"version":3,"file":"rateLimiter.d.ts","sourceRoot":"","sources":["../../src/client/rateLimiter.ts"],"names":[],"mappings":"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"}