@hakam-aldeen-kh/blix 0.6.0 → 0.6.1

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.
@@ -29,7 +29,7 @@ import {
29
29
  setReduxIgnoreList,
30
30
  summarizeInitiator,
31
31
  truncateForPersist
32
- } from "./chunk-FIYP47QZ.js";
32
+ } from "./chunk-AND5H3XH.js";
33
33
 
34
34
  // src/capture/monitorDatabases.ts
35
35
  var REGISTRY_KEY = `${DB_PREFIX}databases`;
@@ -698,10 +698,29 @@ interface InitiatorCaptureTarget {
698
698
  * Wraps the axios instance so every call site records its own stack.
699
699
  *
700
700
  * Wraps the callable form (`apiClient(config)`), plus `request`, `get`, `post`,
701
- * `put`, `patch`, `delete` and `head`. Other entry points (`options`, the
702
- * `*Form` helpers) pass through unwrapped — requests made through them are
701
+ * `put`, `patch`, `delete` and `head`. Other entry points (`options`, `query`,
702
+ * the `*Form` helpers) pass through unwrapped — requests made through them are
703
703
  * still captured, they just carry no initiator stack.
704
704
  *
705
+ * The stack is stashed on the config object in the callable form's and
706
+ * `request`'s *first* argument, so two calls through wrapped methods also
707
+ * carry no initiator stack:
708
+ *
709
+ * - **The string form** — `apiClient("/url")`, `apiClient("/url", config)`,
710
+ * `apiClient.request("/url", config)`. The string is passed to axios as
711
+ * given, never turned into a config, so axios runs the same overload it
712
+ * would unwrapped; the second argument is forwarded untouched.
713
+ * - **A frozen, sealed or otherwise non-extensible config.** It is left
714
+ * alone rather than written to.
715
+ *
716
+ * The stash is an enumerable `__monitorInitiator` property on the caller's own
717
+ * config object, so it appears in that object's `Object.keys` after the call.
718
+ * Development only, and axios does not send unknown config keys.
719
+ *
720
+ * Wrapping a client that is already wrapped returns it unchanged, with a
721
+ * development warning: the second wrapper would record Blix's own frames as
722
+ * the caller.
723
+ *
705
724
  * Generic over the instance, so what the caller gets back is its own type —
706
725
  * an `AxiosInstance` stays an `AxiosInstance`, with `get<T>`, `defaults` and
707
726
  * `interceptors` intact — rather than the minimal shape it was checked against.
@@ -3,12 +3,12 @@ import {
3
3
  attachHttpMonitor,
4
4
  captureEncrypted,
5
5
  tapRealtimeAdapter
6
- } from "../chunk-4JZEVUOR.js";
6
+ } from "../chunk-MKYWUTY4.js";
7
7
  import {
8
8
  createReduxMonitorMiddleware,
9
9
  tapQueryClient,
10
10
  withInitiatorCapture
11
- } from "../chunk-FIYP47QZ.js";
11
+ } from "../chunk-AND5H3XH.js";
12
12
  export {
13
13
  attachFetchMonitor,
14
14
  attachHttpMonitor,
@@ -556,27 +556,59 @@ function captureFrames(skip = 0) {
556
556
  Error.stackTraceLimit = previousLimit;
557
557
  }
558
558
  }
