discord-html-transcripts-fix 1.0.0 โ†’ 1.2.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.
@@ -38,6 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.default = DiscordMessage;
40
40
  const jsx_runtime_1 = require("react/jsx-runtime");
41
+ const discord_js_1 = require("discord.js");
41
42
  const utils_1 = require("../../utils/utils");
42
43
  const attachment_1 = require("./attachment");
43
44
  const components_1 = __importDefault(require("./components"));
@@ -45,15 +46,203 @@ const content_1 = __importStar(require("./content"));
45
46
  const embed_1 = require("./embed");
46
47
  const reply_1 = __importDefault(require("./reply"));
47
48
  const systemMessage_1 = __importDefault(require("./systemMessage"));
48
- async function DiscordMessage({ message, context, }) {
49
- var _a;
50
- if (message.system)
51
- return (0, jsx_runtime_1.jsx)(systemMessage_1.default, { message: message });
52
- const isCrosspost = message.reference && message.reference.guildId !== ((_a = message.guild) === null || _a === void 0 ? void 0 : _a.id);
53
- return ((0, jsx_runtime_1.jsxs)("discord-message", { id: `m-${message.id}`, timestamp: message.createdAt, edited: message.editedAt !== null, server: isCrosspost !== null && isCrosspost !== void 0 ? isCrosspost : undefined, highlight: message.mentions.everyone, profile: message.author.id, children: [(0, jsx_runtime_1.jsx)(reply_1.default, { message: message, context: context }), message.interaction && ((0, jsx_runtime_1.jsx)("discord-command", { slot: "reply", profile: message.interaction.user.id, command: '/' + message.interaction.commandName })), message.content && ((0, jsx_runtime_1.jsx)(content_1.default, { content: message.content, context: Object.assign(Object.assign({}, context), { type: message.webhookId ? content_1.RenderType.WEBHOOK : content_1.RenderType.NORMAL }) })), (0, jsx_runtime_1.jsx)(attachment_1.Attachments, { message: message, context: context }), message.embeds.map((embed, id) => ((0, jsx_runtime_1.jsx)(embed_1.DiscordEmbed, { embed: embed, context: Object.assign(Object.assign({}, context), { index: id, message }) }, id))), message.components.length > 0 && ((0, jsx_runtime_1.jsx)("discord-attachments", { slot: "components", children: message.components.map((component, id) => ((0, jsx_runtime_1.jsx)(components_1.default, { id: id, component: component, context: context }, id))) })), message.reactions.cache.size > 0 && ((0, jsx_runtime_1.jsx)("discord-reactions", { slot: "reactions", children: message.reactions.cache.map((reaction, id) => ((0, jsx_runtime_1.jsx)("discord-reaction", { name: reaction.emoji.name, emoji: (0, utils_1.parseDiscordEmoji)(reaction.emoji), count: reaction.count }, `${message.id}r${id}`))) })), message.hasThread && message.thread && ((0, jsx_runtime_1.jsx)("discord-thread", { slot: "thread", name: message.thread.name, cta: message.thread.messageCount
54
- ? `${message.thread.messageCount} Message${message.thread.messageCount > 1 ? 's' : ''}`
55
- : 'View Thread', children: message.thread.lastMessage ? ((0, jsx_runtime_1.jsx)("discord-thread-message", { profile: message.thread.lastMessage.author.id, children: (0, jsx_runtime_1.jsx)(content_1.default, { content: message.thread.lastMessage.content.length > 128
56
- ? message.thread.lastMessage.content.substring(0, 125) + '...'
57
- : message.thread.lastMessage.content, context: Object.assign(Object.assign({}, context), { type: content_1.RenderType.REPLY }) }) })) : (`Thread messages not saved.`) }))] }, message.id));
58
- }
59
- //# sourceMappingURL=message.js.map
49
+
50
+ const FLAG_SUPPRESS_EMBEDS = 1 << 2;
51
+ const FLAG_IS_VOICE_MESSAGE = 1 << 13;
52
+
53
+ function t(context, key, fallback) {
54
+ const dict = context?.i18n?.[context?.lang] || context?.i18n?.en || {};
55
+ return dict[key] || fallback || key;
56
+ }
57
+
58
+ async function DiscordMessage({ message, context }) {
59
+ try {
60
+ if (message.system)
61
+ return (0, jsx_runtime_1.jsx)(systemMessage_1.default, { message: message, context: context });
62
+
63
+ const isCrosspost = message.reference && message.reference.guildId !== message.guild?.id;
64
+ const stickers = message.stickers && message.stickers.size > 0
65
+ ? Array.from(message.stickers.values()).map((s) => ({
66
+ id: s.id,
67
+ name: s.name,
68
+ url: s.url || `https://media.discordapp.net/stickers/${s.id}.png`,
69
+ format: s.format,
70
+ }))
71
+ : [];
72
+ const poll = (message.poll && (message.poll.question || (message.poll.answers && message.poll.answers.size))) ? message.poll : null;
73
+
74
+ const flags = (typeof message.flags?.bitfield === 'number') ? message.flags.bitfield : 0;
75
+ const suppressEmbeds = !!(flags & FLAG_SUPPRESS_EMBEDS);
76
+ const isVoice = !!(flags & FLAG_IS_VOICE_MESSAGE);
77
+
78
+ // Forwarded message snapshots (messageSnapshots) โ€” render before the empty body
79
+ const snapshots = Array.isArray(message.messageSnapshots) ? message.messageSnapshots : [];
80
+
81
+ const isApp = !!(message.author?.bot && message.applicationId);
82
+
83
+ const editedAtIso = message.editedAt instanceof Date ? message.editedAt.toISOString() : null;
84
+ const pinned = !!message.pinned;
85
+
86
+ return ((0, jsx_runtime_1.jsxs)("discord-message", {
87
+ id: `m-${message.id}`,
88
+ timestamp: message.createdAt,
89
+ edited: message.editedAt !== null,
90
+ server: isCrosspost ?? undefined,
91
+ highlight: message.mentions.everyone || pinned,
92
+ profile: message.author.id,
93
+ children: [
94
+ pinned && (0, jsx_runtime_1.jsx)("div", { className: "dht-pinned-indicator", title: "Pinned", children: "๐Ÿ“Œ" }),
95
+ (0, jsx_runtime_1.jsx)(reply_1.default, { message: message, context: context }),
96
+ message.interaction && ((0, jsx_runtime_1.jsx)("discord-command", { slot: "reply", profile: message.interaction.user.id, command: '/' + message.interaction.commandName })),
97
+ isApp && (0, jsx_runtime_1.jsx)("span", { className: "dht-app-badge", "data-i18n": "appBadge", children: t(context, 'appBadge', 'APP') }),
98
+ editedAtIso && (0, jsx_runtime_1.jsx)("span", { className: "dht-edit-marker", title: editedAtIso, "data-edit-iso": editedAtIso, "data-i18n": "edited", "data-i18n-params": JSON.stringify({ time: editedAtIso }), children: '(' + t(context, 'edited', 'edited') + ')' }),
99
+ Array.isArray(message.editHistory) && message.editHistory.length > 0 && renderEditHistory(message.editHistory, context),
100
+ snapshots.length > 0 && renderSnapshots(snapshots, context),
101
+ message.content && ((0, jsx_runtime_1.jsx)(content_1.default, { content: message.content, context: Object.assign({}, context, { type: message.webhookId ? content_1.RenderType.WEBHOOK : content_1.RenderType.NORMAL }) })),
102
+ (0, jsx_runtime_1.jsx)(attachment_1.Attachments, { message: message, context: context }),
103
+ isVoice && renderVoiceIndicator(message, context),
104
+ stickers.length > 0 && renderStickers(stickers),
105
+ poll && renderPoll(poll, context),
106
+ !suppressEmbeds && message.embeds.map((embed, id) => ((0, jsx_runtime_1.jsx)(embed_1.DiscordEmbed, { embed: embed, context: Object.assign({}, context, { index: id, message }) }, id))),
107
+ suppressEmbeds && message.embeds.length > 0 && (0, jsx_runtime_1.jsx)("span", { className: "dht-suppressed", "data-i18n": "suppressedEmbeds", children: t(context, 'suppressedEmbeds', '(embeds hidden)') }),
108
+ message.components.length > 0 && ((0, jsx_runtime_1.jsx)("discord-attachments", { slot: "components", children: message.components.map((component, id) => ((0, jsx_runtime_1.jsx)(components_1.default, { id: id, component: component, context: context }, id))) })),
109
+ message.reactions.cache.size > 0 && ((0, jsx_runtime_1.jsx)("discord-reactions", {
110
+ slot: "reactions",
111
+ children: Array.from(message.reactions.cache.values()).map((reaction, id) => {
112
+ const burst = reaction.burst_count > 0 || (reaction.count_details?.burst > 0);
113
+ return ((0, jsx_runtime_1.jsx)("discord-reaction", {
114
+ name: reaction.emoji?.name || ':unknown:',
115
+ emoji: (0, utils_1.parseDiscordEmoji)(reaction.emoji) || undefined,
116
+ count: reaction.count ?? 0,
117
+ "data-burst": burst ? 'true' : undefined,
118
+ className: burst ? 'dht-reaction--burst' : undefined
119
+ }, `${message.id}r${id}`));
120
+ })
121
+ })),
122
+ message.hasThread && message.thread && renderThread(message.thread, context),
123
+ ]
124
+ }, message.id));
125
+ } catch (err) {
126
+ console.warn('[discord-html-transcripts-fix] Render failed', message?.id, err?.message || err);
127
+ const safeAuthor = (message?.author?.displayName || message?.author?.username) || 'Unknown';
128
+ return ((0, jsx_runtime_1.jsx)("discord-message", { id: `m-${message?.id}`, children: (0, jsx_runtime_1.jsx)("span", { style: { opacity: 0.6 }, children: `[message from ${safeAuthor} failed to render]` }) }, message?.id));
129
+ }
130
+ }
131
+
132
+ function renderThread(thread, context) {
133
+ const cta = thread.messageCount
134
+ ? `${thread.messageCount} Message${thread.messageCount > 1 ? 's' : ''}`
135
+ : 'View Thread';
136
+ const badges = [];
137
+ if (thread.archived) badges.push((0, jsx_runtime_1.jsx)("span", { className: "dht-thread-badge dht-thread-badge--archived", "data-i18n": "threadArchived", children: t(context, 'threadArchived', 'Archived') }, 'a'));
138
+ if (thread.locked) badges.push((0, jsx_runtime_1.jsx)("span", { className: "dht-thread-badge dht-thread-badge--locked", "data-i18n": "threadLocked", children: t(context, 'threadLocked', 'Locked') }, 'l'));
139
+ return (0, jsx_runtime_1.jsxs)("discord-thread", { slot: "thread", name: thread.name, cta, children: [
140
+ badges,
141
+ thread.lastMessage
142
+ ? (0, jsx_runtime_1.jsx)("discord-thread-message", { profile: thread.lastMessage.author.id, children: (0, jsx_runtime_1.jsx)(content_1.default, { content: thread.lastMessage.content.length > 128 ? thread.lastMessage.content.substring(0, 125) + '...' : thread.lastMessage.content, context: Object.assign({}, context, { type: content_1.RenderType.REPLY }) }) })
143
+ : 'Thread messages not saved.'
144
+ ] });
145
+ }
146
+
147
+ function renderStickers(stickers) {
148
+ return (0, jsx_runtime_1.jsx)("div", {
149
+ className: "dht-stickers",
150
+ children: stickers.map((s) => (0, jsx_runtime_1.jsx)("img", {
151
+ src: s.url,
152
+ alt: s.name || 'sticker',
153
+ title: s.name || '',
154
+ className: "dht-sticker"
155
+ }, s.id))
156
+ });
157
+ }
158
+
159
+ function renderPoll(poll, context) {
160
+ let totalVotes = 0;
161
+ const answers = poll.answers ? Array.from(poll.answers.values()) : [];
162
+ for (const a of answers) totalVotes += a.voteCount || 0;
163
+ const expires = poll.expiresAt instanceof Date ? poll.expiresAt.toLocaleString('de-DE') : '';
164
+
165
+ return (0, jsx_runtime_1.jsxs)("div", {
166
+ className: "dht-poll",
167
+ children: [
168
+ (0, jsx_runtime_1.jsxs)("div", { className: "dht-poll-q", children: ['๐Ÿ“Š ', poll.question?.text || 'Poll'] }),
169
+ (0, jsx_runtime_1.jsx)("div", {
170
+ className: "dht-poll-answers",
171
+ children: answers.map((a, i) => {
172
+ const text = a.text ?? a.media?.text ?? `Option ${i + 1}`;
173
+ const votes = a.voteCount || 0;
174
+ const pct = totalVotes > 0 ? Math.round((votes / totalVotes) * 100) : 0;
175
+ return (0, jsx_runtime_1.jsxs)("div", { className: "dht-poll-a", children: [
176
+ (0, jsx_runtime_1.jsx)("div", { className: "dht-poll-bar", style: { width: pct + '%' } }),
177
+ (0, jsx_runtime_1.jsxs)("div", { className: "dht-poll-line", children: [
178
+ (0, jsx_runtime_1.jsx)("span", { children: String(text) }),
179
+ (0, jsx_runtime_1.jsxs)("span", { className: "dht-poll-pct", children: [votes, ' (', pct, '%)'] })
180
+ ] })
181
+ ] }, i);
182
+ })
183
+ }),
184
+ (0, jsx_runtime_1.jsxs)("div", { className: "dht-poll-foot", children: [totalVotes, ' votes', expires ? ' ยท ends ' + expires : ''] })
185
+ ]
186
+ });
187
+ }
188
+
189
+ function renderVoiceIndicator(message, context) {
190
+ const audio = message.attachments?.find?.((a) => typeof a.contentType === 'string' && a.contentType.startsWith('audio/'));
191
+ const duration = audio?.duration_secs || audio?.durationSecs;
192
+ const waveformB64 = audio?.waveform;
193
+ let waveformSvg = null;
194
+ if (typeof waveformB64 === 'string' && waveformB64.length > 0) {
195
+ try {
196
+ const buf = Buffer.from(waveformB64, 'base64');
197
+ const bars = Array.from(buf).slice(0, 100);
198
+ const max = bars.length ? Math.max(1, ...bars) : 1;
199
+ const width = bars.length * 3;
200
+ const rects = bars.map((b, i) => {
201
+ const h = Math.max(2, (b / max) * 20);
202
+ return `<rect x="${i * 3}" y="${(22 - h) / 2}" width="2" height="${h}" rx="1" fill="#5865F2"/>`;
203
+ }).join('');
204
+ waveformSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} 22" width="${width}" height="22">${rects}</svg>`;
205
+ } catch (_e) {}
206
+ }
207
+ return (0, jsx_runtime_1.jsxs)("div", { className: "dht-voice", children: [
208
+ (0, jsx_runtime_1.jsx)("span", { className: "dht-voice-icon", children: '๐ŸŽค' }),
209
+ (0, jsx_runtime_1.jsx)("span", { className: "dht-voice-label", "data-i18n": "voiceMessage", children: t(context, 'voiceMessage', 'Voice message') }),
210
+ waveformSvg && (0, jsx_runtime_1.jsx)("span", { className: "dht-voice-wave", dangerouslySetInnerHTML: { __html: waveformSvg } }),
211
+ duration ? (0, jsx_runtime_1.jsxs)("span", { className: "dht-voice-dur", children: [Math.round(duration), 's'] }) : null,
212
+ ] });
213
+ }
214
+
215
+ function renderSnapshots(snapshots, context) {
216
+ return (0, jsx_runtime_1.jsx)("div", {
217
+ className: "dht-forwarded-wrap",
218
+ children: snapshots.map((snap, i) => {
219
+ const m = snap.message || snap;
220
+ const author = m?.author?.displayName || m?.author?.username || 'Unknown';
221
+ const text = m?.content || '';
222
+ return (0, jsx_runtime_1.jsxs)("div", { className: "dht-forwarded", children: [
223
+ (0, jsx_runtime_1.jsxs)("div", { className: "dht-forwarded-head", children: [
224
+ (0, jsx_runtime_1.jsx)("span", { className: "dht-forwarded-icon", children: 'โ†ช๏ธ' }),
225
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "forwardedFrom", children: t(context, 'forwardedFrom', 'Forwarded from') }),
226
+ (0, jsx_runtime_1.jsx)("strong", { children: ' ' + author }),
227
+ ] }),
228
+ text && (0, jsx_runtime_1.jsx)("div", { className: "dht-forwarded-body", children: (0, jsx_runtime_1.jsx)(content_1.default, { content: text, context: Object.assign({}, context, { type: content_1.RenderType.REPLY }) }) }),
229
+ Array.isArray(m?.attachments) && m.attachments.length > 0 && (0, jsx_runtime_1.jsxs)("div", { className: "dht-forwarded-attachments", children: [m.attachments.length, ' attachment(s)'] }),
230
+ ] }, i);
231
+ })
232
+ });
233
+ }
234
+
235
+ function renderEditHistory(history, context) {
236
+ // Optional feature โ€” host bot may attach `message.editHistory: [{content, editedAt}, โ€ฆ]`
237
+ return (0, jsx_runtime_1.jsxs)("details", { className: "dht-edit-history", children: [
238
+ (0, jsx_runtime_1.jsx)("summary", { "data-i18n": "editHistoryTitle", children: t(context, 'editHistoryTitle', 'Edit history') }),
239
+ (0, jsx_runtime_1.jsx)("ol", { children: history.map((entry, i) => {
240
+ const when = entry.editedAt instanceof Date ? entry.editedAt.toISOString() : (typeof entry.editedAt === 'string' ? entry.editedAt : '');
241
+ return (0, jsx_runtime_1.jsxs)("li", { children: [
242
+ when && (0, jsx_runtime_1.jsxs)("time", { dateTime: when, children: [t(context, 'editHistoryAt', 'at'), ' ', when] }),
243
+ (0, jsx_runtime_1.jsx)("div", { children: String(entry.content || '') })
244
+ ] }, i);
245
+ }) })
246
+ ] });
247
+ }
248
+ //# sourceMappingURL=message.js.map
@@ -1,53 +1,61 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
2
  var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
