@dasasian/firebase-structured-logger 1.1.0 → 1.3.0-rc.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.
Files changed (45) hide show
  1. package/README.md +202 -33
  2. package/dist/client/breadcrumbs.d.ts +35 -6
  3. package/dist/client/breadcrumbs.d.ts.map +1 -1
  4. package/dist/client/breadcrumbs.js +87 -10
  5. package/dist/client/breadcrumbs.js.map +1 -1
  6. package/dist/client/logger.d.ts.map +1 -1
  7. package/dist/client/logger.js +2 -7
  8. package/dist/client/logger.js.map +1 -1
  9. package/dist/client/navigation/adapterShared.d.ts +18 -0
  10. package/dist/client/navigation/adapterShared.d.ts.map +1 -0
  11. package/dist/client/navigation/adapterShared.js +49 -0
  12. package/dist/client/navigation/adapterShared.js.map +1 -0
  13. package/dist/client/navigation/react-router.d.ts +30 -0
  14. package/dist/client/navigation/react-router.d.ts.map +1 -0
  15. package/dist/client/navigation/react-router.js +57 -0
  16. package/dist/client/navigation/react-router.js.map +1 -0
  17. package/dist/client/navigation/vue-router.d.ts +28 -0
  18. package/dist/client/navigation/vue-router.d.ts.map +1 -0
  19. package/dist/client/navigation/vue-router.js +47 -0
  20. package/dist/client/navigation/vue-router.js.map +1 -0
  21. package/dist/client/navigation.d.ts +29 -4
  22. package/dist/client/navigation.d.ts.map +1 -1
  23. package/dist/client/navigation.js +60 -4
  24. package/dist/client/navigation.js.map +1 -1
  25. package/dist/client/timing.d.ts +20 -0
  26. package/dist/client/timing.d.ts.map +1 -0
  27. package/dist/client/timing.js +133 -0
  28. package/dist/client/timing.js.map +1 -0
  29. package/dist/functions/index.d.ts +2 -0
  30. package/dist/functions/index.d.ts.map +1 -1
  31. package/dist/functions/index.js +5 -1
  32. package/dist/functions/index.js.map +1 -1
  33. package/dist/functions/trace.d.ts +13 -0
  34. package/dist/functions/trace.d.ts.map +1 -0
  35. package/dist/functions/trace.js +68 -0
  36. package/dist/functions/trace.js.map +1 -0
  37. package/dist/shared/trace.d.ts +59 -0
  38. package/dist/shared/trace.d.ts.map +1 -0
  39. package/dist/shared/trace.js +131 -0
  40. package/dist/shared/trace.js.map +1 -0
  41. package/dist/shared/types.d.ts +14 -9
  42. package/dist/shared/types.d.ts.map +1 -1
  43. package/package.json +31 -4
  44. package/skills/logs/SKILL.md +20 -13
  45. package/skills/query-logs/SKILL.md +5 -1
package/README.md CHANGED
@@ -513,7 +513,7 @@ logger.error(err, { orderId })
513
513
  |---|---|---|
514
514
  | `appId`, `releaseId` | client | your `initLogger` config |
515
515
  | `screen` | client | tracked as the user moves |
516
- | `route`, `path`, `routeSource` | client | with `enableNavigation()` — the route pattern, the real path, and where the pattern came from |
516
+ | `route`, `path` | client | with navigation on — the route pattern and the real path (`routeSource` too, deprecated) |
517
517
  | `userId` | client | `setUser`, held for the session |
518
518
  | `platform` | client | user agent — `ios` / `android` / `macos` / `web` |
519
519
  | `browser` | client | user agent |
@@ -578,9 +578,10 @@ export const logger = initLogger<MyAppLabels>({ /* … */ })
578
578
 
579
579
  logger.setUser(uid, { organizationId }) // on sign in — rides every log until cleared
580
580
  logger.clearUser() // on sign out
581
- logger.setScreen('checkout') // on navigation
582
581
  ```
583
582
 
583
+ The screen comes from navigation — see "Navigation, automatically".
584
+
584
585
  **Backend** — scoped to the request:
585
586
 
586
587
  ```ts
