{"_id":"@cartiqo/discord-transcript","_rev":"3-1c2b5c01565b8fd4a13782c61c55d0ec","name":"@cartiqo/discord-transcript","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@cartiqo/discord-transcript","version":"0.1.0","keywords":["discord","transcript","chat-exporter","html","tickets","discord-components","discord.js"],"author":{"name":"CARTIQO"},"license":"MIT","_id":"@cartiqo/discord-transcript@0.1.0","maintainers":[{"name":"duckodas","email":"duckodas@gmail.com"}],"homepage":"https://github.com/cartiqoframework/discord-transcript#readme","bugs":{"url":"https://github.com/cartiqoframework/discord-transcript/issues"},"dist":{"shasum":"b1f81a81b7f8b9001cb00749a55725e66224216a","tarball":"https://registry.npmjs.org/@cartiqo/discord-transcript/-/discord-transcript-0.1.0.tgz","fileCount":9,"integrity":"sha512-zykKuUAzOgPGK78DLnGl0h2YpsS5xXLHDf8bMMKHf9sv99vtBwL8IiBesdEXeofdzkz6hfjKOnmTxIs9/0/4WA==","signatures":[{"sig":"MEQCIFK3HhToN+sM4MUT8EeoPi2BBddh9FAM7xlYHuzbaclkAiBj1gTvI00Y+o4o6OFLBpyes/3dzq9ah5YxLVLtm3FHNQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83101},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"88911e3bfbec96c04212d26494ddea5c015911dd","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"duckodas","email":"duckodas@gmail.com"},"repository":{"url":"git+https://github.com/cartiqoframework/discord-transcript.git","type":"git"},"_npmVersion":"11.6.3","description":"Generate beautiful, self-contained HTML transcripts of Discord channels, rendered with Discord's own message components.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","dependencies":{"@skyra/discord-components-core":"^4.0.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","typescript":"^5.7.2"},"_npmOperationalInternal":{"tmp":"tmp/discord-transcript_0.1.0_1783995975725_0.16330478210750532","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@cartiqo/discord-transcript","version":"0.1.1","keywords":["discord","transcript","chat-exporter","html","tickets","discord-components","discord.js"],"author":{"name":"CARTIQO"},"license":"MIT","_id":"@cartiqo/discord-transcript@0.1.1","maintainers":[{"name":"duckodas","email":"duckodas@gmail.com"}],"homepage":"https://github.com/cartiqoframework/discord-transcript#readme","bugs":{"url":"https://github.com/cartiqoframework/discord-transcript/issues"},"dist":{"shasum":"890a8d3c4dca2c478c4de38af62b78bb2f57ad0f","tarball":"https://registry.npmjs.org/@cartiqo/discord-transcript/-/discord-transcript-0.1.1.tgz","fileCount":9,"integrity":"sha512-u3TFH3GFnSp/BKVvVjsztMuuAndua4FYfAYkFYgFmstCihLbAbYG6UmtdD5GNRh1MRlIMU8hgTcAptGme5AeIQ==","signatures":[{"sig":"MEUCIFpghrrDL7zkTZDZWTTw80nWYxiDnwRvzFWDBHcchsHSAiEApPff0JGF0l2iFX5JG4K5ulS1/GzMOmGjuLy/kDqVd48=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83101},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"88911e3bfbec96c04212d26494ddea5c015911dd","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"duckodas","email":"duckodas@gmail.com"},"repository":{"url":"git+https://github.com/cartiqoframework/discord-transcript.git","type":"git"},"_npmVersion":"11.6.3","description":"Generate beautiful, self-contained HTML transcripts of Discord channels, rendered with Discord's own message components.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","dependencies":{"@skyra/discord-components-core":"^4.0.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","typescript":"^5.7.2"},"_npmOperationalInternal":{"tmp":"tmp/discord-transcript_0.1.1_1783996163203_0.8733175262978408","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@cartiqo/discord-transcript","version":"0.2.0","description":"Generate beautiful, self-contained HTML transcripts of Discord channels, rendered with Discord's own message components.","keywords":["discord","transcript","chat-exporter","html","tickets","discord-components","discord.js"],"license":"MIT","author":{"name":"CARTIQO"},"homepage":"https://github.com/cartiqoframework/discord-transcript#readme","repository":{"type":"git","url":"git+https://github.com/cartiqoframework/discord-transcript.git"},"bugs":{"url":"https://github.com/cartiqoframework/discord-transcript/issues"},"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"sideEffects":false,"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"dependencies":{"@skyra/discord-components-core":"^4.0.2"},"devDependencies":{"tsup":"^8.3.5","typescript":"^5.7.2"},"engines":{"node":">=18"},"publishConfig":{"access":"public"},"gitHead":"c6688d0ff6ef208de4453e895a895e05fb98c829","_id":"@cartiqo/discord-transcript@0.2.0","_nodeVersion":"24.15.0","_npmVersion":"11.6.3","dist":{"integrity":"sha512-1P/HtiC5NRsK9Ft2N9wGxbh3Ndwz4FvpnD6g5U+xrCPL4B+VPnfY/xzhbzz/MwpOONRcpCo5khLLpC6zTShniA==","shasum":"471642e02ed64c41b6c2d184a66937942cdf0bb7","tarball":"https://registry.npmjs.org/@cartiqo/discord-transcript/-/discord-transcript-0.2.0.tgz","fileCount":9,"unpackedSize":112964,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCItlG0ojZA0DMMPAHn4Y2bCQOEnT+w0+R7oXxVBVV/qQIgVTiKdcUb+zhVV5Gl+mt6KEPPgmvdVaHZamvIQ15nvtA="}]},"_npmUser":{"name":"duckodas","email":"duckodas@gmail.com"},"directories":{},"maintainers":[{"name":"duckodas","email":"duckodas@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/discord-transcript_0.2.0_1786612589518_0.13154174544298436"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-14T02:26:15.471Z","modified":"2026-08-13T09:16:29.825Z","0.1.0":"2026-07-14T02:26:15.866Z","0.1.1":"2026-07-14T02:29:23.373Z","0.2.0":"2026-08-13T09:16:29.647Z"},"bugs":{"url":"https://github.com/cartiqoframework/discord-transcript/issues"},"author":{"name":"CARTIQO"},"license":"MIT","homepage":"https://github.com/cartiqoframework/discord-transcript#readme","keywords":["discord","transcript","chat-exporter","html","tickets","discord-components","discord.js"],"repository":{"type":"git","url":"git+https://github.com/cartiqoframework/discord-transcript.git"},"description":"Generate beautiful, self-contained HTML transcripts of Discord channels, rendered with Discord's own message components.","maintainers":[{"name":"duckodas","email":"duckodas@gmail.com"}],"readme":"# @cartiqo/discord-transcript\n\nGenerate beautiful, self-contained **HTML transcripts** of Discord channels —\nrendered with Discord's own message components via\n[`@skyra/discord-components-core`](https://www.npmjs.com/package/@skyra/discord-components-core).\n\nGive it plain message data (author, content, timestamp, attachments, embeds,\nreactions) and get back a single HTML string you can save to a file, upload as an\nattachment, or serve. No headless browser, no runtime dependencies to bundle —\nthe output is one portable `.html` document.\n\n## Install\n\n```bash\nnpm install @cartiqo/discord-transcript\n```\n\n## Usage\n\n```ts\nimport { renderTranscript } from \"@cartiqo/discord-transcript\";\n\nconst html = renderTranscript({\n  guild: { name: \"My Server\", iconURL: \"https://…/icon.png\" },\n  channel: { name: \"ticket-0042\", topic: \"Support ticket for @ada\" },\n  messages: [\n    {\n      author: { name: \"Ada\", avatarURL: \"https://…/ada.png\", color: \"#7c5cff\" },\n      content: \"Hey, I need help with **billing** — here's a screenshot.\",\n      timestamp: new Date(),\n      attachments: [{ url: \"https://…/shot.png\", contentType: \"image/png\" }],\n    },\n    {\n      author: { name: \"Support\", bot: true, verified: true },\n      content: \"On it! Give me a moment.\",\n      timestamp: new Date(),\n      reply: { author: \"Ada\", content: \"I need help with billing\" },\n    },\n  ],\n});\n\n// html is a complete <!doctype html> document.\n```\n\n## From discord.js\n\nThe package is framework-agnostic — it takes plain data — so you map your\nmessages once:\n\n```ts\nimport { renderTranscript, type TranscriptMessage } from \"@cartiqo/discord-transcript\";\n\nconst collection = await channel.messages.fetch({ limit: 100 });\n\nconst messages: TranscriptMessage[] = [...collection.values()]\n  .reverse()\n  .map((m) => ({\n    id: m.id,\n    author: {\n      id: m.author.id,\n      name: m.member?.displayName ?? m.author.username,\n      avatarURL: m.author.displayAvatarURL(),\n      bot: m.author.bot,\n      color: m.member?.displayHexColor,\n    },\n    content: m.content,\n    timestamp: m.createdAt,\n    edited: Boolean(m.editedAt),\n    attachments: [...m.attachments.values()].map((a) => ({\n      url: a.url,\n      name: a.name ?? undefined,\n      contentType: a.contentType ?? undefined,\n      width: a.width ?? undefined,\n      height: a.height ?? undefined,\n      size: a.size,\n    })),\n    embeds: m.embeds.map((e) => ({\n      title: e.title ?? undefined,\n      description: e.description ?? undefined,\n      url: e.url ?? undefined,\n      color: e.hexColor ?? undefined,\n      authorName: e.author?.name,\n      imageURL: e.image?.url,\n      thumbnailURL: e.thumbnail?.url,\n      footerText: e.footer?.text,\n      fields: e.fields.map((f) => ({ name: f.name, value: f.value, inline: f.inline })),\n      timestamp: e.timestamp ?? undefined,\n    })),\n    reactions: m.reactions.cache.map((r) => ({\n      emoji: r.emoji.name ?? \"❓\",\n      imageURL: r.emoji.imageURL() ?? undefined,\n      count: r.count,\n    })),\n    reply: m.reference\n      ? (() => {\n          const ref = collection.get(m.reference!.messageId!);\n          return ref ? { author: ref.author.username, content: ref.content } : undefined;\n        })()\n      : undefined,\n  }));\n\nconst html = renderTranscript({ channel: { name: channel.name }, messages });\n```\n\n## Options\n\n`renderTranscript(options)` accepts:\n\n| Option              | Type                | Default            | Description                                              |\n| ------------------- | ------------------- | ------------------ | -------------------------------------------------------- |\n| `messages`          | `TranscriptMessage[]` | —                | The messages, oldest first.                              |\n| `channel`           | `TranscriptChannel` | —                  | Channel name / topic shown in the header.                |\n| `guild`             | `TranscriptGuild`   | —                  | Server name / icon shown in the header.                  |\n| `generatedAt`       | `Date`              | `new Date()`       | Export timestamp.                                        |\n| `title`             | `string`            | channel name       | The document `<title>`.                                  |\n| `light`             | `boolean`           | `false`            | Use the light theme.                                     |\n| `footerCredit`      | `boolean`           | `true`             | Show a small footer credit.                              |\n| `componentsVersion` | `string`            | current            | Pin the components version loaded from the CDN.          |\n| `offlineFallback`   | `boolean`           | `true`             | Also write a plain-HTML copy, shown only if the components fail to load. |\n\n### Markdown\n\nMessage content and embed descriptions support a safe subset of Discord\nmarkdown: fenced and inline code, **bold**, *italics*, __underline__,\n~~strikethrough~~, spoilers, block quotes, and autolinked URLs. All input is\nHTML-escaped first, so raw message text can never inject markup.\n\n### Rendering\n\nThe output loads `@skyra/discord-components-core` from a CDN (jsDelivr) to render\nthe message components, so the full Discord look needs a network connection the\nfirst time. The surrounding page chrome (header, code blocks, links) is styled\ninline and works offline.\n\n**The transcript stays readable when that request fails.** The Discord components\ncarry the author, timestamp and role colour as *attributes*, so an element that\nnever upgrades loses all three — leaving unattributed text in one block, which is\nworth very little as a record of a conversation. `renderTranscript` therefore\nalso writes a plain-HTML copy of the same messages, hidden by CSS as soon as the\ncomponents define themselves:\n\n```css\ndiscord-messages:not(:defined)   { display: none; }  /* wait for the upgrade */\ndiscord-messages:defined + .dt-fallback { display: none; }  /* then drop the copy */\n```\n\nPure CSS, so it also covers JavaScript being disabled entirely, and the two are\nnever visible at once. It roughly doubles the file size — pass\n`offlineFallback: false` if you are serving the components yourself and can\nguarantee they load.\n\n## License\n\n[MIT](./LICENSE)\n","readmeFilename":"README.md"}