@djangocfg/centrifugo 2.1.101 → 2.1.102

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/logger/consolaLogger.ts","../src/events.ts","../src/components/MessagesFeed/MessageFilters.tsx","../src/components/MessagesFeed/MessagesFeed.tsx","../src/components/SubscriptionsList/SubscriptionsList.tsx","../src/components/CentrifugoMonitor/CentrifugoMonitor.tsx","../src/components/CentrifugoMonitor/CentrifugoMonitorDialog.tsx","../src/config.ts","../src/providers/LogsProvider/LogsProvider.tsx","../src/providers/CentrifugoProvider/CentrifugoProvider.tsx","../src/components/ConnectionStatus/ConnectionStatus.tsx","../src/components/ConnectionStatus/ConnectionStatusCard.tsx","../src/components/CentrifugoMonitor/CentrifugoMonitorFAB.tsx","../src/components/CentrifugoMonitor/CentrifugoMonitorWidget.tsx"],"names":["jsx","jsxs","Badge","Button","useState","useEffect","Card","CardHeader","CardTitle","CardContent","ScrollArea","Trash2","Activity","createContext","useContext","logger","moment","Radio","Wifi","WifiOff"],"mappings":"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","file":"components.mjs","sourcesContent":["/**\n * Shared Consola Logger\n *\n * Single consola instance used across the package for development logging.\n */\n\nimport { createConsola } from 'consola';\n\nimport type { Logger } from './createLogger';\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\n/**\n * Shared consola logger for Centrifugo package\n */\nexport const consolaLogger = createConsola({\n level: isDevelopment ? 4 : 3,\n formatOptions: {\n colors: true,\n date: false,\n compact: !isDevelopment,\n },\n}).withTag('[Centrifugo]');\n\n/**\n * Get a consola logger with custom tag wrapped to match Logger interface\n */\nexport function getConsolaLogger(tag: string): Logger {\n const consola = consolaLogger.withTag(`[${tag}]`);\n\n return {\n debug: (message: string, data?: unknown) => consola.debug(message, data || ''),\n info: (message: string, data?: unknown) => consola.info(message, data || ''),\n success: (message: string, data?: unknown) => consola.success(message, data || ''),\n warning: (message: string, data?: unknown) => consola.warn(message, data || ''),\n error: (message: string, error?: Error | unknown) => consola.error(message, error || ''),\n };\n}\n","/**\n * Centrifugo Package Events\n *\n * Unified event system for Centrifugo client.\n * All events use single 'centrifugo' CustomEvent with type discriminator.\n */\n\nimport { events } from '@djangocfg/ui-core/hooks';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Event Constants\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Single event name for all Centrifugo events.\n * Use `type` field in payload to distinguish event types.\n */\nexport const CENTRIFUGO_EVENT = 'centrifugo' as const;\n\n/**\n * Internal events for UI components (via events.publish)\n */\nexport const CENTRIFUGO_MONITOR_EVENTS = {\n OPEN_MONITOR_DIALOG: 'CENTRIFUGO_OPEN_MONITOR_DIALOG',\n CLOSE_MONITOR_DIALOG: 'CENTRIFUGO_CLOSE_MONITOR_DIALOG',\n} as const;\n\n// Legacy exports for backwards compatibility\nexport const CENTRIFUGO_ERROR_EVENT = CENTRIFUGO_EVENT;\nexport const CENTRIFUGO_VERSION_MISMATCH_EVENT = CENTRIFUGO_EVENT;\n\n// ─────────────────────────────────────────────────────────────────────────\n// Event Types\n// ─────────────────────────────────────────────────────────────────────────\n\nexport type CentrifugoEventType =\n | 'error'\n | 'version_mismatch'\n | 'connected'\n | 'disconnected'\n | 'reconnecting';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Event Payloads\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface CentrifugoErrorData {\n /** RPC method that failed */\n method: string;\n /** Error message */\n error: string;\n /** Error code from Centrifugo */\n code?: number;\n /** Additional data sent with the request */\n data?: any;\n}\n\nexport interface CentrifugoVersionMismatchData {\n /** Client API version hash */\n clientVersion: string;\n /** Server API version hash */\n serverVersion: string;\n /** Human-readable message */\n message: string;\n}\n\nexport interface CentrifugoConnectionData {\n /** User ID */\n userId?: string;\n /** Reconnect attempt number (for reconnecting) */\n attempt?: number;\n /** Reason for disconnect */\n reason?: string;\n}\n\n/**\n * Unified Centrifugo event payload\n */\nexport type CentrifugoEventPayload =\n | { type: 'error'; data: CentrifugoErrorData }\n | { type: 'version_mismatch'; data: CentrifugoVersionMismatchData }\n | { type: 'connected'; data: CentrifugoConnectionData }\n | { type: 'disconnected'; data: CentrifugoConnectionData }\n | { type: 'reconnecting'; data: CentrifugoConnectionData };\n\n/**\n * Full event detail (includes timestamp)\n */\nexport type CentrifugoEventDetail = CentrifugoEventPayload & {\n timestamp: Date;\n};\n\n// ─────────────────────────────────────────────────────────────────────────\n// Monitor Dialog Payloads (internal events)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface OpenMonitorDialogPayload {\n variant?: 'compact' | 'full' | 'minimal';\n defaultTab?: 'connection' | 'messages' | 'subscriptions';\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Legacy Types (for backwards compatibility)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** @deprecated Use CentrifugoErrorData */\nexport type CentrifugoErrorPayload = CentrifugoErrorData;\n\n/** @deprecated Use CentrifugoVersionMismatchData */\nexport type VersionMismatchPayload = CentrifugoVersionMismatchData;\n\n// ─────────────────────────────────────────────────────────────────────────\n// Event Dispatcher\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Dispatch unified Centrifugo event\n *\n * @example\n * ```ts\n * // Dispatch error\n * dispatchCentrifugoEvent({\n * type: 'error',\n * data: { method: 'terminal.input', error: 'timeout' }\n * });\n *\n * // Listen to all Centrifugo events\n * window.addEventListener('centrifugo', (e) => {\n * const { type, data, timestamp } = e.detail;\n * switch (type) {\n * case 'error':\n * console.error('RPC error:', data.method, data.error);\n * break;\n * case 'version_mismatch':\n * toast.warning('Please refresh the page');\n * break;\n * }\n * });\n * ```\n */\nexport const dispatchCentrifugoEvent = (payload: CentrifugoEventPayload): void => {\n if (typeof window === 'undefined') {\n return;\n }\n\n try {\n const detail: CentrifugoEventDetail = {\n ...payload,\n timestamp: new Date(),\n };\n\n window.dispatchEvent(new CustomEvent(CENTRIFUGO_EVENT, {\n detail,\n bubbles: true,\n cancelable: false,\n }));\n } catch (error) {\n // Silently fail - event dispatch should never crash the app\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────\n// Convenience Dispatchers\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Dispatch error event\n */\nexport const dispatchCentrifugoError = (data: CentrifugoErrorData): void => {\n dispatchCentrifugoEvent({ type: 'error', data });\n};\n\n/**\n * Dispatch version mismatch event\n */\nexport const dispatchVersionMismatch = (data: CentrifugoVersionMismatchData): void => {\n dispatchCentrifugoEvent({ type: 'version_mismatch', data });\n};\n\n/**\n * Dispatch connected event\n */\nexport const dispatchConnected = (data: CentrifugoConnectionData = {}): void => {\n dispatchCentrifugoEvent({ type: 'connected', data });\n};\n\n/**\n * Dispatch disconnected event\n */\nexport const dispatchDisconnected = (data: CentrifugoConnectionData = {}): void => {\n dispatchCentrifugoEvent({ type: 'disconnected', data });\n};\n\n/**\n * Dispatch reconnecting event\n */\nexport const dispatchReconnecting = (data: CentrifugoConnectionData = {}): void => {\n dispatchCentrifugoEvent({ type: 'reconnecting', data });\n};\n\n// ─────────────────────────────────────────────────────────────────────────\n// Monitor Dialog Emitters (internal, uses events.publish)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport const emitOpenMonitorDialog = (payload?: OpenMonitorDialogPayload) => {\n events.publish({\n type: CENTRIFUGO_MONITOR_EVENTS.OPEN_MONITOR_DIALOG,\n payload: payload || {},\n });\n};\n\nexport const emitCloseMonitorDialog = () => {\n events.publish({\n type: CENTRIFUGO_MONITOR_EVENTS.CLOSE_MONITOR_DIALOG,\n payload: {},\n });\n};\n","/**\n * Message Filters Component\n *\n * Filtering controls for MessagesFeed\n */\n\n'use client';\n\nimport { Filter, Search, X } from 'lucide-react';\nimport React from 'react';\n\nimport { Badge, Button, Input } from '@djangocfg/ui-nextjs';\n\nimport type { MessageFilters as MessageFiltersType } from './types';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface MessageFiltersProps {\n filters: MessageFiltersType;\n onFiltersChange: (filters: MessageFiltersType) => void;\n autoScroll?: boolean;\n onAutoScrollChange?: (enabled: boolean) => void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function MessageFilters({\n filters,\n onFiltersChange,\n autoScroll,\n onAutoScrollChange,\n}: MessageFiltersProps) {\n const hasActiveFilters =\n (filters.channels && filters.channels.length > 0) ||\n (filters.types && filters.types.length > 0) ||\n (filters.levels && filters.levels.length > 0) ||\n filters.searchQuery;\n\n const handleClearFilters = () => {\n onFiltersChange({});\n };\n\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onFiltersChange({ ...filters, searchQuery: e.target.value });\n };\n\n const handleToggleLevel = (level: 'info' | 'success' | 'warning' | 'error') => {\n const currentLevels = filters.levels || [];\n const newLevels = currentLevels.includes(level)\n ? currentLevels.filter((l) => l !== level)\n : [...currentLevels, level];\n\n onFiltersChange({\n ...filters,\n levels: newLevels.length > 0 ? newLevels : undefined,\n });\n };\n\n const handleToggleType = (type: 'connection' | 'subscription' | 'publication' | 'error' | 'system' | 'unsubscription') => {\n const currentTypes = filters.types || [];\n const newTypes = currentTypes.includes(type)\n ? currentTypes.filter((t) => t !== type)\n : [...currentTypes, type];\n\n onFiltersChange({\n ...filters,\n types: newTypes.length > 0 ? newTypes : undefined,\n });\n };\n\n return (\n <div className=\"space-y-3 p-3 border rounded-lg bg-muted/30\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-sm font-medium\">Filters</span>\n {hasActiveFilters && (\n <Badge variant=\"secondary\" className=\"text-xs\">\n Active\n </Badge>\n )}\n </div>\n {hasActiveFilters && (\n <Button size=\"sm\" variant=\"ghost\" onClick={handleClearFilters}>\n <X className=\"h-3 w-3 mr-1\" />\n Clear\n </Button>\n )}\n </div>\n\n {/* Search */}\n <div className=\"flex items-center gap-2\">\n <Search className=\"h-4 w-4 text-muted-foreground\" />\n <Input\n type=\"text\"\n placeholder=\"Search messages...\"\n value={filters.searchQuery || ''}\n onChange={handleSearchChange}\n className=\"flex-1\"\n />\n </div>\n\n {/* Level Filters */}\n <div className=\"space-y-2\">\n <span className=\"text-xs text-muted-foreground\">Level:</span>\n <div className=\"flex flex-wrap gap-2\">\n {(['info', 'success', 'warning', 'error'] as const).map((level) => {\n const isActive = filters.levels?.includes(level);\n return (\n <Badge\n key={level}\n variant={isActive ? 'default' : 'outline'}\n className=\"cursor-pointer\"\n onClick={() => handleToggleLevel(level)}\n >\n {level}\n </Badge>\n );\n })}\n </div>\n </div>\n\n {/* Type Filters */}\n <div className=\"space-y-2\">\n <span className=\"text-xs text-muted-foreground\">Type:</span>\n <div className=\"flex flex-wrap gap-2\">\n {(['connection', 'subscription', 'publication', 'unsubscription', 'error', 'system'] as const).map((type) => {\n const isActive = filters.types?.includes(type);\n return (\n <Badge\n key={type}\n variant={isActive ? 'default' : 'outline'}\n className=\"cursor-pointer\"\n onClick={() => handleToggleType(type)}\n >\n {type}\n </Badge>\n );\n })}\n </div>\n </div>\n\n {/* Options */}\n {onAutoScrollChange && (\n <div className=\"pt-2 border-t\">\n <label className=\"flex items-center gap-2 text-sm cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={autoScroll}\n onChange={(e) => onAutoScrollChange(e.target.checked)}\n className=\"h-4 w-4 rounded border-gray-300\"\n />\n <span>Auto-scroll to latest</span>\n </label>\n </div>\n )}\n </div>\n );\n}\n\n","/**\n * Messages Feed Component\n *\n * Universal component for displaying real-time Centrifugo messages\n * Supports filtering, search, pause/play, and export\n */\n\n'use client';\n\nimport {\n Activity, AlertCircle, CheckCircle2, Circle, Download, Info, Pause, Play, Trash2\n} from 'lucide-react';\nimport moment from 'moment';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n Badge, Button, Card, CardContent, CardHeader, CardTitle, ScrollArea\n} from '@djangocfg/ui-nextjs';\n\nimport { useCentrifugo } from '../../providers/CentrifugoProvider';\nimport { MessageFilters as MessageFiltersComponent } from './MessageFilters';\n\nimport type { CentrifugoMessage, MessageFilters, MessagesFeedProps } from './types';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function MessagesFeed({\n maxMessages = 100,\n showFilters = true,\n showControls = true,\n channels = [],\n autoScroll: initialAutoScroll = true,\n onMessageClick,\n className = '',\n}: MessagesFeedProps) {\n const { isConnected, client } = useCentrifugo();\n const [messages, setMessages] = useState<CentrifugoMessage[]>([]);\n const [isPaused, setIsPaused] = useState(false);\n const [autoScroll, setAutoScroll] = useState(initialAutoScroll);\n const [filters, setFilters] = useState<MessageFilters>({\n channels: channels.length > 0 ? channels : undefined,\n });\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Add message\n const addMessage = useCallback(\n (message: CentrifugoMessage) => {\n if (isPaused) return;\n\n setMessages((prev) => {\n const newMessages = [message, ...prev];\n return newMessages.slice(0, maxMessages);\n });\n },\n [isPaused, maxMessages]\n );\n\n // Listen to connection events\n useEffect(() => {\n if (!client) return;\n\n const centrifuge = client.getCentrifuge();\n\n const handleConnected = () => {\n const now = moment.utc().valueOf();\n addMessage({\n id: `conn-${now}`,\n timestamp: now,\n type: 'connection',\n level: 'success',\n message: 'Connected to Centrifugo',\n });\n };\n\n const handleDisconnected = () => {\n const now = moment.utc().valueOf();\n addMessage({\n id: `disconn-${now}`,\n timestamp: now,\n type: 'connection',\n level: 'error',\n message: 'Disconnected from Centrifugo',\n });\n };\n\n const handleError = (ctx: any) => {\n const now = moment.utc().valueOf();\n addMessage({\n id: `error-${now}`,\n timestamp: now,\n type: 'error',\n level: 'error',\n message: ctx.error?.message || 'Connection error',\n data: ctx,\n });\n };\n\n centrifuge.on('connected', handleConnected);\n centrifuge.on('disconnected', handleDisconnected);\n centrifuge.on('error', handleError);\n\n return () => {\n centrifuge.off('connected', handleConnected);\n centrifuge.off('disconnected', handleDisconnected);\n centrifuge.off('error', handleError);\n };\n }, [client, addMessage]);\n\n // Listen to subscription events\n useEffect(() => {\n if (!client) return;\n\n const centrifuge = client.getCentrifuge();\n\n const handleSubscribed = (ctx: any) => {\n const now = moment.utc().valueOf();\n addMessage({\n id: `sub-${now}`,\n timestamp: now,\n type: 'subscription',\n level: 'info',\n channel: ctx.channel,\n message: `Subscribed to ${ctx.channel}`,\n data: ctx,\n });\n };\n\n const handleUnsubscribed = (ctx: any) => {\n const now = moment.utc().valueOf();\n addMessage({\n id: `unsub-${now}`,\n timestamp: now,\n type: 'unsubscription',\n level: 'info',\n channel: ctx.channel,\n message: `Unsubscribed from ${ctx.channel}`,\n data: ctx,\n });\n };\n\n const handlePublication = (ctx: any) => {\n const now = moment.utc().valueOf();\n addMessage({\n id: `pub-${now}-${Math.random()}`,\n timestamp: now,\n type: 'publication',\n level: 'success',\n channel: ctx.channel,\n message: `Message from ${ctx.channel}`,\n data: ctx.data,\n });\n };\n\n centrifuge.on('subscribed', handleSubscribed);\n centrifuge.on('unsubscribed', handleUnsubscribed);\n centrifuge.on('publication', handlePublication);\n\n return () => {\n centrifuge.off('subscribed', handleSubscribed);\n centrifuge.off('unsubscribed', handleUnsubscribed);\n centrifuge.off('publication', handlePublication);\n };\n }, [client, addMessage]);\n\n // Auto-scroll to top when new messages arrive\n useEffect(() => {\n if (autoScroll && scrollRef.current) {\n scrollRef.current.scrollTop = 0;\n }\n }, [messages, autoScroll]);\n\n // Filter and prepare messages with pre-computed values\n const filteredMessages = useMemo(() => {\n return messages\n .filter((msg) => {\n if (filters.channels && filters.channels.length > 0) {\n if (!msg.channel || !filters.channels.includes(msg.channel)) {\n return false;\n }\n }\n\n if (filters.types && filters.types.length > 0) {\n if (!filters.types.includes(msg.type)) {\n return false;\n }\n }\n\n if (filters.levels && filters.levels.length > 0) {\n if (!filters.levels.includes(msg.level)) {\n return false;\n }\n }\n\n if (filters.searchQuery) {\n const query = filters.searchQuery.toLowerCase();\n const searchableText = [\n msg.message,\n msg.channel,\n JSON.stringify(msg.data),\n ]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n\n if (!searchableText.includes(query)) {\n return false;\n }\n }\n\n return true;\n })\n .map((msg) => ({\n ...msg,\n formattedTime: moment.utc(msg.timestamp).format('HH:mm:ss'),\n formattedData: msg.data ? JSON.stringify(msg.data, null, 2) : null,\n }));\n }, [messages, filters]);\n\n // Clear messages\n const handleClear = () => {\n setMessages([]);\n };\n\n // Download messages\n const handleDownload = () => {\n const json = JSON.stringify(filteredMessages, null, 2);\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `centrifugo-messages-${moment.utc().format('YYYY-MM-DD-HHmmss')}.json`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n };\n\n // Get icon for message level\n const getLevelIcon = (level: CentrifugoMessage['level']) => {\n switch (level) {\n case 'error':\n return <AlertCircle className=\"h-4 w-4 text-red-500\" />;\n case 'warning':\n return <AlertCircle className=\"h-4 w-4 text-yellow-500\" />;\n case 'success':\n return <CheckCircle2 className=\"h-4 w-4 text-green-500\" />;\n case 'info':\n return <Info className=\"h-4 w-4 text-blue-500\" />;\n default:\n return <Circle className=\"h-4 w-4 text-gray-500\" />;\n }\n };\n\n // Get badge variant for level\n const getLevelVariant = (level: CentrifugoMessage['level']): 'default' | 'destructive' | 'outline' | 'secondary' => {\n switch (level) {\n case 'error':\n return 'destructive';\n case 'warning':\n return 'secondary';\n case 'success':\n return 'outline';\n default:\n return 'default';\n }\n };\n\n return (\n <Card className={className}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"flex items-center gap-2\">\n <Activity className=\"h-5 w-5\" />\n Messages Feed\n <Badge variant=\"outline\">{filteredMessages.length}</Badge>\n </CardTitle>\n\n {showControls && (\n <div className=\"flex items-center gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => setIsPaused(!isPaused)}\n >\n {isPaused ? (\n <Play className=\"h-4 w-4\" />\n ) : (\n <Pause className=\"h-4 w-4\" />\n )}\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={handleClear}\n disabled={messages.length === 0}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={handleDownload}\n disabled={filteredMessages.length === 0}\n >\n <Download className=\"h-4 w-4\" />\n </Button>\n </div>\n )}\n </div>\n </CardHeader>\n\n <CardContent className=\"space-y-4\">\n {showFilters && (\n <MessageFiltersComponent\n filters={filters}\n onFiltersChange={setFilters}\n autoScroll={autoScroll}\n onAutoScrollChange={setAutoScroll}\n />\n )}\n\n <ScrollArea className=\"h-[400px]\" viewportRef={scrollRef}>\n {filteredMessages.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <Activity className=\"h-12 w-12 text-muted-foreground mb-4\" />\n <p className=\"text-sm text-muted-foreground\">\n {isPaused ? 'Paused - Click play to resume' : 'No messages yet'}\n </p>\n </div>\n ) : (\n <div className=\"space-y-2\">\n {filteredMessages.map((msg) => (\n <div\n key={msg.id}\n className=\"p-3 rounded border hover:bg-muted/50 transition-colors cursor-pointer\"\n onClick={() => onMessageClick?.(msg)}\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-shrink-0 mt-0.5\">{getLevelIcon(msg.level)}</div>\n <div className=\"flex-1 min-w-0 space-y-1\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <Badge variant={getLevelVariant(msg.level)} className=\"text-xs\">\n {msg.type}\n </Badge>\n {msg.channel && (\n <Badge variant=\"outline\" className=\"text-xs\">\n {msg.channel}\n </Badge>\n )}\n <span className=\"text-xs text-muted-foreground\">\n {msg.formattedTime}\n </span>\n </div>\n {msg.message && (\n <p className=\"text-sm break-words\">{msg.message}</p>\n )}\n {msg.formattedData && (\n <details className=\"text-xs\">\n <summary className=\"cursor-pointer text-muted-foreground hover:text-foreground\">\n View data\n </summary>\n <pre className=\"mt-2 p-2 bg-muted rounded overflow-x-auto\">\n {msg.formattedData}\n </pre>\n </details>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n </Card>\n );\n}\n\n","/**\n * Subscriptions List Component\n *\n * Displays active Centrifugo subscriptions with status and controls\n */\n\n'use client';\n\nimport { Subscription, SubscriptionState } from 'centrifuge';\nimport { Radio, RefreshCw, Trash2 } from 'lucide-react';\nimport React, { useEffect, useState } from 'react';\n\nimport {\n Badge, Button, Card, CardContent, CardHeader, CardTitle, ScrollArea\n} from '@djangocfg/ui-nextjs';\n\nimport { getConsolaLogger } from '../../core/logger/consolaLogger';\nimport { useCentrifugo } from '../../providers/CentrifugoProvider';\n\nconst logger = getConsolaLogger('SubscriptionsList');\n\n// ─────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────\n\ninterface SubscriptionItem {\n channel: string;\n state: SubscriptionState;\n}\n\nexport interface SubscriptionsListProps {\n showControls?: boolean;\n onSubscriptionClick?: (channel: string) => void;\n className?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function SubscriptionsList({\n showControls = true,\n onSubscriptionClick,\n className = '',\n}: SubscriptionsListProps) {\n const { isConnected, client } = useCentrifugo();\n const [subscriptions, setSubscriptions] = useState<SubscriptionItem[]>([]);\n\n // Update subscriptions list\n const updateSubscriptions = () => {\n if (!client || !isConnected) {\n setSubscriptions([]);\n return;\n }\n\n try {\n const centrifuge = client.getCentrifuge();\n const subs = centrifuge.subscriptions();\n const subscriptionsList: SubscriptionItem[] = [];\n \n for (const [channel, sub] of Object.entries(subs)) {\n subscriptionsList.push({\n channel,\n state: sub.state,\n });\n }\n \n setSubscriptions(subscriptionsList);\n } catch (error) {\n logger.error('Failed to get subscriptions', error);\n setSubscriptions([]);\n }\n };\n\n // Auto-update subscriptions\n useEffect(() => {\n updateSubscriptions();\n\n if (!client) return;\n\n const centrifuge = client.getCentrifuge();\n\n const handleSubscribed = () => updateSubscriptions();\n const handleUnsubscribed = () => updateSubscriptions();\n\n centrifuge.on('subscribed', handleSubscribed);\n centrifuge.on('unsubscribed', handleUnsubscribed);\n\n const interval = setInterval(updateSubscriptions, 3000);\n\n return () => {\n centrifuge.off('subscribed', handleSubscribed);\n centrifuge.off('unsubscribed', handleUnsubscribed);\n clearInterval(interval);\n };\n }, [client, isConnected]);\n\n // Unsubscribe from channel\n const handleUnsubscribe = async (channel: string) => {\n if (!client) return;\n\n try {\n await client.unsubscribe(channel);\n updateSubscriptions();\n } catch (error) {\n logger.error('Failed to unsubscribe', error);\n }\n };\n\n return (\n <Card className={className}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"flex items-center gap-2\">\n <Radio className=\"h-5 w-5\" />\n Active Subscriptions\n <Badge variant=\"outline\">{subscriptions.length}</Badge>\n </CardTitle>\n\n {showControls && (\n <Button size=\"sm\" variant=\"outline\" onClick={updateSubscriptions}>\n <RefreshCw className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n </CardHeader>\n\n <CardContent>\n {!isConnected ? (\n <div className=\"text-center py-8 text-sm text-muted-foreground\">\n Not connected to Centrifugo\n </div>\n ) : subscriptions.length === 0 ? (\n <div className=\"text-center py-8 text-sm text-muted-foreground\">\n No active subscriptions\n </div>\n ) : (\n <ScrollArea className=\"h-[300px]\">\n <div className=\"space-y-2\">\n {subscriptions.map((sub) => (\n <div\n key={sub.channel}\n className=\"flex items-center justify-between p-3 rounded border hover:bg-muted/50 transition-colors\"\n >\n <div\n className=\"flex-1 min-w-0 cursor-pointer\"\n onClick={() => onSubscriptionClick?.(sub.channel)}\n >\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {sub.state}\n </Badge>\n <span className=\"text-sm font-mono truncate\">{sub.channel}</span>\n </div>\n </div>\n\n {showControls && (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => handleUnsubscribe(sub.channel)}\n >\n <Trash2 className=\"h-4 w-4 text-destructive\" />\n </Button>\n )}\n </div>\n ))}\n </div>\n </ScrollArea>\n )}\n </CardContent>\n </Card>\n );\n}\n\n","/**\n * Centrifugo Monitor Component\n *\n * Universal monitoring component that can be embedded anywhere\n * Combines ConnectionStatus, MessagesFeed, and SubscriptionsList\n */\n\n'use client';\n\nimport React from 'react';\n\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '@djangocfg/ui-nextjs';\n\nimport { ConnectionStatus } from '../ConnectionStatus';\nimport { MessagesFeed } from '../MessagesFeed';\nimport { SubscriptionsList } from '../SubscriptionsList';\n\nimport type { CentrifugoMessage } from '../MessagesFeed';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface CentrifugoMonitorProps {\n variant?: 'compact' | 'full' | 'minimal';\n showConnectionStatus?: boolean;\n showMessagesFeed?: boolean;\n showSubscriptions?: boolean;\n showFilters?: boolean;\n showControls?: boolean;\n maxMessages?: number;\n channels?: string[]; // Pre-filter by channels\n autoScroll?: boolean;\n onMessageClick?: (message: CentrifugoMessage) => void;\n onSubscriptionClick?: (channel: string) => void;\n className?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function CentrifugoMonitor({\n variant = 'full',\n showConnectionStatus = true,\n showMessagesFeed = true,\n showSubscriptions = true,\n showFilters = true,\n showControls = true,\n maxMessages = 100,\n channels = [],\n autoScroll = true,\n onMessageClick,\n onSubscriptionClick,\n className = '',\n}: CentrifugoMonitorProps) {\n // Minimal variant - only connection status\n if (variant === 'minimal') {\n return (\n <div className={className}>\n <ConnectionStatus variant=\"detailed\" showUptime showSubscriptions />\n </div>\n );\n }\n\n // Compact variant - connection status + messages feed\n if (variant === 'compact') {\n return (\n <div className={`space-y-4 ${className}`}>\n {showConnectionStatus && (\n <ConnectionStatus variant=\"detailed\" showUptime showSubscriptions />\n )}\n {showMessagesFeed && (\n <MessagesFeed\n maxMessages={maxMessages}\n showFilters={false}\n showControls={showControls}\n channels={channels}\n autoScroll={autoScroll}\n onMessageClick={onMessageClick}\n />\n )}\n </div>\n );\n }\n\n // Full variant - tabs with all features\n const tabsToShow = [\n showConnectionStatus && { value: 'connection', label: 'Connection' },\n showMessagesFeed && { value: 'messages', label: 'Messages' },\n showSubscriptions && { value: 'subscriptions', label: 'Subscriptions' },\n ].filter(Boolean) as { value: string; label: string }[];\n\n if (tabsToShow.length === 0) {\n return null;\n }\n\n return (\n <div className={className}>\n <Tabs defaultValue={tabsToShow[0].value}>\n <TabsList className={`grid w-full grid-cols-${tabsToShow.length}`}>\n {tabsToShow.map((tab) => (\n <TabsTrigger key={tab.value} value={tab.value}>\n {tab.label}\n </TabsTrigger>\n ))}\n </TabsList>\n\n {showConnectionStatus && (\n <TabsContent value=\"connection\" className=\"mt-4\">\n <ConnectionStatus variant=\"detailed\" showUptime showSubscriptions />\n </TabsContent>\n )}\n\n {showMessagesFeed && (\n <TabsContent value=\"messages\" className=\"mt-4\">\n <MessagesFeed\n maxMessages={maxMessages}\n showFilters={showFilters}\n showControls={showControls}\n channels={channels}\n autoScroll={autoScroll}\n onMessageClick={onMessageClick}\n />\n </TabsContent>\n )}\n\n {showSubscriptions && (\n <TabsContent value=\"subscriptions\" className=\"mt-4\">\n <SubscriptionsList\n showControls={showControls}\n onSubscriptionClick={onSubscriptionClick}\n />\n </TabsContent>\n )}\n </Tabs>\n </div>\n );\n}\n\n","/**\n * Centrifugo Monitor Dialog Component\n *\n * Sheet/Dialog wrapper for CentrifugoMonitor\n * Uses event-driven approach - listens to OPEN_MONITOR_DIALOG event\n */\n\n'use client';\n\nimport { Activity } from 'lucide-react';\nimport React, { useState } from 'react';\n\nimport { useEventListener } from '@djangocfg/ui-core/hooks';\nimport {\n Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle\n} from '@djangocfg/ui-nextjs';\n\nimport { CENTRIFUGO_MONITOR_EVENTS, OpenMonitorDialogPayload} from '../../events';\nimport { CentrifugoMonitor } from './CentrifugoMonitor';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function CentrifugoMonitorDialog() {\n const [open, setOpen] = useState(false);\n const [variant, setVariant] = useState<'compact' | 'full' | 'minimal'>('full');\n\n // Listen for dialog open event\n useEventListener<typeof CENTRIFUGO_MONITOR_EVENTS.OPEN_MONITOR_DIALOG, OpenMonitorDialogPayload>(\n CENTRIFUGO_MONITOR_EVENTS.OPEN_MONITOR_DIALOG,\n (payload) => {\n if (payload?.variant) {\n setVariant(payload.variant);\n }\n setOpen(true);\n }\n );\n\n // Listen for dialog close event\n useEventListener(\n CENTRIFUGO_MONITOR_EVENTS.CLOSE_MONITOR_DIALOG,\n () => {\n setOpen(false);\n }\n );\n\n const handleClose = () => {\n setOpen(false);\n };\n\n return (\n <Sheet open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>\n <SheetContent \n side=\"right\" \n className=\"max-w-2xl w-[90vw] sm:w-[672px]\"\n >\n <SheetHeader>\n <SheetTitle className=\"flex items-center gap-2\">\n <Activity className=\"h-5 w-5\" />\n Centrifugo Monitor\n </SheetTitle>\n <SheetDescription>\n Real-time WebSocket monitoring and debugging\n </SheetDescription>\n </SheetHeader>\n\n <div className=\"mt-6\">\n <CentrifugoMonitor variant={variant} />\n </div>\n </SheetContent>\n </Sheet>\n );\n}\n\n","/**\n * Centrifugo Package Configuration\n */\n\nexport const isDevelopment = process.env.NODE_ENV === 'development';\nexport const isProduction = !isDevelopment;\nexport const isStaticBuild = process.env.NEXT_PUBLIC_STATIC_BUILD === 'true';\n\nconst showDebugPanel = isDevelopment && !isStaticBuild;\n\n/**\n * Reconnect configuration with exponential backoff\n */\nexport const reconnectConfig = {\n // Initial delay before first reconnect attempt (ms)\n initialDelay: isDevelopment ? 2000 : 1000,\n // Maximum delay between reconnect attempts (ms)\n maxDelay: isDevelopment ? 30000 : 60000,\n // Multiplier for exponential backoff\n multiplier: 1.5,\n // Maximum number of reconnect attempts\n // Dev: 3 attempts then stop (server probably not running)\n // Prod: 10 attempts then stop (avoid infinite reconnection spam)\n maxAttempts: isDevelopment ? 3 : 10,\n // Jitter factor to randomize delays (0-1)\n jitter: 0.1,\n} as const;\n\nexport const centrifugoConfig = {\n // Show debug panel only in development and not in static builds\n showDebugPanel,\n // Reconnect settings\n reconnect: reconnectConfig,\n} as const;\n\nexport type CentrifugoConfig = typeof centrifugoConfig;\nexport type ReconnectConfig = typeof reconnectConfig;\n","/**\n * Logs Provider\n *\n * Provides access to accumulated logs via React Context.\n * Wraps LogsStore and exposes logs + controls.\n */\n\n'use client';\n\nimport {\n createContext, ReactNode, useCallback, useContext, useEffect, useState\n} from 'react';\n\nimport { getGlobalLogsStore } from '../../core/logger';\n\nimport type { LogEntry, LogLevel } from '../../core/types';\n// ─────────────────────────────────────────────────────────────────────────\n// Context\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface LogsContextValue {\n logs: LogEntry[];\n filteredLogs: LogEntry[];\n filter: LogsFilter;\n setFilter: (filter: Partial<LogsFilter>) => void;\n clearLogs: () => void;\n count: number;\n}\n\nexport interface LogsFilter {\n level?: LogLevel;\n source?: LogEntry['source'];\n search?: string;\n}\n\nconst LogsContext = createContext<LogsContextValue | undefined>(undefined);\n\n// ─────────────────────────────────────────────────────────────────────────\n// Provider\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface LogsProviderProps {\n children: ReactNode;\n}\n\nexport function LogsProvider({ children }: LogsProviderProps) {\n const [logs, setLogs] = useState<LogEntry[]>([]);\n const [filter, setFilterState] = useState<LogsFilter>({});\n\n const logsStore = getGlobalLogsStore();\n\n // Subscribe to log changes\n useEffect(() => {\n // Initial load\n setLogs(logsStore.getAll());\n\n // Subscribe to updates\n const unsubscribe = logsStore.subscribe((updatedLogs) => {\n setLogs(updatedLogs);\n });\n\n return unsubscribe;\n }, [logsStore]);\n\n // Filter logs\n const filteredLogs = logs.filter((log) => {\n if (filter.level && log.level !== filter.level) return false;\n if (filter.source && log.source !== filter.source) return false;\n if (filter.search) {\n const searchLower = filter.search.toLowerCase();\n return log.message.toLowerCase().includes(searchLower);\n }\n return true;\n });\n\n // Set filter (merge with existing)\n const setFilter = useCallback((partialFilter: Partial<LogsFilter>) => {\n setFilterState((prev) => ({ ...prev, ...partialFilter }));\n }, []);\n\n // Clear all logs\n const clearLogs = useCallback(() => {\n logsStore.clear();\n }, [logsStore]);\n\n const value: LogsContextValue = {\n logs,\n filteredLogs,\n filter,\n setFilter,\n clearLogs,\n count: logs.length,\n };\n\n return <LogsContext.Provider value={value}>{children}</LogsContext.Provider>;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Hook\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function useLogs(): LogsContextValue {\n const context = useContext(LogsContext);\n\n if (context === undefined) {\n throw new Error('useLogs must be used within a LogsProvider');\n }\n\n return context;\n}\n","/**\n * Centrifugo Provider\n *\n * Main provider that manages WebSocket connection.\n * Wraps LogsProvider to provide logs accumulation.\n */\n\n'use client';\n\nimport {\n createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState\n} from 'react';\n\nimport { useAuth } from '@djangocfg/api/auth';\n\nimport {\n CentrifugoMonitorDialog\n} from '../../components/CentrifugoMonitor/CentrifugoMonitorDialog';\nimport { isDevelopment, isStaticBuild, reconnectConfig } from '../../config';\nimport { CentrifugoRPCClient } from '../../core/client';\nimport { getConsolaLogger } from '../../core/logger/consolaLogger';\nimport { useCodegenTip } from '../../hooks/useCodegenTip';\nimport { usePageVisibility } from '../../hooks/usePageVisibility';\nimport { LogsProvider } from '../LogsProvider';\n\nimport type { ConnectionState, CentrifugoToken, ActiveSubscription } from '../../core/types';\n// ─────────────────────────────────────────────────────────────────────────\n// Context\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface CentrifugoContextValue {\n // Client\n client: CentrifugoRPCClient | null;\n\n // Connection State\n isConnected: boolean;\n isConnecting: boolean;\n error: Error | null;\n connectionState: ConnectionState;\n\n // Connection Info\n uptime: number; // seconds\n subscriptions: string[];\n activeSubscriptions: ActiveSubscription[];\n\n // Controls\n connect: () => Promise<void>;\n disconnect: () => void;\n reconnect: () => Promise<void>;\n unsubscribe: (channel: string) => void;\n\n // Config\n enabled: boolean;\n}\n\nconst CentrifugoContext = createContext<CentrifugoContextValue | undefined>(undefined);\n\n// ─────────────────────────────────────────────────────────────────────────\n// Provider Props\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface CentrifugoProviderProps {\n children: ReactNode;\n enabled?: boolean;\n url?: string;\n autoConnect?: boolean;\n /**\n * Callback to refresh the Centrifugo token when it expires.\n * If provided, centrifuge-js will automatically call this when token expires.\n * Should return a fresh JWT token string.\n *\n * @example\n * onTokenRefresh={async () => {\n * const response = await getCentrifugoAuthTokenRetrieve();\n * return response.token;\n * }}\n */\n onTokenRefresh?: () => Promise<string>;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Inner Provider (has access to LogsProvider)\n// ─────────────────────────────────────────────────────────────────────────\n\nfunction CentrifugoProviderInner({\n children,\n enabled = false,\n url,\n autoConnect: autoConnectProp = true,\n onTokenRefresh,\n}: CentrifugoProviderProps) {\n // useAuth is SSR-safe - returns default state when outside AuthProvider\n const { isAuthenticated, isLoading, user } = useAuth();\n\n const [client, setClient] = useState<CentrifugoRPCClient | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n const [isConnecting, setIsConnecting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [connectionTime, setConnectionTime] = useState<Date | null>(null);\n const [uptime, setUptime] = useState<number>(0);\n const [subscriptions, setSubscriptions] = useState<string[]>([]);\n const [activeSubscriptions, setActiveSubscriptions] = useState<ActiveSubscription[]>([]);\n\n const logger = useMemo(() => getConsolaLogger('provider'), []);\n\n // Show dev tip about client generation\n useCodegenTip();\n\n const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const hasConnectedRef = useRef(false);\n const isConnectingRef = useRef(false);\n const isMountedRef = useRef(true);\n const reconnectAttemptRef = useRef(0);\n const reconnectStoppedRef = useRef(false); // Track if we should stop reconnecting\n const devWarningShownRef = useRef(false); // Track if server unavailable warning was shown\n const connectRef = useRef<(() => Promise<void>) | null>(null);\n const disconnectRef = useRef<(() => void) | null>(null);\n const wasConnectedBeforeHiddenRef = useRef(false); // Track connection state before page hidden\n const clientInstanceRef = useRef<CentrifugoRPCClient | null>(null); // Stable client reference for reconnection\n\n const centrifugoToken: CentrifugoToken | undefined = user?.centrifugo;\n const hasCentrifugoToken = !!centrifugoToken?.token;\n\n // Calculate reconnect delay with exponential backoff\n const getReconnectDelay = useCallback((attempt: number): number => {\n const { initialDelay, maxDelay, multiplier, jitter } = reconnectConfig;\n\n // Exponential backoff: initialDelay * multiplier^attempt\n let delay = initialDelay * Math.pow(multiplier, attempt);\n\n // Cap at maxDelay\n delay = Math.min(delay, maxDelay);\n\n // Add jitter to prevent thundering herd\n const jitterAmount = delay * jitter * (Math.random() * 2 - 1);\n delay = Math.round(delay + jitterAmount);\n\n return delay;\n }, []);\n\n const wsUrl = useMemo(() => {\n if (url) return url;\n if (centrifugoToken?.centrifugo_url) return centrifugoToken.centrifugo_url;\n return '';\n }, [url, centrifugoToken?.centrifugo_url]);\n\n const autoConnect = autoConnectProp &&\n (isAuthenticated && !isLoading) &&\n enabled &&\n hasCentrifugoToken;\n\n // Log connection decision\n useEffect(() => {\n if (!isLoading) {\n logger.info(`Auto-connect: ${autoConnect ? 'YES' : 'NO'}`, {\n authenticated: isAuthenticated,\n loading: isLoading,\n enabled,\n hasToken: hasCentrifugoToken,\n url: wsUrl,\n });\n }\n }, [autoConnect, isAuthenticated, isLoading, enabled, hasCentrifugoToken, logger, wsUrl]);\n\n // Update uptime every second\n useEffect(() => {\n if (!isConnected || !connectionTime) {\n setUptime(0);\n return;\n }\n\n const updateUptime = () => {\n const now = new Date();\n const diff = Math.floor((now.getTime() - connectionTime.getTime()) / 1000);\n setUptime(diff);\n };\n\n updateUptime();\n const interval = setInterval(updateUptime, 1000);\n\n return () => clearInterval(interval);\n }, [isConnected, connectionTime]);\n\n // Update subscriptions periodically\n useEffect(() => {\n if (!client || !isConnected) {\n setSubscriptions([]);\n setActiveSubscriptions([]);\n return;\n }\n\n const updateSubs = () => {\n try {\n const subs = client.getAllSubscriptions?.() || [];\n setSubscriptions(subs);\n\n // Convert to ActiveSubscription format\n const activeSubs: ActiveSubscription[] = subs.map((channel) => ({\n channel,\n type: 'client' as const,\n subscribedAt: Date.now(),\n }));\n setActiveSubscriptions(activeSubs);\n } catch (error) {\n logger.error('Failed to get subscriptions', error);\n }\n };\n\n updateSubs();\n const interval = setInterval(updateSubs, 2000);\n\n return () => clearInterval(interval);\n }, [client, isConnected, logger]);\n\n // Connect function\n const connect = useCallback(async () => {\n // Don't reconnect if we've decided to stop (dev mode hit max attempts)\n if (reconnectStoppedRef.current) return;\n if (hasConnectedRef.current || isConnectingRef.current) return;\n if (isConnecting || isConnected) return;\n\n isConnectingRef.current = true;\n setIsConnecting(true);\n setError(null);\n\n try {\n // Check if we can reuse existing client (reconnection scenario)\n if (clientInstanceRef.current) {\n logger.info('Reconnecting to WebSocket server (reusing client)...');\n await clientInstanceRef.current.connect();\n\n if (!isMountedRef.current) {\n isConnectingRef.current = false;\n return;\n }\n\n hasConnectedRef.current = true;\n isConnectingRef.current = false;\n\n // Clear any pending reconnect timeout\n if (reconnectTimeoutRef.current) {\n clearTimeout(reconnectTimeoutRef.current);\n reconnectTimeoutRef.current = null;\n }\n\n // Use existing client reference - NO setClient() call to keep reference stable\n setIsConnected(true);\n setConnectionTime(new Date());\n setError(null);\n\n logger.success('WebSocket reconnected');\n\n // Reset reconnect state on successful connection\n reconnectAttemptRef.current = 0;\n devWarningShownRef.current = false;\n reconnectStoppedRef.current = false;\n return;\n }\n\n // First connection - create new client\n logger.info('Connecting to WebSocket server...');\n\n if (!centrifugoToken?.token) {\n throw new Error('No Centrifugo token available');\n }\n\n const token = centrifugoToken.token;\n let userId = user?.id?.toString() || '1';\n\n if (!user?.id) {\n try {\n const tokenPayload = JSON.parse(atob(token.split('.')[1]));\n userId = tokenPayload.user_id?.toString() || tokenPayload.sub?.toString() || '1';\n } catch (err) {\n // Fallback\n }\n }\n\n const rpcClient = new CentrifugoRPCClient({\n url: wsUrl,\n token,\n userId,\n timeout: 30000,\n logger,\n getToken: onTokenRefresh,\n });\n await rpcClient.connect();\n\n if (!isMountedRef.current) {\n rpcClient.disconnect();\n isConnectingRef.current = false;\n return;\n }\n\n hasConnectedRef.current = true;\n isConnectingRef.current = false;\n\n // Clear any pending reconnect timeout\n if (reconnectTimeoutRef.current) {\n clearTimeout(reconnectTimeoutRef.current);\n reconnectTimeoutRef.current = null;\n }\n\n // Store client in ref for future reconnections\n clientInstanceRef.current = rpcClient;\n setClient(rpcClient);\n setIsConnected(true);\n setConnectionTime(new Date());\n setError(null);\n\n logger.success('WebSocket connected');\n\n // Reset reconnect state on successful connection\n reconnectAttemptRef.current = 0;\n devWarningShownRef.current = false;\n reconnectStoppedRef.current = false;\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Connection failed');\n setError(error);\n setClient(null);\n setIsConnected(false);\n setConnectionTime(null);\n hasConnectedRef.current = false;\n isConnectingRef.current = false;\n\n const isAuthError = error.message.includes('token') ||\n error.message.includes('auth') ||\n error.message.includes('expired');\n\n if (isAuthError) {\n logger.error('Authentication failed', error);\n } else {\n // Check if we should attempt reconnect\n const { maxAttempts } = reconnectConfig;\n const currentAttempt = reconnectAttemptRef.current;\n\n // In dev mode: show warning once and stop after maxAttempts\n if (isDevelopment) {\n if (!devWarningShownRef.current) {\n devWarningShownRef.current = true;\n logger.warning(\n '🔌 Centrifugo server is not running. ' +\n 'Start it with: docker compose -f docker-compose-local-services.yml up centrifugo'\n );\n }\n\n // Stop reconnecting after maxAttempts in dev mode\n if (maxAttempts > 0 && currentAttempt >= maxAttempts) {\n reconnectStoppedRef.current = true; // Mark as stopped permanently\n logger.info(`Stopped reconnecting after ${maxAttempts} attempts (dev mode)`);\n return;\n }\n }\n\n // Try to reconnect with exponential backoff (respects maxAttempts)\n if (currentAttempt < maxAttempts) {\n const delay = getReconnectDelay(currentAttempt);\n reconnectAttemptRef.current = currentAttempt + 1;\n\n if (!isDevelopment || currentAttempt < 2) {\n // Only log in prod, or first 2 attempts in dev\n logger.info(`Reconnecting in ${Math.round(delay / 1000)}s (attempt ${currentAttempt + 1}/${maxAttempts})...`);\n }\n\n reconnectTimeoutRef.current = setTimeout(() => {\n connectRef.current?.();\n }, delay);\n } else {\n // Max attempts reached - stop reconnecting\n reconnectStoppedRef.current = true;\n logger.warning(`Stopped reconnecting after ${maxAttempts} attempts. WebSocket server may be unavailable.`);\n }\n }\n } finally {\n setIsConnecting(false);\n }\n }, [wsUrl, centrifugoToken, user, logger, isConnecting, isConnected, getReconnectDelay, onTokenRefresh]);\n\n // Disconnect function\n const disconnect = useCallback(() => {\n if (isConnectingRef.current) return;\n\n if (reconnectTimeoutRef.current) {\n clearTimeout(reconnectTimeoutRef.current);\n reconnectTimeoutRef.current = null;\n }\n\n if (client) {\n logger.info('Disconnecting from WebSocket server...');\n client.disconnect();\n setClient(null);\n setIsConnected(false);\n setConnectionTime(null);\n setError(null);\n setSubscriptions([]);\n }\n\n hasConnectedRef.current = false;\n isConnectingRef.current = false;\n reconnectAttemptRef.current = 0;\n devWarningShownRef.current = false;\n reconnectStoppedRef.current = false; // Reset so manual reconnect works\n }, [client, logger]);\n\n // Reconnect function\n const reconnect = useCallback(async () => {\n disconnect();\n await connect();\n }, [connect, disconnect]);\n\n // Unsubscribe function\n const unsubscribe = useCallback((channel: string) => {\n if (!client) {\n logger.warning('Cannot unsubscribe: client not connected');\n return;\n }\n\n try {\n client.unsubscribe?.(channel);\n logger.info(`Unsubscribed from channel: ${channel}`);\n\n // Update state immediately\n setSubscriptions((prev) => prev.filter((ch) => ch !== channel));\n setActiveSubscriptions((prev) => prev.filter((sub) => sub.channel !== channel));\n } catch (error) {\n logger.error(`Failed to unsubscribe from ${channel}`, error);\n }\n }, [client, logger]);\n\n // Keep refs up-to-date\n connectRef.current = connect;\n disconnectRef.current = disconnect;\n\n // Auto-connect on mount - uses refs to avoid recreation issues\n useEffect(() => {\n isMountedRef.current = true;\n\n if (autoConnect && !hasConnectedRef.current && !reconnectStoppedRef.current) {\n connectRef.current?.();\n }\n\n return () => {\n if (isConnectingRef.current && !hasConnectedRef.current) {\n return;\n }\n\n if (!hasConnectedRef.current) {\n return;\n }\n\n isMountedRef.current = false;\n disconnectRef.current?.();\n };\n }, [autoConnect]); // Only depend on autoConnect, not on connect/disconnect\n\n // ==========================================================================\n // PAGE VISIBILITY HANDLING\n // ==========================================================================\n // When tab becomes hidden: pause reconnect attempts (save battery)\n // When tab becomes visible: trigger reconnect if needed\n\n usePageVisibility({\n onHidden: () => {\n // Save connection state before hiding\n wasConnectedBeforeHiddenRef.current = isConnected;\n\n // Pause reconnect attempts while tab is hidden (save battery)\n if (reconnectTimeoutRef.current) {\n clearTimeout(reconnectTimeoutRef.current);\n reconnectTimeoutRef.current = null;\n logger.debug('Paused reconnect attempts (tab hidden)');\n }\n },\n onVisible: () => {\n // Only attempt reconnect if:\n // 1. We should auto-connect\n // 2. We're not already connected or connecting\n // 3. We haven't stopped reconnecting\n // 4. We were previously connected (or never connected yet)\n const shouldReconnect =\n autoConnect &&\n !isConnected &&\n !isConnectingRef.current &&\n !reconnectStoppedRef.current &&\n (wasConnectedBeforeHiddenRef.current || !hasConnectedRef.current);\n\n if (shouldReconnect) {\n // Reset reconnect attempts for fresh start\n reconnectAttemptRef.current = 0;\n devWarningShownRef.current = false;\n\n logger.info('Tab visible - attempting reconnect...');\n connectRef.current?.();\n } else if (isConnected) {\n logger.debug('Tab visible - connection still active');\n }\n },\n });\n\n const connectionState: ConnectionState = isConnected\n ? 'connected'\n : isConnecting\n ? 'connecting'\n : error\n ? 'error'\n : 'disconnected';\n\n const value: CentrifugoContextValue = {\n client,\n isConnected,\n isConnecting,\n error,\n connectionState,\n uptime,\n subscriptions,\n activeSubscriptions,\n connect,\n disconnect,\n reconnect,\n unsubscribe,\n enabled,\n };\n\n return (\n <CentrifugoContext.Provider value={value}>\n {children}\n </CentrifugoContext.Provider>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Main Provider (wraps LogsProvider and includes Dialog)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function CentrifugoProvider(props: CentrifugoProviderProps) {\n return (\n <LogsProvider>\n <CentrifugoProviderInner {...props}>\n {props.children}\n <CentrifugoMonitorDialog />\n </CentrifugoProviderInner>\n </LogsProvider>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Hook\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function useCentrifugo(): CentrifugoContextValue {\n const context = useContext(CentrifugoContext);\n\n if (context === undefined) {\n throw new Error('useCentrifugo must be used within a CentrifugoProvider');\n }\n\n return context;\n}\n","/**\n * Connection Status Component\n *\n * Universal component for displaying Centrifugo connection status\n * Supports multiple variants: badge, inline, card, detailed\n */\n\n'use client';\n\nimport { Clock, Radio, Wifi, WifiOff } from 'lucide-react';\nimport moment from 'moment';\nimport React, { useEffect, useState } from 'react';\n\nimport { Badge } from '@djangocfg/ui-nextjs';\n\nimport { getConsolaLogger } from '../../core/logger/consolaLogger';\nimport { useCentrifugo } from '../../providers/CentrifugoProvider';\n\nconst logger = getConsolaLogger('ConnectionStatus');\n\n// ─────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface ConnectionStatusProps {\n variant?: 'badge' | 'inline' | 'detailed';\n showUptime?: boolean;\n showSubscriptions?: boolean;\n className?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function ConnectionStatus({\n variant = 'badge',\n showUptime = false,\n showSubscriptions = false,\n className = '',\n}: ConnectionStatusProps) {\n const { isConnected, client } = useCentrifugo();\n const [connectionTime, setConnectionTime] = useState<moment.Moment | null>(null);\n const [uptime, setUptime] = useState<string>('');\n const [activeSubscriptions, setActiveSubscriptions] = useState<number>(0);\n\n // Track connection time\n useEffect(() => {\n if (isConnected && !connectionTime) {\n setConnectionTime(moment.utc());\n } else if (!isConnected) {\n setConnectionTime(null);\n }\n }, [isConnected, connectionTime]);\n\n // Update uptime every second\n useEffect(() => {\n if (!isConnected || !connectionTime) {\n setUptime('');\n return;\n }\n\n const updateUptime = () => {\n const now = moment.utc();\n const duration = moment.duration(now.diff(connectionTime));\n\n const hours = Math.floor(duration.asHours());\n const minutes = duration.minutes();\n const seconds = duration.seconds();\n\n if (hours > 0) {\n setUptime(`${hours}h ${minutes}m`);\n } else if (minutes > 0) {\n setUptime(`${minutes}m ${seconds}s`);\n } else {\n setUptime(`${seconds}s`);\n }\n };\n\n updateUptime();\n const interval = setInterval(updateUptime, 1000);\n\n return () => clearInterval(interval);\n }, [isConnected, connectionTime]);\n\n // Update active subscriptions count\n useEffect(() => {\n if (!client || !isConnected) {\n setActiveSubscriptions(0);\n return;\n }\n\n const updateCount = () => {\n try {\n const centrifuge = client.getCentrifuge();\n const subs = centrifuge.subscriptions();\n setActiveSubscriptions(Object.keys(subs).length);\n } catch (error) {\n logger.error('Failed to get active subscriptions', error);\n }\n };\n\n updateCount();\n const interval = setInterval(updateCount, 2000);\n\n return () => clearInterval(interval);\n }, [client, isConnected]);\n\n // Badge variant\n if (variant === 'badge') {\n return (\n <Badge\n variant={isConnected ? 'default' : 'destructive'}\n className={`flex items-center gap-1 ${isConnected ? 'animate-pulse' : ''} ${className}`}\n >\n <span className={`h-2 w-2 rounded-full ${isConnected ? 'bg-green-500' : 'bg-red-500'}`} />\n {isConnected ? 'Connected' : 'Disconnected'}\n </Badge>\n );\n }\n\n // Inline variant\n if (variant === 'inline') {\n return (\n <div className={`flex items-center gap-2 ${className}`}>\n {isConnected ? (\n <Wifi className=\"h-4 w-4 text-green-600\" />\n ) : (\n <WifiOff className=\"h-4 w-4 text-red-600\" />\n )}\n <span className=\"text-sm font-medium\">\n {isConnected ? 'Connected' : 'Disconnected'}\n </span>\n {showUptime && uptime && (\n <span className=\"text-xs text-muted-foreground\">({uptime})</span>\n )}\n {showSubscriptions && (\n <span className=\"text-xs text-muted-foreground flex items-center gap-1\">\n <Radio className=\"h-3 w-3\" />\n {activeSubscriptions}\n </span>\n )}\n </div>\n );\n }\n\n // Detailed variant\n return (\n <div className={`space-y-3 ${className}`}>\n {/* Status Badge */}\n <div className=\"flex items-center gap-2\">\n <Badge\n variant={isConnected ? 'default' : 'destructive'}\n className={`flex items-center gap-1 ${isConnected ? 'animate-pulse' : ''}`}\n >\n <span className={`h-2 w-2 rounded-full ${isConnected ? 'bg-green-500' : 'bg-red-500'}`} />\n {isConnected ? 'Connected' : 'Disconnected'}\n </Badge>\n </div>\n\n {/* Connection Info */}\n {isConnected ? (\n <div className=\"space-y-2\">\n {/* Uptime */}\n {showUptime && uptime && (\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"text-muted-foreground flex items-center gap-1\">\n <Clock className=\"h-3 w-3\" />\n Uptime:\n </span>\n <span className=\"font-mono font-medium\">{uptime}</span>\n </div>\n )}\n\n {/* Active Subscriptions */}\n {showSubscriptions && (\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"text-muted-foreground flex items-center gap-1\">\n <Radio className=\"h-3 w-3\" />\n Subscriptions:\n </span>\n <span className=\"font-mono font-medium\">{activeSubscriptions}</span>\n </div>\n )}\n </div>\n ) : (\n <div className=\"text-xs text-muted-foreground p-2 rounded bg-red-50 dark:bg-red-950/20\">\n Real-time features unavailable\n </div>\n )}\n </div>\n );\n}\n\n","/**\n * Connection Status Card Component\n *\n * Card wrapper for ConnectionStatus - ready for dashboard widgets\n * Clickable - opens CentrifugoMonitorDialog on click via events\n */\n\n'use client';\n\nimport { Wifi, WifiOff } from 'lucide-react';\nimport React from 'react';\n\nimport { Card, CardContent, CardHeader, CardTitle } from '@djangocfg/ui-nextjs';\n\nimport { emitOpenMonitorDialog } from '../../events';\nimport { useCentrifugo } from '../../providers/CentrifugoProvider';\nimport { ConnectionStatus } from './ConnectionStatus';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface ConnectionStatusCardProps {\n showUptime?: boolean;\n showSubscriptions?: boolean;\n className?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function ConnectionStatusCard({\n showUptime = true,\n showSubscriptions = true,\n className = '',\n}: ConnectionStatusCardProps) {\n const { isConnected } = useCentrifugo();\n\n const statusColor = isConnected ? 'border-green-500' : 'border-red-500';\n\n const handleClick = () => {\n emitOpenMonitorDialog({ variant: 'full' });\n };\n\n return (\n <Card \n className={`${statusColor} ${className} cursor-pointer hover:shadow-lg transition-shadow`} \n style={{ borderLeftWidth: '4px' }}\n onClick={handleClick}\n >\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">WebSocket</CardTitle>\n <div className={isConnected ? 'text-green-600' : 'text-red-600'}>\n {isConnected ? <Wifi className=\"h-4 w-4\" /> : <WifiOff className=\"h-4 w-4\" />}\n </div>\n </CardHeader>\n <CardContent>\n <ConnectionStatus\n variant=\"detailed\"\n showUptime={showUptime}\n showSubscriptions={showSubscriptions}\n />\n </CardContent>\n </Card>\n );\n}\n\n","/**\n * Centrifugo Monitor FAB Component\n *\n * Floating Action Button that opens CentrifugoMonitorDialog via events\n * Replaces the old DebugPanel FAB\n */\n\n'use client';\n\nimport { Activity } from 'lucide-react';\nimport React from 'react';\n\nimport { emitOpenMonitorDialog, OpenMonitorDialogPayload} from '../../events';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface CentrifugoMonitorFABProps {\n position?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';\n size?: 'sm' | 'md' | 'lg';\n variant?: OpenMonitorDialogPayload['variant'];\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function CentrifugoMonitorFAB({\n position = 'bottom-left',\n size = 'md',\n variant = 'full',\n}: CentrifugoMonitorFABProps) {\n\n // Position styles\n const positionStyles = {\n 'bottom-left': { bottom: '1rem', left: '1rem' },\n 'bottom-right': { bottom: '1rem', right: '1rem' },\n 'top-left': { top: '1rem', left: '1rem' },\n 'top-right': { top: '1rem', right: '1rem' },\n };\n\n // Size styles\n const sizeStyles = {\n sm: { width: '48px', height: '48px' },\n md: { width: '56px', height: '56px' },\n lg: { width: '64px', height: '64px' },\n };\n\n const iconSizes = {\n sm: 'h-5 w-5',\n md: 'h-6 w-6',\n lg: 'h-7 w-7',\n };\n\n const handleClick = () => {\n emitOpenMonitorDialog({ variant });\n };\n\n return (\n <button\n onClick={handleClick}\n className=\"rounded-full bg-primary text-primary-foreground shadow-lg hover:bg-primary/90 transition-all duration-200 flex items-center justify-center hover:scale-110\"\n style={{\n position: 'fixed',\n ...positionStyles[position],\n ...sizeStyles[size],\n zIndex: 9999,\n }}\n aria-label=\"Open Centrifugo Monitor\"\n >\n <Activity className={iconSizes[size]} />\n </button>\n );\n}\n\n","/**\n * Centrifugo Monitor Widget Component\n *\n * Card-based widget for dashboards\n * Opens monitor dialog via events\n */\n\n'use client';\n\nimport { Activity, Maximize2 } from 'lucide-react';\nimport React from 'react';\n\nimport { Button, Card, CardContent, CardHeader, CardTitle } from '@djangocfg/ui-nextjs';\n\nimport { emitOpenMonitorDialog } from '../../events';\nimport { ConnectionStatus } from '../ConnectionStatus';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface CentrifugoMonitorWidgetProps {\n title?: string;\n showExpandButton?: boolean;\n className?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────\n\nexport function CentrifugoMonitorWidget({\n title = 'WebSocket Monitor',\n showExpandButton = true,\n className = '',\n}: CentrifugoMonitorWidgetProps) {\n const handleExpand = () => {\n emitOpenMonitorDialog({ variant: 'full' });\n };\n\n return (\n <Card className={className}>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium flex items-center gap-2\">\n <Activity className=\"h-4 w-4\" />\n {title}\n </CardTitle>\n {showExpandButton && (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={handleExpand}\n >\n <Maximize2 className=\"h-4 w-4\" />\n </Button>\n )}\n </CardHeader>\n <CardContent>\n <ConnectionStatus variant=\"detailed\" showUptime showSubscriptions />\n </CardContent>\n </Card>\n );\n}\n\n"]}