discord-html-transcripts-fix 1.8.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,16 +1,26 @@
1
1
  # `discord-html-transcripts-fix`
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/discord-html-transcripts-fix.svg)](https://www.npmjs.com/package/discord-html-transcripts-fix)
4
+ [![license](https://img.shields.io/npm/l/discord-html-transcripts-fix.svg)](./LICENSE)
5
+ [![node](https://img.shields.io/node/v/discord-html-transcripts-fix.svg)](https://nodejs.org)
6
+
3
7
  A nicely formatted HTML transcript generator for [discord.js](https://discord.js.org/) with full **Components V2** support, an **interactive viewer**, and **hardened security**.
4
8
 
5
9
  Forked from [discord-html-transcripts](https://github.com/ItzDerock/discord-html-transcripts).
6
10
 
11
+ ## Requirements
12
+
13
+ - **Node.js ≥ 20** — the image downloader uses `undici` v7.
14
+ - **discord.js v14 or v15** — required peer dependency.
15
+ - **[`sharp`](https://sharp.pixelplumbing.com/)** — *optional* peer dependency, only needed if you use `.withCompression()` to compress / convert transcript images to WebP.
16
+
7
17
  ## Install
8
18
 
9
19
  ```bash
10
20
  npm install discord-html-transcripts-fix
11
21
  ```
12
22
 
13
- Only `discord.js` is a peer dependency; everything else (React, Lit SSR, markdown parser, etc.) is auto-installed.
23
+ `discord.js` is the only **required** peer dependency — React, Lit SSR, the markdown parser, etc. are installed automatically. `sharp` is an optional peer (image compression only).
14
24
 
15
25
  ## Quick start
16
26
 
@@ -18,11 +28,28 @@ Only `discord.js` is a peer dependency; everything else (React, Lit SSR, markdow
18
28
  const { createTranscript } = require('discord-html-transcripts-fix');
19
29
 
20
30
  const attachment = await createTranscript(channel, {
21
- limit: -1,
31
+ limit: -1, // fetch every message
22
32
  saveImages: false,
23
33
  });
24
34
 
25
- channel.send({ files: [attachment] });
35
+ await channel.send({ files: [attachment] });
36
+ ```
37
+
38
+ ### TypeScript
39
+
40
+ In TypeScript, use the `ExportReturnType` enum for `returnType` (the return value is typed accordingly):
41
+
42
+ ```ts
43
+ import { createTranscript, ExportReturnType } from 'discord-html-transcripts-fix';
44
+
45
+ const html = await createTranscript(channel, {
46
+ returnType: ExportReturnType.String, // => Promise<string>
47
+ language: 'de',
48
+ });
49
+
50
+ const stream = await createTranscript(channel, {
51
+ returnType: ExportReturnType.Stream, // => Promise<Readable>, ideal for huge tickets
52
+ });
26
53
  ```
27
54
 
28
55
  ## Options
@@ -31,7 +58,7 @@ channel.send({ files: [attachment] });
31
58
  |---|---|---|---|
32
59
  | `limit` | `number` | `-1` | Max messages to fetch. `-1` = recursive (all). |
33
60
  | `filter` | `(m) => boolean` | `() => true` | Predicate to filter messages. |
34
- | `returnType` | `'attachment'` \| `'buffer'` \| `'string'` \| `'stream'` | `'attachment'` | Return value shape. `'stream'` is best for 5k+ message exports. |
61
+ | `returnType` | `'attachment'` \| `'buffer'` \| `'string'` \| `'stream'` | `'attachment'` | Return value shape. In TypeScript pass the `ExportReturnType` enum. `'stream'` returns a Node `Readable` and is best for 5k+ message exports. |
35
62
  | `filename` | `string` | `transcript-{channel-id}.html` | Output filename when returning as attachment. |
36
63
  | `saveImages` | `boolean` | `false` | Download images and inline them as base64 data URLs. |
37
64
  | `favicon` | `'guild'` \| `string` | `'guild'` | Page favicon — `'guild'` uses the server icon, or pass a URL. |
@@ -39,9 +66,9 @@ channel.send({ files: [attachment] });
39
66
  | `language` | `'en'` \| `'de'` | `'en'` | UI language for participant labels, filter strings, etc. |
40
67
  | `i18n` | `Partial<Record<lang, Record<key,string>>>` | — | Override individual strings per language. |
41
68
  | `statsFooter` | `false` \| `{ enabled?, template? }` | `{ enabled: true }` | Bottom stats line. See below. |
42
- | `footerText` | `string` | — | Legacy "Exported X messages" line. Only renders when `statsFooter` is disabled. |
43
- | `poweredBy` | `boolean` | `false` | Show the original "Powered by discord-html-transcripts" credit link. |
44
- | `callbacks` | `{ resolveUser, resolveRole, resolveChannel }` | — | Custom resolvers for mentions. |
69
+ | `footerText` | `string` | `Exported {number} message{s}.` | Legacy "Exported X messages" line. Only renders when `statsFooter` is disabled. |
70
+ | `poweredBy` | `boolean` | `false` | Show the original "Powered by discord-html-transcripts" credit link. Only renders when `statsFooter` is disabled. |
71
+ | `callbacks` | `{ resolveUser, resolveRole, resolveChannel, resolveImageSrc }` | — | Custom resolvers for mentions / image URLs. |
45
72
 
46
73
  ### Configurable stats footer
47
74
 
@@ -58,6 +85,23 @@ await createTranscript(channel, { statsFooter: false });
58
85
 
59
86
  Placeholders: `{messages}`, `{participants}`, `{images}`, `{from}`, `{to}`, `{span}`.
60
87
 
88
+ ### Image compression (optional)
89
+
90
+ `saveImages: true` inlines images as base64 without any extra dependency. To additionally
91
+ compress them (and optionally convert to WebP), install `sharp` and build a custom downloader:
92
+
93
+ ```js
94
+ const { createTranscript, TranscriptImageDownloader } = require('discord-html-transcripts-fix');
95
+
96
+ const resolveImageSrc = new TranscriptImageDownloader()
97
+ .withMaxSize(2048) // KB per image
98
+ .withConcurrency(8) // parallel downloads (default 6)
99
+ .withCompression(80, true) // quality 80, convert to WebP — requires `sharp`
100
+ .build();
101
+
102
+ await createTranscript(channel, { saveImages: true, callbacks: { resolveImageSrc } });
103
+ ```
104
+
61
105
  ### Optional edit history
62
106
 
63
107
  If your bot tracks edits, attach them to the message *before* rendering:
@@ -130,6 +174,7 @@ In addition to plain text, replies, embeds, and attachments, the viewer supports
130
174
  - **Fix** `parseDiscordEmoji` no longer throws on deleted reactions with `emoji.name === null`
131
175
  - **Fix** `formatBytes(null/undefined/NaN)` no longer returns `NaN undefined`
132
176
  - **Fix** `createTranscript` slice uses the resolved limit instead of the raw `limit`
177
+ - **Fix** `statsFooter` (custom template / `false`) is now forwarded end-to-end — it used to be silently ignored by `createTranscript`/`generateFromMessages`
133
178
  - **Fix** embed fields render through a proper async component (was an inline `async` arrow inside `.map()`)
134
179
  - **Fix** `JoinMessage` text is deterministic per message id — re-rendering the same channel always yields the same join line
135
180
  - **Fix** random `console.log` calls in production paths replaced by the `debug` namespace
@@ -153,8 +198,23 @@ In addition to plain text, replies, embeds, and attachments, the viewer supports
153
198
  ### DX
154
199
 
155
200
  - **`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)
156
- - TypeScript declarations cover all new options
157
- - `discord.js` remains the only peer dependency
201
+ - **`sharp` declared as an optional peer dependency** — needed only for `.withCompression()`, no longer a hidden requirement
202
+ - **TypeScript declarations match runtime** — `ExportReturnType.Stream`, `language`, `i18n`, `stream`, and `withConcurrency()` are now exposed in the types
203
+ - `discord.js` remains the only **required** peer dependency
204
+
205
+ ## API
206
+
207
+ | Export | Description |
208
+ |---|---|
209
+ | `createTranscript(channel, options?)` | Fetch a channel's messages and render a transcript. |
210
+ | `generateFromMessages(messages, channel, options?)` | Render a transcript from a message array/collection you already have. |
211
+ | `ExportReturnType` | Enum: `Attachment` \| `Buffer` \| `String` \| `Stream`. |
212
+ | `TranscriptImageDownloader` | Builder for a custom image-saving callback (`withMaxSize`, `withConcurrency`, `withCompression`, `build`). |
213
+ | `DiscordMessages` | The underlying React component, for advanced/custom rendering. |
214
+
215
+ ## License
216
+
217
+ [Apache-2.0](./LICENSE) — same as the original package.
158
218
 
159
219
  ## Credits
160
220
 
@@ -1,5 +1,24 @@
1
1
  import type { APIAttachment, APIMessage, Awaitable } from 'discord.js';
2
- import type { WebpOptions } from 'sharp';
2
+ /**
3
+ * Subset of sharp's `WebpOptions`. `sharp` is an OPTIONAL peer dependency — it is
4
+ * only needed for `.withCompression(..., convertToWebP)`. Typing it locally (instead
5
+ * of `import('sharp')`) means consumers who don't use compression are not forced to
6
+ * install sharp and don't get a "Cannot find module 'sharp'" error when type-checking.
7
+ */
8
+ export interface WebpOptions {
9
+ quality?: number;
10
+ alphaQuality?: number;
11
+ lossless?: boolean;
12
+ nearLossless?: boolean;
13
+ smartSubsample?: boolean;
14
+ effort?: number;
15
+ loop?: number;
16
+ delay?: number | number[];
17
+ minSize?: boolean;
18
+ mixed?: boolean;
19
+ force?: boolean;
20
+ [option: string]: unknown;
21
+ }
3
22
  /**
4
23
  * Callback used to save an image attachment.
5
24
  * The returned string is the URL that will be used in the transcript.
@@ -22,6 +41,11 @@ export declare class TranscriptImageDownloader {
22
41
  * @param size The maximum file size in kilobytes
23
42
  */
24
43
  withMaxSize(size: number): this;
44
+ /**
45
+ * Sets the maximum number of images downloaded concurrently.
46
+ * @param n Concurrency (default 6)
47
+ */
48
+ withConcurrency(n: number): this;
25
49
  /**
26
50
  * Sets the compression quality for each image. This requires `sharp` to be installed.
27
51
  * Optionally, images can be converted to WebP format which is smaller in size.
package/dist/index.js CHANGED
@@ -78,8 +78,9 @@ async function generateFromMessages(messages, channel, options = {}) {
78
78
  channel,
79
79
  saveImages: options.saveImages ?? false,
80
80
  callbacks,
81
- poweredBy: options.poweredBy ?? true,
81
+ poweredBy: options.poweredBy ?? false,
82
82
  footerText: options.footerText ?? 'Exported {number} message{s}.',
83
+ statsFooter: options.statsFooter,
83
84
  favicon: options.favicon ?? 'guild',
84
85
  hydrate: options.hydrate ?? false,
85
86
  language: options.language ?? 'en',
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { AttachmentBuilder, Message } from 'discord.js';
2
2
  import type { RenderMessageContext } from './generator';
3
+ import type { Readable } from 'stream';
3
4
  export declare enum AttachmentTypes {
4
5
  Audio = 0,
5
6
  Video = 1,
@@ -9,9 +10,10 @@ export declare enum AttachmentTypes {
9
10
  export declare enum ExportReturnType {
10
11
  Buffer = "buffer",
11
12
  String = "string",
12
- Attachment = "attachment"
13
+ Attachment = "attachment",
14
+ Stream = "stream"
13
15
  }
14
- export type ObjectType<T extends ExportReturnType> = T extends ExportReturnType.Buffer ? Buffer : T extends ExportReturnType.String ? string : AttachmentBuilder;
16
+ export type ObjectType<T extends ExportReturnType> = T extends ExportReturnType.Buffer ? Buffer : T extends ExportReturnType.String ? string : T extends ExportReturnType.Stream ? Readable : AttachmentBuilder;
15
17
  export type GenerateFromMessagesOptions<T extends ExportReturnType> = Partial<{
16
18
  /**
17
19
  * The type of object to return
@@ -33,8 +35,9 @@ export type GenerateFromMessagesOptions<T extends ExportReturnType> = Partial<{
33
35
  */
34
36
  filename: string;
35
37
  /**
36
- * Whether to include the "Powered by discord-html-transcripts" footer
37
- * @default true
38
+ * Whether to include the "Powered by discord-html-transcripts" credit link.
39
+ * Only renders when the stats footer is disabled (`statsFooter: false`).
40
+ * @default false
38
41
  */
39
42
  poweredBy: boolean;
40
43
  /**
@@ -68,6 +71,22 @@ export type GenerateFromMessagesOptions<T extends ExportReturnType> = Partial<{
68
71
  enabled?: boolean;
69
72
  template?: string;
70
73
  };
74
+ /**
75
+ * UI language for the built-in strings (participant labels, filter UI, stats footer, …).
76
+ * @default 'en'
77
+ */
78
+ language: 'en' | 'de';
79
+ /**
80
+ * Override individual built-in strings per language. Merged over the defaults.
81
+ * Keys are the string ids used internally (e.g. `statsMessages`, `statsParticipants`).
82
+ */
83
+ i18n: Partial<Record<'en' | 'de', Record<string, string>>>;
84
+ /**
85
+ * Return a Node `Readable` stream of the rendered HTML instead of buffering it.
86
+ * Equivalent to `returnType: ExportReturnType.Stream`. Best for very large exports.
87
+ * @default false
88
+ */
89
+ stream: boolean;
71
90
  }>;
72
91
  export type CreateTranscriptOptions<T extends ExportReturnType> = Partial<GenerateFromMessagesOptions<T> & {
73
92
  /**
package/package.json CHANGED
@@ -1,10 +1,19 @@
1
1
  {
2
2
  "name": "discord-html-transcripts-fix",
3
- "version": "1.8.2",
3
+ "version": "2.0.0",
4
4
  "description": "A nicely formatted html transcript generator for discord.js. Bugfix fork with support for the latest discord.js and Components v2.",
5
5
  "main": "dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "license": "Apache-2.0",
8
+ "author": "Developer-Sven (https://github.com/Developer-Sven)",
9
+ "homepage": "https://github.com/Developer-Sven/discord-html-transcripts-fix#readme",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/Developer-Sven/discord-html-transcripts-fix.git"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/Developer-Sven/discord-html-transcripts-fix/issues"
16
+ },
8
17
  "keywords": [
9
18
  "discord",
10
19
  "discord.js",
@@ -34,7 +43,16 @@
34
43
  "undici": "^7.16.0"
35
44
  },
36
45
  "peerDependencies": {
37
- "discord.js": "^14.0.0 || ^15.0.0"
46
+ "discord.js": "^14.0.0 || ^15.0.0",
47
+ "sharp": ">=0.30.0"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "sharp": {
51
+ "optional": true
52
+ }
53
+ },
54
+ "engines": {
55
+ "node": ">=20"
38
56
  },
39
57
  "scripts": {
40
58
  "prepublishOnly": "node -e \"require('fs').accessSync('dist/index.js'); require('fs').accessSync('dist/index.d.ts');\" || (echo 'dist/index.js or dist/index.d.ts missing — refusing to publish' && exit 1)"