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

discord-html-transcripts-fix

v1.8.2

Published

A nicely formatted html transcript generator for discord.js. Bugfix fork with support for the latest discord.js and Components v2.

Downloads

1,204

Readme

discord-html-transcripts-fix

A nicely formatted HTML transcript generator for discord.js with full Components V2 support, an interactive viewer, and hardened security.

Forked from discord-html-transcripts.

Install

npm install discord-html-transcripts-fix

Only discord.js is a peer dependency; everything else (React, Lit SSR, markdown parser, etc.) is auto-installed.

Quick start

const { createTranscript } = require('discord-html-transcripts-fix');

const attachment = await createTranscript(channel, {
    limit: -1,
    saveImages: false,
});

channel.send({ files: [attachment] });

Options

| Option | Type | Default | Description | |---|---|---|---| | limit | number | -1 | Max messages to fetch. -1 = recursive (all). | | filter | (m) => boolean | () => true | Predicate to filter messages. | | returnType | 'attachment' | 'buffer' | 'string' | 'stream' | 'attachment' | Return value shape. 'stream' is best for 5k+ message exports. | | filename | string | transcript-{channel-id}.html | Output filename when returning as attachment. | | saveImages | boolean | false | Download images and inline them as base64 data URLs. | | favicon | 'guild' | string | 'guild' | Page favicon — 'guild' uses the server icon, or pass a URL. | | hydrate | boolean | false | Server-side hydrate via @lit-labs/ssr (slower; usually leave off). | | language | 'en' | 'de' | 'en' | UI language for participant labels, filter strings, etc. | | i18n | Partial<Record<lang, Record<key,string>>> | — | Override individual strings per language. | | statsFooter | false | { enabled?, template? } | { enabled: true } | Bottom stats line. See below. | | footerText | string | — | Legacy "Exported X messages" line. Only renders when statsFooter is disabled. | | poweredBy | boolean | false | Show the original "Powered by discord-html-transcripts" credit link. | | callbacks | { resolveUser, resolveRole, resolveChannel } | — | Custom resolvers for mentions. |

Configurable stats footer

await createTranscript(channel, {
    statsFooter: {
        template: '{messages} Nachrichten · {participants} Teilnehmer · {images} Bilder · {from} → {to} · {span}',
    },
});

// Or disable entirely:
await createTranscript(channel, { statsFooter: false });

Placeholders: {messages}, {participants}, {images}, {from}, {to}, {span}.

Optional edit history

If your bot tracks edits, attach them to the message before rendering:

message.editHistory = [
    { content: 'first version',     editedAt: new Date('2026-05-13T11:02Z') },
    { content: 'corrected version', editedAt: new Date('2026-05-13T11:05Z') },
];

The viewer will render a collapsible <details> block next to the (edited) marker.

Interactive viewer

One floating button sits top-right — the hamburger menu. It opens a sidebar containing:

  • Live search at the top — keyword highlighting (n of N matches with prev/next), Ctrl/Cmd-F focuses this field
  • Participants (collapsible, open by default) — sorted list of authors; click to jump to their first message
  • Filter (collapsible, open by default) — author, role, date range, pinned-only, has-image, has-embed, has-attachment, has-container/V2

Inline behaviour:

  • Clickable mentions — user/role/channel pills open a Discord-style popup with avatar, display name, username, role pills (colored), server-since, account-since, color, member count, channel topic, etc.
  • Clickable message authors — clicking the avatar or username on a regular message, or the author name on a system message ("X pinned a message…"), opens the same user popup.
  • Clickable slash commands<discord-command> pills open a popup listing the resolved command and every parameter (name: value).
  • Copy buttons — user ID, role ID, channel ID, username, color hex, command name, and every slash parameter value get a one-click clipboard button in the popup.
  • Image lightbox — click any image to open fullscreen, arrow keys to navigate, Escape to close.
  • Date separators between messages — Tuesday, May 13 2026 style, automatically inserted on day boundaries.
  • Author name color uses the highest listed role's color, matching the Discord client.

Content rendered

