@hardlydifficult/chat 1.1.27 → 1.1.29

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.
Files changed (63) hide show
  1. package/README.md +74 -6
  2. package/dist/BatchStore.d.ts +39 -0
  3. package/dist/BatchStore.d.ts.map +1 -0
  4. package/dist/BatchStore.js +105 -0
  5. package/dist/BatchStore.js.map +1 -0
  6. package/dist/Channel.d.ts +51 -4
  7. package/dist/Channel.d.ts.map +1 -1
  8. package/dist/Channel.js +105 -48
  9. package/dist/Channel.js.map +1 -1
  10. package/dist/ChannelBatchHelpers.d.ts +38 -0
  11. package/dist/ChannelBatchHelpers.d.ts.map +1 -0
  12. package/dist/ChannelBatchHelpers.js +106 -0
  13. package/dist/ChannelBatchHelpers.js.map +1 -0
  14. package/dist/ChannelRuntimeFeatures.d.ts +16 -0
  15. package/dist/ChannelRuntimeFeatures.d.ts.map +1 -0
  16. package/dist/ChannelRuntimeFeatures.js +72 -0
  17. package/dist/ChannelRuntimeFeatures.js.map +1 -0
  18. package/dist/ChatClient.d.ts +7 -1
  19. package/dist/ChatClient.d.ts.map +1 -1
  20. package/dist/ChatClient.js +8 -0
  21. package/dist/ChatClient.js.map +1 -1
  22. package/dist/Message.d.ts +3 -3
  23. package/dist/Message.d.ts.map +1 -1
  24. package/dist/Message.js +2 -2
  25. package/dist/Message.js.map +1 -1
  26. package/dist/MessageBatch.d.ts +62 -0
  27. package/dist/MessageBatch.d.ts.map +1 -0
  28. package/dist/MessageBatch.js +129 -0
  29. package/dist/MessageBatch.js.map +1 -0
  30. package/dist/discord/DiscordChatClient.d.ts +3 -2
  31. package/dist/discord/DiscordChatClient.d.ts.map +1 -1
  32. package/dist/discord/DiscordChatClient.js +18 -2
  33. package/dist/discord/DiscordChatClient.js.map +1 -1
  34. package/dist/discord/getMessages.d.ts +7 -0
  35. package/dist/discord/getMessages.d.ts.map +1 -0
  36. package/dist/discord/getMessages.js +87 -0
  37. package/dist/discord/getMessages.js.map +1 -0
  38. package/dist/index.d.ts +2 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +3 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/memberMatching.d.ts +11 -0
  43. package/dist/memberMatching.d.ts.map +1 -0
  44. package/dist/memberMatching.js +114 -0
  45. package/dist/memberMatching.js.map +1 -0
  46. package/dist/slack/SlackChatClient.d.ts +5 -2
  47. package/dist/slack/SlackChatClient.d.ts.map +1 -1
  48. package/dist/slack/SlackChatClient.js +29 -2
  49. package/dist/slack/SlackChatClient.js.map +1 -1
  50. package/dist/slack/fetchChannelMembers.d.ts.map +1 -1
  51. package/dist/slack/fetchChannelMembers.js +3 -0
  52. package/dist/slack/fetchChannelMembers.js.map +1 -1
  53. package/dist/slack/getMessages.d.ts +12 -0
  54. package/dist/slack/getMessages.d.ts.map +1 -0
  55. package/dist/slack/getMessages.js +148 -0
  56. package/dist/slack/getMessages.js.map +1 -0
  57. package/dist/slack/messageOperations.d.ts +2 -2
  58. package/dist/slack/messageOperations.d.ts.map +1 -1
  59. package/dist/slack/messageOperations.js +16 -14
  60. package/dist/slack/messageOperations.js.map +1 -1
  61. package/dist/types.d.ts +79 -0
  62. package/dist/types.d.ts.map +1 -1
  63. package/package.json +3 -3
package/README.md CHANGED
@@ -15,6 +15,7 @@ import { createChatClient } from "@hardlydifficult/chat";
15
15
 