3
+ var ownKeys = function(o){ownKeys = Object.getOwnPropertyNames || function (o){var ar=[];for (var k in o) if (Object.prototype.hasOwnProperty.call(o,k)) ar[ar.length]=k;return ar;};return ownKeys(o);};
4
+ return function (mod){if (mod && mod.__esModule) return mod;var result={};if (mod != null) for (var k=ownKeys(mod), i=0; i<k.length; i++) if (k[i] !== "default") Object.defineProperty(result,k[i],{get:function(){return mod[k[i]];}});Object.defineProperty(result,"default",{value:mod,enumerable:true});return result;};
34
5
  })();
35
6
  Object.defineProperty(exports, "__esModule", { value: true });
36
7
  exports.default = MessageReply;
37
8
  const jsx_runtime_1 = require("react/jsx-runtime");
38
9
  const discord_js_1 = require("discord.js");
39
10
  const content_1 = __importStar(require("./content"));
11
+
12
+ function t(context, key, fallback) {
13
+ const dict = context?.i18n?.[context?.lang] || context?.i18n?.en || {};
14
+ return dict[key] || fallback || key;
15
+ }
16
+
40
17
  async function MessageReply({ message, context }) {
41
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
42
- if (!message.reference)
43
- return null;
44
- if (message.reference.guildId !== ((_a = message.guild) === null || _a === void 0 ? void 0 : _a.id))
45
- return null;
18
+ if (!message.reference) return null;
19
+
20
+ const isCrossGuild = message.reference.guildId !== message.guild?.id;
21
+
22
+ // Cross-guild reply: show a placeholder pill instead of silently dropping.
23
+ if (isCrossGuild) {
24
+ return (0, jsx_runtime_1.jsx)("discord-reply", {
25
+ slot: "reply",
26
+ server: true,
27
+ children: (0, jsx_runtime_1.jsx)("em", { "data-i18n": "crossServerReply", children: t(context, 'crossServerReply', 'Message from another server') })
28
+ });
29
+ }
30
+
46
31
  const referencedMessage = context.messages.find((m) => m.id === message.reference.messageId);
47
32
  if (!referencedMessage)
48
33
  return (0, jsx_runtime_1.jsx)("discord-reply", { slot: "reply", children: "Message could not be loaded." });
49
- const isCrossPost = referencedMessage.reference && referencedMessage.reference.guildId !== ((_b = message.guild) === null || _b === void 0 ? void 0 : _b.id);
34
+
35
+ const isCrossPost = referencedMessage.reference && referencedMessage.reference.guildId !== message.guild?.id;
50
36
  const isCommand = referencedMessage.interaction !== null;
51
- return ((0, jsx_runtime_1.jsx)("discord-reply", { slot: "reply", edited: !isCommand && referencedMessage.editedAt !== null, attachment: referencedMessage.attachments.size > 0, author: (_e = (_d = (_c = referencedMessage.member) === null || _c === void 0 ? void 0 : _c.nickname) !== null && _d !== void 0 ? _d : referencedMessage.author.displayName) !== null && _e !== void 0 ? _e : referencedMessage.author.username, avatar: (_f = referencedMessage.author.avatarURL({ size: 32 })) !== null && _f !== void 0 ? _f : undefined, roleColor: (_h = (_g = referencedMessage.member) === null || _g === void 0 ? void 0 : _g.displayHexColor) !== null && _h !== void 0 ? _h : undefined, bot: !isCrossPost && referencedMessage.author.bot, verified: (_j = referencedMessage.author.flags) === null || _j === void 0 ? void 0 : _j.has(discord_js_1.UserFlags.VerifiedBot), op: ((_l = (_k = message === null || message === void 0 ? void 0 : message.channel) === null || _k === void 0 ? void 0 : _k.isThread) === null || _l === void 0 ? void 0 : _l.call(_k)) && referencedMessage.author.id === ((_m = message === null || message === void 0 ? void 0 : message.channel) === null || _m === void 0 ? void 0 : _m.ownerId), server: isCrossPost !== null && isCrossPost !== void 0 ? isCrossPost : undefined, command: isCommand, children: referencedMessage.content ? ((0, jsx_runtime_1.jsx)("span", { "data-goto": referencedMessage.id, className: "reply-inline", children: (0, jsx_runtime_1.jsx)(content_1.default, { content: referencedMessage.content, context: Object.assign(Object.assign({}, context), { type: content_1.RenderType.REPLY }) }) })) : isCommand ? ((0, jsx_runtime_1.jsx)("em", { "data-goto": referencedMessage.id, children: "Click to see command." })) : ((0, jsx_runtime_1.jsx)("em", { "data-goto": referencedMessage.id, children: "Click to see attachment." })) }));
37
+ const author = referencedMessage.member?.nickname ?? referencedMessage.author.displayName ?? referencedMessage.author.username;
38
+ const avatar = referencedMessage.author.avatarURL?.({ size: 32 }) ?? undefined;
39
+ const roleColor = referencedMessage.member?.displayHexColor ?? undefined;
40
+ const op = referencedMessage.author.id === message?.channel?.ownerId && message?.channel?.isThread?.();
41
+
42
+ return ((0, jsx_runtime_1.jsx)("discord-reply", {
43
+ slot: "reply",
44
+ edited: !isCommand && referencedMessage.editedAt !== null,
45
+ attachment: referencedMessage.attachments.size > 0,
46
+ author: author,
47
+ avatar: avatar,
48
+ roleColor: roleColor,
49
+ bot: !isCrossPost && referencedMessage.author.bot,
50
+ verified: referencedMessage.author.flags?.has?.(discord_js_1.UserFlags.VerifiedBot),
51
+ op: op,
52
+ server: isCrossPost ?? undefined,
53
+ command: isCommand,
54
+ children: referencedMessage.content
55
+ ? (0, jsx_runtime_1.jsx)("span", { "data-goto": referencedMessage.id, className: "reply-inline", children: (0, jsx_runtime_1.jsx)(content_1.default, { content: referencedMessage.content, context: Object.assign({}, context, { type: content_1.RenderType.REPLY }) }) })
56
+ : isCommand
57
+ ? (0, jsx_runtime_1.jsx)("em", { "data-goto": referencedMessage.id, children: "Click to see command." })
58
+ : (0, jsx_runtime_1.jsx)("em", { "data-goto": referencedMessage.id, children: "Click to see attachment." })
59
+ }));
52
60
  }
