@hakam-aldeen-kh/blix 0.3.3 → 0.4.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.
- package/CHANGELOG.md +129 -0
- package/README.md +177 -11
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.4.1] - 2026-08-24
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Documentation only — no code change.
|
|
13
|
+
- Added a Security section documenting what Blix captures, what reaches
|
|
14
|
+
IndexedDB and when, the four redacted header names, retention limits and
|
|
15
|
+
how to purge.
|
|
16
|
+
- Documented `preserve-log`: its default, the three toggles, and that
|
|
17
|
+
switching it on writes the session already in the buffer.
|
|
18
|
+
- Corrected the `dbName` section, which claimed the log persists across a
|
|
19
|
+
reload by default. It does not — persistence is opt-in.
|
|
20
|
+
- Noted that the package is ESM-only.
|
|
21
|
+
- Added `SECURITY.md`.
|
|
22
|
+
|
|
23
|
+
## [0.4.0] - 2026-08-24
|
|
24
|
+
|
|
25
|
+
Identical in code to 0.3.3. It exists only to correct the version number: 0.3.3
|
|
26
|
+
was a feature release with a type-level break and should never have been a patch
|
|
27
|
+
bump. 0.3.3 is deprecated on npm in favour of this release. Everything below is
|
|
28
|
+
new relative to 0.3.2, not to 0.3.3.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Twelve panel themes, behind a new toolbar button. Dark: Midnight (default),
|
|
33
|
+
Carbon, Nord, Tokyo Night, One Dark, Mocha, Dracula, Gruvbox. Light: Daylight,
|
|
34
|
+
GitHub, Latte, Solar. Hovering or arrow-keying an entry applies it to the panel
|
|
35
|
+
behind the menu; moving away restores the previous one. The default preference
|
|
36
|
+
is `auto`, which follows the host app's light/dark class on `<html>`. The
|
|
37
|
+
choice is persisted with the panel's other preferences.
|
|
38
|
+
- A format switch on every payload pane — Tree, Table, JSON, YAML, Text. It
|
|
39
|
+
applies to request and response bodies, realtime frames, the encrypted
|
|
40
|
+
envelope, Redux actions and both Redux state views. Copy returns whichever
|
|
41
|
+
format is on screen (Table copies CSV, YAML copies YAML). The choice is
|
|
42
|
+
persisted.
|
|
43
|
+
- Folding in the JSON view, with a **Collapse all** action; Alt-click in the Tree
|
|
44
|
+
expands or collapses an entire subtree.
|
|
45
|
+
- Keyboard navigation in the payload tree (arrow keys to move, expand, collapse
|
|
46
|
+
and step in/out; Enter to toggle) and in menus (arrows, Home/End, Enter, and
|
|
47
|
+
Esc to close and return focus to the button that opened it). The `?` cheatsheet
|
|
48
|
+
documents both, plus the theme picker and the formats.
|
|
49
|
+
- An export menu with six formats — HAR, JSON, NDJSON, Markdown table (to the
|
|
50
|
+
clipboard), CSV and a cURL script — and a **Shown** / **All** scope toggle that
|
|
51
|
+
shows both counts. Export previously always took the unfiltered buffer,
|
|
52
|
+
whatever the list was showing; Shown is now the default. CSV is written with a
|
|
53
|
+
UTF-8 BOM so Excel reads non-ASCII correctly.
|
|
54
|
+
- A store slice picker on the Redux **State** tab. It opens on the slice the
|
|
55
|
+
selected action wrote to when the action touched exactly one, marks every slice
|
|
56
|
+
the action changed, and keeps `root` selectable.
|
|
57
|
+
- **Copy as fetch** in the row context menu, alongside Copy as cURL.
|
|
58
|
+
- Horizontal scrolling for the tab row and the slice picker when they overflow,
|
|
59
|
+
with edge fades, wheel support and arrow buttons.
|
|
60
|
+
- Accessible names and pressed/expanded state on the toolbar controls, and
|
|
61
|
+
tab/tablist roles on the tab and slice strips.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- The **Preview** and **Response** tabs are merged into a single **Response**
|
|
66
|
+
tab. Both previously rendered the same field — one as a tree, one as raw JSON —
|
|
67
|
+
so the rendering is now chosen with the format switch instead of by picking a
|
|
68
|
+
tab.
|
|
69
|
+
- `MonitorPrefs`, exported from `@hakam-aldeen-kh/blix/capture`, gained two
|
|
70
|
+
required fields: `theme: string` and `dataFormat: string`. This is a
|
|
71
|
+
compile-time break for anyone constructing a `MonitorPrefs` object literal.
|
|
72
|
+
`BlixProps` and every function signature in `/capture` are unchanged.
|
|
73
|
+
- HAR download filename: `network-<timestamp>.har` → `blix-<timestamp>.har`.
|
|
74
|
+
Every other export uses the same `blix-<timestamp>.<ext>` form.
|
|
75
|
+
- A press anywhere outside an open menu now dismisses it, including inside the
|
|
76
|
+
panel; previously only a press outside the panel root did, so a menu left open
|
|
77
|
+
over the panel could only be closed with Esc or its own button. The press is
|
|
78
|
+
not swallowed — it still selects the row or activates the button underneath.
|
|
79
|
+
- The status bar and the detail pane's empty states name what a row is in the
|
|
80
|
+
active section — requests, connections, actions or queries — instead of calling
|
|
81
|
+
every row a "request".
|
|
82
|
+
- Every colour the panel paints now comes from the active theme's tokens: status
|
|
83
|
+
colours, method and section accents, waterfall bars, timing segments and JSON
|
|
84
|
+
syntax highlighting. The previous split, with a light palette in CSS and a
|
|
85
|
+
duplicate dark one in JS, is gone.
|
|
86
|
+
- WebSocket, Redux and Query rows take their section's accent colour rather than
|
|
87
|
+
the shared fallback that HTTP verbs fell through to.
|
|
88
|
+
- The docked badge reads "Blix" rather than "Dev", and the toolbar shows a BLIX
|
|
89
|
+
wordmark beside the status dot.
|
|
90
|
+
|
|
91
|
+
### Fixed
|
|
92
|
+
|
|
93
|
+
- Generated downloads revoke their object URL on the next task instead of
|
|
94
|
+
immediately after the click, which could race the browser's read of the blob
|
|
95
|
+
and save an empty file in Safari.
|
|
96
|
+
|
|
97
|
+
## [0.3.3] - 2026-08-24 — DEPRECATED
|
|
98
|
+
|
|
99
|
+
Released in error as a patch bump: it was a feature release that also added two
|
|
100
|
+
required fields to the publicly exported `MonitorPrefs` type. Superseded by
|
|
101
|
+
0.4.0, which is identical in code. Deprecated on npm — use 0.4.0. Its contents
|
|
102
|
+
are listed under 0.4.0.
|
|
103
|
+
|
|
104
|
+
## [0.3.2] - 2026-08-19
|
|
105
|
+
|
|
106
|
+
### Added
|
|
107
|
+
|
|
108
|
+
- `./package.json` as an export subpath, a top-level `types` field, `engines`
|
|
109
|
+
declaring Node >= 18, and package metadata (repository, homepage, bugs,
|
|
110
|
+
keywords).
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
|
|
114
|
+
- `peerDependencies` narrowed from `*` to `axios ^1.0.0`,
|
|
115
|
+
`@reduxjs/toolkit ^2.0.0` and `@tanstack/react-query ^5.0.0`. Narrowing a peer
|
|
116
|
+
range is breaking by convention and this shipped as a patch — though 0.3.2 was
|
|
117
|
+
the first version on the public npm registry, so no npm consumer could have
|
|
118
|
+
been affected.
|
|
119
|
+
- License: `UNLICENSED` → MIT.
|
|
120
|
+
- Published to the public npm registry instead of GitHub Packages.
|
|
121
|
+
|
|
122
|
+
### Fixed
|
|
123
|
+
|
|
124
|
+
- `tapQueryClient`'s disposer now clears the client's internal tapped mark. A
|
|
125
|
+
dispose-then-reinstall cycle — exactly what React Strict Mode does to an effect
|
|
126
|
+
returning this disposer — hit the idempotency guard and became a permanent
|
|
127
|
+
no-op, leaving the Query tab silently empty for the rest of the session.
|
|
128
|
+
|
|
129
|
+
Versions before 0.3.2 were published to GitHub Packages and are not available on the public npm registry.
|
package/README.md
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# @hakam-aldeen-kh/blix
|
|
2
|
+
[](https://www.npmjs.com/package/@hakam-aldeen-kh/blix)
|
|
2
3
|
|
|
3
4
|
An in-app dev-tools panel for React apps. Captures HTTP requests, Redux
|
|
4
5
|
actions, TanStack Query cache events and realtime traffic, and renders them in
|
|
@@ -7,6 +8,8 @@ a dockable panel with a waterfall, diffing, replay and HAR/cURL export.
|
|
|
7
8
|
The entire panel is eliminated from production builds — see
|
|
8
9
|
[Production elimination](#production-elimination).
|
|
9
10
|
|
|
11
|
+
Release notes are in [CHANGELOG.md](CHANGELOG.md).
|
|
12
|
+
|
|
10
13
|
---
|
|
11
14
|
|
|
12
15
|
## Install
|
|
@@ -29,6 +32,13 @@ while resolving that import. devDependencies have to be present at build time.
|
|
|
29
32
|
Dropping them from the final runtime image is fine: nothing from Blix reaches
|
|
30
33
|
the production output anyway.
|
|
31
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
|
+
|
|
32
42
|
### Peer dependencies
|
|
33
43
|
|
|
34
44
|
`react` and `react-dom` (v19) are required. `axios`, `@reduxjs/toolkit` and
|
|
@@ -348,12 +358,14 @@ as a bounded hex preview plus byte length). They go through the same
|
|
|
348
358
|
serialization and truncation rules as the plaintext bodies, both in the panel
|
|
349
359
|
and in IndexedDB, so a multi-megabyte ciphertext cannot blow out the log.
|
|
350
360
|
|
|
351
|
-
> **Redaction.** Blix masks sensitive *headers*
|
|
352
|
-
>
|
|
353
|
-
>
|
|
354
|
-
> you pass
|
|
355
|
-
>
|
|
356
|
-
>
|
|
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.
|
|
357
369
|
|
|
358
370
|
#### `withInitiatorCapture(instance)`
|
|
359
371
|
|
|
@@ -681,11 +693,15 @@ There is no API for adding your own; a theme is ~20 colours in
|
|
|
681
693
|
|
|
682
694
|
### `dbName` — when you need it
|
|
683
695
|
|
|
684
|
-
The panel
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
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.
|
|
689
705
|
|
|
690
706
|
Give each app its own name to keep them separate:
|
|
691
707
|
|
|
@@ -785,6 +801,156 @@ example above, which is written in the guarded form.
|
|
|
785
801
|
|
|
786
802
|
---
|
|
787
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 | Always available |
|
|
834
|
+
| `Shift+L` | Always available |
|
|
835
|
+
|
|
836
|
+
**Turning it on is retroactive.** The toggle does not mean "from now on".
|
|
837
|
+
Switching it on writes every entry already sitting in the live buffer — the
|
|
838
|
+
session you have *already* captured — to disk immediately, along with
|
|
839
|
+
everything that follows. If you have just reproduced a login flow and then
|
|
840
|
+
reach for the toggle, you have written that login flow to disk. Read that
|
|
841
|
+
again before you assume otherwise; it is the one behaviour here that
|
|
842
|
+
reasonably surprises people.
|
|
843
|
+
|
|
844
|
+
With preserve-log on, this is what is kept:
|
|
845
|
+
|
|
846
|
+
| Captured | Persisted |
|
|
847
|
+
| --- | --- |
|
|
848
|
+
| HTTP entries — bodies, headers, timings | yes |
|
|
849
|
+
| Realtime frames | yes |
|
|
850
|
+
| The encrypted envelope, if you call `captureEncrypted` | yes |
|
|
851
|
+
| Panel preferences and budget totals | yes — preferences are also mirrored to `localStorage` |
|
|
852
|
+
| Redux actions, payloads and diffs | only if you pin the row |
|
|
853
|
+
| Query cache rows | only if you pin the row |
|
|
854
|
+
|
|
855
|
+
### What is redacted
|
|
856
|
+
|
|
857
|
+
Exactly four header names, and nothing else:
|
|
858
|
+
|
|
859
|
+
| Header | Match |
|
|
860
|
+
| --- | --- |
|
|
861
|
+
| `authorization` | exact, case-insensitive |
|
|
862
|
+
| `cookie` | exact, case-insensitive |
|
|
863
|
+
| `set-cookie` | exact, case-insensitive |
|
|
864
|
+
| `x-api-key` | exact, case-insensitive |
|
|
865
|
+
|
|
866
|
+
The match is **exact on the full header name** — not a prefix, not a
|
|
867
|
+
substring, not a pattern. Near-miss names are *not* covered and are written in
|
|
868
|
+
the clear: `x-auth-token` and `api-key` are the two that most often catch
|
|
869
|
+
people out, and `proxy-authorization`, `x-csrf-token` and
|
|
870
|
+
`x-amz-security-token` are equally uncovered. If your auth travels in a header
|
|
871
|
+
that is not one of the four above, it is captured verbatim.
|
|
872
|
+
|
|
873
|
+
Masking is partial rather than total: for a value longer than 12 characters
|
|
874
|
+
the first 8 and last 4 survive, so you can still tell which token you sent.
|
|
875
|
+
Shorter values are replaced outright.
|
|
876
|
+
|
|
877
|
+
**Nothing inside a body is redacted.** Request bodies, response bodies, error
|
|
878
|
+
payloads, the encrypted request/response values, Redux payloads and diffs, and
|
|
879
|
+
realtime frames all pass through a size-only walker — it truncates large
|
|
880
|
+
values and never once inspects a key name. A `password`, `ssn` or
|
|
881
|
+
`refreshToken` field is captured, and with preserve-log on written to disk,
|
|
882
|
+
exactly as it appears. Blix has no mechanism to do otherwise: it has no schema
|
|
883
|
+
for your payloads and no way to tell a secret from any other string.
|
|
884
|
+
|
|
885
|
+
### Retention and clearing
|
|
886
|
+
|
|
887
|
+
| Bound | Value |
|
|
888
|
+
| --- | --- |
|
|
889
|
+
| Records | 200 |
|
|
890
|
+
| Total size | 24 MB |
|
|
891
|
+
| Per payload field | 512 KB |
|
|
892
|
+
| Eviction | oldest first, once either bound is exceeded |
|
|
893
|
+
| Time-based expiry | none |
|
|
894
|
+
|
|
895
|
+
There is **no TTL of any kind**. A record leaves the database when 200 newer
|
|
896
|
+
records or 24 MB of newer traffic push it out, or when you clear it yourself.
|
|
897
|
+
On a low-traffic app with preserve-log left on, a captured token stays in the
|
|
898
|
+
browser profile indefinitely.
|
|
899
|
+
|
|
900
|
+
> **Realtime frames are an exception to the size bound.** They are stored
|
|
901
|
+
> without truncation and are under-counted against the byte budget — a record
|
|
902
|
+
> is charged a flat allowance regardless of how many frames it carries, and a
|
|
903
|
+
> connection can hold hundreds. A long-lived realtime session can therefore
|
|
904
|
+
> occupy considerably more on disk than the 24 MB figure implies, and eviction
|
|
905
|
+
> will not reclaim it. The record and size caps hold for HTTP entries.
|
|
906
|
+
> Tracked in [#N](https://github.com/Hakam-aldeen-Kh/blix/issues/N).
|
|
907
|
+
|
|
908
|
+
To purge, use the persisted-size label in the status bar — the one reading
|
|
909
|
+
`12 saved · 3.4 MB`. It is the control: click once to arm it, at which point
|
|
910
|
+
it changes to `Purge saved log?`, and click again to delete the database.
|
|
911
|
+
|
|
912
|
+
Switching preserve-log **off** also clears the stored entries, so turning it
|
|
913
|
+
off is itself a way to drop everything Blix has written. What survives is the
|
|
914
|
+
database and your panel preferences, not the captured bodies.
|
|
915
|
+
|
|
916
|
+
**The purge control is only rendered while preserve-log is on**, so once you
|
|
917
|
+
have switched it off there is nothing left in the UI to press — and there is
|
|
918
|
+
no programmatic API for it either. Use Purge when you want the database gone
|
|
919
|
+
outright; switch off when clearing the entries is enough.
|
|
920
|
+
|
|
921
|
+
### Threat model
|
|
922
|
+
|
|
923
|
+
IndexedDB is scoped **per origin, not per app**, and it is not encrypted at
|
|
924
|
+
rest. Any script running on that origin can read Blix's database — including
|
|
925
|
+
browser extension content scripts with access to the origin. Whatever you
|
|
926
|
+
capture is readable by whatever you have installed.
|
|
927
|
+
|
|
928
|
+
Export and copy move captured data out of the browser entirely:
|
|
929
|
+
|
|
930
|
+
| Path | Carries |
|
|
931
|
+
| --- | --- |
|
|
932
|
+
| HAR export | Decrypted request and response bodies |
|
|
933
|
+
| JSON / NDJSON export | Everything captured — frames, Redux diffs, timings |
|
|
934
|
+
| **Copy as cURL** / **Copy as fetch** | Headers and bodies, with `Authorization` masked — so the output is not a working request |
|
|
935
|
+
|
|
936
|
+
HAR is the one to watch. It is a plain JSON file carrying your decrypted
|
|
937
|
+
bodies, and it is the artifact most likely to end up attached to a ticket.
|
|
938
|
+
|
|
939
|
+
### If you handle sensitive data
|
|
940
|
+
|
|
941
|
+
- **Leave preserve-log off unless you actively need it.** It is off by
|
|
942
|
+
default. In-memory capture already gives you the entire panel; the toggle
|
|
943
|
+
buys you nothing but survival across a reload.
|
|
944
|
+
- **Purge after any session that captured an auth flow** — and purge *before*
|
|
945
|
+
you switch preserve-log back off, or the control disappears on you.
|
|
946
|
+
- **Use the Redux `ignore` option** for action types that carry credentials or
|
|
947
|
+
personal data, so they are never captured in the first place. See
|
|
948
|
+
[Redux](#redux--createreduxmonitormiddlewareoptions).
|
|
949
|
+
- **Treat an exported HAR as a credential-bearing file.** Do not attach one to
|
|
950
|
+
a public issue, and do not commit one.
|
|
951
|
+
|
|
952
|
+
---
|
|
953
|
+
|
|
788
954
|
## Entry points
|
|
789
955
|
|
|
790
956
|
| Import | Contents | `"use client"` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hakam-aldeen-kh/blix",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Dev-tools panel for React apps — HTTP, Redux, Query and Realtime monitoring.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"devtools",
|
|
@@ -63,7 +63,8 @@
|
|
|
63
63
|
"./package.json": "./package.json"
|
|
64
64
|
},
|
|
65
65
|
"files": [
|
|
66
|
-
"dist"
|
|
66
|
+
"dist",
|
|
67
|
+
"CHANGELOG.md"
|
|
67
68
|
],
|
|
68
69
|
"engines": {
|
|
69
70
|
"node": ">=18"
|