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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@bobfrankston/msger

v0.1.186

Published

Fast, lightweight, cross-platform message box - Rust-powered alternative to msgview

Downloads

11,037

Readme

@bobfrankston/msger

Fast, lightweight message boxes for Node.js applications.

Display native message boxes, dialogs, and HTML content with a simple JavaScript API. Works on Windows, Linux (x64), and Linux (ARM64/Raspberry Pi).

Quick Links

Installation

npm install @bobfrankston/msger

For global CLI usage:

npm install -g @bobfrankston/msger

Supported Platforms:

  • Windows (x64)
  • Linux (x64)
  • Linux (ARM64 / Raspberry Pi)

Command Line Usage

The msger command-line tool provides a quick way to display message boxes from shell scripts, batch files, or terminal.

Basic Examples

# Simple message
msger -message "Hello, World!"
msger Hello World  # shorthand - words become message

# With HTML content
msger -html "<h1>Welcome!</h1><p>This is <strong>HTML</strong></p>"

# Colored text with inline styles
msger -html "<span style='color:red;background-color:yellow'>Alert!</span>"

# Load a URL (web page or local file)
msger -url "https://example.com"
msger -url "file:///path/to/page.html"

# Load URL with hash fragment
msger -url "https://example.com" -hash section1
msger -url "https://example.com" -hash "#intro"

# With input field and placeholder
msger -message "Enter your name:" -input "Your name here" -default "John"

# Custom buttons
msger -message "Save changes?" -buttons Yes No Cancel

# With custom size and position
msger -message "Hello" -size 800,600 -pos 100,100

# Always on top with zoom
msger -message "Important!" -ontop -zoom 150

# Detached URL browser (stays open after script exits)
msger -url "https://example.com" -detach

# Fullscreen mode
msger -fullscreen -url "https://example.com"

# Multi-monitor (Windows only - show on second screen)
msger -message "Second screen" -pos 0,100 -screen 1

# Auto-close timeout
msger -message "Closing in 5 seconds..." -timeout 5

# Open with DevTools for debugging (automatically opens DevTools panel)
msger -url "https://example.com" -dev

# See all options
msger --help

JSON Configuration Files

You can store message box configuration in a JSON file for reuse. JSON files support comments (JSON5 format).

# Load configuration from file
msger -load config.json

# Override specific values from loaded config
msger -load config.json -title "New Title" -size 800,600

# Save current command-line options to a file (only saves explicitly specified values)
msger -title "My Dialog" -message "Hello" -buttons Yes No -save my-config.json

# Save config without showing the message box (uses -noshow)
msger -title "My Dialog" -message "Hello" -buttons Yes No -save my-config -noshow

# Load base config, override, and save the overrides
msger -load base.json -title "Modified" -save modified.json

# Save and show (saves config then displays the message box)
msger -title "Test" -message "Saving config..." -save test.json

Notes:

  • The -save option saves only the explicitly specified command-line arguments, not derived defaults. This keeps config files minimal and allows defaults to evolve.
  • Use -noshow with -save to create config files without displaying the message box.
  • File extensions: If you don't specify .json, it will be added automatically (e.g., myconfig becomes myconfig.json).

Complete JSON Structure

{
    "title": "Window Title",
    "message": "Plain text message (supports ANSI color codes)",
    "html": "<h1>HTML content</h1><p>Rich formatting</p>",
    "url": "https://example.com",
    "hash": "section1",
    "size": {
        "width": 600,
        "height": 400
    },
    "pos": {
        "x": 100,
        "y": 100,
        "screen": 0
    },
    "buttons": ["Cancel", "OK"],
    "defaultValue": "default input text",
    "inputPlaceholder": "Enter text here...",
    "allowInput": false,
    "timeout": 30,
    "autoSize": false,
    "alwaysOnTop": false,
    "fullscreen": false,
    "zoom": 100,
    "debug": false,
    "icon": "path/to/icon.png",
    "dev": false
}

Field Reference

