@debugkit/sdk 0.0.0-stage → 0.1.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 (57) hide show
  1. package/README.md +176 -2
  2. package/dist/chunk-3UN5VMQU.js +41 -0
  3. package/dist/chunk-3UN5VMQU.js.map +1 -0
  4. package/dist/chunk-BD2FNVCP.js +71 -0
  5. package/dist/chunk-BD2FNVCP.js.map +1 -0
  6. package/dist/chunk-KUJ4EW3D.cjs +45 -0
  7. package/dist/chunk-KUJ4EW3D.cjs.map +1 -0
  8. package/dist/chunk-NSWUGBA2.cjs +75 -0
  9. package/dist/chunk-NSWUGBA2.cjs.map +1 -0
  10. package/dist/chunk-VIJ5USKQ.js +300 -0
  11. package/dist/chunk-VIJ5USKQ.js.map +1 -0
  12. package/dist/chunk-XEFWRCN4.cjs +311 -0
  13. package/dist/chunk-XEFWRCN4.cjs.map +1 -0
  14. package/dist/client-drmb0n15.d.cts +103 -0
  15. package/dist/client-drmb0n15.d.ts +103 -0
  16. package/dist/expo-router.cjs +13 -0
  17. package/dist/expo-router.cjs.map +1 -0
  18. package/dist/expo-router.d.cts +10 -0
  19. package/dist/expo-router.d.ts +10 -0
  20. package/dist/expo-router.js +11 -0
  21. package/dist/expo-router.js.map +1 -0
  22. package/dist/expo.cjs +97 -0
  23. package/dist/expo.cjs.map +1 -0
  24. package/dist/expo.d.cts +14 -0
  25. package/dist/expo.d.ts +14 -0
  26. package/dist/expo.js +47 -0
  27. package/dist/expo.js.map +1 -0
  28. package/dist/index.cjs +36 -0
  29. package/dist/index.cjs.map +1 -0
  30. package/dist/index.d.cts +11 -0
  31. package/dist/index.d.ts +11 -0
  32. package/dist/index.js +3 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/node.cjs +85 -0
  35. package/dist/node.cjs.map +1 -0
  36. package/dist/node.d.cts +23 -0
  37. package/dist/node.d.ts +23 -0
  38. package/dist/node.js +50 -0
  39. package/dist/node.js.map +1 -0
  40. package/dist/react-native.cjs +38 -0
  41. package/dist/react-native.cjs.map +1 -0
  42. package/dist/react-native.d.cts +51 -0
  43. package/dist/react-native.d.ts +51 -0
  44. package/dist/react-native.js +5 -0
  45. package/dist/react-native.js.map +1 -0
  46. package/dist/react.cjs +25 -0
  47. package/dist/react.cjs.map +1 -0
  48. package/dist/react.d.cts +50 -0
  49. package/dist/react.d.ts +50 -0
  50. package/dist/react.js +4 -0
  51. package/dist/react.js.map +1 -0
  52. package/expo/package.json +6 -0
  53. package/expo-router/package.json +6 -0
  54. package/node/package.json +6 -0
  55. package/package.json +121 -3
  56. package/react/package.json +6 -0
  57. package/react-native/package.json +6 -0