53
- //# sourceMappingURL=reply.js.map
61
+ //# sourceMappingURL=reply.js.map
@@ -6,60 +6,145 @@ exports.JoinMessage = JoinMessage;
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const discord_js_1 = require("discord.js");
8
8
  const utils_1 = require("../../utils/utils");
9
- async function SystemMessage({ message }) {
10
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
9
+
10
+ function t(context, key, fallback) {
11
+ const dict = context?.i18n?.[context?.lang] || context?.i18n?.en || {};
12
+ return dict[key] || fallback || key;
13
+ }
14
+
15
+ async function SystemMessage({ message, context }) {
16
+ const author = message.author;
17
+ const authorName = author?.displayName ?? author?.username ?? 'Unknown';
18
+ const color = message.member?.roles?.color?.hexColor;
19
+ const ctx = context || {};
20
+
11
21
  switch (message.type) {
12
22
  case discord_js_1.MessageType.RecipientAdd:
13
23
  case discord_js_1.MessageType.UserJoin:
14
- return ((0, jsx_runtime_1.jsx)("discord-system-message", { id: `m-${message.id}`, type: "join", children: (0, jsx_runtime_1.jsx)(JoinMessage, { member: message.member, fallbackUser: message.author }) }, message.id));
24
+ return ((0, jsx_runtime_1.jsx)("discord-system-message", { id: `m-${message.id}`, type: "join", children: (0, jsx_runtime_1.jsx)(JoinMessage, { member: message.member, fallbackUser: author, seed: message.id, context: ctx }) }, message.id));
25
+
15
26
  case discord_js_1.MessageType.ChannelPinnedMessage:
16
- return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "pin", children: [(0, jsx_runtime_1.jsx)(Highlight, { color: (_b = (_a = message.member) === null || _a === void 0 ? void 0 : _a.roles.color) === null || _b === void 0 ? void 0 : _b.hexColor, children: (_c = message.author.displayName) !== null && _c !== void 0 ? _c : message.author.username }), ' ', "pinned ", (0, jsx_runtime_1.jsx)("i", { "data-goto": (_d = message.reference) === null || _d === void 0 ? void 0 : _d.messageId, children: "a message" }), " to this channel.", message.reactions.cache.size > 0 && ((0, jsx_runtime_1.jsx)("discord-reactions", { slot: "reactions", children: message.reactions.cache.map((reaction, id) => ((0, jsx_runtime_1.jsx)("discord-reaction", { name: reaction.emoji.name, emoji: (0, utils_1.parseDiscordEmoji)(reaction.emoji), count: reaction.count }, `${message.id}r${id}`))) }))] }, message.id));
27
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "pin", children: [
28
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
29
+ ' ',
30
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "pinned", children: t(ctx, 'pinned', 'pinned a message to this channel.') }),
31
+ (0, jsx_runtime_1.jsx)("i", { "data-goto": message.reference?.messageId, children: " (jump)" }),
32
+ ] }, message.id));
33
+
17
34
  case discord_js_1.MessageType.GuildBoost:
18
35
  case discord_js_1.MessageType.GuildBoostTier1:
19
36
  case discord_js_1.MessageType.GuildBoostTier2:
20
37
  case discord_js_1.MessageType.GuildBoostTier3:
21
- return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "boost", children: [(0, jsx_runtime_1.jsx)(Highlight, { color: (_f = (_e = message.member) === null || _e === void 0 ? void 0 : _e.roles.color) === null || _f === void 0 ? void 0 : _f.hexColor, children: (_g = message.author.displayName) !== null && _g !== void 0 ? _g : message.author.username }), ' ', "boosted the server!"] }, message.id));
38
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "boost", children: [
39
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
40
+ ' ',
41
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "boosted", children: t(ctx, 'boosted', 'boosted the server!') }),
42
+ ] }, message.id));
43
+
22
44
  case discord_js_1.MessageType.ThreadStarterMessage:
23
- return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `ms-${message.id}`, type: "thread", children: [(0, jsx_runtime_1.jsx)(Highlight, { color: (_j = (_h = message.member) === null || _h === void 0 ? void 0 : _h.roles.color) === null || _j === void 0 ? void 0 : _j.hexColor, children: (_k = message.author.displayName) !== null && _k !== void 0 ? _k : message.author.username }), ' ', "started a thread: ", (0, jsx_runtime_1.jsx)("i", { "data-goto": (_l = message.reference) === null || _l === void 0 ? void 0 : _l.messageId, children: message.content })] }, message.id));
24
- // TODO: implement support for these:
25
- case discord_js_1.MessageType.Default:
26
- case discord_js_1.MessageType.RecipientRemove:
27
- case discord_js_1.MessageType.Call:
45
+ case discord_js_1.MessageType.ThreadCreated:
46
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "thread", children: [
47
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
48
+ ' ',
49
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "threadStarted", children: t(ctx, 'threadStarted', 'started a thread:') }),
50
+ ' ',
51
+ (0, jsx_runtime_1.jsx)("i", { "data-goto": message.reference?.messageId, children: message.content || 'New thread' }),
52
+ ] }, message.id));
53
+
28
54
  case discord_js_1.MessageType.ChannelNameChange:
55
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "edit", children: [
56
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
57
+ ' ',
58
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "changedChannelName", children: t(ctx, 'changedChannelName', 'changed the channel name:') }),
59
+ ' ',
60
+ (0, jsx_runtime_1.jsx)("strong", { children: message.content }),
61
+ ] }, message.id));
62
+
29
63
  case discord_js_1.MessageType.ChannelIconChange:
30
- case discord_js_1.MessageType.ChannelFollowAdd:
31
- case discord_js_1.MessageType.GuildDiscoveryDisqualified:
32
- case discord_js_1.MessageType.GuildDiscoveryRequalified:
33
- case discord_js_1.MessageType.GuildDiscoveryGracePeriodInitialWarning:
34
- case discord_js_1.MessageType.GuildDiscoveryGracePeriodFinalWarning:
35
- case discord_js_1.MessageType.ThreadCreated:
36
- case discord_js_1.MessageType.Reply:
64
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "edit", children: [
65
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
66
+ ' ',
67
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "changedChannelIcon", children: t(ctx, 'changedChannelIcon', 'changed the channel icon.') }),
68
+ ] }, message.id));
69
+
37
70
  case discord_js_1.MessageType.ChatInputCommand:
38
- case discord_js_1.MessageType.GuildInviteReminder:
39
- case discord_js_1.MessageType.ContextMenuCommand:
40
- case discord_js_1.MessageType.AutoModerationAction:
41
- case discord_js_1.MessageType.RoleSubscriptionPurchase:
42
- case discord_js_1.MessageType.InteractionPremiumUpsell:
43
- case discord_js_1.MessageType.StageStart:
44
- case discord_js_1.MessageType.StageEnd:
45
- case discord_js_1.MessageType.StageSpeaker:
46
- case discord_js_1.MessageType.StageRaiseHand:
47
- case discord_js_1.MessageType.StageTopic:
48
- case discord_js_1.MessageType.GuildApplicationPremiumSubscription:
49
- case discord_js_1.MessageType.GuildIncidentAlertModeEnabled:
50
- case discord_js_1.MessageType.GuildIncidentAlertModeDisabled:
71
+ case discord_js_1.MessageType.ContextMenuCommand: {
72
+ const cmd = message.interaction?.commandName ? '/' + message.interaction.commandName : 'a command';
73
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "call", children: [
74
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
75
+ ' ',
76
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "usedCommand", children: t(ctx, 'usedCommand', 'used') }),
77
+ ' ',
78
+ (0, jsx_runtime_1.jsx)("strong", { children: cmd }),
79
+ ] }, message.id));
80
+ }
81
+
82
+ case discord_js_1.MessageType.Call:
83
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "call", children: [
84
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
85
+ ' ',
86
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "startedCall", children: t(ctx, 'startedCall', 'started a call.') }),
87
+ ] }, message.id));
88
+
89
+ case discord_js_1.MessageType.ChannelFollowAdd:
90
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "edit", children: [
91
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
92
+ ' ',
93
+ t(ctx, 'addedFollow', 'added {target} to follow this channel.').replace('{target}', message.content || ''),
94
+ ] }, message.id));
95
+
96
+ case discord_js_1.MessageType.RecipientRemove:
97
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "leave", children: [
98
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
99
+ ' ',
100
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "left", children: t(ctx, 'left', 'left.') }),
101
+ ] }, message.id));
102
+
103
+ case discord_js_1.MessageType.AutoModerationAction: {
104
+ // Discord packs detail into the first embed: matched_keyword, blocked_content, channel_id, rule_name
105
+ const e = message.embeds?.[0];
106
+ const ruleName = e?.fields?.find?.((f) => /rule/i.test(f.name))?.value || e?.title || '';
107
+ const blocked = e?.description || '';
108
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "boost", children: [
109
+ (0, jsx_runtime_1.jsx)("span", { "data-i18n": "autoModBlocked", children: t(ctx, 'autoModBlocked', 'AutoMod blocked a message.') }),
110
+ ruleName && (0, jsx_runtime_1.jsxs)("span", { className: "dht-automod-rule", children: [' ยท ', (0, utils_1.escapeHtml)(ruleName)] }),
111
+ blocked && (0, jsx_runtime_1.jsx)("blockquote", { className: "dht-automod-content", children: blocked }),
112
+ ] }, message.id));
113
+ }
114
+
115
+ case discord_js_1.MessageType.RoleSubscriptionPurchase: {
116
+ const roleName = message.roleSubscriptionData?.tierName || message.content || 'a role';
117
+ return ((0, jsx_runtime_1.jsxs)("discord-system-message", { id: `m-${message.id}`, type: "boost", children: [
118
+ (0, jsx_runtime_1.jsx)(Highlight, { color, children: authorName }),
119
+ ' ',
120
+ t(ctx, 'roleSubPurchased', 'subscribed to {role}!').replace('{role}', roleName),
121
+ ] }, message.id));
122
+ }
123
+
51
124
  case discord_js_1.MessageType.GuildIncidentReportRaid:
52
125
  case discord_js_1.MessageType.GuildIncidentReportFalseAlarm:
53
- case discord_js_1.MessageType.PurchaseNotification:
126
+ case discord_js_1.MessageType.GuildIncidentAlertModeEnabled:
127
+ case discord_js_1.MessageType.GuildIncidentAlertModeDisabled:
128
+ return ((0, jsx_runtime_1.jsx)("discord-system-message", { id: `m-${message.id}`, type: "boost", children: (0, jsx_runtime_1.jsx)("span", { "data-i18n": "serverAlert", children: t(ctx, 'serverAlert', 'Server safety alert.') }) }, message.id));
129
+
54
130
  case discord_js_1.MessageType.PollResult:
131
+ return ((0, jsx_runtime_1.jsx)("discord-system-message", { id: `m-${message.id}`, type: "edit", children: (0, jsx_runtime_1.jsx)("span", { "data-i18n": "pollEnded", children: t(ctx, 'pollEnded', 'A poll ended.') }) }, message.id));
132
+
133
+ // These render through the normal pipeline
134
+ case discord_js_1.MessageType.Default:
135
+ case discord_js_1.MessageType.Reply:
55
136
  return undefined;
137
+
56
138
  default:
57
139
  return undefined;
58
140
  }
59
141
  }
