@hakam-aldeen-kh/blix 0.3.2

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.
@@ -0,0 +1,548 @@
1
+ import { AxiosInstance } from 'axios';
2
+
3
+ /**
4
+ * Blix — HTTP capture entry point.
5
+ *
6
+ * Registers axios interceptors that feed the monitor store with plaintext
7
+ * request/response data. Call once at module-init time, before your app's
8
+ * encryption or auth interceptors, so this interceptor runs last in axios's
9
+ * LIFO request stack and therefore sees the plaintext request body.
10
+ *
11
+ * No-op when `process.env.NODE_ENV !== "development"`.
12
+ */
13
+
14
+ /**
15
+ * Attaches HTTP-capture interceptors to an axios instance.
16
+ *
17
+ * Call this at module init time (e.g. at the bottom of your `axios.ts`),
18
+ * after registering any encryption interceptors so that the monitor sees the
19
+ * plaintext body first.
20
+ */
21
+ declare function attachHttpMonitor(instance: AxiosInstance, options?: {
22
+ dbName?: string;
23
+ }): void;
24
+
25
+ /**
26
+ * Blix — encrypted-payload capture (opt-in).
27
+ *
28
+ * Blix cannot capture ciphertext by itself. It has no knowledge of any app's
29
+ * encryption scheme, and — by design — its own interceptors sit on the
30
+ * *plaintext* side of the pipeline, so the encrypted form simply does not exist
31
+ * at the moment Blix captures. This is the hand-off: the host calls
32
+ * `captureEncrypted` from inside its own encrypt/decrypt interceptors, where
33
+ * the ciphertext does exist, and passes back the same axios config object Blix
34
+ * already stamped.
35
+ *
36
+ * Entirely optional. An app that never calls it behaves exactly as before, and
37
+ * the panel hides the Encrypted tab for every entry that has nothing in it.
38
+ *
39
+ * Like the rest of the capture layer, this must never throw, never warn, and
40
+ * never be reachable in a production build.
41
+ */
42
+ /**
43
+ * What the host hands over. Both sides are optional and independent: the
44
+ * request-side ciphertext is produced early (on the way out) and the
45
+ * response-side late (on the way back), so they normally arrive in two separate
46
+ * calls.
47
+ */
48
+ interface EncryptedPayload {
49
+ /** What actually went on the wire, in place of `requestPayload`. */
50
+ request?: unknown;
51
+ /** What actually came back, before the host decrypted it. */
52
+ response?: unknown;
53
+ }
54
+ /**
55
+ * Attaches the encrypted form of a request and/or response to the entry Blix
56
+ * already captured for `config`.
57
+ *
58
+ * ```ts
59
+ * apiClient.interceptors.request.use((config) => {
60
+ * const encrypted = encrypt(config.data);
61
+ * captureEncrypted(config, { request: encrypted });
62
+ * return { ...config, data: encrypted };
63
+ * });
64
+ * ```
65
+ *
66
+ * Correlation is by identity of the config object, never by URL or timing —
67
+ * two concurrent requests to the same endpoint stay correctly apart. Pass the
68
+ * object axios gave you; a `{ ...config }` copy made by your own interceptor
69
+ * also resolves (see `monitorStamp.ts`). Call it as many times as you like, in
70
+ * either order, before or after the response arrives; each call merges into the
71
+ * existing entry and refreshes the panel. It never creates an entry of its own.
72
+ *
73
+ * A silent no-op — no throw, no console output — in every failure mode:
74
+ * outside development, when `attachHttpMonitor` was never called, when the
75
+ * config carries no stamp (a retry that built a fresh config, say), and when
76
+ * the entry has already been evicted from the ring buffer.
77
+ */
78
+ declare function captureEncrypted(config: unknown, payload: EncryptedPayload): void;
79
+
80
+ /**
81
+ * Network monitor — Redux action capture.
82
+ *
83
+ * A structurally-typed middleware, following the same contract-restatement
84
+ * pattern `realtimeCapture.ts` uses for the realtime adapter: this module
85
+ * never imports `@reduxjs/toolkit`, so the capture layer — which the host's
86
+ * HTTP-client module also depends on — stays free of a dependency on the
87
+ * host's state-management choice. That is what lets `@reduxjs/toolkit` be an
88
+ * optional peer rather than a hard one.
89
+ *
90
+ * Cost per dispatch, dev-only: a handful of reference compares, plus (only
91
+ * when the action actually changed something) a bounded structural diff — see
92
+ * `stateDiff.ts`. RTK's own `immutableCheck`/`serializableCheck` dev
93
+ * middleware already deep-walk the *entire* state on every dispatch; this tap
94
+ * does strictly less work than that, and is entirely absent in production —
95
+ * see the pass-through returned below when `MONITOR_ENABLED` is false.
96
+ */
97
+ /** The subset of a Redux store/middleware API this tap needs, restated
98
+ * structurally so this file never imports `redux` or `@reduxjs/toolkit`. */
99
+ interface MiddlewareApiLike<S> {
100
+ getState(): S;
101
+ }
102
+ type NextLike = (action: unknown) => unknown;
103
+ type MiddlewareLike<S> = (api: MiddlewareApiLike<S>) => (next: NextLike) => (action: unknown) => unknown;
104
+ interface ReduxCaptureOptions {
105
+ /** Action types (exact) or `"prefix/*"` globs never captured. Merged with
106
+ * the built-in defaults (redux-toolkit's own init/replace actions). */
107
+ ignore?: readonly string[];
108
+ /** Consecutive dispatches of the same action type within this window fold
109
+ * into the existing row (`redux.batchCount`) instead of flooding the log. */
110
+ coalesceMs?: number;
111
+ /** Above this dispatch rate, capture drops to type + timing only — no
112
+ * diff — until the rate falls back under it. */
113
+ maxActionsPerSecond?: number;
114
+ }
115
+ /**
116
+ * Builds the Redux-capture middleware. Returns a pure pass-through when the
117
+ * monitor is disabled (production, or SSR), so the `.concat()` call at the
118
+ * host's store setup costs nothing at runtime outside development.
119
+ */
120
+ declare function createReduxMonitorMiddleware<S>(options?: ReduxCaptureOptions): MiddlewareLike<S>;
121
+
122
+ /**
123
+ * Network monitor — TanStack Query cache capture.
124
+ *
125
+ * Structurally typed against the cache-event shape, exactly like
126
+ * `realtimeCapture.ts` restates the realtime adapter contract: this module
127
+ * never imports `@tanstack/react-query`, so the capture layer — which the
128
+ * host's HTTP-client module also depends on — stays free of a dependency on
129
+ * the host's data-fetching library. That is what lets `@tanstack/react-query`
130
+ * be an optional peer rather than a hard one.
131
+ *
132
+ * One entry per `queryHash` (or `mutationId`), accumulating lifecycle frames —
133
+ * the same "one long-lived row" model `realtimeCapture.ts` uses for a socket
134
+ * connection. Under an aggressive `gcTime` a query is added to and removed
135
+ * from the cache repeatedly; hashing by key means the *same row* accumulates
136
+ * that whole session's history instead of flickering in and out of the log —
137
+ * and turns that churn into the panel's most useful signal: a row can show
138
+ * "fetched 7 times this session, 5 of them cache misses".
139
+ *
140
+ * The Query section is backed entirely by this module's own capture, never by
141
+ * a live read of `queryCache.getAll()` — under `gcTime: 0` that read is empty
142
+ * almost all the time, which is the whole reason this capture exists.
143
+ */
144
+ /** Structural subset of a TanStack Query `Query` this tap needs. */
145
+ interface QueryStateLike {
146
+ status: string;
147
+ fetchStatus?: string;
148
+ data?: unknown;
149
+ error?: unknown;
150
+ dataUpdatedAt?: number;
151
+ errorUpdatedAt?: number;
152
+ fetchFailureCount?: number;
153
+ isInvalidated?: boolean;
154
+ }
155
+ interface QueryLike {
156
+ queryHash: string;
157
+ queryKey: readonly unknown[];
158
+ state: QueryStateLike;
159
+ getObserversCount?(): number;
160
+ }
161
+ interface MutationStateLike {
162
+ status: string;
163
+ variables?: unknown;
164
+ data?: unknown;
165
+ error?: unknown;
166
+ }
167
+ interface MutationLike {
168
+ mutationId: number;
169
+ state: MutationStateLike;
170
+ }
171
+ interface CacheEventLike {
172
+ type: string;
173
+ query?: QueryLike;
174
+ mutation?: MutationLike;
175
+ action?: {
176
+ type: string;
177
+ };
178
+ }
179
+ interface CacheLike {
180
+ subscribe(listener: (event: CacheEventLike) => void): () => void;
181
+ getAll(): unknown[];
182
+ }
183
+ /** A TanStack `QueryFilters`-shaped filter — structurally typed, same as
184
+ * everything else in this module, so this file still never imports
185
+ * `@tanstack/react-query`. */
186
+ interface QueryFilterLike {
187
+ queryKey?: readonly unknown[];
188
+ exact?: boolean;
189
+ }
190
+ interface QueryClientLike {
191
+ getQueryCache(): CacheLike;
192
+ getMutationCache(): CacheLike;
193
+ invalidateQueries(filters?: QueryFilterLike): Promise<void>;
194
+ refetchQueries(filters?: QueryFilterLike): Promise<void>;
195
+ removeQueries(filters?: QueryFilterLike): void;
196
+ resetQueries(filters?: QueryFilterLike): Promise<void>;
197
+ }
198
+ /**
199
+ * Installs the tap on a `QueryClient`. Idempotent, and safe to call from a
200
+ * React effect in your query provider rather than the `useState` initializer
201
+ * that creates the client — React Strict Mode double-invokes initializers, and
202
+ * tapping there would tap a client that gets discarded.
203
+ *
204
+ * Because parent effects run *after* child effects, a child's `useQuery` has
205
+ * already fired by the time this installs — so it backfills from
206
+ * `getQueryCache().getAll()` first, rather than starting blind.
207
+ */
208
+ declare function tapQueryClient(client: QueryClientLike): () => void;
209
+
210
+ /**
211
+ * Network monitor — shared types.
212
+ *
213
+ * `MonitorEntry` is both the in-memory shape and (minus a few live-only fields)
214
+ * the persisted shape. Anything added here that should survive a reload must
215
+ * also be JSON-serializable.
216
+ */
217
+ type MonitorState = "pending" | "success" | "error" | "aborted";
218
+ /**
219
+ * HTTP requests, realtime connections, Redux actions and TanStack Query
220
+ * activity all share one table.
221
+ *
222
+ * A WebSocket connection is modelled as a single long-lived entry that
223
+ * accumulates frames — the same shape Chrome uses, where the connection is a
224
+ * row and its traffic lives in a Messages tab. Modelling each frame as its own
225
+ * row would drown the HTTP requests. A Query cache entry reuses that exact
226
+ * model: one row per `queryHash`/`mutationId`, accumulating lifecycle frames
227
+ * (fetch → success/error → invalidate → removed) — because under an aggressive
228
+ * `gcTime` the same key is added to and removed from the cache repeatedly, and
229
+ * hashing by key lets one row carry that whole session's history instead of
230
+ * flickering in and out of the log.
231
+ *
232
+ * A Redux action, by contrast, gets its own row per dispatch: the detail pane,
233
+ * selection, pinning and search are all entry-keyed, and a per-action diff
234
+ * needs a first-class row rather than a frame buried inside one.
235
+ */
236
+ type MonitorKind = "http" | "ws" | "redux" | "query";
237
+ type FrameDirection = "in" | "out" | "system";
238
+ interface WsFrame {
239
+ id: string;
240
+ at: number;
241
+ direction: FrameDirection;
242
+ /** Event/channel name where the transport provides one. */
243
+ event: string;
244
+ data: unknown;
245
+ /** Approximate size, estimated once at capture. */
246
+ sizeBytes: number;
247
+ }
248
+ /**
249
+ * Where a request's wall-clock time actually went.
250
+ *
251
+ * Worth breaking out when the host transforms bodies in its interceptors —
252
+ * encryption, compression, heavy serialization — because "slow request" then
253
+ * means a slow backend *or* a slow client-side pipeline, and the two need
254
+ * telling apart.
255
+ */
256
+ interface TimingMarks {
257
+ encryptMs?: number;
258
+ networkMs?: number;
259
+ decryptMs?: number;
260
+ }
261
+ /** One frame of a captured call stack, already trimmed and made repo-relative. */
262
+ interface InitiatorFrame {
263
+ /** Function or component name, when V8 gave us one. */
264
+ fn?: string;
265
+ /** Repo-relative path, e.g. `src/hooks/useCheckoutForm.ts`. */
266
+ file: string;
267
+ line?: number;
268
+ col?: number;
269
+ }
270
+ type DiffOp = "add" | "change" | "remove";
271
+ /** One changed path from a bounded structural diff — see `stateDiff.ts`. */
272
+ interface StateDiffEntry {
273
+ /** Dotted/bracketed path, e.g. `conversations.allConversations[3].unreadCount`. */
274
+ path: string;
275
+ op: DiffOp;
276
+ /** Bounded, truncated *copies* — never a reference into live state. */
277
+ before?: unknown;
278
+ after?: unknown;
279
+ }
280
+ interface StateDiff {
281
+ changes: StateDiffEntry[];
282
+ /** Hit a depth/node/change ceiling — the diff is a partial picture. */
283
+ truncated: boolean;
284
+ /** Top-level slices touched by this action. */
285
+ slices: string[];
286
+ }
287
+ /** Redux only: the dispatched action and what it changed. */
288
+ interface ReduxActionMeta {
289
+ /** `action.type`, mirrored into `entry.url` so free-text search works free. */
290
+ type: string;
291
+ /** Bounded copy of `action.payload` + `action.meta`. */
292
+ payload?: unknown;
293
+ /** RTK rejected-thunk marker (`action.error === true`). */
294
+ isError?: boolean;
295
+ diff?: StateDiff;
296
+ /** Wall time spent inside `next(action)`. */
297
+ reducerMs: number;
298
+ /** >1 when identical consecutive actions were coalesced into this row. */
299
+ batchCount?: number;
300
+ /** False when the captured payload was truncated — re-dispatching it would
301
+ * not faithfully reproduce the original action, so the panel's Re-dispatch
302
+ * action is disabled. */
303
+ replayable?: boolean;
304
+ }
305
+ /** Query/mutation only: the cache row's current lifecycle state. Deliberately
306
+ * not folded into `MonitorState` — `MonitorState` drives the shared state
307
+ * filter and waterfall colour, and pending/success/error covers this fine;
308
+ * the richer status (fresh/stale/fetching/removed) lives here instead. */
309
+ interface QueryMeta {
310
+ sub: "query" | "mutation";
311
+ /** `query.queryHash` / `String(mutation.mutationId)` — the entry's stable
312
+ * identity, and the correlation handle from an HTTP entry's `ownerId`. */
313
+ hash: string;
314
+ key: unknown[];
315
+ status: "pending" | "success" | "error";
316
+ fetchStatus?: "fetching" | "paused" | "idle";
317
+ observers: number;
318
+ isInvalidated?: boolean;
319
+ dataUpdatedAt?: number;
320
+ errorUpdatedAt?: number;
321
+ failureCount?: number;
322
+ /** The query left the cache — routine under an aggressive `gcTime`, and
323
+ * exactly the fact this panel exists to make visible. */
324
+ gcRemoved?: boolean;
325
+ /** How many times this key has been fetched this session. */
326
+ fetchCount?: number;
327
+ /** Ids of the HTTP entries this query/mutation caused — best-effort, see
328
+ * `monitorContext.ts`. */
329
+ causedIds?: string[];
330
+ }
331
+ interface MonitorEntry {
332
+ id: string;
333
+ /** HTTP request or realtime connection. Defaults to `"http"` when absent, so
334
+ * entries persisted before realtime capture existed still load. */
335
+ kind?: MonitorKind;
336
+ /** Monotonic capture order. `id` embeds `Date.now()` and is unique but not
337
+ * order-comparable; `seq` is what sorting and oldest-first eviction use. */
338
+ seq: number;
339
+ /** Bumped on every `update()`. Lets the deep-search index cache tell whether
340
+ * an entry actually changed without stringifying it. */
341
+ rev: number;
342
+ method: string;
343
+ url: string;
344
+ baseURL?: string;
345
+ /** Wall-clock epoch ms when the request started (for display). */
346
+ at: number;
347
+ /** `performance.now()` at start, used to compute duration. */
348
+ startTime: number;
349
+ endTime?: number;
350
+ durationMs?: number;
351
+ /** `performance.timeOrigin` of the page load that captured this entry. */
352
+ timeOrigin: number;
353
+ /**
354
+ * Start/end as absolute epoch ms (`timeOrigin + startTime`).
355
+ *
356
+ * The waterfall must use these, never `startTime`/`endTime`: those are
357
+ * relative to a per-page-load origin, so a persisted entry's `startTime` is
358
+ * meaningless against the current load's.
359
+ */
360
+ startAbs: number;
361
+ endAbs?: number;
362
+ /** Which page load captured this. Drives the divider rows and the per-load
363
+ * waterfall timeline. */
364
+ loadId: string;
365
+ status?: number;
366
+ state: MonitorState;
367
+ /** Plaintext request body, before encryption. */
368
+ requestPayload?: unknown;
369
+ /** What is actually sent over the wire (encData / aesKey). */
370
+ encryptedRequest?: unknown;
371
+ /** Decrypted response body. */
372
+ responsePayload?: unknown;
373
+ /** Raw encrypted response body from the server. */
374
+ encryptedResponse?: unknown;
375
+ /** Decrypted/raw error payload, when the request failed. */
376
+ error?: unknown;
377
+ /** Outgoing request headers (sanitized to a flat string map). */
378
+ requestHeaders?: Record<string, string>;
379
+ /** Response headers returned by the server. */
380
+ responseHeaders?: Record<string, string>;
381
+ /** Approximate payload size in bytes, estimated once at capture. Computing
382
+ * this lazily in the detail pane meant a full `JSON.stringify` per render. */
383
+ sizeBytes?: number;
384
+ /** Whether the request opted out of the encryption pipeline. Needed to replay
385
+ * a request faithfully — it's a config flag, not a header, so it isn't
386
+ * recoverable from `requestHeaders`. */
387
+ skipEncryption?: boolean;
388
+ /** Whether the body was `FormData`. Such requests can't be replayed: file
389
+ * contents are summarized, not captured. */
390
+ hadFormData?: boolean;
391
+ /** Set when this entry is a replay of another; holds the parent's id. */
392
+ replayOf?: string;
393
+ /** How many replays this entry has spawned. */
394
+ replayCount?: number;
395
+ /** Trimmed call stack captured at the call site. */
396
+ initiator?: InitiatorFrame[];
397
+ /** Where the time went — encryption vs. network vs. decryption. */
398
+ marks?: TimingMarks;
399
+ /**
400
+ * Pinned entries survive Clear and buffer eviction, so a reference response
401
+ * can be held on screen while reproducing an issue.
402
+ */
403
+ pinned?: boolean;
404
+ /** Realtime/Query only: frames/lifecycle events on this connection or key. */
405
+ frames?: WsFrame[];
406
+ /** Realtime only: transport name, shown in the Method column. */
407
+ transport?: string;
408
+ /** Redux only: the dispatched action and its bounded diff. */
409
+ redux?: ReduxActionMeta;
410
+ /** Query only: the cache row's key, status and observer count. */
411
+ query?: QueryMeta;
412
+ /** HTTP only: id of the query/mutation entry that caused this request,
413
+ * when it could be determined — see `monitorContext.ts`. Absence means
414
+ * "unknown", never "not caused by a query". */
415
+ ownerId?: string;
416
+ /** HTTP only: whether the raw call stack (before NOISE-filtering) passed
417
+ * through `@tanstack/query`, independent of whether `ownerId` resolved. */
418
+ initiatorKind?: "query" | "mutation" | "direct";
419
+ }
420
+ /** Shape written to IndexedDB. Payloads may be truncated relative to the live
421
+ * entry; `bytes` is what the storage budget accounts against. */
422
+ interface PersistedEntry extends MonitorEntry {
423
+ schema: number;
424
+ bytes: number;
425
+ }
426
+ type DockMode = "bottom" | "right" | "float";
427
+ type Corner = "bottom-left" | "bottom-right" | "top-left" | "top-right";
428
+ interface Size {
429
+ w: number;
430
+ h: number;
431
+ }
432
+ interface Pos {
433
+ x: number;
434
+ y: number;
435
+ }
436
+ /**
437
+ * Everything the panel remembers between sessions.
438
+ *
439
+ * Stored in IndexedDB (`meta.prefs`) as the source of truth, mirrored into
440
+ * `localStorage["nm:prefs"]` purely as a synchronous read cache so the panel
441
+ * can restore its geometry without a frame of flash. The mirror is expendable —
442
+ * any host that clears web storage wipes it, and the IndexedDB copy silently
443
+ * restores it on next boot.
444
+ */
445
+ interface MonitorPrefs {
446
+ /** Bumped on every write; used to reconcile the two copies. */
447
+ rev: number;
448
+ mode: DockMode;
449
+ /** Dock sizes, per axis. Sharing one value across docks yields absurd
450
+ * geometry when switching. */
451
+ bottomH: number;
452
+ rightW: number;
453
+ float: {
454
+ pos: Pos | null;
455
+ size: Size;
456
+ maximized: boolean;
457
+ };
458
+ /** List/detail splitter, one per split axis. */
459
+ splitW: number;
460
+ splitH: number;
461
+ corner: Corner;
462
+ preserveLog: boolean;
463
+ deepSearch: boolean;
464
+ followLatest: boolean;
465
+ /** Opt out of call-stack capture when profiling a large burst of requests. */
466
+ captureInitiator: boolean;
467
+ /** Last pinned request; restored only if the id still resolves. */
468
+ selectedId: string | null;
469
+ /** Active top-level section — `"network"` (HTTP) or `"realtime"` (sockets). */
470
+ section: string;
471
+ /** Row height preset: compact | normal | comfy. */
472
+ density: string;
473
+ /** User-resized column widths, in px, keyed by column id. */
474
+ columnWidths: Record<string, number>;
475
+ }
476
+
477
+ /**
478
+ * Network monitor — realtime (WebSocket / ActionCable) capture.
479
+ *
480
+ * Realtime traffic routed through an adapter is typically invisible: the
481
+ * browser's own Network tab shows the socket but not the decoded envelope, and
482
+ * an app's own logging goes to the console where it is drowned by everything
483
+ * else.
484
+ *
485
+ * ## Shape of the capture
486
+ *
487
+ * A connection is one long-lived `MonitorEntry` (`kind: "ws"`) that accumulates
488
+ * frames, rather than one entry per frame. That is how Chrome models it — the
489
+ * connection is a row, its traffic lives in a Messages tab — and it stops a
490
+ * chatty channel from burying every HTTP request in the table.
491
+ *
492
+ * ## Why a structural adapter type
493
+ *
494
+ * The host's adapter interface lives in the host, and this package must not
495
+ * import from it. The adapter shape is therefore restated structurally here,
496
+ * so the tap stays a one-line change at the call site with no dependency
497
+ * pointing the wrong way — any object with the right methods satisfies it.
498
+ */
499
+
500
+ /** The subset of the realtime adapter contract this tap needs. */
501
+ interface RealtimeAdapterLike {
502
+ connect(token: string, url: string): void;
503
+ disconnect(): void;
504
+ subscribe(channelName: string): void;
505
+ onMessage(callback: (payload: {
506
+ event: string;
507
+ data: unknown;
508
+ }) => void): void;
509
+ onPresenceUpdate(callback: (status: string) => void): void;
510
+ }
511
+ /**
512
+ * Wraps a realtime adapter so its lifecycle and traffic appear in the monitor.
513
+ *
514
+ * Returns the adapter untouched in production, where `MONITOR_ENABLED` is a
515
+ * constant `false` and the whole wrapper folds away.
516
+ */
517
+ declare function tapRealtimeAdapter<T extends RealtimeAdapterLike>(adapter: T, transport: string): T;
518
+
519
+ /**
520
+ * Network monitor — "who fired this request?"
521
+ *
522
+ * ## Why the stack is taken at the call site, not in the interceptor
523
+ *
524
+ * By the time the axios request interceptor runs, we are already inside axios's
525
+ * promise chain: the interceptor callback executes in a microtask, so
526
+ * `new Error().stack` taken there is `at Object.onFulfilled (axios)` plus a
527
+ * microtask boundary. V8's async stack traces sometimes recover the real
528
+ * caller, but not reliably, and never through React Query's internals.
529
+ *
530
+ * So `withInitiatorCapture` wraps the axios instance, takes the stack
531
+ * synchronously in the caller's own frame, and stashes it on the config for
532
+ * `beginMonitor` to read.
533
+ *
534
+ * The whole module is behind a statically-foldable `NODE_ENV` check at its call
535
+ * site, so it is dead-code-eliminated from production builds.
536
+ */
537
+
538
+ /**
539
+ * Wraps the axios instance so every call site records its own stack.
540
+ *
541
+ * Wraps the callable form (`apiClient(config)`), plus `request`, `get`, `post`,
542
+ * `put`, `patch`, `delete` and `head`. Other entry points (`options`, the
543
+ * `*Form` helpers) pass through unwrapped — requests made through them are
544
+ * still captured, they just carry no initiator stack.
545
+ */
546
+ declare function withInitiatorCapture(instance: AxiosInstance): AxiosInstance;
547
+
548
+ export { type CacheLike, type Corner, type DiffOp, type DockMode, type EncryptedPayload, type FrameDirection, type InitiatorFrame, type MiddlewareApiLike, type MiddlewareLike, type MonitorEntry, type MonitorKind, type MonitorPrefs, type MonitorState, type PersistedEntry, type Pos, type QueryClientLike, type QueryMeta, type RealtimeAdapterLike, type ReduxActionMeta, type ReduxCaptureOptions, type Size, type StateDiff, type StateDiffEntry, type TimingMarks, type WsFrame, attachHttpMonitor, captureEncrypted, createReduxMonitorMiddleware, tapQueryClient, tapRealtimeAdapter, withInitiatorCapture };
@@ -0,0 +1,18 @@
1
+ import {
2
+ attachHttpMonitor,
3
+ captureEncrypted,
4
+ tapRealtimeAdapter
5
+ } from "../chunk-OQHKPRNI.js";
6
+ import {
7
+ createReduxMonitorMiddleware,
8
+ tapQueryClient,
9
+ withInitiatorCapture
10
+ } from "../chunk-MRTSIXR7.js";
11
+ export {
12
+ attachHttpMonitor,
13
+ captureEncrypted,
14
+ createReduxMonitorMiddleware,
15
+ tapQueryClient,
16
+ tapRealtimeAdapter,
17
+ withInitiatorCapture
18
+ };