@djangocfg/monitor 2.1.427 → 2.1.429

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/README.md CHANGED
@@ -171,6 +171,15 @@ pnpm add @djangocfg/debuger
171
171
 
172
172
  Events captured by monitor (JS errors, console, network) appear in the panel as `monitor:JS_ERROR`, `monitor:NETWORK_ERROR`, etc.
173
173
 
174
+ ## Relationship to console log level
175
+
176
+ `@djangocfg/*` packages share a runtime console verbosity controlled by
177
+ `applyRoleLogPolicy` / `setLogLevel` from `@djangocfg/api` — quiet for regular
178
+ users in production, verbose for admins/devs. **Monitor capture is independent of
179
+ that level**: errors (and configured console events) are still captured and sent
180
+ to the backend / debug panel even when the browser console is silenced. So
181
+ production incidents stay diagnosable without spamming end-user consoles.
182
+
174
183
  ## Safety
175
184
 
176
185
  Transport errors are **always swallowed** — monitor never crashes your app and never sends its own errors to itself. If the backend is unreachable, events are silently dropped.
package/dist/client.cjs CHANGED
@@ -391,6 +391,99 @@ async function tryRefresh() {
391
391
  return _refreshInflight;
392
392
  }
393
393
  __name(tryRefresh, "tryRefresh");
394
+ function dpopEnabled() {
395
+ try {
396
+ return typeof process !== "undefined" && process.env?.NEXT_PUBLIC_DPOP_ENABLED === "true";
397
+ } catch {
398
+ return false;
399
+ }
400
+ }
401
+ __name(dpopEnabled, "dpopEnabled");
402
+ var _DPOP_DB = "cfg-auth";
403
+ var _DPOP_STORE = "keys";
404
+ var _DPOP_KEY_ID = "dpop-ec-p256";
405
+ function _idbOpen() {
406
+ return new Promise((resolve, reject) => {
407
+ const req = indexedDB.open(_DPOP_DB, 1);
408
+ req.onupgradeneeded = () => req.result.createObjectStore(_DPOP_STORE);
409
+ req.onsuccess = () => resolve(req.result);
410
+ req.onerror = () => reject(req.error);
411
+ });
412
+ }
413
+ __name(_idbOpen, "_idbOpen");
414
+ function _idbGet(key) {
415
+ return _idbOpen().then((db) => new Promise((resolve, reject) => {
416
+ const tx = db.transaction(_DPOP_STORE, "readonly");
417
+ const req = tx.objectStore(_DPOP_STORE).get(key);
418
+ req.onsuccess = () => resolve(req.result);
419
+ req.onerror = () => reject(req.error);
420
+ }));
421
+ }
422
+ __name(_idbGet, "_idbGet");
423
+ function _idbPut(key, value) {
424
+ return _idbOpen().then((db) => new Promise((resolve, reject) => {
425
+ const tx = db.transaction(_DPOP_STORE, "readwrite");
426
+ tx.objectStore(_DPOP_STORE).put(value, key);
427
+ tx.oncomplete = () => resolve();
428
+ tx.onerror = () => reject(tx.error);
429
+ }));
430
+ }
431
+ __name(_idbPut, "_idbPut");
432
+ var _dpopKeyPromise = null;
433
+ function _getDpopKeyPair() {
434
+ if (_dpopKeyPromise) return _dpopKeyPromise;
435
+ _dpopKeyPromise = (async () => {
436
+ const existing = await _idbGet(_DPOP_KEY_ID).catch(() => void 0);
437
+ if (existing) return existing;
438
+ const pair = await crypto.subtle.generateKey(
439
+ { name: "ECDSA", namedCurve: "P-256" },
440
+ false,
441
+ // extractable:false — JS can sign but never export the private key
442
+ ["sign"]
443
+ );
444
+ await _idbPut(_DPOP_KEY_ID, pair).catch(() => {
445
+ });
446
+ return pair;
447
+ })();
448
+ return _dpopKeyPromise;
449
+ }
450
+ __name(_getDpopKeyPair, "_getDpopKeyPair");
451
+ function _b64urlFromBytes(bytes) {
452
+ const arr = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
453
+ let s = "";
454
+ for (let i = 0; i < arr.length; i++) s += String.fromCharCode(arr[i]);
455
+ return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
456
+ }
457
+ __name(_b64urlFromBytes, "_b64urlFromBytes");
458
+ function _b64urlFromString(str) {
459
+ return _b64urlFromBytes(new TextEncoder().encode(str));
460
+ }
461
+ __name(_b64urlFromString, "_b64urlFromString");
462
+ async function _publicJwk(pub) {
463
+ const jwk = await crypto.subtle.exportKey("jwk", pub);
464
+ return { kty: "EC", crv: "P-256", x: jwk.x, y: jwk.y };
465
+ }
466
+ __name(_publicJwk, "_publicJwk");
467
+ async function _makeDpopProof(method, url) {
468
+ try {
469
+ const pair = await _getDpopKeyPair();
470
+ const jwk = await _publicJwk(pair.publicKey);
471
+ const header = { typ: "dpop+jwt", alg: "ES256", jwk };
472
+ const htu = url.split("#")[0].split("?")[0];
473
+ const jti = crypto.randomUUID && crypto.randomUUID() || _b64urlFromBytes(crypto.getRandomValues(new Uint8Array(16)));
474
+ const payload = { htm: method.toUpperCase(), htu, iat: Math.floor(Date.now() / 1e3), jti };
475
+ const signingInput = `${_b64urlFromString(JSON.stringify(header))}.${_b64urlFromString(JSON.stringify(payload))}`;
476
+ const sig = await crypto.subtle.sign(
477
+ { name: "ECDSA", hash: "SHA-256" },
478
+ pair.privateKey,
479
+ new TextEncoder().encode(signingInput)
480
+ );
481
+ return `${signingInput}.${_b64urlFromBytes(sig)}`;
482
+ } catch {
483
+ return null;
484
+ }
485
+ }
486
+ __name(_makeDpopProof, "_makeDpopProof");
394
487
  function installAuthOnClient(client2) {
395
488
  if (_client) return;
396
489
  _client = client2;
@@ -398,7 +491,7 @@ function installAuthOnClient(client2) {
398
491
  baseUrl: auth.getBaseUrl(),
399
492
  credentials: _withCredentials ? "include" : "same-origin"
400
493
  });