142
+
60
143
  function Highlight({ children, color }) {
61
- return (0, jsx_runtime_1.jsx)("i", { style: { color: color !== null && color !== void 0 ? color : 'white' }, children: children });
144
+ const safe = typeof color === 'string' && /^#[0-9a-fA-F]{3,8}$/.test(color) ? color : 'white';
145
+ return (0, jsx_runtime_1.jsx)("i", { style: { color: safe }, children: children });
62
146
  }
147
+
63
148
  const allJoinMessages = [
64
149
  '{user} just joined the server - glhf!',
65
150
  '{user} just joined. Everyone, look busy!',
@@ -92,24 +177,34 @@ const allJoinMessages = [
92
177
  "We've been expecting you {user}",
93
178
  "It's dangerous to go alone, take {user}!",
94
179
  "{user} has joined the server! It's super effective!",
95
- 'Cheers, love! {user} is here!',
96
180
  '{user} is here, as the prophecy foretold.',
97
181
  "{user} has arrived. Party's over.",
98
182
  'Ready player {user}',
99
183
  '{user} is here to kick butt and chew bubblegum. And {user} is all out of gum.',
100
184
  "Hello. Is it {user} you're looking for?",
101
185
  ];
102
- function JoinMessage({ member, fallbackUser }) {
103
- const randomMessage = allJoinMessages[Math.floor(Math.random() * allJoinMessages.length)];
104
- return randomMessage
186
+
187
+ // Deterministic โ€” seed off message.id so the message text stays stable across re-renders.
188
+ function pickJoinMessage(seed) {
189
+ if (!seed) return allJoinMessages[0];
190
+ try {
191
+ // Hash snowflake โ†’ index. BigInt safe for snowflakes.
192
+ let n = 0;
193
+ for (let i = 0; i < seed.length; i++) n = (n * 31 + seed.charCodeAt(i)) >>> 0;
194
+ return allJoinMessages[n % allJoinMessages.length];
195
+ } catch (_e) {
196
+ return allJoinMessages[0];
197
+ }
198
+ }
199
+
200
+ function JoinMessage({ member, fallbackUser, seed, context }) {
201
+ const template = pickJoinMessage(seed);
202
+ return template
105
203
  .split('{user}')
106
- .flatMap((item, i) => {
107
- var _a, _b, _c;
108
- return [
204
+ .flatMap((item, i) => [
109
205
  item,
110
- (0, jsx_runtime_1.jsx)(Highlight, { color: (_a = member === null || member === void 0 ? void 0 : member.roles.color) === null || _a === void 0 ? void 0 : _a.hexColor, children: (_c = (_b = member === null || member === void 0 ? void 0 : member.nickname) !== null && _b !== void 0 ? _b : fallbackUser.displayName) !== null && _c !== void 0 ? _c : fallbackUser.username }, i),
111
- ];
112
- })
206
+ (0, jsx_runtime_1.jsx)(Highlight, { color: member?.roles?.color?.hexColor, children: member?.nickname ?? fallbackUser.displayName ?? fallbackUser.username }, i),
207
+ ])
113
208
  .slice(0, -1);
114
209
  }
115
- //# sourceMappingURL=systemMessage.js.map
210
+ //# sourceMappingURL=systemMessage.js.map