buncord-transcript 1.0.1 → 1.0.3

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "buncord-transcript",
3
- "version": "1.0.1",
4
- "description": "A high-performance Discord transcript generator built for Bun.",
3
+ "version": "1.0.3",
4
+ "description": "High-performance, Bun-native Discord HTML transcripts with 1:1 visual fidelity.",
5
5
  "module": "src/index.ts",
6
6
  "main": "src/index.ts",
7
7
  "type": "module",
@@ -24,7 +24,10 @@
24
24
  "transcript",
25
25
  "bun",
26
26
  "html",
27
- "generator"
27
+ "generator",
28
+ "performance",
29
+ "zero-dependency",
30
+ "discord-v2"
28
31
  ],
29
32
  "devDependencies": {
30
33
  "@types/bun": "latest"
package/bun.lock DELETED
@@ -1,31 +0,0 @@
1
- {
2
- "lockfileVersion": 1,
3
- "configVersion": 1,
4
- "workspaces": {
5
- "": {
6
- "name": "buncord-transcript",
7
- "dependencies": {
8
- "mustache": "luigicolantuono/mustache",
9
- },
10
- "devDependencies": {
11
- "@types/bun": "latest",
12
- },
13
- "peerDependencies": {
14
- "typescript": "^5",
15
- },
16
- },
17
- },
18
- "packages": {
19
- "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
20
-
21
- "@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
22
-
23
- "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
24
-
25
- "mustache": ["mustache@github:luigicolantuono/mustache#9a14e96", { "bin": { "mustache": "./bin/mustache" } }, "LuigiColantuono-mustache-9a14e96"],
26
-
27
- "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
28
-
29
- "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
30
- }
31
- }
package/index.ts DELETED
@@ -1 +0,0 @@
1
- console.log("Hello via Bun!");
@@ -1,381 +0,0 @@
1
- <!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'><title>Transcript - mention-test</title><style>
2
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
3
- @import url('https://fonts.googleapis.com/css2?family=Fira+Code&display=swap');
4
-
5
- :root {
6
- --background-primary: #313338;
7
- --background-secondary: #2b2d31;
8
- --background-secondary-alt: #242529;
9
- --background-tertiary: #1e1f22;
10
- --background-floating: #1e1f22;
11
- --background-accent: #404249;
12
- --background-modifier-hover: rgba(78, 80, 88, 0.16);
13
- --background-modifier-active: rgba(78, 80, 88, 0.24);
14
- --background-modifier-selected: rgba(78, 80, 88, 0.32);
15
- --text-normal: #dbdee1;
16
- --text-muted: #949ba4;
17
- --text-link: #00a8fc;
18
- --text-positive: #23a559;
19
- --text-warning: #f0b232;
20
- --text-danger: #f23f43;
21
- --header-primary: #f2f3f5;
22
- --header-secondary: #b5bac1;
23
- --interactive-normal: #b5bac1;
24
- --interactive-hover: #dbdee1;
25
- --interactive-active: #ffffff;
26
- --interactive-muted: #4e5058;
27
- --brand-experiment: #5865f2;
28
- --brand-experiment-560: #4752c4;
29
- --status-online: #23a559;
30
- --status-idle: #f0b232;
31
- --status-dnd: #f23f43;
32
- --status-offline: #80848e;
33
- --button-secondary-background: #4e5058;
34
- --button-secondary-background-hover: #6d6f78;
35
- --button-secondary-background-active: #80848e;
36
- --button-danger-background: #da373c;
37
- --button-danger-background-hover: #a12828;
38
- --button-danger-background-active: #892222;
39
- --button-positive-background: #248046;
40
- --button-positive-background-hover: #1a6334;
41
- --button-positive-background-active: #15522b;
42
- --mention-background: rgba(88, 101, 242, 0.3);
43
- --mention-foreground: #dee0fc;
44
- --mention-hover-background: rgba(88, 101, 242, 0.6);
45
- --embed-background: #2b2d31;
46
- --embed-background-alternate: #242529;
47
- --message-margin-horizontal: 16px;
48
- --message-margin-vertical: 1.0625rem;
49
- --avatar-size: 40px;
50
- }
51
-
52
- * { box-sizing: border-box; }
53
-
54
- body {
55
- background-color: var(--background-primary);
56
- color: var(--text-normal);
57
- font-family: 'Inter', 'gg sans', 'Whitney', 'Helvetica Neue', Helvetica, Arial, sans-serif;
58
- font-size: 1rem;
59
- line-height: 1.375rem;
60
- margin: 0;
61
- padding: 0;
62
- -webkit-font-smoothing: antialiased;
63
- }
64
-
65
- a { color: var(--text-link); text-decoration: none; }
66
- a:hover { text-decoration: underline; }
67
-
68
- .guild-header {
69
- background-color: var(--background-primary);
70
- padding: 0 16px;
71
- display: flex;
72
- align-items: center;
73
- position: sticky;
74
- top: 0;
75
- z-index: 100;
76
- height: 48px;
77
- box-shadow: 0 1px 0 rgba(0,0,0,0.2), 0 1.5px 0 rgba(0,0,0,0.05), 0 2px 0 rgba(0,0,0,0.05);
78
- }
79
-
80
- .guild-icon {
81
- width: 24px;
82
- height: 24px;
83
- border-radius: 50%;
84
- margin-right: 8px;
85
- }
86
-
87
- .guild-info h1 {
88
- font-size: 1rem;
89
- font-weight: 600;
90
- color: var(--header-primary);
91
- margin: 0;
92
- }
93
-
94
- .channel-info {
95
- font-size: 0.875rem;
96
- color: var(--header-secondary);
97
- margin-left: 8px;
98
- padding-left: 8px;
99
- border-left: 1px solid var(--background-modifier-active);
100
- }
101
-
102
- .chatlog { padding: 0; }
103
-
104
- .message-group {
105
- display: flex;
106
- margin-top: var(--message-margin-vertical);
107
- padding: 2px 16px;
108
- position: relative;
109
- }
110
-
111
- .message-group:hover {
112
- background-color: rgba(0,0,0,0.02);
113
- }
114
-
115
- .author-avatar {
116
- width: var(--avatar-size);
117
- height: var(--avatar-size);
118
- border-radius: 50%;
119
- margin-right: 16px;
120
- margin-top: 2px;
121
- flex-shrink: 0;
122
- cursor: pointer;
123
- }
124
-
125
- .message-content-wrapper { flex: 1; min-width: 0; }
126
-
127
- .message-header {
128
- display: flex;
129
- align-items: center;
130
- line-height: 1.375rem;
131
- }
132
-
133
- .author-name {
134
- font-size: 1rem;
135
- font-weight: 500;
136
- color: var(--header-primary);
137
- margin-right: 0.25rem;
138
- cursor: pointer;
139
- }
140
-
141
- .author-name:hover { text-decoration: underline; }
142
-
143
- .bot-tag {
144
- background-color: var(--brand-experiment);
145
- color: #ffffff;
146
- font-size: 0.625rem;
147
- text-transform: uppercase;
148
- height: 0.9375rem;
149
- padding: 0 0.275rem;
150
- border-radius: 0.1875rem;
151
- line-height: normal;
152
- font-weight: 500;
153
- margin-left: 0.25rem;
154
- display: inline-flex;
155
- align-items: center;
156
- justify-content: center;
157
- vertical-align: baseline;
158
- position: relative;
159
- top: -1px;
160
- }
161
-
162
- .bot-tag svg {
163
- margin-right: 2px;
164
- width: 14px;
165
- height: 14px;
166
- }
167
-
168
- .bot-tag-text {
169
- line-height: 0.9375rem;
170
- }
171
-
172
- .timestamp {
173
- font-size: 0.75rem;
174
- color: var(--text-muted);
175
- margin-left: 0.5rem;
176
- font-weight: 400;
177
- }
178
-
179
- .message-body {
180
- font-size: 1rem;
181
- line-height: 1.375rem;
182
- color: var(--text-normal);
183
- white-space: pre-wrap;
184
- word-wrap: break-word;
185
- margin-top: 2px;
186
- }
187
-
188
- .mention {
189
- background-color: var(--mention-background);
190
- color: var(--mention-foreground);
191
- border-radius: 3px;
192
- padding: 0 2px;
193
- font-weight: 500;
194
- cursor: pointer;
195
- }
196
-
197
- .mention:hover {
198
- background-color: var(--mention-hover-background);
199
- color: #ffffff;
200
- }
201
-
202
- .reply-reference {
203
- display: flex;
204
- align-items: center;
205
- font-size: 0.875rem;
206
- color: var(--text-muted);
207
- margin-bottom: 4px;
208
- margin-left: 56px;
209
- position: relative;
210
- }
211
-
212
- .reply-reference::before {
213
- content: "";
214
- display: block;
215
- position: absolute;
216
- top: 50%;
217
- left: -33px;
218
- bottom: 0;
219
- border-top: 2px solid #4e5058;
220
- border-left: 2px solid #4e5058;
221
- border-top-left-radius: 6px;
222
- width: 33px;
223
- height: 10px;
224
- }
225
-
226
- .reply-avatar {
227
- width: 16px;
228
- height: 16px;
229
- border-radius: 50%;
230
- margin-right: 4px;
231
- }
232
-
233
- .reply-user {
234
- font-weight: 500;
235
- margin-right: 4px;
236
- cursor: pointer;
237
- }
238
-
239
- .reply-user:hover { text-decoration: underline; }
240
-
241
- .reply-content {
242
- overflow: hidden;
243
- text-overflow: ellipsis;
244
- white-space: nowrap;
245
- }
246
-
247
- .embed {
248
- display: flex;
249
- max-width: 520px;
250
- background-color: var(--background-secondary);
251
- border-radius: 4px;
252
- border-left: 4px solid var(--background-tertiary);
253
- margin-top: 8px;
254
- padding: 8px 16px 16px 12px;
255
- position: relative;
256
- }
257
-
258
- .embed-content {
259
- display: flex;
260
- flex-direction: column;
261
- flex: 1;
262
- }
263
-
264
- .embed-author {
265
- display: flex;
266
- align-items: center;
267
- margin-top: 8px;
268
- margin-bottom: 8px;
269
- }
270
-
271
- .embed-author-icon {
272
- width: 24px;
273
- height: 24px;
274
- border-radius: 50%;
275
- margin-right: 8px;
276
- }
277
-
278
- .embed-author-name {
279
- font-size: 0.875rem;
280
- font-weight: 600;
281
- color: var(--header-primary);
282
- }
283
-
284
- .embed-title {
285
- font-size: 1rem;
286
- font-weight: 600;
287
- color: var(--text-link);
288
- margin-bottom: 4px;
289
- }
290
-
291
- .embed-description {
292
- font-size: 0.875rem;
293
- line-height: 1.125rem;
294
- color: var(--text-normal);
295
- white-space: pre-wrap;
296
- }
297
-
298
- .embed-fields {
299
- display: grid;
300
- grid-gap: 8px;
301
- margin-top: 8px;
302
- }
303
-
304
- .embed-field-name {
305
- font-size: 0.875rem;
306
- font-weight: 600;
307
- color: var(--header-primary);
308
- margin-bottom: 2px;
309
- }
310
-
311
- .embed-field-value {
312
- font-size: 0.875rem;
313
- color: var(--text-normal);
314
- white-space: pre-wrap;
315
- }
316
-
317
- .embed-footer {
318
- display: flex;
319
- align-items: center;
320
- margin-top: 8px;
321
- }
322
-
323
- .embed-footer-icon {
324
- width: 20px;
325
- height: 20px;
326
- border-radius: 50%;
327
- margin-right: 8px;
328
- }
329
-
330
- .embed-footer-text {
331
- font-size: 0.75rem;
332
- color: var(--text-muted);
333
- }
334
-
335
- .message-component-group {
336
- display: flex;
337
- flex-wrap: wrap;
338
- gap: 8px;
339
- margin-top: 8px;
340
- }
341
-
342
- .discord-button {
343
- height: 32px;
344
- min-width: 60px;
345
- padding: 2px 16px;
346
- border-radius: 3px;
347
- font-size: 14px;
348
- font-weight: 500;
349
- color: #ffffff;
350
- border: none;
351
- cursor: pointer;
352
- display: flex;
353
- align-items: center;
354
- justify-content: center;
355
- transition: background-color 0.17s ease;
356
- }
357
-
358
- .discord-button-primary { background-color: var(--brand-experiment); }
359
- .discord-button-primary:hover { background-color: var(--brand-experiment-560); }
360
- .discord-button-secondary { background-color: var(--button-secondary-background); }
361
- .discord-button-secondary:hover { background-color: var(--button-secondary-background-hover); }
362
- .discord-button-success { background-color: var(--button-positive-background); }
363
- .discord-button-success:hover { background-color: var(--button-positive-background-hover); }
364
- .discord-button-destructive { background-color: var(--button-danger-background); }
365
- .discord-button-destructive:hover { background-color: var(--button-danger-background-hover); }
366
-
367
- .discord-container {
368
- background-color: var(--background-secondary);
369
- border: 1px solid rgba(255,255,255,0.05);
370
- border-radius: 8px;
371
- padding: 12px;
372
- margin-top: 8px;
373
- max-width: 520px;
374
- }
375
-
376
- .discord-separator {
377
- height: 1px;
378
- background-color: rgba(255,255,255,0.05);
379
- margin: 8px 0;
380
- }
381
- </style></head><body><header class='guild-header'><div class='guild-info'><h1>mention-test</h1></div><div class='channel-info'>Testing mentions and timestamps</div></header><div class='chatlog'><div class='message-group' id='message-1'><img src='https://cdn.discordapp.com/embed/avatars/0.png' class='author-avatar' alt='Customer'><div class='message-content-wrapper'><div class='message-header'><span class='author-name' >Customer</span><span class='timestamp'>01/25/2026, 11:50 AM</span></div><div class='message-body'>Hi <span class="mention">@Support Bot</span>, I am <span class="mention">@Customer</span>!</div></div></div><div class='message-group' id='message-2'><img src='https://cdn.discordapp.com/embed/avatars/1.png' class='author-avatar' alt='Support Bot'><div class='message-content-wrapper'><div class='message-header'><span class='author-name' >Support Bot</span><span class='bot-tag'><svg aria-hidden='true' role='img' xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='none' viewBox='0 0 24 24'><path fill='white' fill-rule='evenodd' d='M19.06 6.94a1.5 1.5 0 0 1 0 2.12l-8 8a1.5 1.5 0 0 1-2.12 0l-4-4a1.5 1.5 0 0 1 2.12-2.12L10 13.88l6.94-6.94a1.5 1.5 0 0 1 2.12 0Z' clip-rule='evenodd'></path></svg><span class='bot-tag-text'>APP</span></span><span class='timestamp'>01/25/2026, 11:50 AM</span></div><div class='message-body'>Hello <span class="mention">@Customer</span>! This ticket was claimed at <span class="timestamp">25/01/2025, 11:13:20</span>. Mentioning unknown: <span class="mention">@User</span></div><div class='embed' ><div class='embed-content'><div class='embed-author'><span class='embed-author-name'></span></div><div class='embed-description'>Embed mentioning <span class="mention">@Customer</span> and timestamp <span class="timestamp">25/01/2025, 11:30:00</span></div><div class='embed-fields'><div class='embed-field'><div class='embed-field-name'>User</div><div class='embed-field-value'><span class="mention">@Customer</span></div></div></div></div></div></div></div></div></body></html>
@@ -1,695 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Transcript - ticket-001</title>
7
- <style>
8
-
9
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
10
- @import url('https://fonts.googleapis.com/css2?family=Fira+Code&display=swap');
11
-
12
- :root {
13
- /* Colors - Backgrounds */
14
- --background-primary: #313338;
15
- --background-secondary: #2b2d31;
16
- --background-tertiary: #1e1f22;
17
- --background-accent: #404249;
18
- --background-surface-high: #2b2d31;
19
- --background-modifier-hover: rgba(4,4,5,0.07);
20
-
21
- /* Colors - Text */
22
- --text-normal: #dbdee1;
23
- --text-muted: #949ba4;
24
- --text-link: #00a8fc;
25
- --header-primary: #f2f3f5;
26
- --header-secondary: #b5bac1;
27
-
28
- /* Colors - Interactive */
29
- --interactive-normal: #b5bac1;
30
- --interactive-hover: #dbdee1;
31
- --interactive-active: #ffffff;
32
-
33
- /* Colors - Brand & Status */
34
- --brand-experiment: #5865F2;
35
- --danger: #da373c;
36
- --positive: #23a559;
37
- --warning: #f0b232;
38
-
39
- /* Colors - Buttons (HSL) */
40
- --button-primary-bg: hsl(234.935 85.556% 64.706% / 1);
41
- --button-secondary-bg: hsl(240 4% 60.784% / 0.12);
42
- --button-success-bg: hsl(145.97 100% 26.275% / 1);
43
- --button-destructive-bg: hsl(355.636 64.706% 50% / 1);
44
-
45
- /* Components */
46
- --border-subtle: rgba(78, 80, 88, 0.48);
47
- --separator-color: #4f5359;
48
- --mention-bg: rgba(88, 101, 242, 0.3);
49
- --mention-hover-bg: rgba(88, 101, 242, 0.6);
50
-
51
- /* Spacing & Layout */
52
- --space-xxs: 2px;
53
- --space-xs: 4px;
54
- --space-sm: 8px;
55
- --space-md: 16px;
56
-
57
- /* Radii */
58
- --radius-xs: 4px;
59
- --radius-sm: 8px;
60
- --radius-round: 50%;
61
- }
62
-
63
- * { box-sizing: border-box; }
64
-
65
- body {
66
- background-color: var(--background-primary);
67
- color: var(--text-normal);
68
- font-family: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;
69
- font-size: 16px;
70
- line-height: 1.375rem;
71
- margin: 0;
72
- padding: 0;
73
- overflow-x: hidden;
74
- }
75
-
76
- a { color: var(--text-link); text-decoration: none; }
77
- a:hover { text-decoration: underline; }
78
-
79
- /* Header */
80
- .guild-header {
81
- background-color: var(--background-secondary);
82
- padding: 12px 16px;
83
- box-shadow: 0 1px 0 rgba(4,4,5,0.2), 0 1.5px 0 rgba(6,6,7,0.05), 0 2px 0 rgba(4,4,5,0.05);
84
- display: flex;
85
- align-items: center;
86
- position: sticky;
87
- top: 0;
88
- z-index: 100;
89
- }
90
-
91
- .guild-icon {
92
- width: 48px;
93
- height: 48px;
94
- border-radius: var(--radius-round);
95
- margin-right: 12px;
96
- }
97
-
98
- .guild-info h1 {
99
- font-size: 16px;
100
- line-height: 20px;
101
- font-weight: 600;
102
- color: var(--header-primary);
103
- margin: 0;
104
- }
105
-
106
- .channel-info {
107
- font-size: 14px;
108
- color: var(--header-secondary);
109
- margin: 2px 0 0;
110
- }
111
-
112
- /* Chat Log */
113
- .chatlog { padding: var(--space-md) 0; max-width: 100%; }
114
-
115
- .message-group {
116
- display: flex;
117
- margin-top: 1.0625rem;
118
- padding: var(--space-xxs) var(--space-md);
119
- position: relative;
120
- }
121
-
122
- .message-group:hover { background-color: var(--background-modifier-hover); }
123
-
124
- .author-avatar {
125
- width: 40px;
126
- height: 40px;
127
- border-radius: var(--radius-round);
128
- margin-right: var(--space-md);
129
- margin-top: var(--space-xxs);
130
- cursor: pointer;
131
- user-select: none;
132
- flex-shrink: 0;
133
- }
134
-
135
- .message-content-wrapper { flex: 1; min-width: 0; }
136
-
137
- .message-header {
138
- display: flex;
139
- align-items: center;
140
- line-height: 1.375rem;
141
- min-height: 1.375rem;
142
- }
143
-
144
- .author-name {
145
- font-size: 1rem;
146
- font-weight: 500;
147
- color: var(--header-primary);
148
- margin-right: 0.25rem;
149
- cursor: pointer;
150
- }
151
-
152
- .bot-tag {
153
- background-color: var(--brand-experiment);
154
- color: #fff;
155
- font-size: 0.625rem;
156
- text-transform: uppercase;
157
- vertical-align: top;
158
- height: 0.9375rem;
159
- padding: 0 0.275rem;
160
- border-radius: 0.1875rem;
161
- line-height: 0.9375rem;
162
- font-weight: 500;
163
- margin-left: 0.25rem;
164
- margin-right: 0.25rem;
165
- display: inline-flex;
166
- align-items: center;
167
- gap: 2px;
168
- }
169
-
170
- .timestamp {
171
- font-size: 0.75rem;
172
- color: var(--text-muted);
173
- margin-left: 0.25rem;
174
- font-weight: 400;
175
- }
176
-
177
- .message-body {
178
- font-size: 1rem;
179
- line-height: 1.375rem;
180
- color: var(--text-normal);
181
- white-space: pre-wrap;
182
- word-wrap: break-word;
183
- }
184
-
185
- /* Embeds */
186
- .embed {
187
- display: flex;
188
- max-width: 520px;
189
- background-color: var(--background-secondary);
190
- border-radius: var(--radius-xs);
191
- border-left: 4px solid var(--background-tertiary);
192
- margin-top: var(--space-sm);
193
- padding: var(--space-sm) var(--space-md) var(--space-md) 12px;
194
- flex-direction: column;
195
- box-sizing: border-box;
196
- font-size: 14px;
197
- }
198
-
199
- .embed-grid { display: grid; max-width: 100%; }
200
-
201
- .embed-author {
202
- display: flex;
203
- align-items: center;
204
- margin-bottom: var(--space-sm);
205
- margin-top: var(--space-sm);
206
- color: var(--header-primary);
207
- font-weight: 600;
208
- font-size: 14px;
209
- }
210
-
211
- .embed-author-icon {
212
- width: 24px;
213
- height: 24px;
214
- border-radius: var(--radius-round);
215
- margin-right: var(--space-sm);
216
- }
217
-
218
- .embed-title {
219
- font-size: 16px;
220
- font-weight: 600;
221
- color: var(--header-primary);
222
- margin-bottom: var(--space-xs);
223
- display: inline-block;
224
- }
225
-
226
- .embed-description {
227
- font-size: 14px;
228
- line-height: 18px;
229
- color: var(--text-normal);
230
- white-space: pre-wrap;
231
- margin-bottom: var(--space-sm);
232
- }
233
-
234
- .embed-field { margin-bottom: var(--space-sm); }
235
-
236
- .embed-field-name {
237
- color: var(--text-normal);
238
- font-weight: 600;
239
- margin-bottom: var(--space-xxs);
240
- }
241
-
242
- .embed-field-value {
243
- color: var(--text-normal);
244
- white-space: pre-wrap;
245
- }
246
-
247
- .embed-footer {
248
- margin-top: var(--space-sm);
249
- display: flex;
250
- align-items: center;
251
- font-size: 12px;
252
- color: var(--text-muted);
253
- }
254
- .embed-footer-icon {
255
- width: 20px;
256
- height: 20px;
257
- border-radius: var(--radius-round);
258
- margin-right: var(--space-sm);
259
- }
260
-
261
- .embed-image-large {
262
- margin-top: 10px;
263
- border-radius: var(--radius-xs);
264
- overflow: hidden;
265
- max-width: 100%;
266
- display: block;
267
- }
268
- .embed-image-large img {
269
- max-width: 100%;
270
- max-height: 400px;
271
- object-fit: contain;
272
- }
273
-
274
- .embed-content { width: 100%; }
275
-
276
- /* Attachments */
277
- .attachment {
278
- margin-top: var(--space-sm);
279
- max-width: 520px;
280
- border-radius: 3px;
281
- overflow: hidden;
282
- }
283
-
284
- .attachment-image img {
285
- max-width: 100%;
286
- max-height: 350px;
287
- cursor: pointer;
288
- border-radius: var(--radius-xs);
289
- }
290
-
291
- .mention {
292
- background-color: var(--mention-bg);
293
- color: #dee0fc;
294
- border-radius: 3px;
295
- padding: 0 2px;
296
- font-weight: 500;
297
- }
298
- .mention:hover {
299
- background-color: var(--mention-hover-bg);
300
- text-decoration: none;
301
- color: #fff;
302
- }
303
-
304
- /* Reply Reference */
305
- .reply-reference {
306
- font-size: 0.875rem;
307
- color: var(--text-muted);
308
- margin-bottom: var(--space-xs);
309
- margin-left: 20px;
310
- display: flex;
311
- align-items: center;
312
- position: relative;
313
- }
314
-
315
- .reply-reference::before {
316
- content: "";
317
- display: block;
318
- position: absolute;
319
- top: 50%;
320
- left: -36px;
321
- bottom: 0;
322
- right: 0;
323
- border-top: 2px solid #4e5058;
324
- border-left: 2px solid #4e5058;
325
- border-top-left-radius: 6px;
326
- width: 33px;
327
- height: 10px;
328
- margin-top: -1px;
329
- pointer-events: none;
330
- }
331
-
332
- .reply-user {
333
- font-weight: 600;
334
- margin-right: var(--space-xs);
335
- cursor: pointer;
336
- }
337
- .reply-user:hover { text-decoration: underline; }
338
- .reply-content { opacity: 0.8; }
339
- .reply-avatar {
340
- width: 16px;
341
- height: 16px;
342
- border-radius: var(--radius-round);
343
- margin-right: var(--space-xs);
344
- }
345
-
346
-
347
- /* Discord V2 Component Styles (Design System Implementation) */
348
- .discord-container {
349
- display: flex;
350
- flex-direction: column;
351
- background-color: var(--background-surface-high);
352
- border: 1px solid var(--border-subtle);
353
- border-radius: var(--radius-sm);
354
- padding: var(--space-md);
355
- gap: var(--space-sm);
356
- margin-top: var(--space-sm);
357
- max-width: 520px;
358
- color: var(--text-normal);
359
- font-size: 1rem;
360
- line-height: 1.375rem;
361
- overflow: hidden;
362
- }
363
-
364
- .discord-base-image {
365
- overflow: hidden;
366
- position: relative;
367
- background: var(--background-secondary);
368
- }
369
-
370
- .discord-button {
371
- color: #ffffff !important;
372
- padding: 2px 16px;
373
- border-radius: var(--radius-sm);
374
- text-decoration: none !important;
375
- display: inline-flex;
376
- align-items: center;
377
- justify-content: center;
378
- font-size: 14px;
379
- font-weight: 500;
380
- height: 32px;
381
- min-height: 32px;
382
- min-width: 60px;
383
- cursor: pointer;
384
- font-family: Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif;
385
- text-align: center;
386
- box-sizing: border-box;
387
- border: none;
388
- outline: none;
389
- transition: background-color 0.2s ease;
390
- }
391
-
392
- .discord-button-primary { background-color: var(--button-primary-bg); }
393
- .discord-button-secondary { background-color: var(--button-secondary-bg); }
394
- .discord-button-success { background-color: var(--button-success-bg); }
395
- .discord-button-destructive { background-color: var(--button-destructive-bg); }
396
-
397
- .discord-select-menu {
398
- margin-top: var(--space-xxs);
399
- margin-bottom: var(--space-xxs);
400
- position: relative;
401
- width: 100%;
402
- max-width: 500px;
403
- height: 40px;
404
- background-color: var(--background-secondary);
405
- border-radius: var(--radius-xs);
406
- color: var(--interactive-normal);
407
- cursor: pointer;
408
- font-family: Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif;
409
- font-size: 14px;
410
- display: flex;
411
- align-items: center;
412
- padding: 0 var(--space-sm);
413
- justify-content: space-between;
414
- box-sizing: border-box;
415
- border: 1px solid var(--background-tertiary);
416
- }
417
-
418
- .discord-media-gallery { display: grid; gap: var(--space-xs); border-radius: var(--radius-sm); overflow: hidden; margin-top: var(--space-sm); }
419
- .discord-separator { width: 100%; display: block; background-color: var(--separator-color); }
420
- .discord-section { display: flex; flexDirection: row; width: 100%; max-width: 500px; margin-top: var(--space-sm); }
421
- .discord-section-content { display: flex; flexDirection: column; width: 100%; }
422
- .discord-section-accessory { display: flex; width: 100%; max-width: 500px; justifyContent: flex-end; alignItems: center; }
423
-
424
- .message-component-group {
425
- display: flex;
426
- flex-wrap: wrap;
427
- gap: var(--space-sm);
428
- margin-top: var(--space-sm);
429
- }
430
-
431
-
432
-
433
- </style>
434
- </head>
435
- <body>
436
-
437
- <header class="guild-header">
438
- <img src="https://cdn.discordapp.com/icons/887462826343510046/c9066666879e69c4fae958155bb3a8f9.png" alt="Guild Icon" class="guild-icon">
439
- <div class="guild-info">
440
- <h1>ticket-001</h1>
441
- <div class="channel-info">Support ticket for User #123</div>
442
- </div>
443
- </header>
444
-
445
- <div class="chatlog">
446
- <div class="message-group" id="message-1">
447
-
448
- <div class="message-content-wrapper">
449
-
450
- <div class="message-header">
451
- <img src="https://cdn.discordapp.com/embed/avatars/0.png" class="author-avatar" alt="Customer">
452
- <span class="author-name" >Customer</span>
453
-
454
- <span class="timestamp">01/25/2026, 09:45 AM</span>
455
- </div>
456
-
457
- <div class="message-body">
458
- Hello, I need help with my account.
459
- </div>
460
-
461
-
462
-
463
-
464
-
465
-
466
-
467
- </div>
468
- </div>
469
- <div class="message-group" id="message-2">
470
-
471
- <div class="message-content-wrapper">
472
-
473
- <div class="message-header">
474
- <img src="https://cdn.discordapp.com/embed/avatars/1.png" class="author-avatar" alt="Support Bot">
475
- <span class="author-name" >Support Bot</span>
476
- <span class="bot-tag"><svg width="10" height="10" viewBox="0 0 16 16" fill="currentColor"><path d="M7.47 10.78a.75.75 0 0 0 1.06 0l4.25-4.25a.75.75 0 0 0-1.06-1.06L8 9.19 6.28 7.47a.75.75 0 0 0-1.06 1.06l1.75 1.75Z"></path></svg>APP</span>
477
- <span class="timestamp">01/25/2026, 09:47 AM</span>
478
- </div>
479
-
480
- <div class="message-body">
481
- Hi! <b>Support Bot</b> here. What seems to be the issue?
482
- </div>
483
-
484
-
485
-
486
-
487
-
488
-
489
-
490
- </div>
491
- </div>
492
- <div class="message-group" id="message-3">
493
-
494
- <div class="message-content-wrapper">
495
-
496
- <div class="message-header">
497
- <img src="https://cdn.discordapp.com/embed/avatars/0.png" class="author-avatar" alt="Customer">
498
- <span class="author-name" >Customer</span>
499
-
500
- <span class="timestamp">01/25/2026, 09:48 AM</span>
501
- </div>
502
-
503
- <div class="message-body">
504
- I cannot login. Here is a screenshot:
505
- </div>
506
-
507
- <div class="attachment attachment-image">
508
- <a href="https://via.placeholder.com/350x150" target="_blank"><img src="https://via.placeholder.com/350x150" alt="screenshot.png"></a>
509
- </div>
510
-
511
-
512
-
513
-
514
-
515
-
516
- </div>
517
- </div>
518
- <div class="message-group" id="message-4">
519
-
520
- <div class="message-content-wrapper">
521
-
522
- <div class="message-header">
523
- <img src="https://cdn.discordapp.com/embed/avatars/1.png" class="author-avatar" alt="Support Bot">
524
- <span class="author-name" >Support Bot</span>
525
- <span class="bot-tag"><svg width="10" height="10" viewBox="0 0 16 16" fill="currentColor"><path d="M7.47 10.78a.75.75 0 0 0 1.06 0l4.25-4.25a.75.75 0 0 0-1.06-1.06L8 9.19 6.28 7.47a.75.75 0 0 0-1.06 1.06l1.75 1.75Z"></path></svg>APP</span>
526
- <span class="timestamp">01/25/2026, 09:52 AM</span>
527
- </div>
528
-
529
- <div class="message-body">
530
-
531
- </div>
532
-
533
-
534
-
535
-
536
-
537
-
538
- <div class="embed" style="border-left-color: #5865f2;">
539
- <div class="embed-content">
540
- <div class="embed-author">
541
-
542
-
543
-
544
- </div>
545
-
546
- <div class="embed-title">
547
-
548
- Login Troubleshooting
549
- </div>
550
-
551
- <div class="embed-description">Please try the following steps:<br>1. Reset password<br>2. Clear cache</div>
552
-
553
- <div class="embed-fields">
554
- <div class="embed-field">
555
- <div class="embed-field-name">Step 1</div>
556
- <div class="embed-field-value">Click <a href="https://example.com" target="_blank">here</a> to reset.</div>
557
- </div>
558
- <div class="embed-field">
559
- <div class="embed-field-name">Step 2</div>
560
- <div class="embed-field-value">Settings &gt; Privacy &gt; Clear</div>
561
- </div>
562
- </div>
563
-
564
-
565
- <div class="embed-footer">
566
-
567
- <span>Automated Response • 01/25/2026, 09:52 AM</span>
568
- </div>
569
- </div>
570
- </div>
571
-
572
- </div>
573
- </div>
574
- <div class="message-group" id="message-5">
575
-
576
- <div class="message-content-wrapper">
577
-
578
- <div class="message-header">
579
- <img src="https://cdn.discordapp.com/embed/avatars/1.png" class="author-avatar" alt="Support Bot">
580
- <span class="author-name" >Support Bot</span>
581
- <span class="bot-tag"><svg width="10" height="10" viewBox="0 0 16 16" fill="currentColor"><path d="M7.47 10.78a.75.75 0 0 0 1.06 0l4.25-4.25a.75.75 0 0 0-1.06-1.06L8 9.19 6.28 7.47a.75.75 0 0 0-1.06 1.06l1.75 1.75Z"></path></svg>APP</span>
582
- <span class="timestamp">01/25/2026, 10:02 AM</span>
583
- </div>
584
-
585
- <div class="message-body">
586
- This message uses the new <b>Container</b> component:
587
- </div>
588
-
589
-
590
- <div class="discord-container">
591
- **Container Title**
592
- This is content inside a container.
593
- It has a different style than embeds.
594
- </div>
595
-
596
-
597
-
598
-
599
-
600
- </div>
601
- </div>
602
- <div class="message-group" id="message-6">
603
-
604
- <div class="message-content-wrapper">
605
-
606
- <div class="message-header">
607
- <img src="https://cdn.discordapp.com/embed/avatars/1.png" class="author-avatar" alt="Support Bot">
608
- <span class="author-name" >Support Bot</span>
609
- <span class="bot-tag"><svg width="10" height="10" viewBox="0 0 16 16" fill="currentColor"><path d="M7.47 10.78a.75.75 0 0 0 1.06 0l4.25-4.25a.75.75 0 0 0-1.06-1.06L8 9.19 6.28 7.47a.75.75 0 0 0-1.06 1.06l1.75 1.75Z"></path></svg>APP</span>
610
- <span class="timestamp">01/25/2026, 10:02 AM</span>
611
- </div>
612
-
613
- <div class="message-body">
614
- This message has interactive <b>components</b>:
615
- </div>
616
-
617
-
618
-
619
- <div class="message-component-group">
620
-
621
- <button class="discord-button discord-button-primary" type="button" >
622
- <span style="display: flex; align-items: center;"><img src="https://cdn.discordapp.com/emojis/123456789.webp?size=44&quality=lossless" alt="User" style="width: 16px; height: 16px; margin-right: 8px;"></span>
623
-
624
- <span style="display: flex; align-items: center;">Claim Ticket</span>
625
- </button>
626
-
627
-
628
-
629
- <button class="discord-button discord-button-destructive" type="button" >
630
-
631
- <span style="display: flex; align-items: center; margin-right: 8px;">🔒</span>
632
- <span style="display: flex; align-items: center;">Close Ticket</span>
633
- </button>
634
-
635
-
636
- </div>
637
- <div class="message-component-group">
638
-
639
-
640
- <div class="discord-select-menu">
641
- <div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">Select a category...</div>
642
- <div style="display: flex; align-items: center; margin-left: 8px;">
643
- <svg width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M7 10L12 15L17 10H7Z" /></svg>
644
- </div>
645
- </div>
646
-
647
- </div>
648
-
649
- <div class="discord-media-gallery" style="grid-template-columns: repeat(3, 1fr);">
650
- <div class="discord-base-image" style="aspect-ratio: 16/9;">
651
- <img src="https://cdn.discordapp.com/embed/avatars/0.png" alt="Gallery Image 1" style="width: 100%; height: 100%; object-fit: cover;">
652
- </div>
653
- <div class="discord-base-image" style="aspect-ratio: 16/9;">
654
- <img src="https://cdn.discordapp.com/embed/avatars/1.png" alt="Gallery Image 2" style="width: 100%; height: 100%; object-fit: cover;">
655
- </div>
656
- <div class="discord-base-image" style="aspect-ratio: 16/9;">
657
- <img src="https://cdn.discordapp.com/embed/avatars/2.png" alt="Gallery Image 3" style="width: 100%; height: 100%; object-fit: cover;">
658
- </div>
659
- </div>
660
-
661
- <div class="discord-separator" style="height: 1px; margin: 8px 0;"></div>
662
-
663
-
664
- </div>
665
- </div>
666
- <div class="message-group" id="message-7">
667
-
668
- <div class="message-content-wrapper">
669
-
670
- <div class="message-header">
671
- <img src="https://cdn.discordapp.com/embed/avatars/1.png" class="author-avatar" alt="Support Bot">
672
- <span class="author-name" >Support Bot</span>
673
- <span class="bot-tag"><svg width="10" height="10" viewBox="0 0 16 16" fill="currentColor"><path d="M7.47 10.78a.75.75 0 0 0 1.06 0l4.25-4.25a.75.75 0 0 0-1.06-1.06L8 9.19 6.28 7.47a.75.75 0 0 0-1.06 1.06l1.75 1.75Z"></path></svg>APP</span>
674
- <span class="timestamp">01/25/2026, 10:02 AM</span>
675
- </div>
676
-
677
- <div class="message-body">
678
- This message uses V2 Components (Type 17 Container):
679
- </div>
680
-
681
-
682
- <div class="discord-container">
683
- <div class="discord-section"><div class="discord-section-content"><b>Text Display</b> inside container.</div></div><div class="discord-separator" style="height: 1px; margin: 4px 0;"></div><div class="message-component-group"><button class="discord-button discord-button-primary" type="button" ><span style="display: flex; align-items: center;">Button Inside</span></button></div>
684
- </div>
685
-
686
-
687
-
688
-
689
-
690
- </div>
691
- </div>
692
- </div>
693
-
694
- </body>
695
- </html>
package/tests/test_gen.ts DELETED
@@ -1,192 +0,0 @@
1
-
2
- import { createTranscript, type Message, type ChannelInfo } from '../src/index';
3
-
4
- const channel: ChannelInfo = {
5
- id: '123456789',
6
- name: 'ticket-001',
7
- topic: 'Support ticket for User #123',
8
- guildName: 'Support Server',
9
- guildIconUrl: 'https://cdn.discordapp.com/icons/887462826343510046/c9066666879e69c4fae958155bb3a8f9.png'
10
- };
11
-
12
- const messages: Message[] = [
13
- {
14
- id: '1',
15
- content: 'Hello, I need help with my account.',
16
- author: {
17
- id: 'user1',
18
- username: 'Customer',
19
- avatarURL: 'https://cdn.discordapp.com/embed/avatars/0.png',
20
- bot: false
21
- },
22
- timestamp: new Date(Date.now() - 1000000).toISOString(),
23
- attachments: [],
24
- embeds: [],
25
- reactions: []
26
- },
27
- {
28
- id: '2',
29
- content: 'Hi! **Support Bot** here. What seems to be the issue?',
30
- author: {
31
- id: 'bot1',
32
- username: 'Support Bot',
33
- avatarURL: 'https://cdn.discordapp.com/embed/avatars/1.png',
34
- bot: true
35
- },
36
- timestamp: new Date(Date.now() - 900000).toISOString(),
37
- attachments: [],
38
- embeds: [],
39
- reactions: []
40
- },
41
- {
42
- id: '3',
43
- content: 'I cannot login. Here is a screenshot:',
44
- author: {
45
- id: 'user1',
46
- username: 'Customer',
47
- avatarURL: 'https://cdn.discordapp.com/embed/avatars/0.png',
48
- bot: false
49
- },
50
- timestamp: new Date(Date.now() - 800000).toISOString(),
51
- attachments: [
52
- {
53
- id: 'att1',
54
- name: 'screenshot.png',
55
- url: 'https://via.placeholder.com/350x150',
56
- contentType: 'image/png'
57
- }
58
- ],
59
- embeds: [],
60
- reactions: []
61
- },
62
- {
63
- id: '4',
64
- content: '',
65
- author: {
66
- id: 'bot1',
67
- username: 'Support Bot',
68
- avatarURL: 'https://cdn.discordapp.com/embed/avatars/1.png',
69
- bot: true
70
- },
71
- timestamp: new Date(Date.now() - 600000).toISOString(),
72
- attachments: [],
73
- embeds: [
74
- {
75
- title: 'Login Troubleshooting',
76
- description: 'Please try the following steps:\n1. Reset password\n2. Clear cache',
77
- color: 0x5865F2,
78
- fields: [
79
- { name: 'Step 1', value: 'Click [here](https://example.com) to reset.', inline: true },
80
- { name: 'Step 2', value: 'Settings > Privacy > Clear', inline: true }
81
- ],
82
- footer: {
83
- text: 'Automated Response'
84
- }
85
- }
86
- ],
87
- reactions: []
88
- },
89
- {
90
- id: '5',
91
- content: 'This message uses the new **Container** component:',
92
- author: {
93
- id: 'bot1',
94
- username: 'Support Bot',
95
- avatarURL: 'https://cdn.discordapp.com/embed/avatars/1.png',
96
- bot: true
97
- },
98
- timestamp: new Date().toISOString(),
99
- attachments: [],
100
- embeds: [],
101
- containers: [
102
- {
103
- content: "**Container Title**\nThis is content inside a container.\nIt has a different style than embeds."
104
- }
105
- ],
106
- reactions: []
107
- },
108
- {
109
- id: '6',
110
- content: 'This message has interactive **components**:',
111
- author: {
112
- id: 'bot1',
113
- username: 'Support Bot',
114
- avatarURL: 'https://cdn.discordapp.com/embed/avatars/1.png',
115
- bot: true
116
- },
117
- timestamp: new Date().toISOString(),
118
- attachments: [],
119
- embeds: [],
120
- components: [
121
- {
122
- type: 1,
123
- components: [
124
- { type: 2, style: 1, label: 'Claim Ticket', customId: 'claim', emoji: { name: 'User', id: '123456789' } },
125
- { type: 2, style: 4, label: 'Close Ticket', customId: 'close', emoji: { name: '🔒' } }
126
- ]
127
- },
128
- {
129
- type: 1,
130
- components: [
131
- {
132
- type: 3,
133
- customId: 'category',
134
- placeholder: 'Select a category...',
135
- options: [
136
- { label: 'Support', value: 'support' },
137
- { label: 'Billing', value: 'billing' }
138
- ]
139
- }
140
- ]
141
- }
142
- ],
143
- mediaGalleries: [
144
- {
145
- items: [
146
- { media: { url: 'https://cdn.discordapp.com/embed/avatars/0.png' }, description: 'Gallery Image 1' },
147
- { media: { url: 'https://cdn.discordapp.com/embed/avatars/1.png' }, description: 'Gallery Image 2' },
148
- { media: { url: 'https://cdn.discordapp.com/embed/avatars/2.png' }, description: 'Gallery Image 3' }
149
- ]
150
- }
151
- ],
152
- separators: [
153
- { divider: true, spacing: 3 }
154
- ],
155
- reactions: []
156
- },
157
- {
158
- id: '7',
159
- content: 'This message uses V2 Components (Type 17 Container):',
160
- author: {
161
- id: 'bot1',
162
- username: 'Support Bot',
163
- avatarURL: 'https://cdn.discordapp.com/embed/avatars/1.png',
164
- bot: true
165
- },
166
- timestamp: new Date().toISOString(),
167
- attachments: [],
168
- embeds: [],
169
- components: [
170
- {
171
- type: 17,
172
- components: [
173
- { type: 10, content: '**Text Display** inside container.' },
174
- { type: 14, divider: true, spacing: 2 },
175
- {
176
- type: 1,
177
- components: [
178
- { type: 2, style: 1, label: 'Button Inside', customId: 'btn_in' }
179
- ]
180
- }
181
- ]
182
- }
183
- ] as any, // Cast to avoid strict type checking in test file if types aren't fully updated in index export yet
184
- reactions: []
185
- }
186
- ];
187
-
188
- // Run
189
- const htmlBuffer = await createTranscript(messages, channel, { returnType: 'buffer' });
190
- const fs = require('fs');
191
- fs.writeFileSync('test_transcript.html', htmlBuffer);
192
- console.log('Transcript generated at test_transcript.html');
@@ -1,78 +0,0 @@
1
-
2
- import { createTranscript, type Message, type ChannelInfo } from '../src/index';
3
- import fs from 'fs';
4
-
5
- const channel: ChannelInfo = {
6
- id: '123456789',
7
- name: 'mention-test',
8
- topic: 'Testing mentions and timestamps',
9
- };
10
-
11
- const messages: Message[] = [
12
- {
13
- id: '1',
14
- content: 'Hi <@22222>, I am <@11111>!',
15
- author: {
16
- id: '11111',
17
- username: 'Customer',
18
- avatarURL: 'https://cdn.discordapp.com/embed/avatars/0.png',
19
- bot: false
20
- },
21
- timestamp: new Date().toISOString(),
22
- attachments: [],
23
- embeds: [],
24
- reactions: []
25
- },
26
- {
27
- id: '2',
28
- content: 'Hello <@11111>! This ticket was claimed at <t:1737800000:R>. Mentioning unknown: <@99999>',
29
- author: {
30
- id: '22222',
31
- username: 'Support Bot',
32
- avatarURL: 'https://cdn.discordapp.com/embed/avatars/1.png',
33
- bot: true
34
- },
35
- timestamp: new Date().toISOString(),
36
- attachments: [],
37
- embeds: [
38
- {
39
- description: 'Embed mentioning <@11111> and timestamp <t:1737801000:R>',
40
- fields: [
41
- { name: 'User', value: '<@11111>', inline: true }
42
- ]
43
- }
44
- ],
45
- reactions: []
46
- }
47
- ];
48
-
49
- // Run
50
- const html = await createTranscript(messages, channel, { returnType: 'string' }) as string;
51
- fs.writeFileSync('test_mentions.html', html);
52
- console.log('Transcript generated at test_mentions.html');
53
-
54
- // Simple verification in console
55
- if (html.includes('@Customer')) {
56
- console.log('✅ Mention @Customer found');
57
- } else {
58
- console.log('❌ Mention @Customer NOT found');
59
- }
60
-
61
- if (html.includes('@Support Bot')) {
62
- console.log('✅ Mention @Support Bot found');
63
- } else {
64
- console.log('❌ Mention @Support Bot NOT found');
65
- }
66
-
67
- if (html.includes('relative time')) {
68
- console.log('❌ "relative time" found (should be formatted)');
69
- } else {
70
- console.log('✅ "relative time" NOT found');
71
- }
72
-
73
- if (html.includes('@User')) {
74
- // Falls back to @User if id not in map?
75
- // In my code: const username = userMap?.get(id) || 'User';
76
- // So <@99999> becomes @User
77
- console.log('✅ Mention @User (fallback) found');
78
- }