npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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

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-feed

Package 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.sh

The 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 esbuild vulnerability (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 the test:compat matrix and updates the README. See CHANGELOG.md for details.

3.7.0

  • @emotion/react, @emotion/styled, react-inspector moved to peerDependencies — consumers must install these packages explicitly.
  • TypeScript strict mode enabled — tsconfig.json consolidated to "strict": true. HookedConsole.feed is now an optional property (feed?); runtime behavior unchanged but consumers compiling under strict may need an optional guard when accessing console.feed directly.
  • react-inline-center dependency removed — replaced by inline flex styles at the single call site.

3.6.8 — Build / Distribution

  • Dual ESM + CJS build via tsdown (replaces the previous tsc-only CJS build)
  • exports map now branches on import / require for the root and every public subpath (./component, ./hook, ./unhook, ./transform)
  • Default-only subpaths (./hook, ./unhook, ./component) are emitted so that require('@cp949/console-feed/hook') and import Hook from '@cp949/console-feed/hook' both resolve to the function directly — fixes Next/Webpack interop where Hook was 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, prototype key 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/timeEnd support)
  • 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[]) - Required
  • variant?: Theme ("dark" | "light", default: "dark")
  • styles?: Custom style object
  • filter?: Method filter array (Methods[]) - Display only specified methods
  • searchKeywords?: Search keyword string - Regex search in log content
  • logFilter?: Log filtering function - Custom filtering logic when used with searchKeywords
  • logGrouping?: Enable log grouping (default: true) - Group identical logs and display with amount
  • linkifyOptions?: linkifyjs options object - URL link handling options
  • components?: 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)
): HookedConsole

Parameters:

  • console: Console object to hook
  • callback: Callback function called when a log is captured
    • encoded: Log message (first argument)
      • When encode is true: Serialized message (suitable for network transfer/storage)
      • When encode is false: Parsed message (not serialized, for use in the same memory space)
    • 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 storage
    • false: Use parsed messages without serialization (more efficient when used in the same memory space)
  • limit: Serialization depth limit (default: 100, only applies when encode is true)

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): boolean

Parameters:

  • 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): Message

Encode:

  • 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 Message objects
  • Returns a complete log object including the method property
  • Important:
    • When encode is true: The first argument (encoded) of the callback is a serialized message, so Decode must be called
    • When encode is false: The first argument (encoded) of the callback is a parsed message, but calling Decode is recommended for safe usage

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 (load event)
  • The iframe and main window must be same-origin to access contentWindow.console
  • Must call Unhook when 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 workspace

Development 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 library

React 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:react19

Script: 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-it

The 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