16
16
  const client = createChatClient({ type: "discord" });
17
17
  const channel = await client.connect(channelId);
18
+ console.log(client.me?.mention); // "<@123...>"
18
19
 
19
20
  // Post messages
20
21
  await channel.postMessage("Hello!");
@@ -37,6 +38,19 @@ createChatClient({ type: "slack" });
37
38
  createChatClient({ type: "slack", token: "...", appToken: "..." });
38
39
  ```
39
40
 
41
+ ## Bot Identity
42
+
43
+ After `connect()`, `client.me` exposes the authenticated bot user:
44
+
45
+ ```typescript
46
+ const client = createChatClient({ type: "slack" });
47
+ await client.connect(channelId);
48
+
49
+ console.log(client.me?.id); // "U09B00R2R96"
50
+ console.log(client.me?.username); // "sprint-bot"
51
+ console.log(client.me?.mention); // "<@U09B00R2R96>"
52
+ ```
53
+
40
54
  ## Incoming Messages
41
55
 
42
56
  Subscribe to new messages in a channel. The callback receives a full `Message` object — you can delete it, react to it, or reply in its thread.
@@ -110,6 +124,7 @@ const msg = await channel.postMessage("Hello");
110
124
  await msg.update("Updated content");
111
125
  msg.reply("Thread reply");
112
126
  await msg.delete();
127
+ await msg.delete({ cascadeReplies: false }); // keep thread replies
113
128
  ```
114
129
 
115
130
  ### Reactions