| Field | Type | Default | Description | |-------|------|---------|-------------| | title | string | "Message" | Window title | | message | string | null | Plain text message (supports ANSI color codes) | | html | string | null | HTML content to display | | url | string | null | URL to load (web or file://) | | hash | string | null | Hash fragment to append to URL (requires url). Leading # is optional. | | size | object | {"width": 600, "height": 400} | Window size | | size.width | number | 600 (or 1024 for URLs) | Window width in pixels | | size.height | number | 400 (or 768 for URLs) | Window height in pixels | | pos | object | null | Window position | | pos.x | number | - | X coordinate in pixels | | pos.y | number | - | Y coordinate in pixels | | pos.screen | number | null | [Windows only] Screen index (0=primary, 1=second, etc.) | | buttons | string[] | ["OK"] | Button labels | | defaultValue | string | null | Default input value | | inputPlaceholder | string | null | Placeholder text for input field | | allowInput | boolean | false | Show input field | | timeout | number | null | Auto-close after N seconds | | autoSize | boolean | true when no size | Auto-resize window to fit content | | alwaysOnTop | boolean | false | Keep window on top | | fullscreen | boolean | false | Start in fullscreen mode | | zoom | number | 100 | Initial zoom level (100=100%, 150=150%) | | debug | boolean | false | Return debug info in result | | icon | string | null | Path to window icon (.png, .ico) | | dev | boolean | false | Open DevTools automatically (for debugging HTML/URL content) |

Content Priority: Only one content type will be displayed (in order):

  1. url - If provided, loads URL (ignores message/html)
  2. html - If provided, displays HTML (ignores message)
  3. message - Plain text with ANSI color support

Backward Compatibility: The old width and height fields (at the top level) are still supported for backward compatibility, but the size object is preferred. If both are provided, size takes precedence.

JSON Examples

Simple dialog:

{
    "title": "Confirm",
    "message": "Are you sure?",
    "buttons": ["Cancel", "OK"]
}

Input dialog:

{
    "title": "Enter Name",
    "message": "Please enter your name:",
    "allowInput": true,
    "inputPlaceholder": "Your name here",
    "defaultValue": "John Doe",
    "buttons": ["Cancel", "Submit"]
}

HTML content:

{
    "title": "Welcome",
    "html": "<h1>Welcome!</h1><p>Getting started...</p>",
    "size": {
        "width": 700,
        "height": 500
    }
}

Positioned window on second monitor:

{
    "message": "Second screen",
    "pos": {
        "x": 0,
        "y": 100,
        "screen": 1
    }
}

CLI Options Reference

Usage: msger [options] [message words...]

Options:
  -message, --message <text>      Plain text message
  -title, --title <text>          Window title
  -html, --html <html>            HTML content
  -url, --url <url>               URL to load (web or file://)
  -hash, --hash <fragment>        Hash fragment to append to URL (requires -url). Leading # optional.
  -buttons, --buttons <labels>    Button labels (e.g., -buttons Yes No Cancel)
  -ok, --ok                       Add OK button
  -cancel, --cancel               Add Cancel button
  -input, --input [placeholder]   Include input field with optional placeholder text
  -default, --default <text>      Default value for input field
  -size, --size <width,height>    Window size (e.g., -size 800,600)
  -pos, --pos <x,y>               Window position (e.g., -pos 100,200)
  -screen, --screen <number>      [Windows only] Screen index (0=primary, 1=second, etc.)
  -zoom, --zoom <percent>         Zoom level as percentage (e.g., -zoom 150 for 150%)
  -timeout, --timeout <seconds>   Auto-close after specified seconds
  -ontop, --ontop                 Keep window always on top
  -detach, --detach               Launch window independently (parent returns immediately)
  -fullscreen, --fullscreen       Start window in fullscreen mode (F11 to toggle, Escape to exit)
  -debug, --debug                 Return debug info (HTML, size, autoSize) in result
  -v, -version, --version         Show version number
  -help, -?, --help               Show help message

Keyboard Shortcuts:
  - Enter: Click default (last) button
  - Escape: Dismiss dialog or exit fullscreen
  - F11: Toggle fullscreen mode
  - F12: Open developer tools (DevTools/Inspect)
  - Ctrl+Wheel/Plus/Minus: Zoom in/out
  - Ctrl+0: Reset zoom to 100%

Debug Mode:
  - Set environment variable MSGER_DEBUG=1 for diagnostic output
  - Shows: startup info, keyboard events, IPC messages, button clicks
  - Example (PowerShell): $env:MSGER_DEBUG=1; msger "Test"
  - Zero performance impact when disabled

Notes:
  - If no options provided, all non-option arguments are concatenated as message
  - Press ESC to dismiss (returns button: "dismissed")
  - Press Enter to click last (default) button
  - OK button is green by default
  - URLs default to 1024x768 window size
  - Window title automatically updates from loaded page's <title> tag when using -url
  - Windows auto-size to fit content when size not specified
  - Runtime zoom: Ctrl+Wheel, Ctrl+Plus, Ctrl+Minus

Node.js API Reference

Use msger in your Node.js or TypeScript applications with a simple Promise-based API.

Quick Start

import { showMessageBox } from '@bobfrankston/msger';

const result = await showMessageBox({
    title: 'Confirm Action',
    message: 'Are you sure you want to proceed?',
    buttons: ['Cancel', 'OK']
});

console.log('User clicked:', result.button);

if (result.value) {
    console.log('User entered:', result.value);
}

Programmatic Close API (New!)

Close message boxes programmatically from the parent process:

Handle-based API (Recommended):

import { showMessageBoxEx } from '@bobfrankston/msger';

const handle = showMessageBoxEx({
    message: 'Processing...',
    buttons: ['Cancel']
});

console.log('Dialog PID:', handle.pid);

// Close after 5 seconds
setTimeout(() => {
    handle.close();
}, 5000);

// Wait for result
const result = await handle.result;
// Result: {button: 'closed', closed: true} if closed programmatically
// Result: {button: 'Cancel'} if user clicked Cancel

Standalone close function:

import { showMessageBoxEx, closeMessageBox } from '@bobfrankston/msger';

const handle = showMessageBoxEx({ message: 'Working...' });
const pid = handle.pid;

// Close by PID from anywhere
closeMessageBox(pid);

Use cases:

  • Progress dialogs that auto-close when task completes
  • Timeout-based notifications
  • Managing multiple dialogs by PID
  • Detached dialogs closed remotely

See CLOSE-API.md for complete documentation.

API Functions

showMessageBox(options: MessageBoxOptions): Promise<MessageBoxResult>

Display a message box dialog and wait for user response.

MessageBoxOptions

interface MessageBoxOptions {
    title?: string;           // Window title (default: "Message")
    message?: string;         // Plain text message (optional if url or html provided)
    html?: string;            // HTML content to display
    url?: string;             // URL to load (web URL or file:// path)
    hash?: string;            // Hash fragment to append to URL (requires url). Leading # optional.
    size?: {                  // Window size in pixels
        width: number;        // Window width (default: 600, or 1024 for URLs)
        height: number;       // Window height (default: 400, or 768 for URLs)
    };
    pos?: {                   // Window position
        x: number;            // X coordinate in pixels
        y: number;            // Y coordinate in pixels
        screen?: number;      // [Windows only] Screen index (0=primary, 1=second, etc.)
    };
    buttons?: string[];       // Button labels (default: ["OK"])
    defaultValue?: string;    // Default input value
    inputPlaceholder?: string; // Placeholder text (gray hint) for input field
    allowInput?: boolean;     // Show input field (default: false)
    autoSize?: boolean;       // Auto-resize window to fit content (default: true when no size specified)
    alwaysOnTop?: boolean;    // Keep window on top of other windows (default: false)
    zoom?: number;            // Initial zoom level (100=100%, 150=150%, 50=50%)
    timeout?: number;         // Auto-close after N seconds
    detach?: boolean;         // Launch detached from parent process
    fullscreen?: boolean;     // Start window in fullscreen mode (F11 to toggle)
    debug?: boolean;          // Return debug info (HTML, size, autoSize) in result
}

MessageBoxResult

interface MessageBoxResult {
    button: string;       // Label of clicked button
    value?: string;       // Input value (if allowInput was true)
    form?: object;        // Form data (if form elements present)
    closed?: boolean;     // True if closed programmatically via handle.close()
    dismissed?: boolean;  // True if user pressed Escape
    timeout?: boolean;    // True if closed due to timeout
    debug?: {             // Debug info (if debug option was true)
        html: string;     // Generated HTML content
        width: number;    // Window width
        height: number;   // Window height
        autoSize: boolean; // Whether auto-sizing is enabled
    };
}

API Examples

Simple Confirmation Dialog

const result = await showMessageBox({
    title: 'Delete File',
    message: 'Are you sure you want to delete this file?',
    buttons: ['Cancel', 'Delete']
});

if (result.button === 'Delete') {
    // Perform deletion
}

Input Dialog

const result = await showMessageBox({
    title: 'Enter Name',
    message: 'Please enter your name:',
    allowInput: true,
    inputPlaceholder: 'Your name here',
    defaultValue: 'John Doe',
    buttons: ['Cancel', 'OK']
});

if (result.button === 'OK') {
    console.log('Name entered:', result.value);
}

HTML Content

const result = await showMessageBox({
    title: 'Welcome',
    html: `
        <div style="font-family: sans-serif;">
            <h2 style="color: #2563eb;">Welcome!</h2>
            <p>This supports <strong>HTML</strong> content.</p>
            <ul>
                <li>Rich formatting</li>
                <li>Custom styles</li>
                <li>Any HTML elements</li>
            </ul>
        </div>
    `,
    size: { width: 700, height: 500 },
    buttons: ['Close']
});

ANSI Color Codes

Plain text messages automatically support ANSI color escape sequences, which are converted to HTML with proper colors:

const result = await showMessageBox({
    title: 'Color Test',
    message: '\x1b[31mRed text\x1b[0m\n\x1b[32mGreen text\x1b[0m\n\x1b[1m\x1b[34mBold blue\x1b[0m',
    buttons: ['OK']
});

Supported ANSI codes:

  • Colors: Red (31), Green (32), Yellow (33), Blue (34), Magenta (35), Cyan (36), White (37)
  • Styles: Bold (1), Underline (4), Reset (0)
  • Backgrounds: 40-47 (same color numbers as foreground)

CLI example:

echo -e "\x1b[31mError:\x1b[0m Something went wrong" | msger

Display a Web Page

// Load external website
// Note: Window title automatically updates from page's <title> tag
await showMessageBox({
    url: 'https://github.com/BobFrankston/msger',
    size: { width: 1024, height: 768 }
});

// Load local HTML file
await showMessageBox({
    url: 'file:///path/to/help.html',
    size: { width: 800, height: 600 }
});

// Load with DevTools opened automatically (for debugging)
await showMessageBox({
    url: 'https://example.com',
    dev: true,  // Opens DevTools automatically
    size: { width: 1024, height: 768 }
});

Auto-Close with Timeout

// Show notification that auto-closes after 3 seconds
// A translucent countdown indicator appears in the top-right corner
const result = await showMessageBox({
    title: 'Notification',
    message: 'File saved successfully!',
    timeout: 3,
    buttons: ['OK']
});

if (result.timeout) {
    console.log('Notification auto-closed');
}

The countdown timer displays as a subtle yellow badge in the top-right corner, showing the remaining seconds (e.g., "10s", "9s", "8s"...).

HTML Forms

const result = await showMessageBox({
    title: 'User Registration',
    html: `
        <form>
            <label>Name: <input name="name" required /></label><br>
            <label>Email: <input name="email" type="email" required /></label><br>
            <label>Age: <input name="age" type="number" /></label>
        </form>
    `,
    buttons: ['Cancel', 'Submit']
});

if (result.button === 'Submit' && result.form) {
    console.log('Name:', result.form.name);
    console.log('Email:', result.form.email);
    console.log('Age:', result.form.age);
}

Window Positioning

// Position at specific coordinates
await showMessageBox({
    message: 'Positioned window',
    pos: { x: 100, y: 100 }
});

// Position on second monitor (Windows only)
await showMessageBox({
    message: 'On second screen',
    pos: { x: 0, y: 100, screen: 1 }
});

Always On Top & Zoom

// Keep window on top with 150% zoom
await showMessageBox({
    title: 'Important Alert',
    message: 'This window stays on top!',
    alwaysOnTop: true,
    zoom: 150
});

Auto-Sizing Window

// Window automatically sizes to fit content
await showMessageBox({
    message: 'Short message',
    autoSize: true  // default when size not specified
});

Detached URL Browser

// Launch URL window that stays open after script exits
await showMessageBox({
    url: 'https://example.com',
    size: { width: 1200, height: 800 },
    detach: true,
    alwaysOnTop: true
});
// Script continues/exits immediately, window stays open

Fullscreen Mode

// Launch window in fullscreen mode (like F11 in browser)
await showMessageBox({
    url: 'https://example.com',
    fullscreen: true
});
// Users can press F11 to toggle fullscreen or Escape to exit

// Fullscreen with message
await showMessageBox({
    message: 'Full screen presentation',
    fullscreen: true,
    buttons: ['Close']
});

Features

  • ✅ Display plain text, HTML content, or load URLs
  • ✅ Full HTML/CSS support
  • ✅ ANSI color codes (colored terminal output)
  • ✅ Customizable buttons
  • ✅ Input fields and forms
  • ✅ Auto-close with timeout
  • ✅ Window positioning and sizing
  • ✅ Multi-monitor support (Windows)
  • ✅ Always on top mode
  • ✅ Zoom control
  • ✅ Fullscreen mode
  • ✅ TypeScript type definitions
  • ✅ Keyboard shortcuts (Enter, Escape, F11, F12)

Why msger?

  • Fast - Opens in under 200ms
  • Small - Only a few MB installed
  • Simple - Easy Promise-based API
  • Flexible - Plain text, HTML, or load URLs
  • Cross-platform - Works on Windows and Linux

For technical details and performance metrics, see DEVELOPERS.md.

msger vs msgview

This package is the Rust/wry-based implementation. There's also @bobfrankston/msgview - an Electron-based alternative with the same API.

| Aspect | msger (this) | msgview | |--------|--------------|---------| | Startup | ~50-200ms | ~2-3 seconds | | Size | ~5-10MB | ~200MB | | Technology | Rust + wry (WebView2/webkit2gtk) | Electron | | Pi/Linux | ❌ Rendering issues | ✅ Perfect | | Windows/WSL | ✅ Works | ✅ Works |

When to use msger (this package)

  • Speed is critical (CLI tools, automation)
  • Small binary size matters
  • Windows or WSL environment

When to use msgview

  • Running on Raspberry Pi or Linux
  • Need reliable cross-platform rendering
  • Prefer Electron ecosystem

Planned: msgapi

Both packages will share a common JavaScript API (window.msgapi) for file system access, window manipulation, and bidirectional communication. See TODO.md for details.

For the complete feature comparison and roadmap, see the shared TODO.md which tracks both projects.


Additional Information

Important Notes

Taskbar Icons

Icon Behavior Differences:

  • Window Title Bar: Shows custom icon from -icon flag or JSON config
  • Windows Taskbar: Shows the embedded msger.exe icon (cannot be changed at runtime)

This is a Windows limitation for native applications. The taskbar icon comes from the executable's embedded resource, not the runtime window icon. In contrast, Electron-based msgview can set taskbar icons dynamically.

Workaround: The planned -pin feature with AppUserModelID will allow each pinned shortcut to have its own taskbar icon.

Security

⚠️ msger is designed for displaying trusted, friendly content (local apps, your HTML files). It is NOT a secure sandbox for untrusted/hostile web content. Use -htmlfrom and -url with trusted sources only.

msger JavaScript API

Minimal API - Most functionality uses native browser APIs:

  • msger.isAvailable() - Feature detection (returns true in msger)
  • msger.close() - Same as window.close() (native API preferred)

Recommendation: Use native browser APIs (localStorage, window.close()) for compatibility. Code will work in any browser context, not just msger.

For Developers

License

ISC

Author

Bob Frankston