@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.
- package/README.md +74 -6
- package/dist/BatchStore.d.ts +39 -0
- package/dist/BatchStore.d.ts.map +1 -0
- package/dist/BatchStore.js +105 -0
- package/dist/BatchStore.js.map +1 -0
- package/dist/Channel.d.ts +51 -4
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +105 -48
- package/dist/Channel.js.map +1 -1
- package/dist/ChannelBatchHelpers.d.ts +38 -0
- package/dist/ChannelBatchHelpers.d.ts.map +1 -0
- package/dist/ChannelBatchHelpers.js +106 -0
- package/dist/ChannelBatchHelpers.js.map +1 -0
- package/dist/ChannelRuntimeFeatures.d.ts +16 -0
- package/dist/ChannelRuntimeFeatures.d.ts.map +1 -0
- package/dist/ChannelRuntimeFeatures.js +72 -0
- package/dist/ChannelRuntimeFeatures.js.map +1 -0
- package/dist/ChatClient.d.ts +7 -1
- package/dist/ChatClient.d.ts.map +1 -1
- package/dist/ChatClient.js +8 -0
- package/dist/ChatClient.js.map +1 -1
- package/dist/Message.d.ts +3 -3
- package/dist/Message.d.ts.map +1 -1
- package/dist/Message.js +2 -2
- package/dist/Message.js.map +1 -1
- package/dist/MessageBatch.d.ts +62 -0
- package/dist/MessageBatch.d.ts.map +1 -0
- package/dist/MessageBatch.js +129 -0
- package/dist/MessageBatch.js.map +1 -0
- package/dist/discord/DiscordChatClient.d.ts +3 -2
- package/dist/discord/DiscordChatClient.d.ts.map +1 -1
- package/dist/discord/DiscordChatClient.js +18 -2
- package/dist/discord/DiscordChatClient.js.map +1 -1
- package/dist/discord/getMessages.d.ts +7 -0
- package/dist/discord/getMessages.d.ts.map +1 -0
- package/dist/discord/getMessages.js +87 -0
- package/dist/discord/getMessages.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/memberMatching.d.ts +11 -0
- package/dist/memberMatching.d.ts.map +1 -0
- package/dist/memberMatching.js +114 -0
- package/dist/memberMatching.js.map +1 -0
- package/dist/slack/SlackChatClient.d.ts +5 -2
- package/dist/slack/SlackChatClient.d.ts.map +1 -1
- package/dist/slack/SlackChatClient.js +29 -2
- package/dist/slack/SlackChatClient.js.map +1 -1
- package/dist/slack/fetchChannelMembers.d.ts.map +1 -1
- package/dist/slack/fetchChannelMembers.js +3 -0
- package/dist/slack/fetchChannelMembers.js.map +1 -1
- package/dist/slack/getMessages.d.ts +12 -0
- package/dist/slack/getMessages.d.ts.map +1 -0
- package/dist/slack/getMessages.js +148 -0
- package/dist/slack/getMessages.js.map +1 -0
- package/dist/slack/messageOperations.d.ts +2 -2
- package/dist/slack/messageOperations.d.ts.map +1 -1
- package/dist/slack/messageOperations.js +16 -14
- package/dist/slack/messageOperations.js.map +1 -1
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -1
- 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
|
-
|
|
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
|
|
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`,
|
|
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
|
|
41
|
-
private
|
|
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
|
*/
|
package/dist/Channel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Channel.d.ts","sourceRoot":"","sources":["../src/Channel.ts"],"names":[],"mappings":"
|
|
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
|
-
|
|
17
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
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;
|