@@ -177,6 +192,48 @@ if (postedAt !== undefined) {
177
192
 
178
193
  `post()` is fire-and-forget. `edit()` handles the race where the edit arrives before the original post completes — it chains on the stored promise.
179
194
 
195
+ ### Message Batches
196
+
197
+ Group related posted messages so they can be retrieved and cleaned up together.
198
+
199
+ ```typescript
200
+ const batch = await channel.beginBatch({ key: "sprint-update" });
201
+
202
+ for (const member of members) {
203
+ const msg = await batch.post(summary(member));
204
+ await msg.reply(detail(member));
205
+ }
206
+
207
+ await batch.post(callouts);
208
+ await batch.finish();
209
+
210
+ const recent = await channel.getBatches({
211
+ key: "sprint-update",
212
+ author: "me",
213
+ limit: 5,
214
+ });
215
+
216
+ await recent[0].deleteAll({ cascadeReplies: true });
217
+ ```
218
+
219
+ For safer lifecycle handling, use `withBatch` (auto-finishes in `finally`):
220
+
221
+ ```typescript
222
+ await channel.withBatch({ key: "sprint-update" }, async (batch) => {
223
+ await batch.post("Part 1");
224
+ await batch.post("Part 2");
225
+ });
226
+ ```
227
+
228
+ `MessageBatch` includes:
229
+
230
+ - `id`, `key`, `author`, `createdAt`, `closedAt`, `isFinished`
231
+ - `messages` (tracked message refs)
232
+ - `post(content, options?)`
233
+ - `deleteAll(options?)`
234
+ - `keepLatest(n, options?)`
235
+ - `finish()`
236
+
180
237
  ### Threads
181
238
 
182
239
  Create a thread, post messages, and listen for replies. The `Thread` object is the primary interface — all threading internals are hidden.
@@ -267,17 +324,21 @@ console.log(stream.content); // "working...\n" — only pre-abort text
267
324
 
268
325
  ## Mentions
269
326
 
270
- Get channel members and @mention them in messages.
327
+ Resolve fuzzy member queries directly to mention strings.
328
+
329
+ ```typescript
330
+ const mention = await channel.resolveMention("Nick Mancuso");
331
+ await channel.postMessage(`Hey ${mention ?? "@nick"}, check this out!`);
332
+ ```
333
+
334
+ You can still inspect members directly:
271
335
 
272
336
  ```typescript
273
337
  const members = await channel.getMembers();
274
- const user = members.find((m) => m.username === "alice");
275
- if (user) {
276
- await channel.postMessage(`Hey ${user.mention}, check this out!`);
277
- }
338
+ const member = await channel.findMember("@alice");
278
339
  ```
279
340
 
280
- Each `Member` has `id`, `username`, `displayName`, and `mention` (a ready-to-use `<@USER_ID>` string that renders as a clickable @mention on both platforms).
341
+ Each `Member` has `id`, `username`, `displayName`, `mention`, and (when available) `email`.
281
342
 
282
343
  ## Typing Indicator
283
344
 
@@ -307,6 +368,13 @@ Delete messages and manage threads in bulk.
307
368
  // Delete up to 100 recent messages
308
369
  const deletedCount = await channel.bulkDelete(50);
309
370
 
371
+ // List and filter recent messages
372
+ const botMessages = await channel.getMessages({ limit: 50, author: "me" });
373
+ const sameMessages = await channel.getRecentBotMessages(50);
374
+
375
+ // Keep latest 8 bot messages, delete older ones (opinionated cleanup helper)
376
+ await channel.pruneMessages({ author: "me", limit: 50, keep: 8 });
377
+
310
378
  // Get all threads (active and archived) and delete them
311
379
  const threads = await channel.getThreads();
312
380
  for (const thread of threads) {
@@ -0,0 +1,39 @@
1
+ import type { BatchQueryOptions, MessageAuthorFilter, Platform } from "./types.js";
2
+ export interface BatchMessageRefRecord {
3
+ id: string;
4
+ channelId: string;
5
+ platform: Platform;
6
+ postedAt: number;
7
+ }
8
+ export interface BatchRecord {
9
+ id: string;
10
+ key?: string;
11
+ author: MessageAuthorFilter;
12
+ channelId: string;
13
+ platform: Platform;
14
+ createdAt: number;
15
+ closedAt?: number;
16
+ messages: BatchMessageRefRecord[];
17
+ }
18
+ interface BeginBatchRecordOptions {
19
+ key?: string;
20
+ author?: MessageAuthorFilter;
21
+ channelId: string;
22
+ platform: Platform;
23
+ }
24
+ declare class InMemoryBatchStore {
25
+ private byChannel;
26
+ private byId;
27
+ beginBatch(options: BeginBatchRecordOptions): BatchRecord;
28
+ appendMessage(channelId: string, platform: Platform, batchId: string, message: BatchMessageRefRecord): BatchRecord | null;
29
+ finishBatch(channelId: string, platform: Platform, batchId: string): BatchRecord | null;
30
+ removeMessages(channelId: string, platform: Platform, batchId: string, messageIds: string[]): BatchRecord | null;
31
+ getBatch(channelId: string, platform: Platform, batchId: string): BatchRecord | null;
32
+ getBatches(channelId: string, platform: Platform, options?: BatchQueryOptions): BatchRecord[];
33
+ reset(): void;
34
+ }
35
+ export declare const batchStore: InMemoryBatchStore;
36
+ /** @internal Testing helper to isolate batch-store state between tests. */
37
+ export declare function resetBatchStore(): void;
38
+ export {};
39
+ //# sourceMappingURL=BatchStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BatchStore.d.ts","sourceRoot":"","sources":["../src/BatchStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,QAAQ,EACT,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED,UAAU,uBAAuB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAaD,cAAM,kBAAkB;IACtB,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,IAAI,CAAkE;IAE9E,UAAU,CAAC,OAAO,EAAE,uBAAuB,GAAG,WAAW;IAoBzD,aAAa,CACX,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,qBAAqB,GAC7B,WAAW,GAAG,IAAI;IAcrB,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,GACd,WAAW,GAAG,IAAI;IASrB,cAAc,CACZ,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAAE,GACnB,WAAW,GAAG,IAAI;IAerB,QAAQ,CACN,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,GACd,WAAW,GAAG,IAAI;IAQrB,UAAU,CACR,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,iBAAsB,GAC9B,WAAW,EAAE;IAwBhB,KAAK,IAAI,IAAI;CAId;AAED,eAAO,MAAM,UAAU,oBAA2B,CAAC;AAEnD,2EAA2E;AAC3E,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.batchStore = void 0;
4
+ exports.resetBatchStore = resetBatchStore;
5
+ const node_crypto_1 = require("node:crypto");
6
+ function channelKey(channelId, platform) {
7
+ return `${platform}:${channelId}`;
8
+ }
9
+ function cloneRecord(record) {
10
+ return {
11
+ ...record,
12
+ messages: record.messages.map((message) => ({ ...message })),
13
+ };
14
+ }
15
+ class InMemoryBatchStore {
16
+ byChannel = new Map();
17
+ byId = new Map();
18
+ beginBatch(options) {
19
+ const key = channelKey(options.channelId, options.platform);
20
+ const createdAt = Date.now();
21
+ const record = {
22
+ id: (0, node_crypto_1.randomUUID)(),
23
+ key: options.key,
24
+ author: options.author ?? "me",
25
+ channelId: options.channelId,
26
+ platform: options.platform,
27
+ createdAt,
28
+ messages: [],
29
+ };
30
+ const list = this.byChannel.get(key) ?? [];
31
+ list.push(record);
32
+ this.byChannel.set(key, list);
33
+ this.byId.set(record.id, { channelKey: key, record });
34
+ return cloneRecord(record);
35
+ }
36
+ appendMessage(channelId, platform, batchId, message) {
37
+ const existing = this.byId.get(batchId);
38
+ if (existing?.channelKey !== channelKey(channelId, platform)) {
39
+ return null;
40
+ }
41
+ const duplicate = existing.record.messages.some((msg) => msg.id === message.id);
42
+ if (!duplicate) {
43
+ existing.record.messages.push({ ...message });
44
+ }
45
+ return cloneRecord(existing.record);
46
+ }
47
+ finishBatch(channelId, platform, batchId) {
48
+ const existing = this.byId.get(batchId);
49
+ if (existing?.channelKey !== channelKey(channelId, platform)) {
50
+ return null;
51
+ }
52
+ existing.record.closedAt ??= Date.now();
53
+ return cloneRecord(existing.record);
54
+ }
55
+ removeMessages(channelId, platform, batchId, messageIds) {
56
+ if (messageIds.length === 0) {
57
+ return this.getBatch(channelId, platform, batchId);
58
+ }
59
+ const existing = this.byId.get(batchId);
60
+ if (existing?.channelKey !== channelKey(channelId, platform)) {
61
+ return null;
62
+ }
63
+ const toRemove = new Set(messageIds);
64
+ existing.record.messages = existing.record.messages.filter((message) => !toRemove.has(message.id));
65
+ return cloneRecord(existing.record);
66
+ }
67
+ getBatch(channelId, platform, batchId) {
68
+ const existing = this.byId.get(batchId);
69
+ if (existing?.channelKey !== channelKey(channelId, platform)) {
70
+ return null;
71
+ }
72
+ return cloneRecord(existing.record);
73
+ }
74
+ getBatches(channelId, platform, options = {}) {
75
+ const list = this.byChannel.get(channelKey(channelId, platform)) ?? [];
76
+ const includeOpen = options.includeOpen ?? true;
77
+ const filtered = list.filter((record) => {
78
+ if (options.key !== undefined && record.key !== options.key) {
79
+ return false;
80
+ }
81
+ if (options.author !== undefined && record.author !== options.author) {
82
+ return false;
83
+ }
84
+ if (!includeOpen && record.closedAt === undefined) {
85
+ return false;
86
+ }
87
+ return true;
88
+ });
89
+ filtered.sort((a, b) => b.createdAt - a.createdAt);
90
+ const limited = options.limit !== undefined
91
+ ? filtered.slice(0, Math.max(0, options.limit))
92
+ : filtered;
93
+ return limited.map((record) => cloneRecord(record));
94
+ }
95
+ reset() {
96
+ this.byChannel.clear();
97
+ this.byId.clear();
98
+ }
99
+ }
100
+ exports.batchStore = new InMemoryBatchStore();
101
+ /** @internal Testing helper to isolate batch-store state between tests. */
102
+ function resetBatchStore() {
103
+ exports.batchStore.reset();
104
+ }
105
+ //# sourceMappingURL=BatchStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BatchStore.js","sourceRoot":"","sources":["../src/BatchStore.ts"],"names":[],"mappings":"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"}
package/dist/Channel.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Message } from "./Message";
2
+ import type { MessageBatch } from "./MessageBatch.js";
2
3
  import { Thread } from "./Thread";
3
- import type { DisconnectCallback, ErrorCallback, FileAttachment, Member, MessageCallback, MessageContent, MessageData, Platform, ReactionCallback, ThreadData } from "./types";
4
+ import type { BatchQueryOptions, BeginBatchOptions, DeleteMessageOptions, DisconnectCallback, ErrorCallback, FileAttachment, Member, MessageCallback, MessageContent, MessageData, MessageQueryOptions, Platform, ReactionCallback, ThreadData } from "./types";
4
5
  /**
5
6
  * Interface for platform-specific channel operations
6
7
  */
@@ -11,7 +12,7 @@ export interface ChannelOperations {
11
12
  linkPreviews?: boolean;
12
13
  }): Promise<MessageData>;
