@cp949/console-feed
v3.7.3
Published
A React component that displays console logs from the current page, an iframe or transported across a server
Maintainers
Readme
console-feed
한국어 | English
A React component that captures and displays browser console output in a user interface. Supports React 18 and 19.
This is a fork of samdenty/console-feed v3.6.0 with security vulnerability fixes.
Current prepared release: 3.7.2
Installation
npm install @cp949/console-feedPackage info: https://www.npmjs.com/package/@cp949/console-feed
Import Paths
The package root keeps the existing public API for compatibility:
import { Console, Hook, Decode, Unhook } from '@cp949/console-feed'
import type { Message, HookedConsole, Methods } from '@cp949/console-feed'Non-UI utilities can also be imported from stable subpaths:
import Hook from '@cp949/console-feed/hook'
import Unhook from '@cp949/console-feed/unhook'
import { Decode, Encode } from '@cp949/console-feed/transform'Chrome 75 Library Artifacts
The library artifacts target Chrome 75. The package neither injects global polyfills nor requires consumers to install core-js.
pnpm --filter @cp949/console-feed check:chrome75 is a static audit of the built package output. node fixtures/chrome75-consumer/scripts/build-packed.mjs checks an installed tarball in a standalone consumer. Run the exact-browser smoke on Linux with Docker:
bash scripts/test-chrome75.shThe recorded exact smoke uses Docker on Linux and Node 24 with Chromium/HeadlessChrome 75.0.3770.90; the packed consumer completed capture, decode, render, restoration, and style checks, with no fixture or CDP errors. The historical image downloads its snapshot over HTTPS and verifies the pinned Chromium deb SHA-1; trusted=yes applies only to that snapshot source. Podman and Node 22 have no equivalent execution record. This smoke verifies only the computed style checks in the fixture; broader CSS behavior, other browser engines, and other operating systems remain unverified.
Changes
전체 변경 이력은 CHANGELOG.md를 참조하세요. 아래는 최근 주요 변경의 요약입니다.
3.7.2
- Patch release. Fixes a low-severity
esbuildvulnerability (GHSA-g7r4-m6w7-qqqr) left unresolved by prior dependency updates, plus routine dependency bumps (dompurify,linkify-*, testing libraries). No public API change. See CHANGELOG.md for details.
3.7.1
- Patch release. Library code (
dist/) is identical to 3.7.0 — fixes thetest:compatmatrix and updates the README. See CHANGELOG.md for details.
3.7.0
@emotion/react,@emotion/styled,react-inspectormoved topeerDependencies— consumers must install these packages explicitly.- TypeScript
strictmode enabled —tsconfig.jsonconsolidated to"strict": true.HookedConsole.feedis now an optional property (feed?); runtime behavior unchanged but consumers compiling under strict may need an optional guard when accessingconsole.feeddirectly. react-inline-centerdependency removed — replaced by inline flex styles at the single call site.
3.6.8 — Build / Distribution
- Dual ESM + CJS build via
tsdown(replaces the previoustsc-only CJS build) exportsmap now branches onimport/requirefor the root and every public subpath (./component,./hook,./unhook,./transform)- Default-only subpaths (
./hook,./unhook,./component) are emitted so thatrequire('@cp949/console-feed/hook')andimport Hook from '@cp949/console-feed/hook'both resolve to the function directly — fixes Next/Webpack interop whereHookwas being received as{ default: fn }
Earlier — Security Vulnerability Fixes
- react-inspector 9.0.0 upgrade: removed @babel/runtime vulnerabilities
- Jest → Vitest migration: resolved 22 dependency chain vulnerabilities
- Prototype pollution defense:
__proto__,constructor,prototypekey filtering - DOM sanitization: DOMPurify applied without server-side DOM dependencies
- Serialization depth limits added
Current Stack
- TypeScript ^6.0.3
- React 18, 19 support
- Node 20+ baseline
- Vitest ^5.0.1
Features
- Styled console entries (color substitution, clickable links)
- Renders DOM nodes, tables, various console methods
- Serialization (functions, circular structures, DOM references)
- Filtering and search
- Error stack trace display
- Performance measurement (
console.time/timeEndsupport) - Dark/light theme support
Basic Usage
Function component (Hooks):
import React, { useState, useEffect } from 'react'
import { Console, Hook, Decode, Unhook } from '@cp949/console-feed'
import type { Message } from '@cp949/console-feed'
const LogsContainer = () => {
const [logs, setLogs] = useState<Message[]>([])
useEffect(() => {
const hookedConsole = Hook(
window.console,
(encoded, message) => {
// When encode is true: encoded is a serialized message, so Decode is required
// When encode is false: encoded is a parsed message, but using Decode is safe
const decoded = Decode(encoded)
const logMessage: Message = {
...decoded,
id: `log-${Date.now()}-${Math.random()}`,
data: decoded.data || [],
}
setLogs((prevLogs) => [...prevLogs, logMessage])
},
true, // encode: true - serialization for network transfer
100, // limit: 100 - serialization depth limit
)
// Cleanup: Unhook when component unmounts
return () => {
Unhook(hookedConsole)
}
}, [])
return <Console logs={logs} variant="dark" />
}API
Console Component
A React component that displays log messages.
Props:
logs: Array of log messages (Message[]) - Requiredvariant?: Theme ("dark"|"light", default:"dark")styles?: Custom style objectfilter?: Method filter array (Methods[]) - Display only specified methodssearchKeywords?: Search keyword string - Regex search in log contentlogFilter?: Log filtering function - Custom filtering logic when used withsearchKeywordslogGrouping?: Enable log grouping (default:true) - Group identical logs and display withamountlinkifyOptions?: linkifyjs options object - URL link handling optionscomponents?: Component override object - Replace with custom components
Hook Function
Wraps window.console or a console-like object to capture logs.
Hook(
console: Console,
callback: (encoded: Message, message: Payload) => void,
encode?: boolean, // Default: true
limit?: number // Default: 100 (serialization depth limit)
): HookedConsoleParameters:
console: Console object to hookcallback: Callback function called when a log is capturedencoded: Log message (first argument)- When
encodeistrue: Serialized message (suitable for network transfer/storage) - When
encodeisfalse: Parsed message (not serialized, for use in the same memory space)
- When
message: Parsed message (second argument, always non-serialized parsed result)
encode: Whether to serialize logs (default:true)true: Serialize parsed messages for network transfer or localStorage storagefalse: Use parsed messages without serialization (more efficient when used in the same memory space)
limit: Serialization depth limit (default:100, only applies whenencodeistrue)
Return Value:
HookedConsole: Hooked Console object (can be passed to Unhook)
Unhook Function
Restores a console wrapped by Hook to its original state. Must be called when the component unmounts.
Unhook(hookedConsole: HookedConsole): booleanParameters:
hookedConsole: Console object wrapped by Hook
Return Value:
boolean: Success status (true: success,false: failure)
Encode / Decode Functions
Used when transmitting logs across network boundaries.
Encode<T>(data: any, limit?: number): T
Decode(data: any): MessageEncode:
- Converts log objects into JSON-serializable format
- Safely converts functions, circular references, DOM nodes, etc.
limit: Serialization depth limit (default: 100)- Return Value: Flat object structure that can be serialized to JSON
- Complex types (functions, DOM nodes, etc.) from the original object are converted with special type markers
- Can be safely serialized with
JSON.stringify() - Suitable for network transfer, localStorage storage, etc.
Decode:
- Deserializes serialized logs into
Messageobjects - Returns a complete log object including the
methodproperty - Important:
- When
encodeistrue: The first argument (encoded) of the callback is a serialized message, soDecodemust be called - When
encodeisfalse: The first argument (encoded) of the callback is a parsed message, but callingDecodeis recommended for safe usage
- When
Usage Example:
import { Encode, Decode } from '@cp949/console-feed'
// 1. Create log message
const logMessage = {
method: 'log' as const,
data: [
'Hello World',
{ name: 'console-feed', version: '3.7.2' },
[1, 2, 3],
],
timestamp: new Date().toISOString(),
}
// 2. Encode: Serialize for network transfer
const encoded = Encode(logMessage, 100)
// encoded is an object that can be serialized with JSON.stringify()
// Example: { method: 'log', data: [...], timestamp: '...' }
// 3. Simulate network transfer (convert to JSON)
const jsonString = JSON.stringify(encoded)
// Can be stored in localStorage or sent over network
// 4. Parse JSON on receiving side
const received = JSON.parse(jsonString)
// 5. Decode: Deserialize to restore original form
const decoded = Decode(received)
// decoded is a complete log object of type Message
// { method: 'log', data: [...], timestamp: '...' }
// 6. Pass to Console component
<Console logs={[decoded]} variant="dark" />Real-world Usage Scenario:
// Send log to server
const sendLogToServer = (log: Message) => {
const encoded = Encode(log, 100)
fetch('/api/logs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(encoded), // Can be safely serialized
})
}
// Display logs received from server
const receiveLogFromServer = async () => {
const response = await fetch('/api/logs')
const encodedLogs = await response.json()
const decodedLogs = encodedLogs.map((encoded: any) => Decode(encoded))
setLogs(decodedLogs)
}Capturing Logs from iframe
You can display console methods like console.log(), console.error() executed inside an iframe in the main window's console-feed.
Simple Method:
After the iframe loads, hook the iframe's contentWindow.console.
import React, { useState, useEffect, useRef } from 'react'
import { Console, Hook, Decode, Unhook } from '@cp949/console-feed'
import type { Message, HookedConsole } from '@cp949/console-feed'
const IframeLogsContainer = () => {
const [logs, setLogs] = useState<Message[]>([])
const iframeRef = useRef<HTMLIFrameElement | null>(null)
useEffect(() => {
const iframe = iframeRef.current
if (!iframe) return
let hookedConsole: HookedConsole | null = null
// Wait for iframe to load
const handleLoad = () => {
if (!iframe.contentWindow) {
console.error('iframe contentWindow is not available')
return
}
// Hook iframe's console
const iframeConsole = iframe.contentWindow.console
hookedConsole = Hook(
iframeConsole,
(encoded, message) => {
// encode is true, so use Decode to decode the log (required!)
const decoded = Decode(encoded)
const logMessage: Message = {
...decoded,
id: `log-${Date.now()}-${Math.random()}`,
data: decoded.data || [],
}
setLogs((prevLogs) => [...prevLogs, logMessage])
},
true, // encode: true
100, // limit: 100
)
}
iframe.addEventListener('load', handleLoad)
// Cleanup: Clean up when component unmounts
return () => {
if (hookedConsole && iframe.contentWindow) {
Unhook(hookedConsole)
}
iframe.removeEventListener('load', handleLoad)
}
}, [])
return (
<div>
<iframe ref={iframeRef} src="./your-iframe.html" />
<Console logs={logs} variant="dark" />
</div>
)
}Notes:
- Console must be hooked after the iframe loads (
loadevent) - The iframe and main window must be same-origin to access
contentWindow.console - Must call
Unhookwhen the component unmounts to clean up
Development
Project Structure
console-feed/
├── apps/
│ └── demo/ # Demo app (Vite + React)
├── packages/
│ └── console-feed/ # Library core
├── turbo.json # Turborepo configuration
├── pnpm-workspace.yaml # pnpm workspace setup
└── package.json # Root workspaceDevelopment Requirements
- Node
^22.18.0(CI baseline) - pnpm
11.27.1
Development Commands
# Install dependencies
pnpm install
# Run development server for entire workspace
pnpm dev
# Build entire workspace
pnpm build
# Test entire workspace
pnpm test
# Run specific package only
pnpm --filter @cp949/console-feed build # Build library
pnpm --filter demo dev # Run demo app only
pnpm --filter @cp949/console-feed test # Test libraryReact 18/19 Compatibility Testing
# Test both React 18 and 19
pnpm test:compat
# Test React 18 only
pnpm test:react18
# Test React 19 only
pnpm test:react19Script: packages/console-feed/scripts/test-react-compat.sh
Release
Only the library package (@cp949/console-feed) is published to npm.
Releases are always started by a human. Do not run this command from an agent or CI. Before releasing, update and commit CHANGELOG.md; release-it requires a clean working tree.
# Starts the interactive release flow from the repository root.
pnpm release-itThe flow updates only this package's package.json, runs prepublishOnly (build, test, test:dist), publishes to npm, then interactively confirms the release commit, v<version> tag, and push. Use the prompts to choose the version and approve each external action.
License
MIT
