@hakam-aldeen-kh/blix 0.4.0 → 0.4.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.
Files changed (2) hide show
  1. package/README.md +174 -13
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -8,7 +8,7 @@ a dockable panel with a waterfall, diffing, replay and HAR/cURL export.
8
8
  The entire panel is eliminated from production builds — see
9
9
  [Production elimination](#production-elimination).
10
10
 
11
- Release notes are in [CHANGELOG.md](CHANGELOG.md).
11
+ Release notes are in [CHANGELOG.md](https://github.com/Hakam-aldeen-Kh/blix/blob/main/CHANGELOG.md).
12
12
 
13
13
  ---
14
14
 
@@ -32,6 +32,13 @@ while resolving that import. devDependencies have to be present at build time.
32
32
  Dropping them from the final runtime image is fine: nothing from Blix reaches
33
33
  the production output anyway.
34
34
 
35
+ The package ships **ESM only**. Both entry points declare `"types"` and
36
+ `"import"` in `exports`, with no `"require"` and no `"default"` fallback, so
37
+ `require("@hakam-aldeen-kh/blix")` and CJS-only tooling — an older Jest config
38
+ is the usual one — fail with `ERR_PACKAGE_PATH_NOT_EXPORTED`. That is by
39
+ design, not a packaging bug: a dev tool that is eliminated from production has
40
+ no reason to carry a second build output.
41
+
35
42
  ### Peer dependencies
36
43
 
37
44
  `react` and `react-dom` (v19) are required. `axios`, `@reduxjs/toolkit` and
@@ -351,12 +358,14 @@ as a bounded hex preview plus byte length). They go through the same
351
358
  serialization and truncation rules as the plaintext bodies, both in the panel
352
359
  and in IndexedDB, so a multi-megabyte ciphertext cannot blow out the log.
353
360
 
354
- > **Redaction.** Blix masks sensitive *headers* (`authorization`, `cookie`, …).
355
- > It does **not**, and cannot, redact anything inside the values you pass here
356
- > they are bodies, and Blix has no way to tell ciphertext from plaintext. If
357
- > you pass an already-decrypted body as `response`, whatever secrets it
358
- > contains are shown in the panel verbatim and written to IndexedDB when
359
- > preserve-log is on. Pass the wire form, not the decrypted one.
361
+ > **Redaction.** Blix masks sensitive *headers* and the list is closed at
362
+ > exactly four, matched exactly: `authorization`, `cookie`, `set-cookie`,
363
+ > `x-api-key`. It does **not**, and cannot, redact anything inside the values
364
+ > you pass here they are bodies, and Blix has no way to tell ciphertext from
365
+ > plaintext. If you pass an already-decrypted body as `response`, whatever
366
+ > secrets it contains are shown in the panel verbatim and written to IndexedDB
367
+ > when preserve-log is on. Pass the wire form, not the decrypted one. See
368
+ > [Security](#security) for the full picture.
360
369
 
361
370
  #### `withInitiatorCapture(instance)`
362
371
 
@@ -684,11 +693,15 @@ There is no API for adding your own; a theme is ~20 colours in
684
693
 
685
694
  ### `dbName` — when you need it
686
695
 
687
- The panel persists its log to IndexedDB so it survives a reload. IndexedDB is
688
- scoped **per origin**, not per app so two apps served from the same origin
689
- (different ports in dev are different origins, but path-based routing,
690
- multi-zone Next.js setups and anything behind one reverse proxy are not) both
691
- open `nm-devtools` and interleave their logs into one database.
696
+ The panel can persist its log to IndexedDB so it survives a reload, but only
697
+ when you opt in: **preserve-log is off by default**, and while it is off
698
+ nothing is written to disk. See [Security](#security) for what the toggle does
699
+ and what lands there.
700
+
701
+ IndexedDB is scoped **per origin**, not per app — so two apps served from the
702
+ same origin (different ports in dev are different origins, but path-based
703
+ routing, multi-zone Next.js setups and anything behind one reverse proxy are
704
+ not) both open `nm-devtools` and interleave their logs into one database.
692
705
 
693
706
  Give each app its own name to keep them separate:
694
707
 
@@ -788,6 +801,154 @@ example above, which is written in the guarded form.
788
801
 
789
802
  ---
790
803
 
804
+ ## Security
805
+
806
+ Blix is a debugger, and it captures what a debugger has to capture: **full
807
+ request and response bodies, request and response headers, Redux action
808
+ payloads and state diffs, and realtime frames**. It captures them in
809
+ plaintext — the request body *before* your encryption interceptor runs, the
810
+ response body *after* your decryption interceptor. That is the whole point of
811
+ it, and it means the log holds whatever your traffic holds, credentials
812
+ included.
813
+
814
+ By default all of that is **in memory only**. Nothing is written to disk, and
815
+ a reload starts clean.
816
+
817
+ All of it is dev-only regardless. Capture is gated on
818
+ `process.env.NODE_ENV === "development" && typeof window !== "undefined"`, and
819
+ the database is opened only when the panel mounts — see
820
+ [Production elimination](#production-elimination).
821
+
822
+ ### What reaches disk, and when
823
+
824
+ **Preserve-log** is the sole gate on disk writes. It is off by default, and
825
+ while it is off nothing Blix captures reaches IndexedDB — the store is
826
+ actively cleared on every panel mount.
827
+
828
+ Three ways to toggle it:
829
+
830
+ | Where | Note |
831
+ | --- | --- |
832
+ | Toolbar button | Hidden in the compact layout |
833
+ | **⋯ More actions** overflow menu | — |
834
+ | `Shift+L` | — |
835
+
836
+ All three require the panel to be mounted.
837
+
838
+ **Turning it on is retroactive.** The toggle does not mean "from now on".
839
+ Switching it on writes every entry already sitting in the live buffer — the
840
+ session you have *already* captured — to disk immediately, along with
841
+ everything that follows. If you have just reproduced a login flow and then
842
+ reach for the toggle, you have written that login flow to disk. Read that
843
+ again before you assume otherwise; it is the one behaviour here that
844
+ reasonably surprises people.
845
+
846
+ With preserve-log on, this is what is kept:
847
+
848
+ | Captured | Persisted |
849
+ | --- | --- |
850
+ | HTTP entries — bodies, headers, timings | yes |
851
+ | Realtime frames | yes |
852
+ | The encrypted envelope, if you call `captureEncrypted` | yes |
853
+ | Panel preferences and budget totals | yes — preferences are also mirrored to `localStorage` |
854
+ | Redux actions, payloads and diffs | only if you pin the row |
855
+ | Query cache rows | only if you pin the row |
856
+
857
+ ### What is redacted
858
+
859
+ Exactly four header names, and nothing else:
860
+
861
+ | Header | Match |
862
+ | --- | --- |
863
+ | `authorization` | exact, case-insensitive |
864
+ | `cookie` | exact, case-insensitive |
865
+ | `set-cookie` | exact, case-insensitive |
866
+ | `x-api-key` | exact, case-insensitive |
867
+
868
+ The match is **exact on the full header name** — not a prefix, not a
869
+ substring, not a pattern. Near-miss names are *not* covered and are written in
870
+ the clear: `x-auth-token` and `api-key` are the two that most often catch
871
+ people out, and `proxy-authorization`, `x-csrf-token` and
872
+ `x-amz-security-token` are equally uncovered. If your auth travels in a header
873
+ that is not one of the four above, it is captured verbatim.
874
+
875
+ Masking is partial rather than total: for a value longer than 12 characters
876
+ the first 8 and last 4 survive, so you can still tell which token you sent.
877
+ Shorter values are replaced outright.
878
+
879
+ **Nothing inside a body is redacted.** Request bodies, response bodies, error
880
+ payloads, the encrypted request/response values, Redux payloads and diffs, and
881
+ realtime frames all pass through a size-only walker — it truncates large
882
+ values and never once inspects a key name. A `password`, `ssn` or
883
+ `refreshToken` field is captured, and with preserve-log on written to disk,
884
+ exactly as it appears. Blix has no mechanism to do otherwise: it has no schema
885
+ for your payloads and no way to tell a secret from any other string.
886
+
887
+ ### Retention and clearing
888
+
889
+ | Bound | Value |
890
+ | --- | --- |
891
+ | Records | 200 |
892
+ | Total size | 24 MB — HTTP entries only |
893
+ | Per payload field | 512 KB |
894
+ | Eviction | oldest first, once either bound is exceeded |
895
+ | Time-based expiry | none |
896
+
897
+ There is **no TTL of any kind**. A record leaves the database when 200 newer
898
+ records or 24 MB of newer traffic push it out, or when you clear it yourself.
899
+ On a low-traffic app with preserve-log left on, a captured token stays in the
900
+ browser profile indefinitely.
901
+
902
+ To purge, use the persisted-size label in the status bar — the one reading
903
+ `12 saved · 3.4 MB`. It is the control: click once to arm it, at which point
904
+ it changes to `Purge saved log?`, and click again to delete the database.
905
+
906
+ Switching preserve-log **off** also clears the stored entries, so turning it
907
+ off is itself a way to drop everything Blix has written.
908
+
909
+ Both paths clear the captured entries; Purge additionally deletes the
910
+ IndexedDB database itself. **Your panel preferences survive either way** —
911
+ they are mirrored to `localStorage`, and a fresh database is re-seeded from
912
+ that mirror on the next boot. There is no UI or API for clearing them.
913
+
914
+ **The purge control is only rendered while preserve-log is on**, so once you
915
+ have switched it off there is nothing left in the UI to press. There is no
916
+ programmatic API for either path.
917
+
918
+ ### Threat model
919
+
920
+ IndexedDB is scoped **per origin, not per app**, and it is not encrypted at
921
+ rest. Any script running on that origin can read Blix's database — including
922
+ browser extension content scripts with access to the origin. Whatever you
923
+ capture is readable by whatever you have installed.
924
+
925
+ Export and copy move captured data out of the browser entirely:
926
+
927
+ | Path | Carries |
928
+ | --- | --- |
929
+ | HAR export | Decrypted request and response bodies |
930
+ | JSON / NDJSON export | Everything captured — frames, Redux diffs, timings |
931
+ | **Copy as cURL** / **Copy as fetch** | Headers and bodies, with the four redacted headers masked — so the output is not a working request |
932
+
933
+ HAR is the one to watch. It is a plain JSON file carrying your decrypted
934
+ bodies, and it is the artifact most likely to end up attached to a ticket.
935
+
936
+ ### If you handle sensitive data
937
+
938
+ - **Leave preserve-log off unless you actively need it.** It is off by
939
+ default. In-memory capture already gives you the entire panel; the toggle
940
+ buys you nothing but survival across a reload.
941
+ - **Clear the log after any session that captured an auth flow** —
942
+ switching preserve-log off is enough; Purge additionally deletes the
943
+ database, though neither removes your panel preferences.
944
+ - **Use the Redux `ignore` option** for action types that carry credentials or
945
+ personal data, so they are never captured in the first place. See
946
+ [Redux](#redux--createreduxmonitormiddlewareoptions).
947
+ - **Treat an exported HAR as a credential-bearing file.** Do not attach one to
948
+ a public issue, and do not commit one.
949
+
950
+ ---
951
+
791
952
  ## Entry points
792
953
 
793
954
  | Import | Contents | `"use client"` |
@@ -810,4 +971,4 @@ The `/capture` entry exports `attachHttpMonitor`, `captureEncrypted`,
810
971
 
811
972
  ## License
812
973
 
813
- MIT — see [LICENSE](./LICENSE).
974
+ MIT — see [LICENSE](https://github.com/Hakam-aldeen-Kh/blix/blob/main/LICENSE).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hakam-aldeen-kh/blix",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Dev-tools panel for React apps — HTTP, Redux, Query and Realtime monitoring.",
5
5
  "keywords": [
6
6
  "devtools",