@scotthamilton77/discord-bot-lib 0.1.2 → 1.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 +21 -26
- package/dist/index.cjs +100 -108
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -21
- package/dist/index.d.ts +20 -21
- package/dist/index.js +100 -108
- package/dist/index.js.map +1 -1
- package/package.json +2 -7
package/dist/index.js
CHANGED
|
@@ -7,6 +7,10 @@ var EventBuffer = class {
|
|
|
7
7
|
buffer = [];
|
|
8
8
|
resolve = null;
|
|
9
9
|
closed = false;
|
|
10
|
+
onClose;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.onClose = options?.onClose;
|
|
13
|
+
}
|
|
10
14
|
push(value) {
|
|
11
15
|
if (this.closed) return;
|
|
12
16
|
if (this.resolve) {
|
|
@@ -18,7 +22,9 @@ var EventBuffer = class {
|
|
|
18
22
|
}
|
|
19
23
|
}
|
|
20
24
|
close() {
|
|
25
|
+
if (this.closed) return;
|
|
21
26
|
this.closed = true;
|
|
27
|
+
this.onClose?.();
|
|
22
28
|
if (this.resolve) {
|
|
23
29
|
const r = this.resolve;
|
|
24
30
|
this.resolve = null;
|
|
@@ -41,6 +47,10 @@ var EventBuffer = class {
|
|
|
41
47
|
return new Promise((resolve) => {
|
|
42
48
|
this.resolve = resolve;
|
|
43
49
|
});
|
|
50
|
+
},
|
|
51
|
+
return: () => {
|
|
52
|
+
this.close();
|
|
53
|
+
return Promise.resolve({ value: void 0, done: true });
|
|
44
54
|
}
|
|
45
55
|
};
|
|
46
56
|
}
|
|
@@ -117,9 +127,7 @@ var Bot = class _Bot {
|
|
|
117
127
|
client;
|
|
118
128
|
sentMessages;
|
|
119
129
|
_connectedAt = null;
|
|
120
|
-
|
|
121
|
-
replyHandlers = [];
|
|
122
|
-
channelSubscriptions = /* @__PURE__ */ new Map();
|
|
130
|
+
messageHandlers = [];
|
|
123
131
|
errorHandlers = [];
|
|
124
132
|
_includeBotMessages;
|
|
125
133
|
constructor(id, name, client, sentMessageCacheSize, includeBotMessages) {
|
|
@@ -185,18 +193,10 @@ var Bot = class _Bot {
|
|
|
185
193
|
);
|
|
186
194
|
}
|
|
187
195
|
async reply(channelId, messageId, content) {
|
|
188
|
-
const channel = await this.
|
|
196
|
+
const { channel, message } = await this.fetchMessage(channelId, messageId, "reply to");
|
|
189
197
|
if (!("send" in channel)) {
|
|
190
198
|
throw new Error(`Channel ${channelId} is not a sendable channel`);
|
|
191
199
|
}
|
|
192
|
-
let message;
|
|
193
|
-
try {
|
|
194
|
-
message = await channel.messages.fetch(messageId);
|
|
195
|
-
} catch (error) {
|
|
196
|
-
throw new Error(
|
|
197
|
-
`Cannot reply to message ${messageId}: ${error instanceof Error ? error.message : String(error)}`
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
200
|
return this.sendPayloads(content, (payload, i) => {
|
|
201
201
|
if (i === 0) {
|
|
202
202
|
return message.reply(payload);
|
|
@@ -206,9 +206,8 @@ var Bot = class _Bot {
|
|
|
206
206
|
}
|
|
207
207
|
// --- Channel operations ---
|
|
208
208
|
async react(channelId, messageId, emoji) {
|
|
209
|
-
const
|
|
209
|
+
const { message } = await this.fetchMessage(channelId, messageId, "react to");
|
|
210
210
|
try {
|
|
211
|
-
const message = await channel.messages.fetch(messageId);
|
|
212
211
|
await message.react(emoji);
|
|
213
212
|
} catch (error) {
|
|
214
213
|
throw new Error(
|
|
@@ -217,9 +216,8 @@ var Bot = class _Bot {
|
|
|
217
216
|
}
|
|
218
217
|
}
|
|
219
218
|
async editMessage(channelId, messageId, content) {
|
|
220
|
-
const
|
|
219
|
+
const { message } = await this.fetchMessage(channelId, messageId, "edit");
|
|
221
220
|
try {
|
|
222
|
-
const message = await channel.messages.fetch(messageId);
|
|
223
221
|
await message.edit(content);
|
|
224
222
|
} catch (error) {
|
|
225
223
|
throw new Error(
|
|
@@ -270,76 +268,48 @@ var Bot = class _Bot {
|
|
|
270
268
|
}
|
|
271
269
|
}
|
|
272
270
|
async getMessageAttachments(channelId, messageId) {
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
contentType: att.contentType
|
|
282
|
-
}));
|
|
283
|
-
} catch (error) {
|
|
284
|
-
throw new Error(
|
|
285
|
-
`Cannot fetch attachments for message ${messageId}: ${error instanceof Error ? error.message : String(error)}`
|
|
286
|
-
);
|
|
287
|
-
}
|
|
271
|
+
const { message } = await this.fetchMessage(channelId, messageId, "fetch attachments for");
|
|
272
|
+
return [...message.attachments.values()].map((att) => ({
|
|
273
|
+
id: att.id,
|
|
274
|
+
size: att.size,
|
|
275
|
+
name: att.name,
|
|
276
|
+
url: att.url,
|
|
277
|
+
contentType: att.contentType
|
|
278
|
+
}));
|
|
288
279
|
}
|
|
289
280
|
// --- Receiving (event-driven) ---
|
|
290
|
-
|
|
291
|
-
this.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (typeof handlerOrOpts === "function") {
|
|
300
|
-
handler = handlerOrOpts;
|
|
301
|
-
} else {
|
|
302
|
-
filter = handlerOrOpts.filter;
|
|
303
|
-
if (!maybeHandler) {
|
|
304
|
-
throw new Error("Handler is required when providing filter options");
|
|
305
|
-
}
|
|
306
|
-
handler = maybeHandler;
|
|
307
|
-
}
|
|
308
|
-
const subs = this.channelSubscriptions.get(channelId) ?? [];
|
|
309
|
-
subs.push({ filter, handler });
|
|
310
|
-
this.channelSubscriptions.set(channelId, subs);
|
|
281
|
+
onMessage(handler) {
|
|
282
|
+
this.messageHandlers.push(handler);
|
|
283
|
+
let removed = false;
|
|
284
|
+
return () => {
|
|
285
|
+
if (removed) return;
|
|
286
|
+
removed = true;
|
|
287
|
+
const index = this.messageHandlers.indexOf(handler);
|
|
288
|
+
if (index !== -1) this.messageHandlers.splice(index, 1);
|
|
289
|
+
};
|
|
311
290
|
}
|
|
312
291
|
// --- Receiving (async iterable) ---
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
292
|
+
messages(options) {
|
|
293
|
+
let unsubscribe;
|
|
294
|
+
const buffer = new EventBuffer({
|
|
295
|
+
onClose: () => unsubscribe?.()
|
|
317
296
|
});
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const buffer = new EventBuffer();
|
|
322
|
-
this.onReply((event, original) => {
|
|
323
|
-
buffer.push([event, original]);
|
|
297
|
+
unsubscribe = this.onMessage((event) => {
|
|
298
|
+
if (options?.filter && !options.filter(event)) return;
|
|
299
|
+
buffer.push(event);
|
|
324
300
|
});
|
|
325
301
|
return buffer;
|
|
326
302
|
}
|
|
327
|
-
messages(channelId, options) {
|
|
328
|
-
const buffer = new EventBuffer();
|
|
329
|
-
if (options?.filter) {
|
|
330
|
-
this.onMessage(channelId, { filter: options.filter }, (event) => {
|
|
331
|
-
buffer.push(event);
|
|
332
|
-
});
|
|
333
|
-
} else {
|
|
334
|
-
this.onMessage(channelId, (event) => {
|
|
335
|
-
buffer.push(event);
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
return buffer;
|
|
339
|
-
}
|
|
340
303
|
// --- Error handling ---
|
|
341
304
|
on(_event, handler) {
|
|
342
305
|
this.errorHandlers.push(handler);
|
|
306
|
+
let removed = false;
|
|
307
|
+
return () => {
|
|
308
|
+
if (removed) return;
|
|
309
|
+
removed = true;
|
|
310
|
+
const index = this.errorHandlers.indexOf(handler);
|
|
311
|
+
if (index !== -1) this.errorHandlers.splice(index, 1);
|
|
312
|
+
};
|
|
343
313
|
}
|
|
344
314
|
emitError(error) {
|
|
345
315
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
@@ -351,6 +321,8 @@ var Bot = class _Bot {
|
|
|
351
321
|
async disconnect() {
|
|
352
322
|
this.client.removeAllListeners();
|
|
353
323
|
await this.client.destroy();
|
|
324
|
+
this.messageHandlers.length = 0;
|
|
325
|
+
this.errorHandlers.length = 0;
|
|
354
326
|
this._status = "disconnected";
|
|
355
327
|
this._connectedAt = null;
|
|
356
328
|
}
|
|
@@ -364,6 +336,17 @@ var Bot = class _Bot {
|
|
|
364
336
|
}
|
|
365
337
|
return channel;
|
|
366
338
|
}
|
|
339
|
+
async fetchMessage(channelId, messageId, verb) {
|
|
340
|
+
const channel = await this.fetchTextChannel(channelId);
|
|
341
|
+
try {
|
|
342
|
+
const message = await channel.messages.fetch(messageId);
|
|
343
|
+
return { channel, message };
|
|
344
|
+
} catch (error) {
|
|
345
|
+
throw new Error(
|
|
346
|
+
`Cannot ${verb} message ${messageId}: ${error instanceof Error ? error.message : String(error)}`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
367
350
|
toFetchedMessage(msg) {
|
|
368
351
|
return {
|
|
369
352
|
messageId: msg.id,
|
|
@@ -411,27 +394,8 @@ var Bot = class _Bot {
|
|
|
411
394
|
if (message.author.id === this.client.user?.id) return;
|
|
412
395
|
if (message.author.bot && !this._includeBotMessages) return;
|
|
413
396
|
const event = this.toMessageEvent(message);
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
if (botUser && (message.mentions.has(botUser.id) || isDM)) {
|
|
417
|
-
for (const handler of this.mentionHandlers) {
|
|
418
|
-
handler(event);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
if (message.reference?.messageId) {
|
|
422
|
-
const original = this.sentMessages.get(message.reference.messageId);
|
|
423
|
-
if (original) {
|
|
424
|
-
for (const handler of this.replyHandlers) {
|
|
425
|
-
handler(event, original);
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
const subs = this.channelSubscriptions.get(message.channelId);
|
|
430
|
-
if (subs) {
|
|
431
|
-
for (const sub of subs) {
|
|
432
|
-
if (sub.filter && !sub.filter(event)) continue;
|
|
433
|
-
sub.handler(event);
|
|
434
|
-
}
|
|
397
|
+
for (const handler of this.messageHandlers) {
|
|
398
|
+
handler(event);
|
|
435
399
|
}
|
|
436
400
|
} catch (error) {
|
|
437
401
|
this.emitError(error);
|
|
@@ -439,6 +403,18 @@ var Bot = class _Bot {
|
|
|
439
403
|
});
|
|
440
404
|
}
|
|
441
405
|
toMessageEvent(message) {
|
|
406
|
+
const isDM = message.channel.type === ChannelType.DM;
|
|
407
|
+
const botUser = this.client.user;
|
|
408
|
+
const isMention = isDM || (botUser ? message.mentions.has(botUser.id) : false);
|
|
409
|
+
let isReply = false;
|
|
410
|
+
let replyTo = null;
|
|
411
|
+
if (message.reference?.messageId) {
|
|
412
|
+
const original = this.sentMessages.get(message.reference.messageId);
|
|
413
|
+
if (original) {
|
|
414
|
+
isReply = true;
|
|
415
|
+
replyTo = original;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
442
418
|
return {
|
|
443
419
|
messageId: message.id,
|
|
444
420
|
author: {
|
|
@@ -451,7 +427,11 @@ var Bot = class _Bot {
|
|
|
451
427
|
guildId: message.guildId ?? null,
|
|
452
428
|
timestamp: message.createdAt,
|
|
453
429
|
mentions: [...message.mentions.users.keys()],
|
|
454
|
-
raw: message
|
|
430
|
+
raw: message,
|
|
431
|
+
isDM,
|
|
432
|
+
isMention,
|
|
433
|
+
isReply,
|
|
434
|
+
replyTo
|
|
455
435
|
};
|
|
456
436
|
}
|
|
457
437
|
async sendPayloads(content, dispatcher) {
|
|
@@ -658,21 +638,28 @@ var BotOnboarding = class {
|
|
|
658
638
|
// src/connector-manager.ts
|
|
659
639
|
var ConnectorManager = class {
|
|
660
640
|
botMap = /* @__PURE__ */ new Map();
|
|
661
|
-
|
|
641
|
+
botUnsubscribers = /* @__PURE__ */ new Map();
|
|
642
|
+
messageHandlers = [];
|
|
662
643
|
lifecycleHandlers = /* @__PURE__ */ new Map();
|
|
663
644
|
addBot(bot) {
|
|
664
645
|
if (this.botMap.has(bot.id)) {
|
|
665
646
|
throw new Error(`Bot with id "${bot.id}" already exists in this manager.`);
|
|
666
647
|
}
|
|
667
648
|
this.botMap.set(bot.id, bot);
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
649
|
+
const unsubs = [];
|
|
650
|
+
unsubs.push(
|
|
651
|
+
bot.onMessage((event) => {
|
|
652
|
+
for (const handler of this.messageHandlers) {
|
|
653
|
+
handler(event, bot);
|
|
654
|
+
}
|
|
655
|
+
})
|
|
656
|
+
);
|
|
657
|
+
unsubs.push(
|
|
658
|
+
bot.on("error", (error) => {
|
|
659
|
+
this.emitLifecycle("botError", bot, error);
|
|
660
|
+
})
|
|
661
|
+
);
|
|
662
|
+
this.botUnsubscribers.set(bot.id, unsubs);
|
|
676
663
|
}
|
|
677
664
|
getBot(id) {
|
|
678
665
|
return this.botMap.get(id);
|
|
@@ -681,6 +668,11 @@ var ConnectorManager = class {
|
|
|
681
668
|
return this.botMap.values();
|
|
682
669
|
}
|
|
683
670
|
removeBot(id) {
|
|
671
|
+
const unsubs = this.botUnsubscribers.get(id);
|
|
672
|
+
if (unsubs) {
|
|
673
|
+
for (const unsub of unsubs) unsub();
|
|
674
|
+
this.botUnsubscribers.delete(id);
|
|
675
|
+
}
|
|
684
676
|
this.botMap.delete(id);
|
|
685
677
|
}
|
|
686
678
|
status() {
|
|
@@ -690,8 +682,8 @@ var ConnectorManager = class {
|
|
|
690
682
|
status: bot.status
|
|
691
683
|
}));
|
|
692
684
|
}
|
|
693
|
-
|
|
694
|
-
this.
|
|
685
|
+
onMessage(handler) {
|
|
686
|
+
this.messageHandlers.push(handler);
|
|
695
687
|
}
|
|
696
688
|
on(event, callback) {
|
|
697
689
|
const handlers = this.lifecycleHandlers.get(event) ?? [];
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bot.ts","../src/event-buffer.ts","../src/message-utils.ts","../src/attachment-utils.ts","../src/onboarding.ts","../src/connector-manager.ts"],"sourcesContent":["import { Client, ChannelType, GatewayIntentBits, Partials, Events, LimitedCollection, AttachmentBuilder, type Message } from \"discord.js\";\nimport { stat } from \"node:fs/promises\";\nimport type {\n BotConfig,\n BotStatus,\n FetchedMessage,\n FetchHistoryOptions,\n FileAttachment,\n MessageEvent,\n SentMessage,\n MessageContent,\n MessageFilter,\n} from \"./types.js\";\nimport { EventBuffer } from \"./event-buffer.js\";\nimport { chunkMessage } from \"./message-utils.js\";\nimport { validateAttachmentSize, type DownloadableAttachment } from \"./attachment-utils.js\";\n\nexport const DEFAULT_SENT_MESSAGE_CACHE_SIZE = 1000;\n\nexport const DEFAULT_INTENTS = [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.DirectMessages,\n] as const;\n\nexport const DEFAULT_PARTIALS = [Partials.Channel, Partials.Message] as const;\n\ntype MentionHandler = (message: MessageEvent) => void;\ntype ReplyHandler = (message: MessageEvent, original: SentMessage) => void;\ntype MessageHandler = (message: MessageEvent) => void;\ntype ErrorHandler = (error: Error) => void;\n\ninterface ChannelSubscription {\n filter?: MessageFilter;\n handler: MessageHandler;\n}\n\nexport class Bot {\n readonly id: string;\n readonly name: string;\n\n private _status: BotStatus;\n private readonly client: Client;\n private readonly sentMessages: LimitedCollection<string, SentMessage>;\n private _connectedAt: Date | null = null;\n private readonly mentionHandlers: MentionHandler[] = [];\n private readonly replyHandlers: ReplyHandler[] = [];\n private readonly channelSubscriptions = new Map<string, ChannelSubscription[]>();\n private readonly errorHandlers: ErrorHandler[] = [];\n private readonly _includeBotMessages: boolean;\n\n private constructor(\n id: string,\n name: string,\n client: Client,\n sentMessageCacheSize: number,\n includeBotMessages: boolean,\n ) {\n this.id = id;\n this.name = name;\n this.client = client;\n this.sentMessages = new LimitedCollection({ maxSize: sentMessageCacheSize });\n this._includeBotMessages = includeBotMessages;\n this._status = \"connecting\";\n }\n\n get includeBotMessages(): boolean {\n return this._includeBotMessages;\n }\n\n get status(): BotStatus {\n return this._status;\n }\n\n get guildCount(): number {\n return this.client.guilds.cache.size;\n }\n\n get connectedAt(): Date | null {\n return this._connectedAt;\n }\n\n /**\n * Fast path: create a bot from a complete config, connect, verify, and\n * return a ready Bot — or throw with diagnostics.\n */\n static async fromConfig(config: BotConfig): Promise<Bot> {\n const cacheSize = config.sentMessageCacheSize ?? DEFAULT_SENT_MESSAGE_CACHE_SIZE;\n if (cacheSize < 1 || !Number.isInteger(cacheSize)) {\n throw new Error(\n `sentMessageCacheSize must be a positive integer, got ${String(cacheSize)}`,\n );\n }\n\n const includeBotMessages = config.includeBotMessages ?? false;\n\n const client = new Client({\n intents: config.intents ?? [...DEFAULT_INTENTS],\n partials: config.partials ?? [...DEFAULT_PARTIALS],\n });\n\n const bot = new Bot(config.id, config.name, client, cacheSize, includeBotMessages);\n\n await bot.connect(config.token);\n bot.verify();\n bot.setupEventHandlers();\n bot._status = \"ready\";\n bot._connectedAt = new Date();\n\n return bot;\n }\n\n // --- Sending ---\n\n async send(channelId: string, content: MessageContent): Promise<SentMessage[]> {\n const channel = await this.fetchTextChannel(channelId);\n if (!(\"send\" in channel)) {\n throw new Error(`Channel ${channelId} is not a sendable channel`);\n }\n return this.sendPayloads(content, (payload) =>\n (channel as unknown as { send(opts: unknown): Promise<Message> }).send(payload),\n );\n }\n\n async sendDM(userId: string, content: MessageContent): Promise<SentMessage[]> {\n const user = await this.client.users.fetch(userId);\n return this.sendPayloads(content, (payload) =>\n user.send(payload as Parameters<typeof user.send>[0]),\n );\n }\n\n async reply(channelId: string, messageId: string, content: MessageContent): Promise<SentMessage[]> {\n const channel = await this.fetchTextChannel(channelId);\n if (!(\"send\" in channel)) {\n throw new Error(`Channel ${channelId} is not a sendable channel`);\n }\n let message: Message;\n try {\n message = await channel.messages.fetch(messageId);\n } catch (error) {\n throw new Error(\n `Cannot reply to message ${messageId}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n return this.sendPayloads(content, (payload, i) => {\n if (i === 0) {\n return message.reply(payload as Parameters<Message[\"reply\"]>[0]);\n }\n return (channel as unknown as { send(opts: unknown): Promise<Message> }).send(payload);\n });\n }\n\n // --- Channel operations ---\n\n async react(channelId: string, messageId: string, emoji: string): Promise<void> {\n const channel = await this.fetchTextChannel(channelId);\n try {\n const message = await channel.messages.fetch(messageId);\n await message.react(emoji);\n } catch (error) {\n throw new Error(\n `Cannot react to message ${messageId}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async editMessage(channelId: string, messageId: string, content: string): Promise<void> {\n const channel = await this.fetchTextChannel(channelId);\n try {\n const message = await channel.messages.fetch(messageId);\n await message.edit(content);\n } catch (error) {\n throw new Error(\n `Cannot edit message ${messageId}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async fetchMessages(channelId: string, limit?: number): Promise<FetchedMessage[]> {\n const channel = await this.fetchTextChannel(channelId);\n const clamped = Math.max(1, Math.min(limit ?? 20, 100));\n const messages = await channel.messages.fetch({ limit: clamped });\n return [...messages.values()].reverse().map((m) => this.toFetchedMessage(m));\n }\n\n async *fetchHistory(\n channelId: string,\n options: FetchHistoryOptions,\n ): AsyncGenerator<FetchedMessage[]> {\n const { after, before, limit = 500 } = options;\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard for JS consumers\n if (after && before) {\n throw new Error('Cannot specify both \"after\" and \"before\"');\n }\n\n let cursor: string;\n let direction: \"after\" | \"before\";\n if (after) {\n cursor = after;\n direction = \"after\";\n } else if (before) {\n cursor = before;\n direction = \"before\";\n } else {\n throw new Error('At least one of \"after\" or \"before\" must be specified');\n }\n\n const effectiveLimit = Math.min(limit, 5000);\n const channel = await this.fetchTextChannel(channelId);\n\n let totalFetched = 0;\n\n while (totalFetched < effectiveLimit) {\n const pageSize = Math.min(100, effectiveLimit - totalFetched);\n\n const fetched = await this.fetchPageWithRetry(channel, {\n limit: pageSize,\n [direction]: cursor,\n });\n\n if (fetched.size === 0) break;\n\n const rawMessages = [...fetched.values()];\n const messages = rawMessages.map((m) => this.toFetchedMessage(m));\n\n yield messages;\n totalFetched += messages.length;\n\n const lastMessage = rawMessages.at(-1);\n if (!lastMessage) break;\n cursor = lastMessage.id;\n\n if (fetched.size < pageSize) break;\n }\n }\n\n async getMessageAttachments(\n channelId: string,\n messageId: string,\n ): Promise<DownloadableAttachment[]> {\n const channel = await this.fetchTextChannel(channelId);\n try {\n const message = await channel.messages.fetch(messageId);\n return [...message.attachments.values()].map((att) => ({\n id: att.id,\n size: att.size,\n name: att.name,\n url: att.url,\n contentType: att.contentType,\n }));\n } catch (error) {\n throw new Error(\n `Cannot fetch attachments for message ${messageId}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // --- Receiving (event-driven) ---\n\n onMention(handler: MentionHandler): void {\n this.mentionHandlers.push(handler);\n }\n\n onReply(handler: ReplyHandler): void {\n this.replyHandlers.push(handler);\n }\n\n onMessage(channelId: string, handler: MessageHandler): void;\n onMessage(channelId: string, opts: { filter: MessageFilter }, handler: MessageHandler): void;\n onMessage(\n channelId: string,\n handlerOrOpts: MessageHandler | { filter: MessageFilter },\n maybeHandler?: MessageHandler,\n ): void {\n let filter: MessageFilter | undefined;\n let handler: MessageHandler;\n\n if (typeof handlerOrOpts === \"function\") {\n handler = handlerOrOpts;\n } else {\n filter = handlerOrOpts.filter;\n if (!maybeHandler) {\n throw new Error(\"Handler is required when providing filter options\");\n }\n handler = maybeHandler;\n }\n\n const subs = this.channelSubscriptions.get(channelId) ?? [];\n subs.push({ filter, handler });\n this.channelSubscriptions.set(channelId, subs);\n }\n\n // --- Receiving (async iterable) ---\n\n mentions(): AsyncIterable<MessageEvent> {\n const buffer = new EventBuffer<MessageEvent>();\n this.onMention((event) => {\n buffer.push(event);\n });\n return buffer;\n }\n\n replies(): AsyncIterable<[MessageEvent, SentMessage]> {\n const buffer = new EventBuffer<[MessageEvent, SentMessage]>();\n this.onReply((event, original) => {\n buffer.push([event, original]);\n });\n return buffer;\n }\n\n messages(channelId: string, options?: { filter?: MessageFilter }): AsyncIterable<MessageEvent> {\n const buffer = new EventBuffer<MessageEvent>();\n if (options?.filter) {\n this.onMessage(channelId, { filter: options.filter }, (event) => {\n buffer.push(event);\n });\n } else {\n this.onMessage(channelId, (event) => {\n buffer.push(event);\n });\n }\n return buffer;\n }\n\n // --- Error handling ---\n\n on(_event: \"error\", handler: ErrorHandler): void {\n this.errorHandlers.push(handler);\n }\n\n private emitError(error: unknown): void {\n const err = error instanceof Error ? error : new Error(String(error));\n for (const handler of this.errorHandlers) {\n handler(err);\n }\n }\n\n // --- Lifecycle ---\n\n async disconnect(): Promise<void> {\n this.client.removeAllListeners();\n await this.client.destroy();\n this._status = \"disconnected\";\n this._connectedAt = null;\n }\n\n // --- Private ---\n\n private async fetchTextChannel(channelId: string) {\n const channel = await this.client.channels.fetch(channelId);\n if (!channel?.isTextBased()) {\n throw new Error(\n `Channel ${channelId} is not a text-based channel or does not exist`,\n );\n }\n return channel;\n }\n\n private toFetchedMessage(msg: Message): FetchedMessage {\n return {\n messageId: msg.id,\n channelId: msg.channelId,\n author: {\n id: msg.author.id,\n username: msg.author.username,\n bot: msg.author.bot,\n },\n content: msg.content,\n timestamp: msg.createdAt,\n attachmentCount: msg.attachments.size,\n };\n }\n\n private async fetchPageWithRetry(\n channel: { messages: { fetch(opts: unknown): Promise<Map<string, Message>> } },\n options: Record<string, unknown>,\n maxRetryMs = 5000,\n ): Promise<Map<string, Message>> {\n try {\n return await channel.messages.fetch(options);\n } catch (err) {\n if (err instanceof Error && \"retryAfter\" in err) {\n const { retryAfter } = err;\n if (typeof retryAfter === \"number\" && retryAfter <= maxRetryMs) {\n await new Promise((resolve) => setTimeout(resolve, retryAfter));\n return channel.messages.fetch(options);\n }\n }\n throw err;\n }\n }\n\n private async connect(token: string): Promise<void> {\n this._status = \"connecting\";\n await this.client.login(token);\n }\n\n private verify(): void {\n this._status = \"verifying\";\n\n if (this.client.guilds.cache.size === 0) {\n this._status = \"failed\";\n throw new Error(\n \"Bot is not in any guild. Invite the bot to at least one server before connecting.\",\n );\n }\n }\n\n private setupEventHandlers(): void {\n this.client.on(Events.MessageCreate, (message: Message) => {\n try {\n // Always ignore own messages (prevent infinite loops)\n if (message.author.id === this.client.user?.id) return;\n // Ignore other bots unless opted in\n if (message.author.bot && !this._includeBotMessages) return;\n\n const event = this.toMessageEvent(message);\n const botUser = this.client.user;\n\n // Check mention handlers — DMs are implicit mentions.\n // Note: a DM reply to a tracked message fires BOTH onMention and onReply.\n const isDM = message.channel.type === ChannelType.DM;\n if (botUser && (message.mentions.has(botUser.id) || isDM)) {\n for (const handler of this.mentionHandlers) {\n handler(event);\n }\n }\n\n // Check reply handlers\n if (message.reference?.messageId) {\n const original = this.sentMessages.get(message.reference.messageId);\n if (original) {\n for (const handler of this.replyHandlers) {\n handler(event, original);\n }\n }\n }\n\n // Check channel subscriptions\n const subs = this.channelSubscriptions.get(message.channelId);\n if (subs) {\n for (const sub of subs) {\n if (sub.filter && !sub.filter(event)) continue;\n sub.handler(event);\n }\n }\n } catch (error) {\n this.emitError(error);\n }\n });\n }\n\n private toMessageEvent(message: Message): MessageEvent {\n return {\n messageId: message.id,\n author: {\n id: message.author.id,\n username: message.author.username,\n bot: message.author.bot,\n },\n content: message.content,\n channelId: message.channelId,\n guildId: message.guildId ?? null,\n timestamp: message.createdAt,\n mentions: [...message.mentions.users.keys()],\n raw: message,\n };\n }\n\n private async sendPayloads(\n content: MessageContent,\n dispatcher: (payload: ChunkedPayload, index: number) => Promise<Message>,\n ): Promise<SentMessage[]> {\n const files =\n typeof content !== \"string\" && content.files?.length\n ? await validateAndBuildAttachments(content.files)\n : undefined;\n const payloads = toChunkedPayloads(content, files);\n const results: SentMessage[] = [];\n let i = 0;\n for (const payload of payloads) {\n const msg = await dispatcher(payload, i++);\n results.push(this.trackSentMessage(msg));\n }\n return results;\n }\n\n private trackSentMessage(message: Message): SentMessage {\n const sent: SentMessage = {\n messageId: message.id,\n channelId: message.channelId,\n timestamp: message.createdAt,\n raw: message,\n };\n this.sentMessages.set(sent.messageId, sent);\n return sent;\n }\n}\n\ninterface ChunkedPayload {\n content?: string;\n embeds?: unknown[];\n files?: AttachmentBuilder[];\n}\n\nfunction toChunkedPayloads(\n content: MessageContent,\n files?: AttachmentBuilder[],\n): ChunkedPayload[] {\n if (typeof content === \"string\") {\n const chunks = chunkMessage(content);\n return chunks.map((text, i) => ({\n content: text,\n ...(i === 0 && files?.length ? { files } : {}),\n }));\n }\n const text = content.content ?? \"\";\n const chunks = chunkMessage(text);\n if (chunks.length === 0) {\n return [{ embeds: content.embeds, ...(files?.length ? { files } : {}) }];\n }\n return chunks.map((chunk, i) => ({\n content: chunk,\n ...(i === 0 && content.embeds ? { embeds: content.embeds } : {}),\n ...(i === 0 && files?.length ? { files } : {}),\n }));\n}\n\nconst MAX_FILES_PER_MESSAGE = 10;\n\nasync function validateAndBuildAttachments(\n files: FileAttachment[],\n): Promise<AttachmentBuilder[]> {\n if (files.length > MAX_FILES_PER_MESSAGE) {\n throw new Error(\n `Too many attachments: ${String(files.length)} exceeds Discord's limit of ${String(MAX_FILES_PER_MESSAGE)} attachments per message`,\n );\n }\n\n const sizes = await Promise.all(\n files.map((file) =>\n typeof file.data === \"string\"\n ? stat(file.data).then((st) => st.size)\n : Promise.resolve(file.data.byteLength),\n ),\n );\n\n return files.map((file, i) => {\n const size = sizes[i];\n if (size === undefined) throw new Error(`Missing size for attachment: ${file.name}`);\n validateAttachmentSize({ size, name: file.name, id: file.name });\n return new AttachmentBuilder(file.data, { name: file.name });\n });\n}\n","/**\n * Single-consumer async iterable buffer. Each call to mentions(), replies(),\n * or messages() on a Bot creates its own buffer. Do not share a single\n * EventBuffer between multiple for-await consumers.\n */\nexport class EventBuffer<T> implements AsyncIterable<T> {\n private buffer: T[] = [];\n private resolve: ((value: IteratorResult<T>) => void) | null = null;\n private closed = false;\n\n push(value: T): void {\n if (this.closed) return;\n if (this.resolve) {\n const r = this.resolve;\n this.resolve = null;\n r({ value, done: false });\n } else {\n this.buffer.push(value);\n }\n }\n\n close(): void {\n this.closed = true;\n if (this.resolve) {\n const r = this.resolve;\n this.resolve = null;\n r({ value: undefined as unknown as T, done: true });\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return {\n next: (): Promise<IteratorResult<T>> => {\n if (this.buffer.length > 0) {\n // Length check guarantees shift() returns a value\n const value = this.buffer.shift() as T;\n return Promise.resolve({ value, done: false });\n }\n if (this.closed) {\n return Promise.resolve({\n value: undefined as unknown as T,\n done: true,\n });\n }\n return new Promise((resolve) => {\n this.resolve = resolve;\n });\n },\n };\n }\n}\n","// Message utility functions for discord-bot-lib\n\n/** Discord's hard limit on message length. */\nexport const DISCORD_MAX_MESSAGE_LENGTH = 2000;\n\n/**\n * Splits text into chunks that fit within Discord's message length limit.\n * Prefers splitting at paragraph boundaries (\\n\\n), then line breaks (\\n),\n * then spaces, then hard-cuts as a last resort.\n *\n * @param text - The text to split\n * @param limit - Maximum characters per chunk (default: {@link DISCORD_MAX_MESSAGE_LENGTH})\n * @returns Array of text chunks, each within the limit\n */\nexport function chunkMessage(\n text: string,\n limit: number = DISCORD_MAX_MESSAGE_LENGTH,\n): string[] {\n if (!text) return [];\n if (text.length <= limit) return [text];\n\n const chunks: string[] = [];\n const halfLimit = limit / 2;\n let rest = text;\n\n while (rest.length > limit) {\n const para = rest.lastIndexOf(\"\\n\\n\", limit);\n const line = rest.lastIndexOf(\"\\n\", limit);\n const space = rest.lastIndexOf(\" \", limit);\n const cut =\n para > halfLimit\n ? para\n : line > halfLimit\n ? line\n : space > 0\n ? space\n : limit;\n\n chunks.push(rest.slice(0, cut));\n rest = rest.slice(cut).replace(/^\\n+/, \"\");\n }\n\n if (rest) chunks.push(rest);\n\n return chunks;\n}\n","// Attachment utility functions for discord-bot-lib\n\n/** Maximum attachment size in bytes (25 MB). Matches Discord's default file size limit. */\nexport const MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024; // 26_214_400\n\n/** Shape compatible with discord.js Attachment for attachment utilities. */\nexport interface AttachmentLike {\n size: number;\n name?: string | null;\n id: string;\n}\n\n/**\n * Validates that an attachment does not exceed Discord's size limit.\n * Designed for use in both upload (sending files) and download paths.\n *\n * @throws Error if the attachment exceeds {@link MAX_ATTACHMENT_BYTES}\n */\nexport function validateAttachmentSize(attachment: AttachmentLike): void {\n if (attachment.size > MAX_ATTACHMENT_BYTES) {\n const actualMB = (attachment.size / 1024 / 1024).toFixed(1);\n const limitMB = MAX_ATTACHMENT_BYTES / 1024 / 1024;\n const nameInfo = attachment.name ? `: ${attachment.name}` : \"\";\n throw new Error(\n `Attachment too large (${actualMB} MB > ${String(limitMB)} MB limit)${nameInfo}`,\n );\n }\n}\n\n/**\n * Sanitizes an attachment filename by replacing unsafe characters\n * (`[`, `]`, `\\r`, `\\n`, `;`) with underscores. Falls back to the\n * attachment ID when the name is missing or empty after sanitization.\n */\nconst UNSAFE_CHARS = /[[\\]\\r\\n;]/g;\n\nexport function sanitizeAttachmentName(\n attachment: Pick<AttachmentLike, \"name\" | \"id\">,\n): string {\n const raw = attachment.name;\n if (!raw || raw.replace(UNSAFE_CHARS, \"\").length === 0) {\n return attachment.id;\n }\n return raw.replace(UNSAFE_CHARS, \"_\");\n}\n\n/** Result of downloading a Discord attachment. */\nexport interface DownloadedAttachment {\n buffer: Buffer;\n filename: string;\n contentType: string;\n}\n\n/** Shape accepted by {@link downloadAttachment}. Compatible with discord.js `Attachment`. */\nexport interface DownloadableAttachment extends AttachmentLike {\n url: string;\n contentType?: string | null;\n}\n\n/**\n * Downloads a Discord message attachment to a raw buffer.\n * Validates size and sanitizes filename before returning.\n *\n * @throws Error if attachment exceeds {@link MAX_ATTACHMENT_BYTES}\n * @throws Error if the fetch response is not ok\n */\nexport async function downloadAttachment(\n attachment: DownloadableAttachment,\n): Promise<DownloadedAttachment> {\n validateAttachmentSize(attachment);\n\n const res = await fetch(attachment.url);\n if (!res.ok) {\n throw new Error(\n `Failed to download attachment: ${String(res.status)} ${res.statusText}`,\n );\n }\n\n const ab = await res.arrayBuffer();\n const buffer = Buffer.from(ab, 0, ab.byteLength);\n const filename = sanitizeAttachmentName(attachment);\n const contentType = attachment.contentType ?? \"application/octet-stream\";\n\n return { buffer, filename, contentType };\n}\n","import { Client } from \"discord.js\";\nimport type { OnboardingStep, OnboardingStepStatus, StepResult } from \"./types.js\";\nimport { Bot, DEFAULT_INTENTS, DEFAULT_PARTIALS } from \"./bot.js\";\n\nfunction toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\ntype StepAction = (...args: unknown[]) => Promise<StepResult>;\n\nclass OnboardingStepImpl implements OnboardingStep {\n id: string;\n label: string;\n instructions: string;\n status: OnboardingStepStatus;\n error?: string;\n nextSibling?: OnboardingStepImpl;\n\n private readonly _action: StepAction;\n private readonly _dependencies: OnboardingStepImpl[];\n\n constructor(\n id: string,\n label: string,\n instructions: string,\n action: StepAction,\n dependencies: OnboardingStepImpl[] = [],\n initialStatus: OnboardingStepStatus = \"pending\",\n ) {\n this.id = id;\n this.label = label;\n this.instructions = instructions;\n this._action = action;\n this._dependencies = dependencies;\n this.status = initialStatus;\n }\n\n async complete(...args: unknown[]): Promise<StepResult> {\n // Check dependencies\n for (const dep of this._dependencies) {\n if (dep.status !== \"completed\") {\n const error = `Cannot complete '${this.id}': dependency '${dep.id}' is not completed.`;\n this.status = \"failed\";\n this.error = error;\n return { success: false, error };\n }\n }\n\n try {\n const result = await this._action(...args);\n if (result.success) {\n this.status = \"completed\";\n this.error = undefined;\n // Promote next step to ready\n if (this.nextSibling?.status === \"pending\") {\n this.nextSibling.status = \"ready\";\n result.nextStep = this.nextSibling;\n }\n } else {\n this.status = \"failed\";\n this.error = result.error;\n }\n return result;\n } catch (err) {\n const message = toErrorMessage(err);\n this.status = \"failed\";\n this.error = message;\n return { success: false, error: message };\n }\n }\n}\n\nexport class BotOnboarding {\n readonly id: string;\n readonly name: string;\n readonly steps: OnboardingStep[];\n\n private _bot: Bot | undefined;\n private _token: string | undefined;\n\n constructor(id: string, name: string) {\n this.id = id;\n this.name = name;\n const provideToken = new OnboardingStepImpl(\n \"provide_token\",\n \"Provide Bot Token\",\n \"Enter your Discord bot token. You can find this in the Discord Developer Portal under your application's Bot settings.\",\n async (...args: unknown[]) => {\n const token = args[0] as string;\n const client = new Client({ intents: [...DEFAULT_INTENTS], partials: [...DEFAULT_PARTIALS] });\n try {\n await client.login(token);\n await client.destroy();\n this._token = token;\n return { success: true };\n } catch (err) {\n return { success: false, error: toErrorMessage(err) };\n }\n },\n [],\n \"ready\",\n );\n\n const inviteToServer = new OnboardingStepImpl(\n \"invite_to_server\",\n \"Invite Bot to Server\",\n \"Add the bot to at least one Discord server using the OAuth2 URL from the Developer Portal.\",\n async () => {\n if (!this._token) {\n return {\n success: false,\n error: \"Token not set — complete the provide_token step first.\",\n };\n }\n const client = new Client({ intents: [...DEFAULT_INTENTS], partials: [...DEFAULT_PARTIALS] });\n try {\n await client.login(this._token);\n if (client.guilds.cache.size === 0) {\n await client.destroy();\n return { success: false, error: \"Bot is not in any server yet\" };\n }\n await client.destroy();\n return { success: true };\n } catch (err) {\n return { success: false, error: toErrorMessage(err) };\n }\n },\n [provideToken],\n );\n\n const verifyPermissions = new OnboardingStepImpl(\n \"verify_permissions\",\n \"Verify Permissions\",\n \"Verify the bot has the required permissions in your server.\",\n async () => {\n if (!this._token) {\n return {\n success: false,\n error: \"Token not set — complete the provide_token step first.\",\n };\n }\n try {\n this._bot = await Bot.fromConfig({\n id: this.id,\n name: this.name,\n token: this._token,\n });\n return { success: true };\n } catch (err) {\n return { success: false, error: toErrorMessage(err) };\n }\n },\n [inviteToServer],\n );\n\n // Wire nextSibling chain for step promotion\n provideToken.nextSibling = inviteToServer;\n inviteToServer.nextSibling = verifyPermissions;\n\n this.steps = [provideToken, inviteToServer, verifyPermissions];\n }\n\n get bot(): Bot | undefined {\n return this._bot;\n }\n}\n","import { Bot } from \"./bot.js\";\nimport { BotOnboarding } from \"./onboarding.js\";\nimport type { MessageEvent } from \"./types.js\";\n\ntype LifecycleEvent = \"botReady\" | \"botDisconnected\" | \"botError\";\n\nexport class ConnectorManager {\n private botMap = new Map<string, Bot>();\n private mentionHandlers: ((event: MessageEvent, bot: Bot) => void)[] = [];\n private lifecycleHandlers = new Map<LifecycleEvent, ((...args: unknown[]) => void)[]>();\n\n addBot(bot: Bot): void {\n if (this.botMap.has(bot.id)) {\n throw new Error(`Bot with id \"${bot.id}\" already exists in this manager.`);\n }\n this.botMap.set(bot.id, bot);\n bot.onMention((event) => {\n for (const handler of this.mentionHandlers) {\n handler(event, bot);\n }\n });\n bot.on(\"error\", (error) => {\n this.emitLifecycle(\"botError\", bot, error);\n });\n }\n\n getBot(id: string): Bot | undefined {\n return this.botMap.get(id);\n }\n\n get bots(): Iterable<Bot> {\n return this.botMap.values();\n }\n\n removeBot(id: string): void {\n this.botMap.delete(id);\n }\n\n status(): { id: string; name: string; status: string }[] {\n return [...this.botMap.values()].map((bot) => ({\n id: bot.id,\n name: bot.name,\n status: bot.status,\n }));\n }\n\n onMention(callback: (event: MessageEvent, bot: Bot) => void): void {\n this.mentionHandlers.push(callback);\n }\n\n on(event: LifecycleEvent, callback: (...args: unknown[]) => void): void {\n const handlers = this.lifecycleHandlers.get(event) ?? [];\n handlers.push(callback);\n this.lifecycleHandlers.set(event, handlers);\n }\n\n private emitLifecycle(event: LifecycleEvent, ...args: unknown[]): void {\n const handlers = this.lifecycleHandlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n handler(...args);\n }\n }\n }\n\n onboardBot(id: string, name: string): BotOnboarding {\n return new BotOnboarding(id, name);\n }\n\n async disconnectAll(): Promise<void> {\n await Promise.all([...this.botMap.values()].map((bot) => bot.disconnect()));\n }\n\n async shutdown(): Promise<void> {\n await this.disconnectAll();\n }\n}\n"],"mappings":"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","names":["chunks","text","Client","Client"]}
|
|
1
|
+
{"version":3,"sources":["../src/bot.ts","../src/event-buffer.ts","../src/message-utils.ts","../src/attachment-utils.ts","../src/onboarding.ts","../src/connector-manager.ts"],"sourcesContent":["import { Client, ChannelType, GatewayIntentBits, Partials, Events, LimitedCollection, AttachmentBuilder, type Message } from \"discord.js\";\nimport { stat } from \"node:fs/promises\";\nimport type {\n BotConfig,\n BotStatus,\n FetchedMessage,\n FetchHistoryOptions,\n FileAttachment,\n MessageEvent,\n SentMessage,\n MessageContent,\n MessageFilter,\n} from \"./types.js\";\nimport { EventBuffer } from \"./event-buffer.js\";\nimport { chunkMessage } from \"./message-utils.js\";\nimport { validateAttachmentSize, type DownloadableAttachment } from \"./attachment-utils.js\";\n\nexport const DEFAULT_SENT_MESSAGE_CACHE_SIZE = 1000;\n\nexport const DEFAULT_INTENTS = [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.DirectMessages,\n] as const;\n\nexport const DEFAULT_PARTIALS = [Partials.Channel, Partials.Message] as const;\n\ntype MessageHandler = (event: MessageEvent) => void;\ntype ErrorHandler = (error: Error) => void;\n\nexport class Bot {\n readonly id: string;\n readonly name: string;\n\n private _status: BotStatus;\n private readonly client: Client;\n private readonly sentMessages: LimitedCollection<string, SentMessage>;\n private _connectedAt: Date | null = null;\n private readonly messageHandlers: MessageHandler[] = [];\n private readonly errorHandlers: ErrorHandler[] = [];\n private readonly _includeBotMessages: boolean;\n\n private constructor(\n id: string,\n name: string,\n client: Client,\n sentMessageCacheSize: number,\n includeBotMessages: boolean,\n ) {\n this.id = id;\n this.name = name;\n this.client = client;\n this.sentMessages = new LimitedCollection({ maxSize: sentMessageCacheSize });\n this._includeBotMessages = includeBotMessages;\n this._status = \"connecting\";\n }\n\n get includeBotMessages(): boolean {\n return this._includeBotMessages;\n }\n\n get status(): BotStatus {\n return this._status;\n }\n\n get guildCount(): number {\n return this.client.guilds.cache.size;\n }\n\n get connectedAt(): Date | null {\n return this._connectedAt;\n }\n\n /**\n * Fast path: create a bot from a complete config, connect, verify, and\n * return a ready Bot — or throw with diagnostics.\n */\n static async fromConfig(config: BotConfig): Promise<Bot> {\n const cacheSize = config.sentMessageCacheSize ?? DEFAULT_SENT_MESSAGE_CACHE_SIZE;\n if (cacheSize < 1 || !Number.isInteger(cacheSize)) {\n throw new Error(\n `sentMessageCacheSize must be a positive integer, got ${String(cacheSize)}`,\n );\n }\n\n const includeBotMessages = config.includeBotMessages ?? false;\n\n const client = new Client({\n intents: config.intents ?? [...DEFAULT_INTENTS],\n partials: config.partials ?? [...DEFAULT_PARTIALS],\n });\n\n const bot = new Bot(config.id, config.name, client, cacheSize, includeBotMessages);\n\n await bot.connect(config.token);\n bot.verify();\n bot.setupEventHandlers();\n bot._status = \"ready\";\n bot._connectedAt = new Date();\n\n return bot;\n }\n\n // --- Sending ---\n\n async send(channelId: string, content: MessageContent): Promise<SentMessage[]> {\n const channel = await this.fetchTextChannel(channelId);\n if (!(\"send\" in channel)) {\n throw new Error(`Channel ${channelId} is not a sendable channel`);\n }\n return this.sendPayloads(content, (payload) =>\n (channel as unknown as { send(opts: unknown): Promise<Message> }).send(payload),\n );\n }\n\n async sendDM(userId: string, content: MessageContent): Promise<SentMessage[]> {\n const user = await this.client.users.fetch(userId);\n return this.sendPayloads(content, (payload) =>\n user.send(payload as Parameters<typeof user.send>[0]),\n );\n }\n\n async reply(channelId: string, messageId: string, content: MessageContent): Promise<SentMessage[]> {\n const { channel, message } = await this.fetchMessage(channelId, messageId, \"reply to\");\n if (!(\"send\" in channel)) {\n throw new Error(`Channel ${channelId} is not a sendable channel`);\n }\n return this.sendPayloads(content, (payload, i) => {\n if (i === 0) {\n return message.reply(payload as Parameters<Message[\"reply\"]>[0]);\n }\n return (channel as unknown as { send(opts: unknown): Promise<Message> }).send(payload);\n });\n }\n\n // --- Channel operations ---\n\n async react(channelId: string, messageId: string, emoji: string): Promise<void> {\n const { message } = await this.fetchMessage(channelId, messageId, \"react to\");\n try {\n await message.react(emoji);\n } catch (error) {\n throw new Error(\n `Cannot react to message ${messageId}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async editMessage(channelId: string, messageId: string, content: string): Promise<void> {\n const { message } = await this.fetchMessage(channelId, messageId, \"edit\");\n try {\n await message.edit(content);\n } catch (error) {\n throw new Error(\n `Cannot edit message ${messageId}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async fetchMessages(channelId: string, limit?: number): Promise<FetchedMessage[]> {\n const channel = await this.fetchTextChannel(channelId);\n const clamped = Math.max(1, Math.min(limit ?? 20, 100));\n const messages = await channel.messages.fetch({ limit: clamped });\n return [...messages.values()].reverse().map((m) => this.toFetchedMessage(m));\n }\n\n async *fetchHistory(\n channelId: string,\n options: FetchHistoryOptions,\n ): AsyncGenerator<FetchedMessage[]> {\n const { after, before, limit = 500 } = options;\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard for JS consumers\n if (after && before) {\n throw new Error('Cannot specify both \"after\" and \"before\"');\n }\n\n let cursor: string;\n let direction: \"after\" | \"before\";\n if (after) {\n cursor = after;\n direction = \"after\";\n } else if (before) {\n cursor = before;\n direction = \"before\";\n } else {\n throw new Error('At least one of \"after\" or \"before\" must be specified');\n }\n\n const effectiveLimit = Math.min(limit, 5000);\n const channel = await this.fetchTextChannel(channelId);\n\n let totalFetched = 0;\n\n while (totalFetched < effectiveLimit) {\n const pageSize = Math.min(100, effectiveLimit - totalFetched);\n\n const fetched = await this.fetchPageWithRetry(channel, {\n limit: pageSize,\n [direction]: cursor,\n });\n\n if (fetched.size === 0) break;\n\n const rawMessages = [...fetched.values()];\n const messages = rawMessages.map((m) => this.toFetchedMessage(m));\n\n yield messages;\n totalFetched += messages.length;\n\n const lastMessage = rawMessages.at(-1);\n if (!lastMessage) break;\n cursor = lastMessage.id;\n\n if (fetched.size < pageSize) break;\n }\n }\n\n async getMessageAttachments(\n channelId: string,\n messageId: string,\n ): Promise<DownloadableAttachment[]> {\n const { message } = await this.fetchMessage(channelId, messageId, \"fetch attachments for\");\n return [...message.attachments.values()].map((att) => ({\n id: att.id,\n size: att.size,\n name: att.name,\n url: att.url,\n contentType: att.contentType,\n }));\n }\n\n // --- Receiving (event-driven) ---\n\n onMessage(handler: MessageHandler): () => void {\n this.messageHandlers.push(handler);\n let removed = false;\n return () => {\n if (removed) return;\n removed = true;\n const index = this.messageHandlers.indexOf(handler);\n if (index !== -1) this.messageHandlers.splice(index, 1);\n };\n }\n\n // --- Receiving (async iterable) ---\n\n messages(options?: { filter?: MessageFilter }): AsyncIterable<MessageEvent> {\n let unsubscribe: (() => void) | undefined;\n const buffer = new EventBuffer<MessageEvent>({\n onClose: () => unsubscribe?.(),\n });\n unsubscribe = this.onMessage((event) => {\n if (options?.filter && !options.filter(event)) return;\n buffer.push(event);\n });\n return buffer;\n }\n\n // --- Error handling ---\n\n on(_event: \"error\", handler: ErrorHandler): () => void {\n this.errorHandlers.push(handler);\n let removed = false;\n return () => {\n if (removed) return;\n removed = true;\n const index = this.errorHandlers.indexOf(handler);\n if (index !== -1) this.errorHandlers.splice(index, 1);\n };\n }\n\n private emitError(error: unknown): void {\n const err = error instanceof Error ? error : new Error(String(error));\n for (const handler of this.errorHandlers) {\n handler(err);\n }\n }\n\n // --- Lifecycle ---\n\n async disconnect(): Promise<void> {\n this.client.removeAllListeners();\n await this.client.destroy();\n this.messageHandlers.length = 0;\n this.errorHandlers.length = 0;\n this._status = \"disconnected\";\n this._connectedAt = null;\n }\n\n // --- Private ---\n\n private async fetchTextChannel(channelId: string) {\n const channel = await this.client.channels.fetch(channelId);\n if (!channel?.isTextBased()) {\n throw new Error(\n `Channel ${channelId} is not a text-based channel or does not exist`,\n );\n }\n return channel;\n }\n\n private async fetchMessage(\n channelId: string,\n messageId: string,\n verb: string,\n ): Promise<{ channel: Awaited<ReturnType<Bot[\"fetchTextChannel\"]>>; message: Message }> {\n const channel = await this.fetchTextChannel(channelId);\n try {\n const message = await channel.messages.fetch(messageId);\n return { channel, message };\n } catch (error) {\n throw new Error(\n `Cannot ${verb} message ${messageId}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n private toFetchedMessage(msg: Message): FetchedMessage {\n return {\n messageId: msg.id,\n channelId: msg.channelId,\n author: {\n id: msg.author.id,\n username: msg.author.username,\n bot: msg.author.bot,\n },\n content: msg.content,\n timestamp: msg.createdAt,\n attachmentCount: msg.attachments.size,\n };\n }\n\n private async fetchPageWithRetry(\n channel: { messages: { fetch(opts: unknown): Promise<Map<string, Message>> } },\n options: Record<string, unknown>,\n maxRetryMs = 5000,\n ): Promise<Map<string, Message>> {\n try {\n return await channel.messages.fetch(options);\n } catch (err) {\n if (err instanceof Error && \"retryAfter\" in err) {\n const { retryAfter } = err;\n if (typeof retryAfter === \"number\" && retryAfter <= maxRetryMs) {\n await new Promise((resolve) => setTimeout(resolve, retryAfter));\n return channel.messages.fetch(options);\n }\n }\n throw err;\n }\n }\n\n private async connect(token: string): Promise<void> {\n this._status = \"connecting\";\n await this.client.login(token);\n }\n\n private verify(): void {\n this._status = \"verifying\";\n\n if (this.client.guilds.cache.size === 0) {\n this._status = \"failed\";\n throw new Error(\n \"Bot is not in any guild. Invite the bot to at least one server before connecting.\",\n );\n }\n }\n\n private setupEventHandlers(): void {\n this.client.on(Events.MessageCreate, (message: Message) => {\n try {\n // Always ignore own messages (prevent infinite loops)\n if (message.author.id === this.client.user?.id) return;\n // Ignore other bots unless opted in\n if (message.author.bot && !this._includeBotMessages) return;\n\n const event = this.toMessageEvent(message);\n\n for (const handler of this.messageHandlers) {\n handler(event);\n }\n } catch (error) {\n this.emitError(error);\n }\n });\n }\n\n private toMessageEvent(message: Message): MessageEvent {\n const isDM = message.channel.type === ChannelType.DM;\n const botUser = this.client.user;\n const isMention = isDM || (botUser ? message.mentions.has(botUser.id) : false);\n\n let isReply = false;\n let replyTo: SentMessage | null = null;\n if (message.reference?.messageId) {\n const original = this.sentMessages.get(message.reference.messageId);\n if (original) {\n isReply = true;\n replyTo = original;\n }\n }\n\n return {\n messageId: message.id,\n author: {\n id: message.author.id,\n username: message.author.username,\n bot: message.author.bot,\n },\n content: message.content,\n channelId: message.channelId,\n guildId: message.guildId ?? null,\n timestamp: message.createdAt,\n mentions: [...message.mentions.users.keys()],\n raw: message,\n isDM,\n isMention,\n isReply,\n replyTo,\n };\n }\n\n private async sendPayloads(\n content: MessageContent,\n dispatcher: (payload: ChunkedPayload, index: number) => Promise<Message>,\n ): Promise<SentMessage[]> {\n const files =\n typeof content !== \"string\" && content.files?.length\n ? await validateAndBuildAttachments(content.files)\n : undefined;\n const payloads = toChunkedPayloads(content, files);\n const results: SentMessage[] = [];\n let i = 0;\n for (const payload of payloads) {\n const msg = await dispatcher(payload, i++);\n results.push(this.trackSentMessage(msg));\n }\n return results;\n }\n\n private trackSentMessage(message: Message): SentMessage {\n const sent: SentMessage = {\n messageId: message.id,\n channelId: message.channelId,\n timestamp: message.createdAt,\n raw: message,\n };\n this.sentMessages.set(sent.messageId, sent);\n return sent;\n }\n}\n\ninterface ChunkedPayload {\n content?: string;\n embeds?: unknown[];\n files?: AttachmentBuilder[];\n}\n\nfunction toChunkedPayloads(\n content: MessageContent,\n files?: AttachmentBuilder[],\n): ChunkedPayload[] {\n if (typeof content === \"string\") {\n const chunks = chunkMessage(content);\n return chunks.map((text, i) => ({\n content: text,\n ...(i === 0 && files?.length ? { files } : {}),\n }));\n }\n const text = content.content ?? \"\";\n const chunks = chunkMessage(text);\n if (chunks.length === 0) {\n return [{ embeds: content.embeds, ...(files?.length ? { files } : {}) }];\n }\n return chunks.map((chunk, i) => ({\n content: chunk,\n ...(i === 0 && content.embeds ? { embeds: content.embeds } : {}),\n ...(i === 0 && files?.length ? { files } : {}),\n }));\n}\n\nconst MAX_FILES_PER_MESSAGE = 10;\n\nasync function validateAndBuildAttachments(\n files: FileAttachment[],\n): Promise<AttachmentBuilder[]> {\n if (files.length > MAX_FILES_PER_MESSAGE) {\n throw new Error(\n `Too many attachments: ${String(files.length)} exceeds Discord's limit of ${String(MAX_FILES_PER_MESSAGE)} attachments per message`,\n );\n }\n\n const sizes = await Promise.all(\n files.map((file) =>\n typeof file.data === \"string\"\n ? stat(file.data).then((st) => st.size)\n : Promise.resolve(file.data.byteLength),\n ),\n );\n\n return files.map((file, i) => {\n const size = sizes[i];\n if (size === undefined) throw new Error(`Missing size for attachment: ${file.name}`);\n validateAttachmentSize({ size, name: file.name, id: file.name });\n return new AttachmentBuilder(file.data, { name: file.name });\n });\n}\n","/**\n * Single-consumer async iterable buffer. Each call to messages() on a Bot\n * creates its own buffer. Do not share a single EventBuffer between\n * multiple for-await consumers.\n */\nexport class EventBuffer<T> implements AsyncIterable<T> {\n private buffer: T[] = [];\n private resolve: ((value: IteratorResult<T>) => void) | null = null;\n private closed = false;\n private readonly onClose: (() => void) | undefined;\n\n constructor(options?: { onClose?: () => void }) {\n this.onClose = options?.onClose;\n }\n\n push(value: T): void {\n if (this.closed) return;\n if (this.resolve) {\n const r = this.resolve;\n this.resolve = null;\n r({ value, done: false });\n } else {\n this.buffer.push(value);\n }\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.onClose?.();\n if (this.resolve) {\n const r = this.resolve;\n this.resolve = null;\n r({ value: undefined as unknown as T, done: true });\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return {\n next: (): Promise<IteratorResult<T>> => {\n if (this.buffer.length > 0) {\n // Length check guarantees shift() returns a value\n const value = this.buffer.shift() as T;\n return Promise.resolve({ value, done: false });\n }\n if (this.closed) {\n return Promise.resolve({\n value: undefined as unknown as T,\n done: true,\n });\n }\n return new Promise((resolve) => {\n this.resolve = resolve;\n });\n },\n return: (): Promise<IteratorResult<T>> => {\n this.close();\n return Promise.resolve({ value: undefined as unknown as T, done: true });\n },\n };\n }\n}\n","// Message utility functions for discord-bot-lib\n\n/** Discord's hard limit on message length. */\nexport const DISCORD_MAX_MESSAGE_LENGTH = 2000;\n\n/**\n * Splits text into chunks that fit within Discord's message length limit.\n * Prefers splitting at paragraph boundaries (\\n\\n), then line breaks (\\n),\n * then spaces, then hard-cuts as a last resort.\n *\n * @param text - The text to split\n * @param limit - Maximum characters per chunk (default: {@link DISCORD_MAX_MESSAGE_LENGTH})\n * @returns Array of text chunks, each within the limit\n */\nexport function chunkMessage(\n text: string,\n limit: number = DISCORD_MAX_MESSAGE_LENGTH,\n): string[] {\n if (!text) return [];\n if (text.length <= limit) return [text];\n\n const chunks: string[] = [];\n const halfLimit = limit / 2;\n let rest = text;\n\n while (rest.length > limit) {\n const para = rest.lastIndexOf(\"\\n\\n\", limit);\n const line = rest.lastIndexOf(\"\\n\", limit);\n const space = rest.lastIndexOf(\" \", limit);\n const cut =\n para > halfLimit\n ? para\n : line > halfLimit\n ? line\n : space > 0\n ? space\n : limit;\n\n chunks.push(rest.slice(0, cut));\n rest = rest.slice(cut).replace(/^\\n+/, \"\");\n }\n\n if (rest) chunks.push(rest);\n\n return chunks;\n}\n","// Attachment utility functions for discord-bot-lib\n\n/** Maximum attachment size in bytes (25 MB). Matches Discord's default file size limit. */\nexport const MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024; // 26_214_400\n\n/** Shape compatible with discord.js Attachment for attachment utilities. */\nexport interface AttachmentLike {\n size: number;\n name?: string | null;\n id: string;\n}\n\n/**\n * Validates that an attachment does not exceed Discord's size limit.\n * Designed for use in both upload (sending files) and download paths.\n *\n * @throws Error if the attachment exceeds {@link MAX_ATTACHMENT_BYTES}\n */\nexport function validateAttachmentSize(attachment: AttachmentLike): void {\n if (attachment.size > MAX_ATTACHMENT_BYTES) {\n const actualMB = (attachment.size / 1024 / 1024).toFixed(1);\n const limitMB = MAX_ATTACHMENT_BYTES / 1024 / 1024;\n const nameInfo = attachment.name ? `: ${attachment.name}` : \"\";\n throw new Error(\n `Attachment too large (${actualMB} MB > ${String(limitMB)} MB limit)${nameInfo}`,\n );\n }\n}\n\n/**\n * Sanitizes an attachment filename by replacing unsafe characters\n * (`[`, `]`, `\\r`, `\\n`, `;`) with underscores. Falls back to the\n * attachment ID when the name is missing or empty after sanitization.\n */\nconst UNSAFE_CHARS = /[[\\]\\r\\n;]/g;\n\nexport function sanitizeAttachmentName(\n attachment: Pick<AttachmentLike, \"name\" | \"id\">,\n): string {\n const raw = attachment.name;\n if (!raw || raw.replace(UNSAFE_CHARS, \"\").length === 0) {\n return attachment.id;\n }\n return raw.replace(UNSAFE_CHARS, \"_\");\n}\n\n/** Result of downloading a Discord attachment. */\nexport interface DownloadedAttachment {\n buffer: Buffer;\n filename: string;\n contentType: string;\n}\n\n/** Shape accepted by {@link downloadAttachment}. Compatible with discord.js `Attachment`. */\nexport interface DownloadableAttachment extends AttachmentLike {\n url: string;\n contentType?: string | null;\n}\n\n/**\n * Downloads a Discord message attachment to a raw buffer.\n * Validates size and sanitizes filename before returning.\n *\n * @throws Error if attachment exceeds {@link MAX_ATTACHMENT_BYTES}\n * @throws Error if the fetch response is not ok\n */\nexport async function downloadAttachment(\n attachment: DownloadableAttachment,\n): Promise<DownloadedAttachment> {\n validateAttachmentSize(attachment);\n\n const res = await fetch(attachment.url);\n if (!res.ok) {\n throw new Error(\n `Failed to download attachment: ${String(res.status)} ${res.statusText}`,\n );\n }\n\n const ab = await res.arrayBuffer();\n const buffer = Buffer.from(ab, 0, ab.byteLength);\n const filename = sanitizeAttachmentName(attachment);\n const contentType = attachment.contentType ?? \"application/octet-stream\";\n\n return { buffer, filename, contentType };\n}\n","import { Client } from \"discord.js\";\nimport type { OnboardingStep, OnboardingStepStatus, StepResult } from \"./types.js\";\nimport { Bot, DEFAULT_INTENTS, DEFAULT_PARTIALS } from \"./bot.js\";\n\nfunction toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\ntype StepAction = (...args: unknown[]) => Promise<StepResult>;\n\nclass OnboardingStepImpl implements OnboardingStep {\n id: string;\n label: string;\n instructions: string;\n status: OnboardingStepStatus;\n error?: string;\n nextSibling?: OnboardingStepImpl;\n\n private readonly _action: StepAction;\n private readonly _dependencies: OnboardingStepImpl[];\n\n constructor(\n id: string,\n label: string,\n instructions: string,\n action: StepAction,\n dependencies: OnboardingStepImpl[] = [],\n initialStatus: OnboardingStepStatus = \"pending\",\n ) {\n this.id = id;\n this.label = label;\n this.instructions = instructions;\n this._action = action;\n this._dependencies = dependencies;\n this.status = initialStatus;\n }\n\n async complete(...args: unknown[]): Promise<StepResult> {\n // Check dependencies\n for (const dep of this._dependencies) {\n if (dep.status !== \"completed\") {\n const error = `Cannot complete '${this.id}': dependency '${dep.id}' is not completed.`;\n this.status = \"failed\";\n this.error = error;\n return { success: false, error };\n }\n }\n\n try {\n const result = await this._action(...args);\n if (result.success) {\n this.status = \"completed\";\n this.error = undefined;\n // Promote next step to ready\n if (this.nextSibling?.status === \"pending\") {\n this.nextSibling.status = \"ready\";\n result.nextStep = this.nextSibling;\n }\n } else {\n this.status = \"failed\";\n this.error = result.error;\n }\n return result;\n } catch (err) {\n const message = toErrorMessage(err);\n this.status = \"failed\";\n this.error = message;\n return { success: false, error: message };\n }\n }\n}\n\nexport class BotOnboarding {\n readonly id: string;\n readonly name: string;\n readonly steps: OnboardingStep[];\n\n private _bot: Bot | undefined;\n private _token: string | undefined;\n\n constructor(id: string, name: string) {\n this.id = id;\n this.name = name;\n const provideToken = new OnboardingStepImpl(\n \"provide_token\",\n \"Provide Bot Token\",\n \"Enter your Discord bot token. You can find this in the Discord Developer Portal under your application's Bot settings.\",\n async (...args: unknown[]) => {\n const token = args[0] as string;\n const client = new Client({ intents: [...DEFAULT_INTENTS], partials: [...DEFAULT_PARTIALS] });\n try {\n await client.login(token);\n await client.destroy();\n this._token = token;\n return { success: true };\n } catch (err) {\n return { success: false, error: toErrorMessage(err) };\n }\n },\n [],\n \"ready\",\n );\n\n const inviteToServer = new OnboardingStepImpl(\n \"invite_to_server\",\n \"Invite Bot to Server\",\n \"Add the bot to at least one Discord server using the OAuth2 URL from the Developer Portal.\",\n async () => {\n if (!this._token) {\n return {\n success: false,\n error: \"Token not set — complete the provide_token step first.\",\n };\n }\n const client = new Client({ intents: [...DEFAULT_INTENTS], partials: [...DEFAULT_PARTIALS] });\n try {\n await client.login(this._token);\n if (client.guilds.cache.size === 0) {\n await client.destroy();\n return { success: false, error: \"Bot is not in any server yet\" };\n }\n await client.destroy();\n return { success: true };\n } catch (err) {\n return { success: false, error: toErrorMessage(err) };\n }\n },\n [provideToken],\n );\n\n const verifyPermissions = new OnboardingStepImpl(\n \"verify_permissions\",\n \"Verify Permissions\",\n \"Verify the bot has the required permissions in your server.\",\n async () => {\n if (!this._token) {\n return {\n success: false,\n error: \"Token not set — complete the provide_token step first.\",\n };\n }\n try {\n this._bot = await Bot.fromConfig({\n id: this.id,\n name: this.name,\n token: this._token,\n });\n return { success: true };\n } catch (err) {\n return { success: false, error: toErrorMessage(err) };\n }\n },\n [inviteToServer],\n );\n\n // Wire nextSibling chain for step promotion\n provideToken.nextSibling = inviteToServer;\n inviteToServer.nextSibling = verifyPermissions;\n\n this.steps = [provideToken, inviteToServer, verifyPermissions];\n }\n\n get bot(): Bot | undefined {\n return this._bot;\n }\n}\n","import { Bot } from \"./bot.js\";\nimport { BotOnboarding } from \"./onboarding.js\";\nimport type { MessageEvent } from \"./types.js\";\n\ntype LifecycleEvent = \"botReady\" | \"botDisconnected\" | \"botError\";\n\nexport class ConnectorManager {\n private botMap = new Map<string, Bot>();\n private botUnsubscribers = new Map<string, (() => void)[]>();\n private messageHandlers: ((event: MessageEvent, bot: Bot) => void)[] = [];\n private lifecycleHandlers = new Map<LifecycleEvent, ((...args: unknown[]) => void)[]>();\n\n addBot(bot: Bot): void {\n if (this.botMap.has(bot.id)) {\n throw new Error(`Bot with id \"${bot.id}\" already exists in this manager.`);\n }\n this.botMap.set(bot.id, bot);\n\n const unsubs: (() => void)[] = [];\n unsubs.push(\n bot.onMessage((event) => {\n for (const handler of this.messageHandlers) {\n handler(event, bot);\n }\n }),\n );\n unsubs.push(\n bot.on(\"error\", (error) => {\n this.emitLifecycle(\"botError\", bot, error);\n }),\n );\n this.botUnsubscribers.set(bot.id, unsubs);\n }\n\n getBot(id: string): Bot | undefined {\n return this.botMap.get(id);\n }\n\n get bots(): Iterable<Bot> {\n return this.botMap.values();\n }\n\n removeBot(id: string): void {\n const unsubs = this.botUnsubscribers.get(id);\n if (unsubs) {\n for (const unsub of unsubs) unsub();\n this.botUnsubscribers.delete(id);\n }\n this.botMap.delete(id);\n }\n\n status(): { id: string; name: string; status: string }[] {\n return [...this.botMap.values()].map((bot) => ({\n id: bot.id,\n name: bot.name,\n status: bot.status,\n }));\n }\n\n onMessage(handler: (event: MessageEvent, bot: Bot) => void): void {\n this.messageHandlers.push(handler);\n }\n\n on(event: LifecycleEvent, callback: (...args: unknown[]) => void): void {\n const handlers = this.lifecycleHandlers.get(event) ?? [];\n handlers.push(callback);\n this.lifecycleHandlers.set(event, handlers);\n }\n\n private emitLifecycle(event: LifecycleEvent, ...args: unknown[]): void {\n const handlers = this.lifecycleHandlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n handler(...args);\n }\n }\n }\n\n onboardBot(id: string, name: string): BotOnboarding {\n return new BotOnboarding(id, name);\n }\n\n async disconnectAll(): Promise<void> {\n await Promise.all([...this.botMap.values()].map((bot) => bot.disconnect()));\n }\n\n async shutdown(): Promise<void> {\n await this.disconnectAll();\n }\n}\n"],"mappings":"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","names":["chunks","text","Client","Client"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scotthamilton77/discord-bot-lib",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "TypeScript library for managing Discord bot identities, messaging, and multi-bot coordination",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -52,13 +52,8 @@
|
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=20"
|
|
54
54
|
},
|
|
55
|
-
"pnpm": {
|
|
56
|
-
"overrides": {
|
|
57
|
-
"undici": "^6.24.0"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
55
|
"dependencies": {
|
|
61
|
-
"discord.js": "^14.
|
|
56
|
+
"discord.js": "^14.26.2"
|
|
62
57
|
},
|
|
63
58
|
"devDependencies": {
|
|
64
59
|
"@eslint/js": "^9.39.4",
|