13
14
  updateMessage(messageId: string, channelId: string, content: MessageContent): Promise<void>;
14
- deleteMessage(messageId: string, channelId: string): Promise<void>;
15
+ deleteMessage(messageId: string, channelId: string, options?: DeleteMessageOptions): Promise<void>;
15
16
  addReaction(messageId: string, channelId: string, emoji: string): Promise<void>;
16
17
  removeReaction(messageId: string, channelId: string, emoji: string): Promise<void>;
17
18
  removeAllReactions(messageId: string, channelId: string): Promise<void>;
@@ -20,6 +21,7 @@ export interface ChannelOperations {
20
21
  sendTyping(channelId: string): Promise<void>;
21
22
  startThread(messageId: string, channelId: string, name: string, autoArchiveDuration?: number): Promise<ThreadData>;
22
23
  bulkDelete(channelId: string, count: number): Promise<number>;
24
+ getMessages(channelId: string, options?: MessageQueryOptions): Promise<MessageData[]>;
23
25
  getThreads(channelId: string): Promise<ThreadData[]>;
24
26
  deleteThread(threadId: string, channelId: string): Promise<void>;
25
27
  getMembers(channelId: string): Promise<Member[]>;
@@ -37,8 +39,8 @@ export declare class Channel {
37
39
  private operations;
38
40
  private messageReactionCallbacks;
39
41
  private unsubscribeFromPlatform;
40
- private typingRefCount;
41
- private typingInterval;
42
+ private readonly batchAdapter;
43
+ private readonly typingController;
42
44
  constructor(id: string, platform: Platform, operations: ChannelOperations);
43
45
  /**
44
46
  * Post a message to this channel
@@ -126,6 +128,24 @@ export declare class Channel {
126
128
  * @returns Message object that callers can interact with before dismissal
127
129
  */
128
130
  postDismissable(content: MessageContent, ownerId: string): Promise<Message>;
131
+ /**
132
+ * Begin a logical message batch for grouping related posts.
133
+ * Batches can later be queried with getBatches()/getBatch().
134
+ */
135
+ beginBatch(options?: BeginBatchOptions): Promise<MessageBatch>;
136
+ /**
137
+ * Execute a callback with an auto-finishing message batch.
138
+ * finish() is guaranteed in finally, even when callback throws.
139
+ */
140
+ withBatch<T>(optionsOrCallback: BeginBatchOptions | ((batch: MessageBatch) => Promise<T>), maybeCallback?: (batch: MessageBatch) => Promise<T>): Promise<T>;
141
+ /**
142
+ * Retrieve a batch by ID within this channel.
143
+ */
144
+ getBatch(id: string): Promise<MessageBatch | null>;
145
+ /**
146
+ * List batches in this channel, newest first.
147
+ */
148
+ getBatches(options?: BatchQueryOptions): Promise<MessageBatch[]>;
129
149
  /**
130
150
  * Bulk delete messages in this channel
131
151
  * @param count - Number of recent messages to delete
@@ -142,6 +162,33 @@ export declare class Channel {
142
162
  * @returns Array of members with mention strings
143
163
  */
144
164
  getMembers(): Promise<Member[]>;
165
+ /**
166
+ * Find a channel member by fuzzy query (mention, username, display name, or email).
167
+ * Returns null when no unambiguous match is found.
168
+ */
169
+ findMember(query: string): Promise<Member | null>;
170
+ /**
171
+ * Resolve a user query to a mention string (e.g., "<@U123>").
172
+ * Returns null when no unambiguous match is found.
173
+ */
174
+ resolveMention(query: string): Promise<string | null>;
175
+ /**
176
+ * Get recent messages in this channel.
177
+ * Supports filtering by author and timestamp window.
178
+ */
179
+ getMessages(options?: MessageQueryOptions): Promise<Message[]>;
180
+ /**
181
+ * Convenience helper to fetch recent messages authored by the connected bot.
182
+ */
183
+ getRecentBotMessages(limit?: number): Promise<Message[]>;
184
+ /**
185
+ * Opinionated cleanup helper: keep the newest N messages and delete the rest.
186
+ * Returns the number of deleted messages.
187
+ */
188
+ pruneMessages(options?: MessageQueryOptions & {
189
+ keep?: number;
190
+ cascadeReplies?: boolean;
191
+ }): Promise<number>;
145
192
  /**
146
193
  * Disconnect from this channel (cleanup)
147
194
  */
@@ -1 +1 @@
1
- {"version":3,"file":"Channel.d.ts","sourceRoot":"","sources":["../src/Channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Channel.d.ts","sourceRoot":"","sources":["../src/Channel.ts"],"names":[],"mappings":"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"}
package/dist/Channel.js CHANGED
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Channel = void 0;
4
+ const ChannelBatchHelpers_js_1 = require("./ChannelBatchHelpers.js");
5
+ const ChannelRuntimeFeatures_js_1 = require("./ChannelRuntimeFeatures.js");
6
+ const memberMatching_1 = require("./memberMatching");
4
7
  const Message_1 = require("./Message");
5
8
  const PendingMessage_1 = require("./PendingMessage");
6
9
  const Thread_1 = require("./Thread");
7
- /** Default interval (ms) for refreshing the typing indicator. Discord expires after ~10s. */
8
- const TYPING_REFRESH_MS = 8000;
9
10
  /** A platform-agnostic channel that provides messaging, reactions, typing indicators, and thread management. */
10
11
  class Channel {
11
12
  id;
@@ -13,12 +14,14 @@ class Channel {
13
14
  operations;
14
15
  messageReactionCallbacks = new Map();
15
16
  unsubscribeFromPlatform = null;
16
- typingRefCount = 0;
17
- typingInterval = null;
17
+ batchAdapter;
18
+ typingController;
18
19
  constructor(id, platform, operations) {
19
20
  this.id = id;
20
21
  this.platform = platform;
21
22
  this.operations = operations;
23
+ this.batchAdapter = (0, ChannelBatchHelpers_js_1.createChannelBatchAdapter)(this.id, this.platform, (content, options) => this.postMessage(content, options), (messageId, options) => this.operations.deleteMessage(messageId, this.id, options));
24
+ this.typingController = new ChannelRuntimeFeatures_js_1.TypingController(() => this.operations.sendTyping(this.id));
22
25
  // Subscribe to platform reactions and forward to message-specific callbacks
23
26
  this.unsubscribeFromPlatform = this.operations.subscribeToReactions(id, (event) => this.emitReaction(event));
24
27
  }
@@ -99,7 +102,7 @@ class Channel {
99
102
  removeReaction: (messageId, channelId, emoji) => this.operations.removeReaction(messageId, channelId, emoji),
100
103
  removeAllReactions: (messageId, channelId) => this.operations.removeAllReactions(messageId, channelId),
101
104
  updateMessage: (messageId, channelId, content) => this.operations.updateMessage(messageId, channelId, content),
102
- deleteMessage: (messageId, channelId) => this.operations.deleteMessage(messageId, channelId),
105
+ deleteMessage: (messageId, channelId, options) => this.operations.deleteMessage(messageId, channelId, options),
103
106
  reply: async (channelId, threadTs, content, files) => this.operations.postMessage(channelId, content, { threadTs, files }),
104
107
  subscribeToReactions: (messageId, callback) => this.subscribeToMessageReactions(messageId, callback),
105
108
  startThread: async (messageId, channelId, name, autoArchiveDuration) => {
@@ -168,32 +171,14 @@ class Channel {
168
171
  * can overlap — the indicator stays active until the last one ends.
169
172
  */
170
173
  beginTyping() {
171
- this.typingRefCount++;
172
- if (this.typingRefCount === 1) {
173
- this.operations.sendTyping(this.id).catch(() => {
174
- // Ignore typing indicator failures
175
- });
176
- this.typingInterval = setInterval(() => {
177
- if (this.typingRefCount > 0) {
178
- this.operations.sendTyping(this.id).catch(() => {
179
- // Ignore typing indicator failures
180
- });
181
- }
182
- }, TYPING_REFRESH_MS);
183
- }
174
+ this.typingController.begin();
184
175
  }
185
176
  /**
186
177
  * Mark the end of one unit of work. When all outstanding beginTyping()
187
178
  * calls have been balanced by endTyping(), the refresh interval stops.
188
179
  */
189
180
  endTyping() {
190
- if (this.typingRefCount > 0) {
191
- this.typingRefCount--;
192
- }
193
- if (this.typingRefCount === 0 && this.typingInterval) {
194
- clearInterval(this.typingInterval);
195
- this.typingInterval = null;
196
- }
181
+ this.typingController.end();
197
182
  }
198
183
  /**
199
184
  * Show a typing indicator while executing a function.
@@ -203,13 +188,7 @@ class Channel {
203
188
  * @returns The return value of fn
204
189
  */
205
190
  async withTyping(fn) {
206
- this.beginTyping();
207
- try {
208
- return await fn();
209
- }
210
- finally {
211
- this.endTyping();
212
- }
191
+ return this.typingController.withTyping(fn);
213
192
  }
214
193
  /**
215
194
  * Post a message with a trash can reaction that the owner can click to dismiss.
@@ -218,17 +197,33 @@ class Channel {
218
197
  * @returns Message object that callers can interact with before dismissal
219
198
  */
220
199
  async postDismissable(content, ownerId) {
221
- const emoji = this.platform === "slack" ? ":wastebasket:" : "🗑️";
222
- const emojiMatch = this.platform === "slack" ? "wastebasket" : "🗑️";
223
- const msg = await this.postMessage(content);
224
- msg.addReactions([emoji]).onReaction(async (event) => {
225
- if (event.user.id !== ownerId || event.emoji !== emojiMatch) {
226
- return;
227
- }
228
- msg.offReaction();
229
- await msg.delete();
230
- });
231
- return msg;
200
+ return (0, ChannelRuntimeFeatures_js_1.postDismissableMessage)(this.platform, async (messageContent) => this.postMessage(messageContent), content, ownerId);
201
+ }
202
+ /**
203
+ * Begin a logical message batch for grouping related posts.
204
+ * Batches can later be queried with getBatches()/getBatch().
205
+ */
206
+ beginBatch(options = {}) {
207
+ return (0, ChannelBatchHelpers_js_1.beginChannelBatch)(this.batchAdapter, options);
208
+ }
209
+ /**
210
+ * Execute a callback with an auto-finishing message batch.
211
+ * finish() is guaranteed in finally, even when callback throws.
212
+ */
213
+ withBatch(optionsOrCallback, maybeCallback) {
214
+ return (0, ChannelBatchHelpers_js_1.withChannelBatchFromArgs)(this.batchAdapter, optionsOrCallback, maybeCallback);
215
+ }
216
+ /**
217
+ * Retrieve a batch by ID within this channel.
218
+ */
219
+ getBatch(id) {
220
+ return (0, ChannelBatchHelpers_js_1.getChannelBatch)(this.batchAdapter, id);
221
+ }
222
+ /**
223
+ * List batches in this channel, newest first.
224
+ */
225
+ getBatches(options = {}) {
226
+ return (0, ChannelBatchHelpers_js_1.getChannelBatches)(this.batchAdapter, options);
232
227
  }
233
228
  /**
234
229
  * Bulk delete messages in this channel
@@ -253,6 +248,72 @@ class Channel {
253
248
  async getMembers() {
254
249
  return this.operations.getMembers(this.id);
255
250
  }
251
+ /**
252
+ * Find a channel member by fuzzy query (mention, username, display name, or email).
253
+ * Returns null when no unambiguous match is found.
254
+ */
255
+ async findMember(query) {
256
+ const members = await this.getMembers();
257
+ return (0, memberMatching_1.findBestMemberMatch)(members, query);
258
+ }
259
+ /**
260
+ * Resolve a user query to a mention string (e.g., "<@U123>").
261
+ * Returns null when no unambiguous match is found.
262
+ */
263
+ async resolveMention(query) {
264
+ const member = await this.findMember(query);
265
+ return member?.mention ?? null;
266
+ }
267
+ /**
268
+ * Get recent messages in this channel.
269
+ * Supports filtering by author and timestamp window.
270
+ */
271
+ async getMessages(options = {}) {
272
+ const { author: optionAuthor } = options;
273
+ let author = optionAuthor;
274
+ if (author !== undefined && author !== "me") {
275
+ const mentionId = (0, memberMatching_1.extractMentionId)(author);
276
+ if (mentionId !== null) {
277
+ author = mentionId;
278
+ }
279
+ else {
280
+ const member = await this.findMember(author);
281
+ if (member !== null) {
282
+ author = member.id;
283
+ }
284
+ }
285
+ }
286
+ const data = await this.operations.getMessages(this.id, {
287
+ ...options,
288
+ author,
289
+ });
290
+ return data.map((message) => new Message_1.Message(message, this.createMessageOperations()));
291
+ }
292
+ /**
293
+ * Convenience helper to fetch recent messages authored by the connected bot.
294
+ */
295
+ async getRecentBotMessages(limit = 50) {
296
+ return this.getMessages({ limit, author: "me" });
297
+ }
298
+ /**
299
+ * Opinionated cleanup helper: keep the newest N messages and delete the rest.
300
+ * Returns the number of deleted messages.
301
+ */
302
+ async pruneMessages(options = {}) {
303
+ const keep = Math.max(0, options.keep ?? 0);
304
+ const cascadeReplies = options.cascadeReplies ?? true;
305
+ const messages = await this.getMessages({
306
+ limit: options.limit,
307
+ author: options.author,
308
+ after: options.after,
309
+ before: options.before,
310
+ });
311
+ const toDelete = messages.slice(keep);
312
+ for (const message of toDelete) {
313
+ await message.delete({ cascadeReplies });
314
+ }
315
+ return toDelete.length;
316
+ }
256
317
  /**
257
318
  * Disconnect from this channel (cleanup)
258
319
  */
@@ -262,11 +323,7 @@ class Channel {
262
323
  this.unsubscribeFromPlatform = null;
263
324
  }
264
325
  this.messageReactionCallbacks.clear();
265
- if (this.typingInterval) {
266
- clearInterval(this.typingInterval);
267
- this.typingInterval = null;
268
- }
269
- this.typingRefCount = 0;
326
+ this.typingController.clear();
270
327
  }
271
328
  }
272
329
  exports.Channel = Channel;