@djangocfg/monitor 2.1.229 → 2.1.231

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/monitor",
3
- "version": "2.1.229",
3
+ "version": "2.1.231",
4
4
  "description": "Browser error and event monitoring SDK for django-cfg backends. Captures JS errors, network failures, console logs, and performance metrics.",
5
5
  "keywords": [
6
6
  "django",
@@ -83,7 +83,7 @@
83
83
  }
84
84
  },
85
85
  "devDependencies": {
86
- "@djangocfg/typescript-config": "^2.1.229",
86
+ "@djangocfg/typescript-config": "^2.1.231",
87
87
  "p-retry": "^6.2.0",
88
88
  "@types/node": "^24.7.2",
89
89
  "@types/react": "^19.1.0",
@@ -0,0 +1,84 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * useDebugMode — shared debug mode detection hook.
5
+ *
6
+ * Logic:
7
+ * - development: always true (no localStorage needed)
8
+ * - production:
9
+ * - ?debug=1 in URL → persist to localStorage, remove param from URL
10
+ * - ?debug=0 in URL → clear localStorage, disable debug mode
11
+ * - localStorage.__debug_mode__ === '1' → true
12
+ * - otherwise → false
13
+ *
14
+ * @example
15
+ * const isDebug = useDebugMode()
16
+ */
17
+
18
+ import { useEffect, useState } from 'react'
19
+ import { isDevelopment } from '../utils/env'
20
+
21
+ const LS_KEY = '__debug_mode__'
22
+
23
+ function readFromStorage(): boolean {
24
+ try {
25
+ return localStorage.getItem(LS_KEY) === '1'
26
+ } catch {
27
+ return false
28
+ }
29
+ }
30
+
31
+ function persistToStorage(): void {
32
+ try {
33
+ localStorage.setItem(LS_KEY, '1')
34
+ } catch {
35
+ // ignore — private browsing or quota exceeded
36
+ }
37
+ }
38
+
39
+ function clearFromStorage(): void {
40
+ try {
41
+ localStorage.removeItem(LS_KEY)
42
+ } catch {
43
+ // ignore
44
+ }
45
+ }
46
+
47
+ function consumeDebugParam(): boolean | null {
48
+ if (typeof window === 'undefined') return null
49
+ const params = new URLSearchParams(window.location.search)
50
+ const value = params.get('debug')
51
+ if (value === null) return null
52
+
53
+ if (value === '1') {
54
+ persistToStorage()
55
+ } else {
56
+ // ?debug=0 or any other value → explicitly disable and clear stored flag
57
+ clearFromStorage()
58
+ }
59
+
60
+ params.delete('debug')
61
+ const newUrl = `${window.location.pathname}${params.toString() ? `?${params.toString()}` : ''}${window.location.hash}`
62
+ window.history.replaceState(null, '', newUrl)
63
+ return value === '1'
64
+ }
65
+
66
+ export function useDebugMode(): boolean {
67
+ // In development, always true — no side effects needed
68
+ if (isDevelopment) return true
69
+
70
+ // eslint-disable-next-line react-hooks/rules-of-hooks
71
+ const [isDebug, setIsDebug] = useState(false)
72
+
73
+ // eslint-disable-next-line react-hooks/rules-of-hooks
74
+ useEffect(() => {
75
+ const fromUrl = consumeDebugParam()
76
+ if (fromUrl !== null) {
77
+ setIsDebug(fromUrl)
78
+ return
79
+ }
80
+ setIsDebug(readFromStorage())
81
+ }, [])
82
+
83
+ return isDebug
84
+ }
@@ -36,6 +36,8 @@ export type { MonitorProviderProps } from './MonitorProvider'
36
36
  export { initWindowMonitor } from './window'
37
37
  export type { WindowMonitorAPI } from './window'
38
38
  export { monitorStore } from './store'
39
+ export { useDebugMode } from './hooks/useDebugMode'
40
+ export { isDevelopment, isProduction, MONITOR_VERSION } from './utils/env'
39
41
 
40
42
  let flushInterval: ReturnType<typeof setInterval> | null = null
41
43
  const cleanupFns: Array<() => void> = []
@@ -1,6 +1,7 @@
1
1
  import { createStore } from 'zustand/vanilla'
2
2
  import type { MonitorEvent, MonitorConfig } from '../../types'
3
3
  import { sendBatch } from '../transport/ingest'
4
+ import { MONITOR_VERSION } from '../utils/env'
4
5
 
5
6
  // Circuit breaker: pause flushing after N consecutive transport failures
6
7
  const CIRCUIT_BREAKER_THRESHOLD = 3
@@ -28,6 +29,7 @@ export const monitorStore = createStore<MonitorState>((set, get) => ({
28
29
  const { config, buffer } = get()
29
30
  const maxSize = config.maxBufferSize ?? 20
30
31
  const sanitized: MonitorEvent = {
32
+ build_id: event.build_id ?? config.buildId ?? `sdk:${MONITOR_VERSION}`,
31
33
  ...event,
32
34
  // Enforce field size limits before buffering (last-resort backstop)
33
35
  message: event.message && event.message.length > 4997
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Environment utilities.
3
+ *
4
+ * Use these constants instead of inline process.env.NODE_ENV checks.
5
+ * Webpack/esbuild replaces process.env.NODE_ENV statically at build time,
6
+ * so these are zero-cost — they tree-shake correctly in both client and server bundles.
7
+ */
8
+
9
+ /** True only in `next dev` / jest / vitest */
10
+ export const isDevelopment = process.env.NODE_ENV === 'development'
11
+
12
+ /** True in production builds and test environments */
13
+ export const isProduction = process.env.NODE_ENV !== 'development'
14
+
15
+ /** Package version — injected at build time via tsup define, falls back to package.json value */
16
+ export const MONITOR_VERSION: string = (process.env.MONITOR_VERSION as string) ?? '2.1.230'
@@ -16,6 +16,7 @@
16
16
  import { monitorStore } from './store'
17
17
  import { EventType, EventLevel } from '../_api'
18
18
  import { getSessionId } from './capture/session'
19
+ import { MONITOR_VERSION } from './utils/env'
19
20
  import type { MonitorEvent } from '../types'
20
21
 
21
22
  export interface WindowMonitorAPI {
@@ -105,6 +106,8 @@ export function initWindowMonitor(): void {
105
106
  status() {
106
107
  const state = monitorStore.getState()
107
108
  console.group('[monitor] status')
109
+ console.log('sdk version:', MONITOR_VERSION)
110
+ console.log('build_id:', state.config.buildId ?? `sdk:${MONITOR_VERSION}`)
108
111
  console.log('config:', state.config)
109
112
  console.log('buffer size:', state.buffer.length)
110
113
  console.log('initialized:', state.initialized)