In addition to plain text, replies, embeds, and attachments, the viewer supports:

  • Components V2 — Containers, Sections, Text Display, Media Gallery, Thumbnail, File, Separator, with accent colors and spoiler support
  • Action rows — buttons with proper spacing and Discord-style colors (primary, secondary, success, destructive)
  • Stickers — PNG, APNG, GIF, Lottie placeholder
  • Polls — question, answer bars with vote counts and percentages, expiry
  • Forwarded messages (messageSnapshots) — quoted-block style with original author, recursive nesting
  • Voice messages🎤 indicator, inline SVG waveform from attachment.waveform, duration
  • Pinned messages — Discord-style amber left rail (no extra icon clutter)
  • Slash command interactions{user} used /cmd header + clickable pill that reveals parameters
  • System messagesChannelPinnedMessage, ChannelNameChange, ChannelIconChange, ThreadCreated, ChatInputCommand, ContextMenuCommand, Call, ChannelFollowAdd, RecipientRemove, RoleSubscriptionPurchase, guild incident reports, poll result, AutoMod actions
  • Cross-guild replies — show a "Message from another server" pill
  • Burst / super-reactions flagged
  • Thread state badgesArchived, Locked
  • GIFV / animated GIFs<video autoplay loop muted> like Discord
  • Attachment description (alt text) used as alt/title
  • <id:guide>, <id:browse>, <id:customize> pseudo-channels → styled pills with proper labels
  • </cmd:id> slash command mentions → blue monospace pills
  • Embed video link and embed provider ("YouTube" etc.) shown
  • Edit history with collapsible <details> (opt-in via message.editHistory)
  • Suppressed embeds flag is honored — when set, embeds aren't rendered (a small (embeds hidden) note is shown)

Changes vs. the original

Security

  • Critical fix </script> breakout via inlined JSON is prevented (<, >, &, U+2028/2029 escaped)
  • Critical fix markdown links with javascript:, data:, vbscript: and other dangerous URI schemes are rewritten to #
  • Hardened inline style="color:…" sinks in the mention popup are hex-validated to block CSS injection
  • Hardened data: URI MIME types from the image downloader are restricted to image types only (no text/html smuggling)
  • Fixed process.exit(1) on discord.js version mismatch removed — library no longer kills the host bot

Robustness

  • Fix invalid Discord timestamp markers (<t:abc:F>, oversized values) no longer abort the transcript with RangeError
  • Fix per-AST-node error boundary in MessageSingleASTNode and per-message error boundary in DiscordMessage — one broken message can never kill the whole render
  • Fix parseDiscordEmoji no longer throws on deleted reactions with emoji.name === null
  • Fix formatBytes(null/undefined/NaN) no longer returns NaN undefined
  • Fix createTranscript slice uses the resolved limit instead of the raw limit
  • Fix embed fields render through a proper async component (was an inline async arrow inside .map())
  • Fix JoinMessage text is deterministic per message id — re-rendering the same channel always yields the same join line
  • Fix random console.log calls in production paths replaced by the debug namespace

Layout

  • Fix Components V2 Container/Section used display:flex;flex-direction:column;gap:8px, which forced every inline <strong> / <br> / mention pill / text node into its own row. Switched to block flow so messages read like Discord again.
  • Fix <discord-system-message> is no longer forced to display:block; the pin needle on "X pinned a message…" now sits at the left where Discord renders it.
  • Fix action-row buttons no longer touch — discord-action-row ships an 8 px gap rule.
  • Fix duplicate APP badge on bot/application messages removed — the web component already renders one.

Performance

  • Single-pass profile collectorbuildAllContext builds profiles + extended dicts in one walk over the message list
  • Image downloader is concurrent — bounded pool (default 6, configurable via withConcurrency) instead of sequential
  • @skyra/discord-components-core version is pinned to an exact resolved version → CDN cacheable
  • Inline JSON is shipped via <script type="application/json"> so it doesn't block HTML parse
  • Emoji URL resolution is memoized
  • returnType: 'stream' option streams the rendered HTML out instead of buffering — usable for 5,000+ message tickets

DX

  • react, react-dom, debug moved into regular dependencies so users don't install them manually (debug was actually a missing runtime dep in the original — images.js requires it)
  • TypeScript declarations cover all new options
  • discord.js remains the only peer dependency

Credits

Original package by ItzDerock. Styles from @derockdev/discord-components.