401
- client2.interceptors.request.use((request) => {
494
+ client2.interceptors.request.use(async (request) => {
402
495
  const token = auth.getToken();
403
496
  if (token) request.headers.set("Authorization", `Bearer ${token}`);
404
497
  const locale = auth.getLocale();
@@ -411,6 +504,10 @@ function installAuthOnClient(client2) {
411
504
  } catch {
412
505
  }
413
506
  request.headers.set("X-Client-Time", (/* @__PURE__ */ new Date()).toISOString());
507
+ if (dpopEnabled() && typeof window !== "undefined") {
508
+ const proof = await _makeDpopProof(request.method, request.url);
509
+ if (proof) request.headers.set("DPoP", proof);
510
+ }
414
511
  return request;
415
512
  });
416
513
  client2.interceptors.error.use((err, res, req) => {
@@ -444,6 +541,10 @@ function installAuthOnClient(client2) {
444
541
  const retry = request.clone();
445
542
  retry.headers.set("Authorization", `Bearer ${newToken}`);
446
543
  retry.headers.set(RETRY_MARKER, "1");
544
+ if (dpopEnabled() && typeof window !== "undefined") {
545
+ const proof = await _makeDpopProof(retry.method, retry.url);
546
+ if (proof) retry.headers.set("DPoP", proof);
547
+ }
447
548
  try {
448
549
  const retried = await fetch(retry);
449
550
  if (retried.status === 401 && _onUnauthorized) {
@@ -1489,7 +1590,7 @@ __name(sendBatch, "sendBatch");
1489
1590
  // src/client/utils/env.ts
1490
1591
  var isDevelopment = process.env.NODE_ENV === "development";
1491
1592
  var isProduction = !isDevelopment;
1492
- var MONITOR_VERSION = "2.1.427";
1593
+ var MONITOR_VERSION = "2.1.429";
1493
1594
 
1494
1595
  // src/client/constants.ts
1495
1596
  var MONITOR_INGEST_PATTERN = /cfg\/monitor\/ingest/;