package/README.md CHANGED
@@ -1,3 +1,177 @@
1
- # Temporary Holding Version
1
+ # @debugkit/sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Log errors and events from your app into **your own** cloud. This is the client half of
4
+ [deBug](https://github.com/Abantu-Digital/deBug): events go to an ingest function you deploy
5
+ in Firebase or AWS, and a dashboard you run yourself tells you what is failing and why.
6
+
7
+ - About 3 KB gzipped, with no runtime dependencies in your bundle.
8
+ - Works with React, React Native (bare and Expo), Expo Router, TanStack Start/Router, Next.js
9
+ and plain Node.
10
+ - Captures crashes, unhandled rejections and render errors automatically. Batches, retries,
11
+ and queues events while offline.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install @debugkit/sdk
17
+ ```
18
+
19
+ Pick the entry point for your platform. Each one adds the right device context and error
20
+ hooks, and they all share the same `deBug` client.
21
+
22
+ | You have | Import from | Also install |
23
+ |---|---|---|
24
+ | Expo | `@debugkit/sdk/expo` | `npx expo install expo-device expo-application` |
25
+ | Expo Router | `@debugkit/sdk/expo-router`, plus the above | |
26
+ | Bare React Native | `@debugkit/sdk/react-native` | `react-native-device-info` (optional, for model and app version) |
27
+ | React on the web (Vite and others) | `@debugkit/sdk/react` | |
28
+ | TanStack Start / Router | `@debugkit/sdk/react` for the browser, `@debugkit/sdk/node` for the server | |
29
+ | Next.js, Remix, Express, any Node server | `@debugkit/sdk/node` | |
30
+ | Anything else (workers, edge, vanilla JS) | `@debugkit/sdk` | |
31
+
32
+ Your ingest endpoint and key come from your deBug deployment. During development, point at a
33
+ dashboard running in demo mode: `http://localhost:4400/api/ingest` with key `pk_local`.
34
+
35
+ ## Expo
36
+
37
+ ```tsx
38
+ // src/debug.ts
39
+ import { initExpo } from "@debugkit/sdk/expo";
40
+
41
+ initExpo({
42
+ endpoint: "https://<your-ingest-url>",
43
+ ingestKey: "pk_live_yourapp",
44
+ app: { id: "your-app" }, // version and build are read from expo-application
45
+ });
46
+ ```
47
+
48
+ ```tsx
49
+ // src/app/_layout.tsx
50
+ import "@/debug";
51
+ import { DebugErrorBoundary } from "@debugkit/sdk/expo";
52
+ import { useDebugExpoRouter } from "@debugkit/sdk/expo-router";
53
+
54
+ export default function RootLayout() {
55
+ useDebugExpoRouter(); // a breadcrumb for every screen change
56
+ return (
57
+ <DebugErrorBoundary flow="app.root" fallback={({ reset }) => <CrashScreen onRetry={reset} />}>
58
+ <Stack />
59
+ </DebugErrorBoundary>
60
+ );
61
+ }
62
+ ```
63
+
64
+ In Expo Go, the app version reported is Expo Go's own. Development and production builds
65
+ report yours.
66
+
67
+ ## Bare React Native
68
+
69
+ ```tsx
70
+ import DeviceInfo from "react-native-device-info";
71
+ import { initReactNative, DebugErrorBoundary, trackReactNavigation } from "@debugkit/sdk/react-native";
72
+
73
+ initReactNative({ endpoint, ingestKey, app: { id: "your-app" }, deviceInfo: DeviceInfo });
74
+
75
+ const nav = useNavigationContainerRef();
76
+ <NavigationContainer ref={nav} {...trackReactNavigation(nav)}>…</NavigationContainer>
77
+ ```
78
+
79
+ Without `react-native-device-info` you still get the OS, OS version and JS engine. On Android
80
+ you also get the model and brand.
81
+
82
+ React Native also gets:
83
+
84
+ - **Crashes** through React Native's global error handler.
85
+ - **Unhandled promise rejections** (Hermes). In production only by default, so the yellow-box
86
+ warning still works in development. Pass `captureUnhandledRejections: true` to capture them
87
+ in development too.
88
+ - **A flush when the app goes to the background.** Pass AsyncStorage as `storage` to keep
89
+ unsent events across restarts.
90
+
91
+ ## React (web)
92
+
93
+ ```tsx
94
+ import { deBug, DebugErrorBoundary } from "@debugkit/sdk/react";
95
+
96
+ deBug.init({ endpoint, ingestKey, app: { id: "your-web-app", version: "1.4.0" } });
97
+
98
+ createRoot(el).render(
99
+ <DebugErrorBoundary fallback={<p>Something went wrong.</p>}>
100
+ <App />
101
+ </DebugErrorBoundary>,
102
+ );
103
+ ```
104
+
105
+ Uncaught errors and unhandled rejections are captured from `window`. The OS, browser, screen
106
+ and network type are detected automatically.
107
+
108
+ ## TanStack Start / Router
109
+
110
+ ```tsx
111
+ // src/router.tsx: the browser side
112
+ import { deBug, trackTanStackRouter } from "@debugkit/sdk/react";
113
+
114
+ if (typeof window !== "undefined") deBug.init({ endpoint, ingestKey, app: { id: "web" } });
115
+
116
+ export function getRouter() {
117
+ const router = createRouter({ routeTree });
118
+ if (typeof window !== "undefined") trackTanStackRouter(router);
119
+ return router;
120
+ }
121
+ ```
122
+
123
+ ```ts
124
+ // src/server/debug.ts: server only
125
+ import { deBug, initNode } from "@debugkit/sdk/node";
126
+
127
+ export const serverDebug = () =>
128
+ deBug.initialized ? deBug : initNode({ endpoint, ingestKey, app: { id: "web", environment: "server" } });
129
+ ```
130
+
131
+ ```ts
132
+ // src/server/fns.ts
133
+ import { createServerFn } from "@tanstack/react-start";
134
+ import { withDebug } from "@debugkit/sdk/node";
135
+ import { serverDebug } from "./debug";
136
+
137
+ export const charge = createServerFn({ method: "POST" }).handler(
138
+ withDebug("checkout.payment", async ({ data }) => {
139
+ serverDebug(); // initialise lazily, inside the handler, so none of this reaches the client bundle
140
+ /* … */
141
+ }),
142
+ );
143
+ ```
144
+
145
+ When the browser calls a server function that is wrapped in `withDebug`, record only the
146
+ outcome there, so the error isn't counted twice:
147
+ `deBug.track("checkout.payment", "charge", () => charge(), { captureError: false })`.
148
+
149
+ ## Node
150
+
151
+ `initNode()` captures uncaught exceptions and unhandled rejections. It flushes events and then
152
+ exits the way Node would. Pass `captureProcessErrors: false` to manage those hooks yourself,
153
+ for example inside a dev server.
154
+
155
+ On edge runtimes such as Cloudflare Workers, timers aren't allowed at startup. Use the base
156
+ entry with `flushIntervalMs: 0`, and `await deBug.flush()` before each response returns.
157
+
158
+ ## The API
159
+
160
+ ```ts
161
+ deBug.error(err, { flow: "checkout.payment", step: "create_intent" });
162
+ deBug.event("signup_abandoned", { flow: "onboarding.signup", outcome: "abandoned" });
163
+ await deBug.track("auth.login", "submit_otp", () => api.verifyOtp(code)); // success or failure, plus the error
164
+ deBug.breadcrumb("navigation", "Login → OtpScreen");
165
+ deBug.setUser("user_123");
166
+ deBug.setContext({ app: { environment: "staging" } });
167
+ await deBug.flush();
168
+ ```
169
+
170
+ `flow` names the part of your app, in dotted lowercase like `auth.login`. It's the main axis
171
+ of the dashboard, so keep it consistent.
172
+
173
+ To scrub personal data before anything leaves the device, use `beforeSend`:
174
+
175
+ ```ts
176
+ deBug.init({ …, beforeSend: (e) => (e.type === "event" && e.name === "secret" ? null : e) });
177
+ ```
@@ -0,0 +1,41 @@
1
+ import { deBug, __publicField } from './chunk-VIJ5USKQ.js';
2
+ import { Component, useEffect } from 'react';
3
+
4
+ var DebugErrorBoundary = class extends Component {
5
+ constructor() {
6
+ super(...arguments);
7
+ __publicField(this, "state", { error: null });
8
+ __publicField(this, "reset", () => this.setState({ error: null }));
9
+ }
10
+ static getDerivedStateFromError(error) {
11
+ return { error };
12
+ }
13
+ componentDidCatch(error, info) {
14
+ var _a, _b, _c;
15
+ const client = (_a = this.props.client) != null ? _a : deBug;
16
+ if (info.componentStack) {
17
+ client.breadcrumb("ui", "React render error", { componentStack: info.componentStack.trim().slice(0, 1500) }, "error");
18
+ }
19
+ client.error(error, { flow: this.props.flow, handled: false, tags: { source: "error-boundary" } });
20
+ void client.flush();
21
+ (_c = (_b = this.props).onError) == null ? void 0 : _c.call(_b, error, info);
22
+ }
23
+ render() {
24
+ const { error } = this.state;
25
+ if (!error) return this.props.children;
26
+ const { fallback } = this.props;
27
+ return typeof fallback === "function" ? fallback({ error, reset: this.reset }) : fallback != null ? fallback : null;
28
+ }
29
+ };
30
+ function useDebugNavigation(path, client = deBug) {
31
+ useEffect(() => {
32
+ if (path) client.breadcrumb("navigation", path);
33
+ }, [path, client]);
34
+ }
35
+ function trackTanStackRouter(router, client = deBug) {
36
+ return router.subscribe("onResolved", ({ toLocation }) => client.breadcrumb("navigation", toLocation.pathname));
37
+ }
38
+
39
+ export { DebugErrorBoundary, trackTanStackRouter, useDebugNavigation };
40
+ //# sourceMappingURL=chunk-3UN5VMQU.js.map
41
+ //# sourceMappingURL=chunk-3UN5VMQU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.tsx"],"names":[],"mappings":";;;AAqBO,IAAM,kBAAA,GAAN,cAAiC,SAAA,CAA0C;AAAA,EAA3E,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA;AACL,IAAA,aAAA,CAAA,IAAA,EAAA,OAAA,EAAe,EAAE,OAAO,IAAA,EAAK,CAAA;AAgB7B,IAAA,aAAA,CAAA,IAAA,EAAA,OAAA,EAAQ,MAAM,IAAA,CAAK,QAAA,CAAS,EAAE,KAAA,EAAO,MAAM,CAAA,CAAA;AAAA,EAAA;AAAA,EAd3C,OAAO,yBAAyB,KAAA,EAAqB;AACnD,IAAA,OAAO,EAAE,KAAA,EAAM;AAAA,EACjB;AAAA,EAEA,iBAAA,CAAkB,OAAc,IAAA,EAAiB;AA5BnD,IAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AA6BI,IAAA,MAAM,MAAA,GAAA,CAAS,EAAA,GAAA,IAAA,CAAK,KAAA,CAAM,MAAA,KAAX,IAAA,GAAA,EAAA,GAAqB,KAAA;AACpC,IAAA,IAAI,KAAK,cAAA,EAAgB;AACvB,MAAA,MAAA,CAAO,UAAA,CAAW,IAAA,EAAM,oBAAA,EAAsB,EAAE,gBAAgB,IAAA,CAAK,cAAA,CAAe,IAAA,EAAK,CAAE,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,IAAK,OAAO,CAAA;AAAA,IACtH;AACA,IAAA,MAAA,CAAO,KAAA,CAAM,KAAA,EAAO,EAAE,IAAA,EAAM,KAAK,KAAA,CAAM,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,IAAA,EAAM,EAAE,MAAA,EAAQ,gBAAA,IAAoB,CAAA;AACjG,IAAA,KAAK,OAAO,KAAA,EAAM;AAClB,IAAA,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,IAAA,CAAK,KAAA,EAAM,OAAA,KAAX,IAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,EAAA,EAAqB,KAAA,EAAO,IAAA,CAAA;AAAA,EAC9B;AAAA,EAIA,MAAA,GAAS;AACP,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,IAAA,CAAK,KAAA;AACvB,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,IAAA,CAAK,KAAA,CAAM,QAAA;AAC9B,IAAA,MAAM,EAAE,QAAA,EAAS,GAAI,IAAA,CAAK,KAAA;AAC1B,IAAA,OAAO,OAAO,QAAA,KAAa,UAAA,GAAa,QAAA,CAAS,EAAE,KAAA,EAAO,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,CAAA,GAAK,QAAA,IAAA,IAAA,GAAA,QAAA,GAAY,IAAA;AAAA,EAChG;AACF;AAGO,SAAS,kBAAA,CAAmB,IAAA,EAA0B,MAAA,GAAsB,KAAA,EAAO;AACxF,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,IAAA,EAAM,MAAA,CAAO,UAAA,CAAW,YAAA,EAAc,IAAI,CAAA;AAAA,EAChD,CAAA,EAAG,CAAC,IAAA,EAAM,MAAM,CAAC,CAAA;AACnB;AAYO,SAAS,mBAAA,CAAoB,MAAA,EAAoB,MAAA,GAAsB,KAAA,EAAO;AACnF,EAAA,OAAO,MAAA,CAAO,SAAA,CAAU,YAAA,EAAc,CAAC,EAAE,UAAA,EAAW,KAAM,MAAA,CAAO,UAAA,CAAW,YAAA,EAAc,UAAA,CAAW,QAAQ,CAAC,CAAA;AAChH","file":"chunk-3UN5VMQU.js","sourcesContent":["import { Component, useEffect, type ErrorInfo, type ReactNode } from \"react\";\nimport { deBug, type DebugClient } from \"./index\";\n\nexport interface DebugErrorBoundaryProps {\n children?: ReactNode;\n /** What to render after a crash. A function gets the error and a reset callback. */\n fallback?: ReactNode | ((props: { error: Error; reset: () => void }) => ReactNode);\n /** Part of the app this boundary protects, e.g. \"checkout\". */\n flow?: string;\n client?: DebugClient;\n onError?: (error: Error, info: ErrorInfo) => void;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Catches render errors that React would otherwise swallow (or turn into a white/red screen)\n * and reports them. Works in React DOM and React Native.\n */\nexport class DebugErrorBoundary extends Component<DebugErrorBoundaryProps, State> {\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n const client = this.props.client ?? deBug;\n if (info.componentStack) {\n client.breadcrumb(\"ui\", \"React render error\", { componentStack: info.componentStack.trim().slice(0, 1500) }, \"error\");\n }\n client.error(error, { flow: this.props.flow, handled: false, tags: { source: \"error-boundary\" } });\n void client.flush();\n this.props.onError?.(error, info);\n }\n\n reset = () => this.setState({ error: null });\n\n render() {\n const { error } = this.state;\n if (!error) return this.props.children;\n const { fallback } = this.props;\n return typeof fallback === \"function\" ? fallback({ error, reset: this.reset }) : (fallback ?? null);\n }\n}\n\n/** Adds a navigation breadcrumb whenever `path` changes. Works with any router. */\nexport function useDebugNavigation(path: string | undefined, client: DebugClient = deBug) {\n useEffect(() => {\n if (path) client.breadcrumb(\"navigation\", path);\n }, [path, client]);\n}\n\n/** Minimal shape of a TanStack Router instance (avoids a hard dependency). */\ninterface RouterLike {\n subscribe(event: \"onResolved\", fn: (e: { toLocation: { pathname: string; href?: string } }) => void): () => void;\n}\n\n/**\n * Records a breadcrumb for every navigation in a TanStack Router app:\n * const router = createRouter({ routeTree }); trackTanStackRouter(router);\n * Returns an unsubscribe function.\n */\nexport function trackTanStackRouter(router: RouterLike, client: DebugClient = deBug) {\n return router.subscribe(\"onResolved\", ({ toLocation }) => client.breadcrumb(\"navigation\", toLocation.pathname));\n}\n\nexport { deBug } from \"./index\";\n"]}
@@ -0,0 +1,71 @@
1
+ import { deBug, timezone, locale, mergeContext } from './chunk-VIJ5USKQ.js';
2
+ import { Platform, AppState } from 'react-native';
3
+
4
+ function nativeContext(opts = {}) {
5
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
6
+ const c = (_a = Platform.constants) != null ? _a : {};
7
+ const di = opts.deviceInfo;
8
+ const rn = c.reactNativeVersion;
9
+ const hermes = typeof globalThis.HermesInternal !== "undefined";
10
+ const call = (fn) => {
11
+ try {
12
+ return fn == null ? void 0 : fn();
13
+ } catch {
14
+ return void 0;
15
+ }
16
+ };
17
+ const totalMemory = call((_b = di == null ? void 0 : di.getTotalMemorySync) == null ? void 0 : _b.bind(di));
18
+ return {
19
+ os: { name: Platform.OS, version: Platform.OS === "android" ? (_c = c.Release) != null ? _c : String(Platform.Version) : String(Platform.Version) },
20
+ runtime: { name: "react-native", version: rn ? `${rn.major}.${rn.minor}.${rn.patch}` : void 0, engine: hermes ? "hermes" : "jsc" },
21
+ device: {
22
+ model: (_d = call(di == null ? void 0 : di.getModel.bind(di))) != null ? _d : c.Model,
23
+ brand: (_e = call(di == null ? void 0 : di.getBrand.bind(di))) != null ? _e : c.Brand,
24
+ manufacturer: (_g = call((_f = di == null ? void 0 : di.getManufacturerSync) == null ? void 0 : _f.bind(di))) != null ? _g : c.Manufacturer,
25
+ isEmulator: (_i = call((_h = di == null ? void 0 : di.isEmulatorSync) == null ? void 0 : _h.bind(di))) != null ? _i : c.Fingerprint ? /generic|emulator/i.test(c.Fingerprint) : void 0,
26
+ memoryMb: totalMemory ? Math.round(totalMemory / 1024 / 1024) : void 0,
27
+ type: di ? call(di.isTablet.bind(di)) ? "tablet" : "phone" : Platform.OS === "ios" && Platform.isPad ? "tablet" : "phone"
28
+ },
29
+ app: { version: call(di == null ? void 0 : di.getVersion.bind(di)), build: call(di == null ? void 0 : di.getBuildNumber.bind(di)) },
30
+ locale: locale(),
31
+ timezone: timezone()
32
+ };
33
+ }
34
+ function initReactNative(options, client = deBug) {
35
+ var _a, _b;
36
+ const { deviceInfo, captureUnhandledRejections = "production", ...rest } = options;
37
+ const base = nativeContext({ deviceInfo });
38
+ client.init({
39
+ ...rest,
40
+ app: { ...base.app, ...rest.app },
41
+ context: mergeContext(base, (_a = rest.context) != null ? _a : {})
42
+ });
43
+ AppState.addEventListener("change", (state) => {
44
+ if (state !== "active") void client.flush();
45
+ });
46
+ const dev = typeof __DEV__ !== "undefined" && __DEV__;
47
+ const tracker = (_b = globalThis.HermesInternal) == null ? void 0 : _b.enablePromiseRejectionTracker;
48
+ if (tracker && (captureUnhandledRejections === true || captureUnhandledRejections === "production" && !dev)) {
49
+ tracker({
50
+ allRejections: true,
51
+ onUnhandled: (_id, reason) => client.error(reason, { handled: false, tags: { source: "unhandled-rejection" } }),
52
+ onHandled: () => {
53
+ }
54
+ });
55
+ }
56
+ return client;
57
+ }
58
+ function trackReactNavigation(ref, client = deBug) {
59
+ let last;
60
+ const record = () => {
61
+ var _a;
62
+ const name = (_a = ref.getCurrentRoute()) == null ? void 0 : _a.name;
63
+ if (name && name !== last) client.breadcrumb("navigation", last ? `${last} \u2192 ${name}` : name);
64
+ last = name != null ? name : last;
65
+ };
66
+ return { onReady: record, onStateChange: record };
67
+ }
68
+
69
+ export { initReactNative, nativeContext, trackReactNavigation };
70
+ //# sourceMappingURL=chunk-BD2FNVCP.js.map
71
+ //# sourceMappingURL=chunk-BD2FNVCP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react-native.ts"],"names":[],"mappings":"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","file":"chunk-BD2FNVCP.js","sourcesContent":["import { AppState, Platform } from \"react-native\";\nimport { deBug, type DebugClient, type InitOptions } from \"./index\";\nimport { locale, mergeContext, timezone, type ContextPatch } from \"./context\";\n\nexport * from \"./react\";\n\n/** The subset of react-native-device-info we read. Pass the module itself: `import DeviceInfo from \"react-native-device-info\"`. */\nexport interface DeviceInfoModule {\n getModel(): string;\n getBrand(): string;\n getVersion(): string;\n getBuildNumber(): string;\n isTablet(): boolean;\n getManufacturerSync?(): string;\n isEmulatorSync?(): boolean;\n getTotalMemorySync?(): number;\n}\n\ntype RNConstants = {\n Release?: string;\n Model?: string;\n Brand?: string;\n Manufacturer?: string;\n Fingerprint?: string;\n reactNativeVersion?: { major: number; minor: number; patch: number };\n};\n\n/**\n * Context for bare React Native. Reads what `react-native` exposes on its own; pass\n * react-native-device-info for model, app version and memory on both platforms.\n */\nexport function nativeContext(opts: { deviceInfo?: DeviceInfoModule } = {}): ContextPatch {\n const c = (Platform.constants ?? {}) as RNConstants;\n const di = opts.deviceInfo;\n const rn = c.reactNativeVersion;\n const hermes = typeof (globalThis as { HermesInternal?: unknown }).HermesInternal !== \"undefined\";\n const call = <T,>(fn?: () => T) => {\n try {\n return fn?.();\n } catch {\n return undefined;\n }\n };\n const totalMemory = call(di?.getTotalMemorySync?.bind(di));\n return {\n os: { name: Platform.OS, version: Platform.OS === \"android\" ? (c.Release ?? String(Platform.Version)) : String(Platform.Version) },\n runtime: { name: \"react-native\", version: rn ? `${rn.major}.${rn.minor}.${rn.patch}` : undefined, engine: hermes ? \"hermes\" : \"jsc\" },\n device: {\n model: call(di?.getModel.bind(di)) ?? c.Model,\n brand: call(di?.getBrand.bind(di)) ?? c.Brand,\n manufacturer: call(di?.getManufacturerSync?.bind(di)) ?? c.Manufacturer,\n isEmulator: call(di?.isEmulatorSync?.bind(di)) ?? (c.Fingerprint ? /generic|emulator/i.test(c.Fingerprint) : undefined),\n memoryMb: totalMemory ? Math.round(totalMemory / 1024 / 1024) : undefined,\n type: di ? (call(di.isTablet.bind(di)) ? \"tablet\" : \"phone\") : Platform.OS === \"ios\" && (Platform as { isPad?: boolean }).isPad ? \"tablet\" : \"phone\",\n },\n app: { version: call(di?.getVersion.bind(di)), build: call(di?.getBuildNumber.bind(di)) } as ContextPatch[\"app\"],\n locale: locale(),\n timezone: timezone(),\n };\n}\n\nexport interface ReactNativeInitOptions extends InitOptions {\n deviceInfo?: DeviceInfoModule;\n /**\n * Report unhandled promise rejections (Hermes). Default \"production\": in development React\n * Native's own yellow-box warning keeps working. `true` captures in development too.\n */\n captureUnhandledRejections?: boolean | \"production\";\n}\n\ndeclare const __DEV__: boolean | undefined;\n\n/** Initialise deBug in a React Native app (bare or Expo). Fills in device context and flushes when the app is backgrounded. */\nexport function initReactNative(options: ReactNativeInitOptions, client: DebugClient = deBug): DebugClient {\n const { deviceInfo, captureUnhandledRejections = \"production\", ...rest } = options;\n const base = nativeContext({ deviceInfo });\n client.init({\n ...rest,\n app: { ...(base.app as object), ...rest.app },\n context: mergeContext(base, rest.context ?? {}),\n });\n\n AppState.addEventListener(\"change\", (state) => {\n if (state !== \"active\") void client.flush();\n });\n\n const dev = typeof __DEV__ !== \"undefined\" && __DEV__;\n const tracker = (globalThis as { HermesInternal?: { enablePromiseRejectionTracker?: (o: object) => void } }).HermesInternal\n ?.enablePromiseRejectionTracker;\n if (tracker && (captureUnhandledRejections === true || (captureUnhandledRejections === \"production\" && !dev))) {\n tracker({\n allRejections: true,\n onUnhandled: (_id: number, reason: unknown) => client.error(reason, { handled: false, tags: { source: \"unhandled-rejection\" } }),\n onHandled: () => {},\n });\n }\n return client;\n}\n\n/** Minimal shape of a React Navigation container ref. */\ninterface NavigationRefLike {\n getCurrentRoute(): { name: string } | undefined;\n}\n\n/**\n * Breadcrumbs for React Navigation. Spread the result onto your container:\n * const nav = useNavigationContainerRef();\n * <NavigationContainer ref={nav} {...trackReactNavigation(nav)}>\n */\nexport function trackReactNavigation(ref: NavigationRefLike, client: DebugClient = deBug) {\n let last: string | undefined;\n const record = () => {\n const name = ref.getCurrentRoute()?.name;\n if (name && name !== last) client.breadcrumb(\"navigation\", last ? `${last} → ${name}` : name);\n last = name ?? last;\n };\n return { onReady: record, onStateChange: record };\n}\n"]}
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ var chunkXEFWRCN4_cjs = require('./chunk-XEFWRCN4.cjs');
4
+ var react = require('react');
5
+
6
+ var DebugErrorBoundary = class extends react.Component {
7
+ constructor() {
8
+ super(...arguments);
9
+ chunkXEFWRCN4_cjs.__publicField(this, "state", { error: null });
10
+ chunkXEFWRCN4_cjs.__publicField(this, "reset", () => this.setState({ error: null }));
11
+ }
12
+ static getDerivedStateFromError(error) {
13
+ return { error };
14
+ }
15
+ componentDidCatch(error, info) {
16
+ var _a, _b, _c;
17
+ const client = (_a = this.props.client) != null ? _a : chunkXEFWRCN4_cjs.deBug;
18
+ if (info.componentStack) {
19
+ client.breadcrumb("ui", "React render error", { componentStack: info.componentStack.trim().slice(0, 1500) }, "error");
20
+ }
21
+ client.error(error, { flow: this.props.flow, handled: false, tags: { source: "error-boundary" } });
22
+ void client.flush();
23
+ (_c = (_b = this.props).onError) == null ? void 0 : _c.call(_b, error, info);
24
+ }
25
+ render() {
26
+ const { error } = this.state;
27
+ if (!error) return this.props.children;
28
+ const { fallback } = this.props;
29
+ return typeof fallback === "function" ? fallback({ error, reset: this.reset }) : fallback != null ? fallback : null;
30
+ }
31
+ };
32
+ function useDebugNavigation(path, client = chunkXEFWRCN4_cjs.deBug) {
33
+ react.useEffect(() => {
34
+ if (path) client.breadcrumb("navigation", path);
35
+ }, [path, client]);
36
+ }
37
+ function trackTanStackRouter(router, client = chunkXEFWRCN4_cjs.deBug) {
38
+ return router.subscribe("onResolved", ({ toLocation }) => client.breadcrumb("navigation", toLocation.pathname));
39
+ }
40
+
41
+ exports.DebugErrorBoundary = DebugErrorBoundary;
42
+ exports.trackTanStackRouter = trackTanStackRouter;
43
+ exports.useDebugNavigation = useDebugNavigation;
44
+ //# sourceMappingURL=chunk-KUJ4EW3D.cjs.map
45
+ //# sourceMappingURL=chunk-KUJ4EW3D.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.tsx"],"names":["Component","__publicField","deBug","useEffect"],"mappings":";;;;;AAqBO,IAAM,kBAAA,GAAN,cAAiCA,eAAA,CAA0C;AAAA,EAA3E,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA;AACL,IAAAC,+BAAA,CAAA,IAAA,EAAA,OAAA,EAAe,EAAE,OAAO,IAAA,EAAK,CAAA;AAgB7B,IAAAA,+BAAA,CAAA,IAAA,EAAA,OAAA,EAAQ,MAAM,IAAA,CAAK,QAAA,CAAS,EAAE,KAAA,EAAO,MAAM,CAAA,CAAA;AAAA,EAAA;AAAA,EAd3C,OAAO,yBAAyB,KAAA,EAAqB;AACnD,IAAA,OAAO,EAAE,KAAA,EAAM;AAAA,EACjB;AAAA,EAEA,iBAAA,CAAkB,OAAc,IAAA,EAAiB;AA5BnD,IAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AA6BI,IAAA,MAAM,MAAA,GAAA,CAAS,EAAA,GAAA,IAAA,CAAK,KAAA,CAAM,MAAA,KAAX,IAAA,GAAA,EAAA,GAAqBC,uBAAA;AACpC,IAAA,IAAI,KAAK,cAAA,EAAgB;AACvB,MAAA,MAAA,CAAO,UAAA,CAAW,IAAA,EAAM,oBAAA,EAAsB,EAAE,gBAAgB,IAAA,CAAK,cAAA,CAAe,IAAA,EAAK,CAAE,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,IAAK,OAAO,CAAA;AAAA,IACtH;AACA,IAAA,MAAA,CAAO,KAAA,CAAM,KAAA,EAAO,EAAE,IAAA,EAAM,KAAK,KAAA,CAAM,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,IAAA,EAAM,EAAE,MAAA,EAAQ,gBAAA,IAAoB,CAAA;AACjG,IAAA,KAAK,OAAO,KAAA,EAAM;AAClB,IAAA,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,IAAA,CAAK,KAAA,EAAM,OAAA,KAAX,IAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,EAAA,EAAqB,KAAA,EAAO,IAAA,CAAA;AAAA,EAC9B;AAAA,EAIA,MAAA,GAAS;AACP,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,IAAA,CAAK,KAAA;AACvB,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,IAAA,CAAK,KAAA,CAAM,QAAA;AAC9B,IAAA,MAAM,EAAE,QAAA,EAAS,GAAI,IAAA,CAAK,KAAA;AAC1B,IAAA,OAAO,OAAO,QAAA,KAAa,UAAA,GAAa,QAAA,CAAS,EAAE,KAAA,EAAO,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,CAAA,GAAK,QAAA,IAAA,IAAA,GAAA,QAAA,GAAY,IAAA;AAAA,EAChG;AACF;AAGO,SAAS,kBAAA,CAAmB,IAAA,EAA0B,MAAA,GAAsBA,uBAAA,EAAO;AACxF,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,IAAA,EAAM,MAAA,CAAO,UAAA,CAAW,YAAA,EAAc,IAAI,CAAA;AAAA,EAChD,CAAA,EAAG,CAAC,IAAA,EAAM,MAAM,CAAC,CAAA;AACnB;AAYO,SAAS,mBAAA,CAAoB,MAAA,EAAoB,MAAA,GAAsBD,uBAAA,EAAO;AACnF,EAAA,OAAO,MAAA,CAAO,SAAA,CAAU,YAAA,EAAc,CAAC,EAAE,UAAA,EAAW,KAAM,MAAA,CAAO,UAAA,CAAW,YAAA,EAAc,UAAA,CAAW,QAAQ,CAAC,CAAA;AAChH","file":"chunk-KUJ4EW3D.cjs","sourcesContent":["import { Component, useEffect, type ErrorInfo, type ReactNode } from \"react\";\nimport { deBug, type DebugClient } from \"./index\";\n\nexport interface DebugErrorBoundaryProps {\n children?: ReactNode;\n /** What to render after a crash. A function gets the error and a reset callback. */\n fallback?: ReactNode | ((props: { error: Error; reset: () => void }) => ReactNode);\n /** Part of the app this boundary protects, e.g. \"checkout\". */\n flow?: string;\n client?: DebugClient;\n onError?: (error: Error, info: ErrorInfo) => void;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Catches render errors that React would otherwise swallow (or turn into a white/red screen)\n * and reports them. Works in React DOM and React Native.\n */\nexport class DebugErrorBoundary extends Component<DebugErrorBoundaryProps, State> {\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n const client = this.props.client ?? deBug;\n if (info.componentStack) {\n client.breadcrumb(\"ui\", \"React render error\", { componentStack: info.componentStack.trim().slice(0, 1500) }, \"error\");\n }\n client.error(error, { flow: this.props.flow, handled: false, tags: { source: \"error-boundary\" } });\n void client.flush();\n this.props.onError?.(error, info);\n }\n\n reset = () => this.setState({ error: null });\n\n render() {\n const { error } = this.state;\n if (!error) return this.props.children;\n const { fallback } = this.props;\n return typeof fallback === \"function\" ? fallback({ error, reset: this.reset }) : (fallback ?? null);\n }\n}\n\n/** Adds a navigation breadcrumb whenever `path` changes. Works with any router. */\nexport function useDebugNavigation(path: string | undefined, client: DebugClient = deBug) {\n useEffect(() => {\n if (path) client.breadcrumb(\"navigation\", path);\n }, [path, client]);\n}\n\n/** Minimal shape of a TanStack Router instance (avoids a hard dependency). */\ninterface RouterLike {\n subscribe(event: \"onResolved\", fn: (e: { toLocation: { pathname: string; href?: string } }) => void): () => void;\n}\n\n/**\n * Records a breadcrumb for every navigation in a TanStack Router app:\n * const router = createRouter({ routeTree }); trackTanStackRouter(router);\n * Returns an unsubscribe function.\n */\nexport function trackTanStackRouter(router: RouterLike, client: DebugClient = deBug) {\n return router.subscribe(\"onResolved\", ({ toLocation }) => client.breadcrumb(\"navigation\", toLocation.pathname));\n}\n\nexport { deBug } from \"./index\";\n"]}
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+
3
+ var chunkXEFWRCN4_cjs = require('./chunk-XEFWRCN4.cjs');
4
+ var reactNative = require('react-native');
5
+
6
+ function nativeContext(opts = {}) {
7
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
8
+ const c = (_a = reactNative.Platform.constants) != null ? _a : {};
9
+ const di = opts.deviceInfo;
10
+ const rn = c.reactNativeVersion;
11
+ const hermes = typeof globalThis.HermesInternal !== "undefined";
12
+ const call = (fn) => {
13
+ try {
14
+ return fn == null ? void 0 : fn();
15
+ } catch {
16
+ return void 0;
17
+ }
18
+ };
19
+ const totalMemory = call((_b = di == null ? void 0 : di.getTotalMemorySync) == null ? void 0 : _b.bind(di));
20
+ return {
21
+ os: { name: reactNative.Platform.OS, version: reactNative.Platform.OS === "android" ? (_c = c.Release) != null ? _c : String(reactNative.Platform.Version) : String(reactNative.Platform.Version) },
22
+ runtime: { name: "react-native", version: rn ? `${rn.major}.${rn.minor}.${rn.patch}` : void 0, engine: hermes ? "hermes" : "jsc" },
23
+ device: {
24
+ model: (_d = call(di == null ? void 0 : di.getModel.bind(di))) != null ? _d : c.Model,
25
+ brand: (_e = call(di == null ? void 0 : di.getBrand.bind(di))) != null ? _e : c.Brand,
26
+ manufacturer: (_g = call((_f = di == null ? void 0 : di.getManufacturerSync) == null ? void 0 : _f.bind(di))) != null ? _g : c.Manufacturer,
27
+ isEmulator: (_i = call((_h = di == null ? void 0 : di.isEmulatorSync) == null ? void 0 : _h.bind(di))) != null ? _i : c.Fingerprint ? /generic|emulator/i.test(c.Fingerprint) : void 0,
28
+ memoryMb: totalMemory ? Math.round(totalMemory / 1024 / 1024) : void 0,
29
+ type: di ? call(di.isTablet.bind(di)) ? "tablet" : "phone" : reactNative.Platform.OS === "ios" && reactNative.Platform.isPad ? "tablet" : "phone"
30
+ },
31
+ app: { version: call(di == null ? void 0 : di.getVersion.bind(di)), build: call(di == null ? void 0 : di.getBuildNumber.bind(di)) },
32
+ locale: chunkXEFWRCN4_cjs.locale(),
33
+ timezone: chunkXEFWRCN4_cjs.timezone()
34
+ };
35
+ }
36
+ function initReactNative(options, client = chunkXEFWRCN4_cjs.deBug) {
37
+ var _a, _b;
38
+ const { deviceInfo, captureUnhandledRejections = "production", ...rest } = options;
39
+ const base = nativeContext({ deviceInfo });
40
+ client.init({
41
+ ...rest,
42
+ app: { ...base.app, ...rest.app },
43
+ context: chunkXEFWRCN4_cjs.mergeContext(base, (_a = rest.context) != null ? _a : {})
44
+ });
45
+ reactNative.AppState.addEventListener("change", (state) => {
46
+ if (state !== "active") void client.flush();
47
+ });
48
+ const dev = typeof __DEV__ !== "undefined" && __DEV__;
49
+ const tracker = (_b = globalThis.HermesInternal) == null ? void 0 : _b.enablePromiseRejectionTracker;
50
+ if (tracker && (captureUnhandledRejections === true || captureUnhandledRejections === "production" && !dev)) {
51
+ tracker({
52
+ allRejections: true,
53
+ onUnhandled: (_id, reason) => client.error(reason, { handled: false, tags: { source: "unhandled-rejection" } }),
54
+ onHandled: () => {
55
+ }
56
+ });
57
+ }
58
+ return client;
59
+ }
60
+ function trackReactNavigation(ref, client = chunkXEFWRCN4_cjs.deBug) {
61
+ let last;
62
+ const record = () => {
63
+ var _a;
64
+ const name = (_a = ref.getCurrentRoute()) == null ? void 0 : _a.name;
65
+ if (name && name !== last) client.breadcrumb("navigation", last ? `${last} \u2192 ${name}` : name);
66
+ last = name != null ? name : last;
67
+ };
68
+ return { onReady: record, onStateChange: record };
69
+ }
70
+
71
+ exports.initReactNative = initReactNative;
72
+ exports.nativeContext = nativeContext;
73
+ exports.trackReactNavigation = trackReactNavigation;
74
+ //# sourceMappingURL=chunk-NSWUGBA2.cjs.map
75
+ //# sourceMappingURL=chunk-NSWUGBA2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react-native.ts"],"names":["Platform","locale","timezone","deBug","mergeContext","AppState"],"mappings":"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","file":"chunk-NSWUGBA2.cjs","sourcesContent":["import { AppState, Platform } from \"react-native\";\nimport { deBug, type DebugClient, type InitOptions } from \"./index\";\nimport { locale, mergeContext, timezone, type ContextPatch } from \"./context\";\n\nexport * from \"./react\";\n\n/** The subset of react-native-device-info we read. Pass the module itself: `import DeviceInfo from \"react-native-device-info\"`. */\nexport interface DeviceInfoModule {\n getModel(): string;\n getBrand(): string;\n getVersion(): string;\n getBuildNumber(): string;\n isTablet(): boolean;\n getManufacturerSync?(): string;\n isEmulatorSync?(): boolean;\n getTotalMemorySync?(): number;\n}\n\ntype RNConstants = {\n Release?: string;\n Model?: string;\n Brand?: string;\n Manufacturer?: string;\n Fingerprint?: string;\n reactNativeVersion?: { major: number; minor: number; patch: number };\n};\n\n/**\n * Context for bare React Native. Reads what `react-native` exposes on its own; pass\n * react-native-device-info for model, app version and memory on both platforms.\n */\nexport function nativeContext(opts: { deviceInfo?: DeviceInfoModule } = {}): ContextPatch {\n const c = (Platform.constants ?? {}) as RNConstants;\n const di = opts.deviceInfo;\n const rn = c.reactNativeVersion;\n const hermes = typeof (globalThis as { HermesInternal?: unknown }).HermesInternal !== \"undefined\";\n const call = <T,>(fn?: () => T) => {\n try {\n return fn?.();\n } catch {\n return undefined;\n }\n };\n const totalMemory = call(di?.getTotalMemorySync?.bind(di));\n return {\n os: { name: Platform.OS, version: Platform.OS === \"android\" ? (c.Release ?? String(Platform.Version)) : String(Platform.Version) },\n runtime: { name: \"react-native\", version: rn ? `${rn.major}.${rn.minor}.${rn.patch}` : undefined, engine: hermes ? \"hermes\" : \"jsc\" },\n device: {\n model: call(di?.getModel.bind(di)) ?? c.Model,\n brand: call(di?.getBrand.bind(di)) ?? c.Brand,\n manufacturer: call(di?.getManufacturerSync?.bind(di)) ?? c.Manufacturer,\n isEmulator: call(di?.isEmulatorSync?.bind(di)) ?? (c.Fingerprint ? /generic|emulator/i.test(c.Fingerprint) : undefined),\n memoryMb: totalMemory ? Math.round(totalMemory / 1024 / 1024) : undefined,\n type: di ? (call(di.isTablet.bind(di)) ? \"tablet\" : \"phone\") : Platform.OS === \"ios\" && (Platform as { isPad?: boolean }).isPad ? \"tablet\" : \"phone\",\n },\n app: { version: call(di?.getVersion.bind(di)), build: call(di?.getBuildNumber.bind(di)) } as ContextPatch[\"app\"],\n locale: locale(),\n timezone: timezone(),\n };\n}\n\nexport interface ReactNativeInitOptions extends InitOptions {\n deviceInfo?: DeviceInfoModule;\n /**\n * Report unhandled promise rejections (Hermes). Default \"production\": in development React\n * Native's own yellow-box warning keeps working. `true` captures in development too.\n */\n captureUnhandledRejections?: boolean | \"production\";\n}\n\ndeclare const __DEV__: boolean | undefined;\n\n/** Initialise deBug in a React Native app (bare or Expo). Fills in device context and flushes when the app is backgrounded. */\nexport function initReactNative(options: ReactNativeInitOptions, client: DebugClient = deBug): DebugClient {\n const { deviceInfo, captureUnhandledRejections = \"production\", ...rest } = options;\n const base = nativeContext({ deviceInfo });\n client.init({\n ...rest,\n app: { ...(base.app as object), ...rest.app },\n context: mergeContext(base, rest.context ?? {}),\n });\n\n AppState.addEventListener(\"change\", (state) => {\n if (state !== \"active\") void client.flush();\n });\n\n const dev = typeof __DEV__ !== \"undefined\" && __DEV__;\n const tracker = (globalThis as { HermesInternal?: { enablePromiseRejectionTracker?: (o: object) => void } }).HermesInternal\n ?.enablePromiseRejectionTracker;\n if (tracker && (captureUnhandledRejections === true || (captureUnhandledRejections === \"production\" && !dev))) {\n tracker({\n allRejections: true,\n onUnhandled: (_id: number, reason: unknown) => client.error(reason, { handled: false, tags: { source: \"unhandled-rejection\" } }),\n onHandled: () => {},\n });\n }\n return client;\n}\n\n/** Minimal shape of a React Navigation container ref. */\ninterface NavigationRefLike {\n getCurrentRoute(): { name: string } | undefined;\n}\n\n/**\n * Breadcrumbs for React Navigation. Spread the result onto your container:\n * const nav = useNavigationContainerRef();\n * <NavigationContainer ref={nav} {...trackReactNavigation(nav)}>\n */\nexport function trackReactNavigation(ref: NavigationRefLike, client: DebugClient = deBug) {\n let last: string | undefined;\n const record = () => {\n const name = ref.getCurrentRoute()?.name;\n if (name && name !== last) client.breadcrumb(\"navigation\", last ? `${last} → ${name}` : name);\n last = name ?? last;\n };\n return { onReady: record, onStateChange: record };\n}\n"]}