@djangocfg/devtools 2.1.470 → 2.1.471
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/package.json +4 -4
- package/src/ingest.ts +32 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/devtools",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.471",
|
|
4
4
|
"description": "Frontend devtools for django-cfg apps: error/console capture with backend ingest, plus a floating debug panel. One package, one event stream.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"django",
|
|
@@ -48,15 +48,15 @@
|
|
|
48
48
|
"lint": "eslint ."
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@djangocfg/ui-core": "^2.1.
|
|
51
|
+
"@djangocfg/ui-core": "^2.1.471",
|
|
52
52
|
"lucide-react": ">=0.400.0",
|
|
53
53
|
"react": "^19.2.4",
|
|
54
54
|
"react-dom": "^19.2.4",
|
|
55
55
|
"zustand": "^5.0.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
59
|
-
"@djangocfg/ui-core": "^2.1.
|
|
58
|
+
"@djangocfg/typescript-config": "^2.1.471",
|
|
59
|
+
"@djangocfg/ui-core": "^2.1.471",
|
|
60
60
|
"@types/node": "^25.9.5",
|
|
61
61
|
"@types/react": "19.2.15",
|
|
62
62
|
"lucide-react": "^0.545.0",
|
package/src/ingest.ts
CHANGED
|
@@ -2,8 +2,34 @@
|
|
|
2
2
|
* Ingest transport — one plain fetch to `POST /cfg/monitor/ingest/`.
|
|
3
3
|
*
|
|
4
4
|
* The endpoint is AllowAny + rate-limited on the backend and always answers
|
|
5
|
-
* 202; nothing here needs auth headers or a generated client.
|
|
6
|
-
*
|
|
5
|
+
* 202; nothing here needs auth headers or a generated client.
|
|
6
|
+
*
|
|
7
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
* WHY THIS DOES NOT USE @djangocfg/analytics' BeaconTransport
|
|
9
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
* It would be the obvious dedup, and it is wrong: BeaconTransport is
|
|
11
|
+
* fire-and-forget, while `sendBatch` MUST reject on failure — `store.ts` drives
|
|
12
|
+
* a circuit breaker off that rejection (BREAKER_THRESHOLD / BREAKER_COOLDOWN_MS),
|
|
13
|
+
* and `server.ts` awaits it outside the browser entirely. Swapping in a
|
|
14
|
+
* fire-and-forget transport would silently disable the breaker, so a backend
|
|
15
|
+
* outage would turn into an unbounded retry loop from every open tab.
|
|
16
|
+
*
|
|
17
|
+
* What IS shared is the rule below, and it is the part that was actually broken.
|
|
18
|
+
*
|
|
19
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
* THE UNLOAD PATH MUST NOT SEND application/json
|
|
21
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
+
* `application/json` is NOT CORS-safelisted, so a cross-origin request carrying
|
|
23
|
+
* it leaves no-cors mode and triggers an OPTIONS preflight. During page unload
|
|
24
|
+
* that preflight usually cannot complete, so the POST is never sent — and the
|
|
25
|
+
* events lost are the ones that mattered most: whatever crashed the page and
|
|
26
|
+
* caused the navigation away.
|
|
27
|
+
*
|
|
28
|
+
* `text/plain` IS CORS-safelisted, so the same JSON body is delivered with no
|
|
29
|
+
* preflight. The body is unchanged; only the label differs. The server reads it
|
|
30
|
+
* with an additive parser scoped to the ingest view.
|
|
31
|
+
*
|
|
32
|
+
* Same trap, same fix, as @djangocfg/analytics. Verified in Chrome 149.
|
|
7
33
|
*/
|
|
8
34
|
|
|
9
35
|
import { INGEST_PATH } from './internal'
|
|
@@ -18,7 +44,10 @@ export async function sendBatch(
|
|
|
18
44
|
|
|
19
45
|
const res = await fetch(`${baseUrl}${INGEST_PATH}`, {
|
|
20
46
|
method: 'POST',
|
|
21
|
-
headers: {
|
|
47
|
+
headers: {
|
|
48
|
+
// Unload flushes must stay CORS-simple or they never leave the browser.
|
|
49
|
+
'Content-Type': useBeacon ? 'text/plain' : 'application/json',
|
|
50
|
+
},
|
|
22
51
|
body: JSON.stringify({ events }),
|
|
23
52
|
credentials: 'include',
|
|
24
53
|
...(useBeacon ? { keepalive: true } : {}),
|