@@ -604,10 +605,9 @@ from [setup](#logging-from-your-cloud-functions) is the same thing without that.
604
605
  ```ts
605
606
  import { bc } from '@dasasian/firebase-structured-logger/client'
606
607
 
607
- bc.nav('Checkout') // also sets labels.screen
608
608
  bc.action('apply_discount', { code: 'SAVE10' })
609
609
  bc.state('total_recalculated', { total: 42.00 })
610
- bc.error('ValidationError', { field: 'price' })
610
+ bc.handledError('draft_save_failed', { attempt: 1 }) // an error you handled and did not log
611
611
  ```
612
612
 
613
613
  A stack trace tells you where the code broke. It cannot tell you what the person did to
@@ -615,65 +615,213 @@ get there, which is usually the part you need to reproduce it. Breadcrumbs are t
615
615
  a rolling record of the last steps, attached automatically to every error and every piece
616
616
  of feedback, with no correlation work on your side.
617
617
 
618
- Drop a `bc.action` before anything that can fail and a `bc.nav` on every screen change, and
619
- `total is wrong` arrives as `navigate_Checkout · apply_discount · total_recalculated ·
620
- tap_place_order`.
618
+ Turn on navigation, drop a `bc.action` before anything that can fail, and `total is wrong`
619
+ arrives as `Checkout · apply_discount · total_recalculated · tap_place_order`.
621
620
 
622
621
  The trail is capped at **50 entries** and **5 minutes** — old enough to cover the steps that
623
622
  led here, short enough that it stays the current attempt rather than the whole session, and
624
623
  bounded so a long-lived tab cannot grow it without limit. It lives in memory only, so it
625
624
  never touches storage and never leaves the device except attached to a log you send.
626
625
 
627
- Breadcrumbs are session-global by design: one user, one path. `bc.nav()` also sets the
628
- current screen, so `labels.screen` stays correct without a second call.
626
+ Breadcrumbs are session-global by design: one user, one path.
627
+
628
+ **Errors and breadcrumbs.** An error you log is already in the logs, in time order with
629
+ everything else the user did — it needs no breadcrumb too. `bc.handledError` is for the
630
+ other kind: an error your code handled and chose not to log, like a save that failed and
631
+ then worked on retry. It costs nothing unless something else goes wrong, and then the
632
+ trail shows it as a clue. (`bc.error`, its old name, warns once and is removed in 2.0.)
629
633
 
630
634
  > Record the step, not the data. Breadcrumb `data` is written to your logs verbatim — keep
631
635
  > PII, tokens and card numbers out of it, the same as you would for any label.
632
636
 
633
637
  ### Navigation, automatically
634
638
 
639
+ Where the user is has one way in for each kind of place:
640
+
641
+ | What changed | Record it with | Gives |
642
+ |---|---|---|
643
+ | a page, and the URL changed | `enableNavigation()`, or a router adapter — automatic | one `nav` breadcrumb; `screen`, `route` and `path` labels |
644
+ | a page, but the URL did not | `navigatedTo('Checkout')` | the same breadcrumb and labels |
645
+ | something inside or on top of a page | markup (`data-fsl-view`, planned in #58) | a `view` label |
646
+
635
647
  ```ts
636
- import { enableNavigation } from '@dasasian/firebase-structured-logger/client/navigation'
648
+ import { enableNavigation, navigatedTo, defaultLabelsFor } from '@dasasian/firebase-structured-logger/client/navigation'
637
649
 
638
650
  enableNavigation()
639
-
640
- // or name routes the way your router does
641
- enableNavigation({
642
- routeFor: (path) => router.match(path)?.name, // undefined falls back to the id rule
643
- })
644
651
  ```
645
652
 
646
653
  Its own entry point, so an app that never imports it ships none of it, whatever its
647
654
  bundler — and the import says plainly that it wraps `history.pushState` and
648
655
  `replaceState`, the only way to notice a single-page app changing route. Call it once,
649
- before or after `initLogger`. It records the current page at once and every route change
650
- after it, back and forward included, as a `nav` breadcrumb, and every entry carries three
651
- labels:
656
+ before or after `initLogger`. It records the current page at once and every page change
657
+ after it, back and forward included, and every entry carries:
652
658
 
653
659
  | Label | Example | Means |
654
660
  |---|---|---|
655
661
  | `route` | `/orders/:id/items` | the pattern — for grouping and counting |
656
662
  | `path` | `/orders/1042/items` | the real path — for "what went wrong for order 1042?" |
657
- | `routeSource` | `router` or `pattern` | whether `route` came from your `routeFor`, or from the id rule |
663
+ | `screen` | `OrderItems`, or the route when there is no name | the page's name |
664
+ | `routeSource` | `pattern` | **deprecated, removed in 2.0** — set only by the default labels |
665
+
666
+ **The default — the id rule.** A path segment that is all digits, a UUID, a long hex
667
+ string or a ULID becomes `:id`; anything else is kept as written, so a slug like
668
+ `/blog/my-post` stays as it is. `screen` is the route.
669
+
670
+ **Your own labels — `labelsFor`.** One function: it gets the real path and returns the
671
+ labels for it. Whatever it returns is used exactly as returned, and a field it leaves out
672
+ is not logged.
673
+
674
+ ```ts
675
+ enableNavigation({
676
+ labelsFor: (path) => ({ ...defaultLabelsFor(path), screen: path.startsWith('/admin') ? 'Admin' : undefined }),
677
+ })
678
+ ```
679
+
680
+ It must be synchronous — it runs inside your router's own `pushState` — and if it throws,
681
+ that page gets `defaultLabelsFor(path)` and the console says so once.
682
+
683
+ **With React Router or Vue Router — an adapter.** Your router already knows each page's
684
+ pattern and name, so the adapter asks it instead of guessing from the path. It listens to
685
+ the router's own events and does not wrap `history`; `labelsFor` does not apply to it.
658
686
 
659
- `screen` keeps its meaning — the name you give with `bc.nav` or `setScreen` — and falls
660
- back to `route` when you never set one, so an app that does nothing still gets a useful
661
- screen.
687
+ ```ts
688
+ // Vue Router 4
689
+ import { enableVueRouterNavigation } from '@dasasian/firebase-structured-logger/client/navigation/vue-router'
690
+ enableVueRouterNavigation(router)
691
+
692
+ // React Router 6.4+ or 7, data router (createBrowserRouter and friends)
693
+ import { enableReactRouterNavigation } from '@dasasian/firebase-structured-logger/client/navigation/react-router'
694
+ enableReactRouterNavigation(router)
695
+ ```
696
+
697
+ | Label | Vue Router | React Router |
698
+ |---|---|---|
699
+ | `route` | the full pattern of the deepest match, `/orders/:id/items` | the same, joined from each match's `path`, without the `basename` |
700
+ | `screen` | the `name` of the deepest matched route that has one | `handle.screen` of the deepest match that has one |
701
+ | `path` | `to.path` — never the query or hash | `location.pathname` |
702
+
703
+ No name anywhere in the match → `screen` is the route. Vue names that are symbols are
704
+ skipped. One page change is one breadcrumb: a React Router redirect records only the page
705
+ it ends on, and a Vue navigation that was blocked or cancelled records nothing.
706
+
707
+ One option, `adjust`, takes the router's labels and returns the ones to log — for
708
+ cleaning personal data out of a path:
709
+
710
+ ```ts
711
+ enableVueRouterNavigation(router, {
712
+ adjust: (labels) => ({ ...labels, path: labels.path?.replace(/[^/]+@[^/]+/g, ':email') }),
713
+ })
714
+ ```
715
+
716
+ Each adapter returns a function that stops it. Calling an adapter again stops the first
717
+ one. If you call both an adapter and `enableNavigation()`, the adapter wins and the
718
+ console says so once. Neither router is a dependency of this package: the adapter only
719
+ reads the router you pass in.
720
+
721
+ **Without URL routing** — screens that switch without the address changing — call
722
+ `navigatedTo(screen, { route?, path? })` on each change. It records the same breadcrumb and
723
+ labels as automatic navigation.
724
+
725
+ **One breadcrumb per page change**, structured so it reads without parsing:
726
+
727
+ ```
728
+ { type: "nav", name: "OrderItems", data: { route: "/orders/:id/items", path: "/orders/1042/items" } }
729
+ ```
662
730
 
663
- **The id rule**, when there is no `routeFor` or it returns `undefined`: a path segment that
664
- is all digits, a UUID, a long hex string or a ULID becomes `:id`. Anything else is kept as
665
- written, so a slug like `/blog/my-post` stays as it is — no rule tells a slug from a page
666
- name reliably, which is what `routeFor` is for.
731
+ `name` is the screen, else the route, else the path; `data.path` is absent when your
732
+ `labelsFor` leaves `path` out.
667
733
 
668
734
  **What never leaves the browser:** the query string, always — it is where tokens and
669
735
  emails usually ride. The fragment too, unless it is a route: `#/orders/1042` is read as the
670
- path, `#section-3` or `#access_token=…` is dropped. If your paths themselves can hold
671
- personal data (`/users/jane@example.com`), clean them or switch `path` off:
736
+ path, `#section-3` or `#access_token=…` is dropped. `labelsFor` receives the path already
737
+ stripped. If your paths themselves can hold personal data, clean them there:
672
738
 
673
739
  ```ts
674
- enableNavigation({ cleanPath: (path) => path.replace(/[^/]+@[^/]+/g, ':email') })
675
- enableNavigation({ path: false })
740
+ enableNavigation({
741
+ labelsFor: (path) => {
742
+ const labels = defaultLabelsFor(path)
743
+ return { ...labels, path: labels.path?.replace(/[^/]+@[^/]+/g, ':email') }
744
+ },
745
+ })
746
+ ```
747
+
748
+ **With navigation on, `bc.nav` and `setScreen` are ignored** — they would record the same
749
+ page change twice — and the console says so once.
750
+
751
+ **Deprecated in 1.3, removed in 2.0:** `routeFor`, `cleanPath` and `path: false` (each
752
+ warns once; use `labelsFor`), the `routeSource` label, and `bc.nav` / `setScreen` (use
753
+ `enableNavigation`, or `navigatedTo` without URL routing).
754
+
755
+ ## Timing: when something is too slow
756
+
757
+ Some failures never throw. A loading screen waits on eight pieces, one of them takes 30
758
+ seconds, and the logs say nothing — because nothing failed. Traces report exactly that
759
+ case, and only that case: something took longer than you said it should, or never
760
+ finished. A trace that finishes in time sends nothing at all.
761
+
762
+ ```ts
763
+ import { trace, startTrace } from '@dasasian/firebase-structured-logger/client/timing'
764
+
765
+ await trace('app_boot', async (boot) => {
766
+ const user = await boot.step('sign-in', () => signIn())
767
+ await Promise.all([
768
+ boot.step('products', () => loadProducts(user)),
769
+ boot.step('places', () => loadPlaces(user)),
770
+ ])
771
+ })
772
+
773
+ // A flow that spans functions — a screen that starts on mount and ends when its data is in
774
+ const open = startTrace('order_open')
775
+ await open.step('order', () => loadOrder(id))
776
+ open.end()
777
+ ```
778
+
779
+ Your code holds names only. The limits live in one place, set once at startup:
780
+
781
+ ```ts
782
+ import { configureTraces } from '@dasasian/firebase-structured-logger/client/timing'
783
+
784
+ configureTraces({
785
+ app_boot: { warnAfterMs: 8000, steps: { products: 3000 } },
786
+ order_open: { warnAfterMs: 2000 },
787
+ })
788
+ ```
789
+
790
+ A trace with no limits configured is timed but never reported. Limits are read when a run
791
+ starts, so configure before the first one.
792
+
793
+ **What gets sent.** One `WARNING` per run, the moment the first limit is crossed — the
794
+ trace's, or a step's own — while it is still running, so a step that never finishes is
795
+ reported too. Nothing more is sent for that run afterwards.
796
+
676
797
  ```
798
+ WARNING app_boot slow: products passed 3000 ms, still waiting
799
+ labels.trace="app_boot" labels.run="<id>" labels.slow="step" labels.step="products"
800
+ timing: { elapsedMs: 3000, limitMs: 3000,
801
+ steps: { sign-in: 610, places: 410 }, waiting: ["products"] }
802
+ ```
803
+
804
+ `labels.slow` is `"trace"` or `"step"`. Durations are in milliseconds, always in `timing`.
805
+ `labels.run` tells two overlapping runs of the same trace apart.
806
+
807
+ **What is never judged.** A browser pauses pages it is not showing: a hidden tab, a phone
808
+ switching apps, a laptop going to sleep. Time spent paused is not your app being slow, so
809
+ a run that was hidden at any point, or that was paused — a one-second check that arrives
810
+ five or more seconds late — is not reported. Laptop sleep often fires no event at all,
811
+ which is why the late check exists.
812
+
813
+ **Underneath** each step is a standard `performance.mark` and `performance.measure`, so
814
+ it shows in the browser's Performance panel and in other tools that read them. Ours are
815
+ cleared when the run ends. A `step` after `end()`, or a second `end()`, is ignored.
816
+
817
+ **On the server**, `trace` and `startTrace` come from `/functions`, with the same entry. A
818
+ server run is judged when a step or the trace ends — there is no timer, because Cloud
819
+ Functions and Cloud Run can throttle the CPU once a response is sent. A request that hangs
820
+ outright is ended by the platform's timeout, which logs it. Inside `withLogging`, the entry
821
+ carries that request's labels like any other.
822
+
823
+ Traces explain the slow case; they do not measure what is normal. There are no
824
+ percentiles here and no sampling — if you need those, that is a monitoring tool's job.
677
825
 
678
826
  ## User feedback
679
827
 
@@ -922,6 +1070,7 @@ Narrow it when you need to:
922
1070
  | `labels.truncated="true"` | entries shortened to fit — the full copy is `fsl-overflow.json` |
923
1071
  | `labels.repeatKey="<key>" OR labels.repeatOf="<key>"` | one repeating error: its full copies and its summaries |
924
1072
  | `labels.sentLate="true"` | repeat summaries sent on a later visit |
1073
+ | `labels.trace="app_boot"` | slow runs of one trace — `labels.slow` says whether the trace or a step was late |
925
1074
 
926
1075
  Locally, the emulator's JSONL answers the same questions. Point
927
1076
  **[firebase-mcp-server](https://github.com/dasasian/firebase-mcp-server)** at either and ask
@@ -949,7 +1098,7 @@ logger.debug(message, labels?, context?, attachments?) // suppressed in producti
949
1098
 
950
1099
  logger.setUser(uid, extraLabels?)
951
1100
  logger.clearUser()
952
- logger.setScreen(screen)
1101
+ logger.setScreen(screen) // deprecated in 1.3 — use navigation
953
1102
  logger.addBreadcrumb(type, name, data?)
954
1103
 
955
1104
  ```
@@ -957,8 +1106,16 @@ logger.addBreadcrumb(type, name, data?)
957
1106
  Optional helpers are separate entry points, so an app ships only what it imports:
958
1107
 
959
1108
  ```ts
960
- import { enableNavigation } from '@dasasian/firebase-structured-logger/client/navigation'
961
- enableNavigation({ routeFor?, cleanPath?, path? }) // see "Navigation, automatically"
1109
+ import { enableNavigation, navigatedTo, defaultLabelsFor } from '@dasasian/firebase-structured-logger/client/navigation'
1110
+ enableNavigation({ labelsFor?: (path) => ({ route?, screen?, path? }) }) // see "Navigation, automatically"
1111
+ navigatedTo(screen, { route?, path? }) // a page change with no URL change
1112
+
1113
+ import { enableVueRouterNavigation } from '@dasasian/firebase-structured-logger/client/navigation/vue-router'
1114
+ import { enableReactRouterNavigation } from '@dasasian/firebase-structured-logger/client/navigation/react-router'
1115
+ const stop = enableVueRouterNavigation(router, { adjust?: (labels) => labels }) // the same for React Router
1116
+
1117
+ import { trace, startTrace, configureTraces } from '@dasasian/firebase-structured-logger/client/timing'
1118
+ configureTraces({ name: { warnAfterMs?, steps?: { step: ms } } }) // see "Timing"
962
1119
  ```
963
1120
 
964
1121
  Also exported: `initLogger`, `getClientLogger`, `setupGlobalErrorHandler`, `handleReactError`,
@@ -978,6 +1135,16 @@ and are removed in 2.0:
978
1135
  | `triggerTestLog()` | `sendTestLog()` |
979
1136
  | `fsl upload-sourcemaps --functions=<dir>` | `--backend=<dir>` (it is not only for Cloud Functions) |
980
1137
 
1138
+ **Deprecated in 1.3.** Still working in 1.x, each with a one-time console warning where
1139
+ code can warn; removed in 2.0:
1140
+
1141
+ | Old | New |
1142
+ |---|---|
1143
+ | `enableNavigation({ routeFor })`, `({ cleanPath })`, `({ path: false })` | `enableNavigation({ labelsFor })` |
1144
+ | label `routeSource` | none — `labelsFor`'s answer is final |
1145
+ | `bc.nav(screen)`, `logger.setScreen(screen)` | `enableNavigation()`, or `navigatedTo(screen)` without URL routing |
1146
+ | `bc.error(type, data?)` | `bc.handledError(type, data?)` — only for errors you handled and did not log |
1147
+
981
1148
  `Logger` is exported as a **type only** — the client logger is a session singleton, so
982
1149
  annotate with `Logger<MyAppLabels>` and construct with `initLogger()`. A second instance
983
1150
  would silently share breadcrumbs, screen and the rate-limit budget while looking independent.
@@ -993,6 +1160,8 @@ getLogger() // the current request's writer, or an anonymo
993
1160
  logError / logWarn / logInfo / logDebug (message, labels?, context?, attachments?)
994
1161
 
995
1162
  configureAttachments({ bucket?, prefix? }) // once, at module load — see Attachments
1163
+ configureTraces({ name: { warnAfterMs?, steps? } }) // once — see "Timing"
1164
+ trace(name, async (t) => { await t.step(name, fn) }) // or startTrace(name) … .end()
996
1165
 
997
1166
  // Receiving client logs. All three take the same source-map config:
998
1167
  // { bucket?, sourceMaps?: { bucket?, prefix? } }
@@ -13,25 +13,54 @@ import type { BreadcrumbEntry, NavigationLabels } from '../shared/types';
13
13
  * would have reproduced the bug.
14
14
  */
15
15
  export declare const MAX_BREADCRUMBS = 50;
16
+ /**
17
+ * Set by `enableNavigation()` and `navigatedTo()` (`client/navigation.ts`), never by
18
+ * the core itself — the setter a helper hands data through, mirroring `setCurrentRoute`.
19
+ * Once true, the legacy `bc.nav`/`setScreen` path is ignored: one page change must give
20
+ * exactly one `nav` breadcrumb, never two for the same event.
21
+ */
22
+ export declare function setNavigationEnabled(enabled: boolean): void;
23
+ /** Called by a router adapter's own registration/`stop()` — never by the core itself. */
24
+ export declare function setAdapterActive(active: boolean): void;
25
+ export declare function isAdapterActive(): boolean;
26
+ /** Called once, by `enableNavigation()`, the first time it wraps `history`. */
27
+ export declare function noteHistoryWrapperWired(): void;
28
+ /** @deprecated Use `enableNavigation()`, or `navigatedTo()` without URL routing. */
16
29
  export declare function setCurrentScreen(screen: string): void;
17
30
  export declare function getCurrentScreen(): string | undefined;
18
31
  /**
19
- * Called by `enableNavigation()` (`client/navigation.ts`) on the current page and on
20
- * every route change after it — never by the core itself. Mirrors `setCurrentScreen`:
21
- * the one-way setter a helper hands data through, rather than the core reaching out to
22
- * the helper. Adds a `nav` breadcrumb named after the real path, or the route pattern
23
- * when `path` was omitted (`enableNavigation({ path: false })`).
32
+ * Called by `enableNavigation()` and `navigatedTo()` (`client/navigation.ts`) on every
33
+ * page change — never by the core itself. Mirrors `setNavigationEnabled`: the one-way
34
+ * setter a helper hands data through, rather than the core reaching out to the helper.
35
+ * Adds one `nav` breadcrumb named after `labels.screen`, else `labels.route`, else
36
+ * `labels.path`; `labels` itself is stored exactly as given, so a field left out of it
37
+ * stays absent from the entry labels built from `getCurrentRoute()`.
24
38
  */
25
39
  export declare function setCurrentRoute(labels: NavigationLabels): void;
26
- /** The current page's navigation labels, or `undefined` when `enableNavigation()` was never called. */
40
+ /** The current page's navigation labels, or `undefined` when navigation was never turned on. */
27
41
  export declare function getCurrentRoute(): NavigationLabels | undefined;
42
+ /**
43
+ * The screen to label an entry with right now — navigation's, when it has one,
44
+ * else the legacy `setScreen`/`bc.nav` value. Written once so the label and the
45
+ * repeat signature can never read two different answers to the same question.
46
+ */
47
+ export declare function getActiveScreen(): string | undefined;
28
48
  export declare function addBreadcrumb(type: BreadcrumbEntry['type'], name: string, data?: Record<string, unknown>): void;
29
49
  export declare function getLastBreadcrumbs(count: number): BreadcrumbEntry[];
30
50
  export declare function clearBreadcrumbs(): void;
51
+ /**
52
+ * One way in for each kind of breadcrumb (CLAUDE.md, "Where the user is"). `nav` and
53
+ * `error` are deprecated — `enableNavigation()`/`navigatedTo()` and `handledError`
54
+ * replace them — and each still works, warning once.
55
+ */
31
56
  export declare const bc: {
32
57
  action: (name: string, data?: Record<string, unknown>) => void;
33
58
  state: (name: string, data?: Record<string, unknown>) => void;
59
+ /** @deprecated Use `enableNavigation()`, or `navigatedTo()` without URL routing. */
34
60
  nav: (screen: string) => void;
61
+ /** @deprecated Use `bc.handledError` — only for an error your code handled and did not log. */
35
62
  error: (type: string, data?: Record<string, unknown>) => void;
63
+ /** An error your code handled and chose not to log — a clue if something else goes wrong. */
64
+ handledError: (type: string, data?: Record<string, unknown>) => void;
36
65
  };
37
66
  //# sourceMappingURL=breadcrumbs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumbs.d.ts","sourceRoot":"","sources":["../../src/client/breadcrumbs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAExE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,KAAK,CAAA;AAMjC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGrD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAErD;AAID;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAG9D;AAED,uGAAuG;AACvG,wBAAgB,eAAe,IAAI,gBAAgB,GAAG,SAAS,CAE9D;AAoBD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAQN;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAKnE;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAED,eAAO,MAAM,EAAE;mBACE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;kBACtC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;kBACpC,MAAM;kBACR,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CACtD,CAAA"}
1
+ {"version":3,"file":"breadcrumbs.d.ts","sourceRoot":"","sources":["../../src/client/breadcrumbs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGxE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,KAAK,CAAA;AAMjC;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE3D;AAgBD,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAGtD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,+EAA+E;AAC/E,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C;AAQD,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGrD;AAOD,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAErD;AAID;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAM9D;AAED,gGAAgG;AAChG,wBAAgB,eAAe,IAAI,gBAAgB,GAAG,SAAS,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,SAAS,CAEpD;AAoBD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAQN;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAKnE;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAED;;;;GAIG;AACH,eAAO,MAAM,EAAE;mBACE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;kBACvC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpD,oFAAoF;kBACtE,MAAM;IACpB,+FAA+F;kBACjF,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIpD,6FAA6F;yBACxE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAC5D,CAAA"}
@@ -1,13 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.bc = exports.MAX_BREADCRUMBS = void 0;
4
+ exports.setNavigationEnabled = setNavigationEnabled;
5
+ exports.setAdapterActive = setAdapterActive;
6
+ exports.isAdapterActive = isAdapterActive;
7
+ exports.noteHistoryWrapperWired = noteHistoryWrapperWired;
4
8
  exports.setCurrentScreen = setCurrentScreen;
5
9
  exports.getCurrentScreen = getCurrentScreen;
6
10
  exports.setCurrentRoute = setCurrentRoute;
7
11
  exports.getCurrentRoute = getCurrentRoute;
12
+ exports.getActiveScreen = getActiveScreen;
8
13
  exports.addBreadcrumb = addBreadcrumb;
9
14
  exports.getLastBreadcrumbs = getLastBreadcrumbs;
10
15
  exports.clearBreadcrumbs = clearBreadcrumbs;
16
+ const deprecate_1 = require("../shared/deprecate");
11
17
  /**
12
18
  * How many breadcrumbs are retained — and therefore how many are sent.
13
19
  *
@@ -25,29 +31,88 @@ exports.MAX_BREADCRUMBS = 50;
25
31
  const MAX_AGE_MS = 5 * 60 * 1000; // 5 minutes
26
32
  let currentScreen;
27
33
  let breadcrumbs = [];
28
- function setCurrentScreen(screen) {
34
+ /**
35
+ * Set by `enableNavigation()` and `navigatedTo()` (`client/navigation.ts`), never by
36
+ * the core itself — the setter a helper hands data through, mirroring `setCurrentRoute`.
37
+ * Once true, the legacy `bc.nav`/`setScreen` path is ignored: one page change must give
38
+ * exactly one `nav` breadcrumb, never two for the same event.
39
+ */
40
+ function setNavigationEnabled(enabled) {
41
+ navigationEnabled = enabled;
42
+ }
43
+ let navigationEnabled = false;
44
+ let adapterActive = false;
45
+ let historyWrapperWired = false;
46
+ let adapterWinsWarned = false;
47
+ function warnAdapterWins() {
48
+ if (adapterWinsWarned)
49
+ return;
50
+ adapterWinsWarned = true;
51
+ console.warn('[fsl] a router adapter and enableNavigation() are both active — the adapter wins, and the history wrapper stops recording.');
52
+ }
53
+ /** Called by a router adapter's own registration/`stop()` — never by the core itself. */
54
+ function setAdapterActive(active) {
55
+ if (active && historyWrapperWired)
56
+ warnAdapterWins();
57
+ adapterActive = active;
58
+ }
59
+ function isAdapterActive() {
60
+ return adapterActive;
61
+ }
62
+ /** Called once, by `enableNavigation()`, the first time it wraps `history`. */
63
+ function noteHistoryWrapperWired() {
64
+ if (adapterActive)
65
+ warnAdapterWins();
66
+ historyWrapperWired = true;
67
+ }
68
+ function recordScreenChange(screen) {
69
+ if (navigationEnabled)
70
+ return;
29
71
  currentScreen = screen;
30
72
  addBreadcrumb('nav', `navigate_${screen}`);
31
73
  }
74
+ /** @deprecated Use `enableNavigation()`, or `navigatedTo()` without URL routing. */
75
+ function setCurrentScreen(screen) {
76
+ (0, deprecate_1.warnDeprecated)('setScreen', 'enableNavigation(), or navigatedTo() without URL routing');
77
+ recordScreenChange(screen);
78
+ }
79
+ function legacyNav(screen) {
80
+ (0, deprecate_1.warnDeprecated)('bc.nav', 'enableNavigation(), or navigatedTo() without URL routing');
81
+ recordScreenChange(screen);
82
+ }
32
83
  function getCurrentScreen() {
33
84
  return currentScreen;
34
85
  }
35
86
  let currentRoute;
36
87
  /**
37
- * Called by `enableNavigation()` (`client/navigation.ts`) on the current page and on
38
- * every route change after it — never by the core itself. Mirrors `setCurrentScreen`:
39
- * the one-way setter a helper hands data through, rather than the core reaching out to
40
- * the helper. Adds a `nav` breadcrumb named after the real path, or the route pattern
41
- * when `path` was omitted (`enableNavigation({ path: false })`).
88
+ * Called by `enableNavigation()` and `navigatedTo()` (`client/navigation.ts`) on every
89
+ * page change — never by the core itself. Mirrors `setNavigationEnabled`: the one-way
90
+ * setter a helper hands data through, rather than the core reaching out to the helper.
91
+ * Adds one `nav` breadcrumb named after `labels.screen`, else `labels.route`, else
92
+ * `labels.path`; `labels` itself is stored exactly as given, so a field left out of it
93
+ * stays absent from the entry labels built from `getCurrentRoute()`.
42
94
  */
43
95
  function setCurrentRoute(labels) {
44
96
  currentRoute = labels;
45
- addBreadcrumb('nav', labels.path ?? labels.route, labels.path !== undefined ? { route: labels.route } : undefined);
97
+ const data = {};
98
+ if (labels.route !== undefined)
99
+ data.route = labels.route;
100
+ if (labels.path !== undefined)
101
+ data.path = labels.path;
102
+ addBreadcrumb('nav', labels.screen ?? labels.route ?? labels.path ?? '', Object.keys(data).length > 0 ? data : undefined);
46
103
  }
47
- /** The current page's navigation labels, or `undefined` when `enableNavigation()` was never called. */
104
+ /** The current page's navigation labels, or `undefined` when navigation was never turned on. */
48
105
  function getCurrentRoute() {
49
106
  return currentRoute;
50
107
  }
108
+ /**
109
+ * The screen to label an entry with right now — navigation's, when it has one,
110
+ * else the legacy `setScreen`/`bc.nav` value. Written once so the label and the
111
+ * repeat signature can never read two different answers to the same question.
112
+ */
113
+ function getActiveScreen() {
114
+ return currentRoute?.screen ?? currentScreen;
115
+ }
51
116
  /**
52
117
  * Drop anything past the age cutoff.
53
118
  *
@@ -84,10 +149,22 @@ function clearBreadcrumbs() {
84
149
  breadcrumbs = [];
85
150
  currentScreen = undefined;
86
151
  }
152
+ /**
153
+ * One way in for each kind of breadcrumb (CLAUDE.md, "Where the user is"). `nav` and
154
+ * `error` are deprecated — `enableNavigation()`/`navigatedTo()` and `handledError`
155
+ * replace them — and each still works, warning once.
156
+ */
87
157
  exports.bc = {
88
158
  action: (name, data) => addBreadcrumb('action', name, data),
89
159
  state: (name, data) => addBreadcrumb('state', name, data),
90
- nav: (screen) => setCurrentScreen(screen),
91
- error: (type, data) => addBreadcrumb('error', type, data),
160
+ /** @deprecated Use `enableNavigation()`, or `navigatedTo()` without URL routing. */
161
+ nav: (screen) => legacyNav(screen),
162
+ /** @deprecated Use `bc.handledError` — only for an error your code handled and did not log. */
163
+ error: (type, data) => {
164
+ (0, deprecate_1.warnDeprecated)('bc.error', 'bc.handledError');
165
+ addBreadcrumb('error', type, data);
166
+ },
167
+ /** An error your code handled and chose not to log — a clue if something else goes wrong. */
168
+ handledError: (type, data) => addBreadcrumb('error', type, data),
92
169
  };
93
170
  //# sourceMappingURL=breadcrumbs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumbs.js","sourceRoot":"","sources":["../../src/client/breadcrumbs.ts"],"names":[],"mappings":";;;AAqBA,4CAGC;AAED,4CAEC;AAWD,0CAGC;AAGD,0CAEC;AAoBD,sCAYC;AAED,gDAKC;AAED,4CAGC;AAzFD;;;;;;;;;;;;GAYG;AACU,QAAA,eAAe,GAAG,EAAE,CAAA;AACjC,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAA,CAAC,YAAY;AAE7C,IAAI,aAAiC,CAAA;AACrC,IAAI,WAAW,GAAsB,EAAE,CAAA;AAEvC,SAAgB,gBAAgB,CAAC,MAAc;IAC7C,aAAa,GAAG,MAAM,CAAA;IACtB,aAAa,CAAC,KAAK,EAAE,YAAY,MAAM,EAAE,CAAC,CAAA;AAC5C,CAAC;AAED,SAAgB,gBAAgB;IAC9B,OAAO,aAAa,CAAA;AACtB,CAAC;AAED,IAAI,YAA0C,CAAA;AAE9C;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,MAAwB;IACtD,YAAY,GAAG,MAAM,CAAA;IACrB,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;AACpH,CAAC;AAED,uGAAuG;AACvG,SAAgB,eAAe;IAC7B,OAAO,YAAY,CAAA;AACrB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,SAAS,CAAC,OAA0B,EAAE,GAAW;IACxD,MAAM,MAAM,GAAG,GAAG,GAAG,UAAU,CAAA;IAC/B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,MAAM;QAAE,OAAO,OAAO,CAAA;IACzE,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,GAAG,MAAM,CAAC,CAAA;AACtD,CAAC;AAED,SAAgB,aAAa,CAC3B,IAA6B,EAC7B,IAAY,EACZ,IAA8B;IAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACtB,WAAW,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACtD,WAAW,GAAG,SAAS,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;IAEzC,IAAI,WAAW,CAAC,MAAM,GAAG,uBAAe,EAAE,CAAC;QACzC,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,uBAAe,CAAC,CAAA;IACvE,CAAC;AACH,CAAC;AAED,SAAgB,kBAAkB,CAAC,KAAa;IAC9C,2EAA2E;IAC3E,8BAA8B;IAC9B,WAAW,GAAG,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAChD,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAA;AACnE,CAAC;AAED,SAAgB,gBAAgB;IAC9B,WAAW,GAAG,EAAE,CAAA;IAChB,aAAa,GAAG,SAAS,CAAA;AAC3B,CAAC;AAEY,QAAA,EAAE,GAAG;IAChB,MAAM,EAAE,CAAC,IAAY,EAAE,IAA8B,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC;IAC7F,KAAK,EAAG,CAAC,IAAY,EAAE,IAA8B,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;IAC5F,GAAG,EAAK,CAAC,MAAc,EAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC;IACpD,KAAK,EAAG,CAAC,IAAY,EAAE,IAA8B,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;CAC7F,CAAA"}
1
+ {"version":3,"file":"breadcrumbs.js","sourceRoot":"","sources":["../../src/client/breadcrumbs.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/client/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAgB,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAaxF,OAAO,EAQL,KAAK,eAAe,EAErB,MAAM,eAAe,CAAA;AAEtB,YAAY,EAAE,eAAe,EAAE,CAAA;AAE/B,KAAK,WAAW,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAEzD,MAAM,WAAW,eAAe,CAC9B,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAEzF,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC,CAAA;IAClD,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,CAAA;CACzC;AAED,MAAM,WAAW,gBAAgB,CAC/B,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAEzF,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,WAAW,CAAA;IACxB,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,gBAAgB,CAAC,EAAE,eAAe,CAAA;IAClC,qCAAqC;IACrC,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAgED,qBAAa,MAAM,CACjB,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAEzF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,UAAU,CAAyB;gBAE/B,MAAM,EAAE,gBAAgB,CAAC,SAAS,CAAC;IAS/C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI;IAK5D,SAAS,IAAI,IAAI;IAMjB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,aAAa,CACX,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,EAC1C,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI;IAIP,KAAK,CACH,GAAG,EAAE,OAAO,EACZ,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,EACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC,GACjD,IAAI;IAmBP,IAAI,CACF,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,EACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC,GACjD,IAAI;IAIP,OAAO,CACL,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,EACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC,GACjD,IAAI;IAIP,KAAK,CACH,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,EACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC,GACjD,IAAI;IAIP;;;;;;;;;;;;;;OAcG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,CAAC,SAAS,CAAC,GAAG,IAAI;YAavD,IAAI;IAoIlB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoB;IAEtD,iFAAiF;IACjF,oBAAoB,IAAI,IAAI;IAQ5B;;;;;;;;;;;OAWG;YACW,iBAAiB;CAgChC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACzF,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,CAAC,SAAS,CAAC,GAAG,IAAI,CAEzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAWlC;AAED,uCAAuC;AACvC,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAKD,wBAAgB,UAAU,CACxB,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACzF,MAAM,EAAE,gBAAgB,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,CAYxD;AAED,wBAAgB,eAAe,CAC7B,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KACtF,MAAM,CAAC,SAAS,CAAC,CAGrB"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/client/logger.ts"],"names":[],"mappings":"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"}
@@ -105,7 +105,7 @@ class Logger {
105
105
  errorType: error.name || 'UnknownError',
106
106
  ...labels,
107
107
  };
108
- void this.send(error.message, 'ERROR', errorLabels, context, attachments, (0, error_1.toErrorPayload)(error), (0, rateLimiter_1.signatureFor)(error, (0, breadcrumbs_1.getCurrentScreen)()));
108
+ void this.send(error.message, 'ERROR', errorLabels, context, attachments, (0, error_1.toErrorPayload)(error), (0, rateLimiter_1.signatureFor)(error, (0, breadcrumbs_1.getActiveScreen)()));
109
109
  }
110
110
  info(message, labels, context, attachments) {
111
111
  void this.send(message, 'INFO', labels, context, attachments);
@@ -146,16 +146,11 @@ class Logger {
146
146
  skipBudget = false, timestamp) {
147
147
  if (!bypassVolumeControls && severity_1.SEVERITY_ORDER[severity] > this.minLevel)
148
148
  return false;
149
- // Set only by enableNavigation() (@dasasian/firebase-structured-logger/client/navigation),
150
- // through the setter it calls in breadcrumbs.ts — undefined for an app that never
151
- // imports that entry point.
152
149
  const nav = (0, breadcrumbs_1.getCurrentRoute)();
153
150
  const allLabels = {
154
151
  appId: this.config.appId,
155
152
  releaseId: this.config.releaseId,
156
- // Falls back to the route pattern so an app that never calls setScreen/bc.nav
157
- // still gets a useful screen label once navigation is enabled.
158
- screen: (0, breadcrumbs_1.getCurrentScreen)() ?? nav?.route,
153
+ screen: (0, breadcrumbs_1.getActiveScreen)(),
159
154
  route: nav?.route,
160
155
  path: nav?.path,
161
156
  routeSource: nav?.routeSource,