559
+ var WRAPPER_MARK = /* @__PURE__ */ Symbol.for("blix.initiatorCapture");
559
560
  function withInitiatorCapture(instance) {
560
561
  if (!MONITOR_ENABLED) return instance;
562
+ if (instance[WRAPPER_MARK] === true) {
563
+ if (process.env.NODE_ENV === "development") {
564
+ console.warn(
565
+ "[blix] withInitiatorCapture was given a client it has already wrapped, and returned it unchanged. Wrap the axios instance once and export the wrapped one \u2014 a second wrapper would record Blix's own frames as the caller of every request."
566
+ );
567
+ }
568
+ return instance;
569
+ }
561
570
  const attach = (config) => {
562
- if (!config) return config;
563
- if (!config.__monitorInitiator) config.__monitorInitiator = captureFrames(2);
571
+ if (typeof config === "object" && config !== null && Object.isExtensible(config) && config.__monitorId === void 0) {
572
+ config.__monitorInitiator = captureFrames(2);
573
+ }
564
574
  return config;
565
575
  };
566
576
  const proxy = new Proxy(instance, {
577
+ // The wrapper mark, reported as an enumerable own property of the proxy
578
+ // alone — see `WRAPPER_MARK`. A property the target lacks may only be
579
+ // reported while the target is extensible, so a non-extensible instance
580
+ // goes without it in `ownKeys`; `get` still answers, and that is what the
581
+ // double-wrap check reads.
582
+ has(target, prop) {
583
+ return prop === WRAPPER_MARK || Reflect.has(target, prop);
584
+ },
585
+ ownKeys(target) {
586
+ const keys = Reflect.ownKeys(target);
587
+ return Object.isExtensible(target) && !keys.includes(WRAPPER_MARK) ? [...keys, WRAPPER_MARK] : keys;
588
+ },
589
+ getOwnPropertyDescriptor(target, prop) {
590
+ const own = Reflect.getOwnPropertyDescriptor(target, prop);
591
+ if (prop === WRAPPER_MARK && !own && Object.isExtensible(target)) {
592
+ return { value: true, enumerable: true, writable: false, configurable: true };
593
+ }
594
+ return own;
595
+ },
596
+ // Every argument is forwarded: axios accepts `apiClient(url, config)`, and
597
+ // passing only the first would drop the config.
567
598
  apply(target, thisArg, args) {
568
- const [config] = args;
599
+ const [config, ...rest] = args;
569
600
  return Reflect.apply(
570
601
  target,
571
602
  thisArg,
572
- [attach(config)]
603
+ [attach(config), ...rest]
573
604
  );
574
605
  },
575
606
  get(target, prop, receiver) {
607
+ if (prop === WRAPPER_MARK) return true;
576
608
  const value = Reflect.get(target, prop, receiver);
577
609
  if (typeof value !== "function") return value;
578
610
  if (prop === "request") {
579
- return (config) => value.call(target, attach(config));
611
+ return (config, ...rest) => value.call(target, attach(config), ...rest);
580
612
  }
581
613
  if (prop === "post" || prop === "put" || prop === "patch") {
582
614
  return (url, data, config) => value.call(target, url, data, attach(config != null ? config : {}));
@@ -13,7 +13,7 @@ import {
13
13
  serializeBody,
14
14
  serializeHeaders,
15
15
  truncateForPersist
16
- } from "./chunk-FIYP47QZ.js";
16
+ } from "./chunk-AND5H3XH.js";
17
17
 
18
18
  // src/capture/monitorStamp.ts
19
19
  var MONITOR_ID = /* @__PURE__ */ Symbol.for("blix.monitorId");
@@ -329,7 +329,7 @@ function planRequestBody(outgoing) {
329
329
  return __spreadProps(__spreadValues({}, none), { payload: notCaptured("the request body was already read before fetch was called") });
330
330
  }
331
331
  try {
332
- return __spreadProps(__spreadValues({}, none), { clone: request.clone() });
332
+ return __spreadProps(__spreadValues({}, none), { bytes: void 0, clone: request.clone() });
333
333
  } catch (e) {
334
334
  return __spreadProps(__spreadValues({}, none), { payload: notCaptured("the request body is locked and could not be cloned") });
335
335
  }
@@ -340,19 +340,27 @@ function readRequestClone(id, clone, cap, headers) {
340
340
  const contentType = headerValue(headers, "content-type");
341
341
  const retain = isTextual(contentType);
342
342
  void readCapped(body, cap, retain).then((result) => {
343
+ var _a;
343
344
  let requestPayload;
345
+ let sizeBytes;
344
346
  if (result.kind === "complete") {
345
347
  requestPayload = result.bytes ? decodeBody(result.bytes, contentType) : binarySummary(contentType, result.length);
348
+ sizeBytes = result.length;
346
349
  } else if (result.kind === "over-cap") {
347
350
  requestPayload = notCaptured(
348
351
  `the request body passed the ${describeBytes(cap)} capture limit`
349
352
  );
353
+ sizeBytes = result.length;
350
354
  } else {
351
355
  requestPayload = notCaptured(
352
356
  `the request body could not be read (${describeError(result.error)})`
353
357
  );
354
358
  }
355
- settle(id, { requestPayload });
359
+ const unsized = ((_a = networkMonitor.getById(id)) == null ? void 0 : _a.sizeBytes) === void 0;
360
+ settle(
361
+ id,
362
+ sizeBytes !== void 0 && unsized ? { requestPayload, sizeBytes } : { requestPayload }
363
+ );
356
364
  });
357
365
  }
358
366
  function begin(outgoing, initiator, cap) {
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  attachHttpMonitor,
5
5
  captureEncrypted,
6
6
  tapRealtimeAdapter
7
- } from "./chunk-4JZEVUOR.js";
7
+ } from "./chunk-MKYWUTY4.js";
8
8
  import {
9
9
  BlixContext
10
10
  } from "./chunk-PQIOIMAQ.js";
@@ -13,7 +13,7 @@ import {
13
13
  createReduxMonitorMiddleware,
14
14
  tapQueryClient,
15
15
  withInitiatorCapture
16
- } from "./chunk-FIYP47QZ.js";
16
+ } from "./chunk-AND5H3XH.js";
17
17
 
18
18
  // src/ui/Blix.tsx
19
19
  import { lazy, Suspense, useEffect, useRef } from "react";
@@ -29,7 +29,7 @@ function Blix({ store, apiClient, dbName }) {
29
29
  }, []);
30
30
  if (typeof window !== "undefined" && process.env.NODE_ENV === "development") {
31
31
  if (!panelRef.current) {
32
- panelRef.current = lazy(() => import("./DevToolsPanel-QTVFBNU5.js"));
32
+ panelRef.current = lazy(() => import("./DevToolsPanel-RKJRDXHT.js"));
33
33
  }
34
34
  const Panel = panelRef.current;
35
35
  if (dbName) configureDbName(dbName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hakam-aldeen-kh/blix",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Dev-tools panel for React apps — HTTP, Redux, Query and Realtime monitoring.",
5
5
  "keywords": [
6
6
  "devtools",