@hardlydifficult/chat 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +134 -45
  2. package/dist/Channel.d.ts +24 -13
  3. package/dist/Channel.d.ts.map +1 -1
  4. package/dist/Channel.js +99 -46
  5. package/dist/Channel.js.map +1 -1
  6. package/dist/ChatClient.d.ts +2 -2
  7. package/dist/ChatClient.d.ts.map +1 -1
  8. package/dist/ChatClient.js +5 -1
  9. package/dist/ChatClient.js.map +1 -1
  10. package/dist/Message.d.ts +91 -6
  11. package/dist/Message.d.ts.map +1 -1
  12. package/dist/Message.js +138 -9
  13. package/dist/Message.js.map +1 -1
  14. package/dist/discord/DiscordChatClient.d.ts +19 -3
  15. package/dist/discord/DiscordChatClient.d.ts.map +1 -1
  16. package/dist/discord/DiscordChatClient.js +79 -15
  17. package/dist/discord/DiscordChatClient.js.map +1 -1
  18. package/dist/discord/index.d.ts +1 -1
  19. package/dist/discord/index.d.ts.map +1 -1
  20. package/dist/discord/index.js +5 -1
  21. package/dist/discord/index.js.map +1 -1
  22. package/dist/index.d.ts +8 -8
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +24 -10
  25. package/dist/index.js.map +1 -1
  26. package/dist/outputters/discord.d.ts +19 -0
  27. package/dist/outputters/discord.d.ts.map +1 -0
  28. package/dist/outputters/discord.js +64 -0
  29. package/dist/outputters/discord.js.map +1 -0
  30. package/dist/outputters/index.d.ts +4 -0
  31. package/dist/outputters/index.d.ts.map +1 -0
  32. package/dist/outputters/index.js +8 -0
  33. package/dist/outputters/index.js.map +1 -0
  34. package/dist/outputters/slack.d.ts +24 -0
  35. package/dist/outputters/slack.d.ts.map +1 -0
  36. package/dist/outputters/slack.js +149 -0
  37. package/dist/outputters/slack.js.map +1 -0
  38. package/dist/slack/SlackChatClient.d.ts +12 -2
  39. package/dist/slack/SlackChatClient.d.ts.map +1 -1
  40. package/dist/slack/SlackChatClient.js +54 -8
  41. package/dist/slack/SlackChatClient.js.map +1 -1
  42. package/dist/slack/index.d.ts +1 -1
  43. package/dist/slack/index.d.ts.map +1 -1
  44. package/dist/slack/index.js +5 -1
  45. package/dist/slack/index.js.map +1 -1
  46. package/dist/types.d.ts +12 -0
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/types.js +7 -1
  49. package/dist/types.js.map +1 -1
  50. package/dist/utils.d.ts +7 -0
  51. package/dist/utils.d.ts.map +1 -0
  52. package/dist/utils.js +10 -0
  53. package/dist/utils.js.map +1 -0
  54. package/package.json +5 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hardlydifficult/chat
2
2
 
3
- Unified API for posting messages with emoji reactions to Discord and Slack.
3
+ Unified API for Discord and Slack messaging with rich document support.
4
4
 
5
5
  ## Installation
6
6
 
@@ -11,93 +11,152 @@ npm install @hardlydifficult/chat
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { createChatClient } from '@hardlydifficult/chat';
14
+ import { createChatClient } from "@hardlydifficult/chat";
15
15
 
16
16
  // Uses DISCORD_TOKEN and DISCORD_GUILD_ID env vars
17
- const client = createChatClient({ type: 'discord' });
17
+ const client = createChatClient({ type: "discord" });
18
18
 
19
19
  // Or for Slack: uses SLACK_BOT_TOKEN and SLACK_APP_TOKEN env vars
20
- const client = createChatClient({ type: 'slack' });
20
+ const client = createChatClient({ type: "slack" });
21
21
 
22
22
  const channel = await client.connect(channelId);
23
23
 
24
24
  await channel
25
- .postMessage('Vote: (1) Pizza, (2) Burgers, (3) Salad')
26
- .addReactions(['1️⃣', '2️⃣', '3️⃣']);
25
+ .postMessage("Vote: (1) Pizza, (2) Burgers, (3) Salad")
26
+ .addReactions(["1️⃣", "2️⃣", "3️⃣"])
27
+ .onReaction((event) => {
28
+ console.log(`${event.user.username} voted ${event.emoji}`);
29
+ });
30
+ ```
31
+
32
+ ## Rich Documents
33
+
34
+ Post rich, formatted messages using the `@hardlydifficult/document-generator` package:
35
+
36
+ ```typescript
37
+ import { doc } from '@hardlydifficult/document-generator';
38
+ import { createChatClient } from '@hardlydifficult/chat';
39
+
40
+ const client = createChatClient({ type: 'slack' });
41
+ const channel = await client.connect(channelId);
42
+
43
+ const report = doc()
44
+ .header("Daily Report")
45
+ .text("Here are today's **highlights**:")
46
+ .list(["Feature A completed", "Bug B fixed", "99.9% uptime"])
47
+ .divider()
48
+ .link("View dashboard", "https://example.com/dashboard")
49
+ .context("Generated automatically");
50
+
51
+ // Automatically converted to Slack Block Kit / Discord Embed
52
+ await channel.postMessage(report);
53
+ ```
54
+
55
+ ## Message Operations
56
+
57
+ ### Update Messages
58
+
59
+ ```typescript
60
+ const msg = await channel.postMessage('Initial content');
61
+ await msg.update('Updated content');
62
+ await msg.update(doc().header('New Header').text('New body'));
63
+ ```
64
+
65
+ ### Delete Messages
66
+
67
+ ```typescript
68
+ const msg = await channel.postMessage('Temporary message');
69
+ await msg.delete();
70
+ ```
71
+
72
+ ### Thread Replies
73
+
74
+ ```typescript
75
+ const msg = await channel.postMessage('Main message');
76
+ msg.postReply('This is a thread reply');
77
+ msg.postReply(doc().text('Rich reply with **formatting**'));
78
+ ```
79
+
80
+ ### Reactions
27
81
 
28
- channel.onReaction((event) => {
29
- console.log(`${event.user.username} voted ${event.emoji}`);
30
- });
82
+ ```typescript
83
+ // Add reactions and listen for user votes (chainable)
84
+ await channel
85
+ .postMessage("Pick one")
86
+ .addReactions(["👍", "👎", "🤷"])
87
+ .onReaction((event) => {
88
+ console.log(`${event.user.username} reacted with ${event.emoji}`);
89
+ });
90
+
91
+ // Or wait for reactions to be added before continuing
92
+ const msg = await channel.postMessage("Loading...").wait();
93
+ msg.addReactions(["✅"]);
94
+ await msg.waitForReactions();
31
95
  ```
32
96
 
33
- ## API
97
+ ## API Reference
34
98
 
35
99
  ### `createChatClient(config)`
36
100
 
37
101
  ```typescript
38
102
  // Discord - env vars: DISCORD_TOKEN, DISCORD_GUILD_ID
39
103
  createChatClient({ type: 'discord' });
40
- createChatClient({ type: 'discord', token: '...', guildId: '...' }); // override
104
+ createChatClient({ type: 'discord', token: '...', guildId: '...' });
41
105
 
42
106
  // Slack - env vars: SLACK_BOT_TOKEN, SLACK_APP_TOKEN
43
107
  createChatClient({ type: 'slack' });
44
- createChatClient({ type: 'slack', token: '...', appToken: '...' }); // override
108
+ createChatClient({ type: 'slack', token: '...', appToken: '...' });
45
109
  ```
46
110
 
47
111
  ### `client.connect(channelId): Promise<Channel>`
48
112
 
49
113
  Connect to a channel.
50
114
 
51
- ### `channel.postMessage(text): Message`
115
+ ### `channel.postMessage(content): Message`
52
116
 
53
- Post a message. Returns a chainable `Message`.
117
+ Post a message. Content can be a string or a Document.
54
118
 
55
119
  ### `message.addReactions(emojis): Message`
56
120
 
57
121
  Add reactions. Chainable and awaitable.
58
122
 
59
- ```typescript
60
- await channel.postMessage('Pick one').addReactions(['1️⃣', '2️⃣']);
61
- ```
123
+ ### `message.postReply(content): Message`
62
124
 
63
- ### `channel.onReaction(callback): () => void`
125
+ Post a reply in the message's thread.
64
126
 
65
- Listen for reactions. Returns unsubscribe function.
127
+ ### `message.update(content): Promise<void>`
66
128
 
67
- ```typescript
68
- const unsubscribe = channel.onReaction((event) => {
69
- // event.emoji, event.user.id, event.user.username, event.messageId
70
- });
71
- ```
129
+ Update the message content.
72
130
 
73
- ### `client.disconnect(): Promise<void>`
131
+ ### `message.delete(): Promise<void>`
74
132
 
75
- Disconnect from the platform.
133
+ Delete the message.
76
134
 
77
- ## Example: Poll
135
+ ### `message.waitForReactions(): Promise<void>`
78
136
 
79
- ```typescript
80
- import { createChatClient } from '@hardlydifficult/chat';
137
+ Wait for all pending reactions to complete.
81
138
 
82
- const client = createChatClient({ type: 'discord' });
83
- const channel = await client.connect(process.env.CHANNEL_ID);
139
+ ### `message.onReaction(callback): Message`
84
140
 
85
- const options = ['Pizza', 'Burgers', 'Salad'];
86
- const emojis = ['1️⃣', '2️⃣', '3️⃣'];
141
+ Listen for reactions on this message. Chainable.
87
142
 
88
- const message = await channel
89
- .postMessage(options.map((o, i) => `${emojis[i]} ${o}`).join('\n'))
90
- .addReactions(emojis);
143
+ ```typescript
144
+ channel
145
+ .postMessage("Vote!")
146
+ .addReactions(["👍", "👎"])
147
+ .onReaction((event) => {
148
+ // event.emoji, event.user.id, event.user.username,
149
+ // event.messageId, event.channelId, event.timestamp
150
+ });
151
+ ```
91
152
 
92
- channel.onReaction((event) => {
93
- if (event.messageId !== message.id) return;
153
+ ### `message.offReaction(): void`
94
154
 
95
- const choice = options[emojis.indexOf(event.emoji)];
96
- if (choice) {
97
- console.log(`${event.user.username} voted for ${choice}`);
98
- }
99
- });
100
- ```
155
+ Stop listening for reactions on this message.
156
+
157
+ ### `client.disconnect(): Promise<void>`
158
+
159
+ Disconnect from the platform.
101
160
 
102
161
  ## Platform Setup
103
162
 
@@ -112,6 +171,36 @@ channel.onReaction((event) => {
112
171
 
113
172
  1. Create app at [Slack API](https://api.slack.com/apps)
114
173
  2. Enable Socket Mode, generate App Token
115
- 3. Bot scopes: `chat:write`, `reactions:write`, `reactions:read`
174
+ 3. Bot scopes: `chat:write`, `chat:write.public`, `reactions:write`, `reactions:read`
116
175
  4. Subscribe to: `reaction_added`
117
176
  5. Set `SLACK_BOT_TOKEN` and `SLACK_APP_TOKEN` env vars
177
+
178
+ ## Example: Interactive Poll
179
+
180
+ ```typescript
181
+ import { createChatClient } from "@hardlydifficult/chat";
182
+ import { doc } from "@hardlydifficult/document-generator";
183
+
184
+ const client = createChatClient({ type: "discord" });
185
+ const channel = await client.connect(process.env.CHANNEL_ID);
186
+
187
+ const options = ["Pizza", "Burgers", "Salad"];
188
+ const emojis = ["1️⃣", "2️⃣", "3️⃣"];
189
+ const votes: Record<string, string> = {};
190
+
191
+ const pollDoc = doc()
192
+ .header("🗳️ Lunch Poll")
193
+ .text("What should we order?")
194
+ .list(options.map((o, i) => `${emojis[i]} ${o}`));
195
+
196
+ await channel
197
+ .postMessage(pollDoc)
198
+ .addReactions(emojis)
199
+ .onReaction((event) => {
200
+ const choice = options[emojis.indexOf(event.emoji)];
201
+ if (choice) {
202
+ votes[event.user.id] = choice;
203
+ console.log(`${event.user.username} voted for ${choice}`);
204
+ }
205
+ });
206
+ ```
package/dist/Channel.d.ts CHANGED
@@ -1,10 +1,15 @@
1
- import type { Platform, ReactionCallback, MessageData } from './types.js';
2
- import { Message, type ReactionAdder } from './Message.js';
1
+ import type { Platform, ReactionCallback, MessageData, MessageContent } from './types';
2
+ import { Message } from './Message';
3
3
  /**
4
4
  * Interface for platform-specific channel operations
5
5
  */
6
- export interface ChannelOperations extends ReactionAdder {
7
- postMessage(channelId: string, text: string): Promise<MessageData>;
6
+ export interface ChannelOperations {
7
+ postMessage(channelId: string, content: MessageContent, options?: {
8
+ threadTs?: string;
9
+ }): Promise<MessageData>;
10
+ updateMessage(messageId: string, channelId: string, content: MessageContent): Promise<void>;
11
+ deleteMessage(messageId: string, channelId: string): Promise<void>;
12
+ addReaction(messageId: string, channelId: string, emoji: string): Promise<void>;
8
13
  subscribeToReactions(channelId: string, callback: ReactionCallback): () => void;
9
14
  }
10
15
  /**
@@ -14,25 +19,31 @@ export declare class Channel {
14
19
  readonly id: string;
15
20
  readonly platform: Platform;
16
21
  private operations;
17
- private reactionCallbacks;
22
+ private messageReactionCallbacks;
18
23
  private unsubscribeFromPlatform;
19
24
  constructor(id: string, platform: Platform, operations: ChannelOperations);
20
25
  /**
21
26
  * Post a message to this channel
22
- * @param text - Message content
27
+ * @param content - Message content (string or Document)
28
+ * @param options - Optional message options (e.g., threadTs for threading)
23
29
  * @returns Message object with chainable reaction methods
24
30
  */
25
- postMessage(text: string): Message;
31
+ postMessage(content: MessageContent, options?: {
32
+ threadTs?: string;
33
+ }): Message;
26
34
  /**
27
- * Register a callback for reaction events on this channel
28
- * @param callback - Function called when users add reactions
29
- * @returns Unsubscribe function
35
+ * Emit a reaction event to registered message-specific callbacks
30
36
  */
31
- onReaction(callback: ReactionCallback): () => void;
37
+ private emitReaction;
32
38
  /**
33
- * Emit a reaction event to all registered callbacks
39
+ * Subscribe to reactions for a specific message
40
+ * @internal Used by Message.onReaction
34
41
  */
35
- private emitReaction;
42
+ private subscribeToMessageReactions;
43
+ /**
44
+ * Create MessageOperations from ChannelOperations
45
+ */
46
+ private createMessageOperations;
36
47
  /**
37
48
  * Disconnect from this channel (cleanup)
38
49
  */
@@ -1 +1 @@
1
- {"version":3,"file":"Channel.d.ts","sourceRoot":"","sources":["../src/Channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACnE,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAAC;CACjF;AAED;;GAEG;AACH,qBAAa,OAAO;IAClB,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,SAAgB,QAAQ,EAAE,QAAQ,CAAC;IAEnC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,uBAAuB,CAA6B;gBAEhD,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB;IAWzE;;;;OAIG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAQlC;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI;IAOlD;;OAEG;YACW,YAAY;IAS1B;;OAEG;IACH,UAAU,IAAI,IAAI;CAOnB"}
1
+ {"version":3,"file":"Channel.d.ts","sourceRoot":"","sources":["../src/Channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,OAAO,EAA0B,MAAM,WAAW,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAC9B,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5F,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAAC;CACjF;AAED;;GAEG;AACH,qBAAa,OAAO;IAClB,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,SAAgB,QAAQ,EAAE,QAAQ,CAAC;IAEnC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,wBAAwB,CAA4C;IAC5E,OAAO,CAAC,uBAAuB,CAA6B;gBAEhD,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB;IAWzE;;;;;OAKG;IACH,WAAW,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO;IAY9E;;OAEG;YACW,YAAY;IAa1B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAgBnC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAe/B;;OAEG;IACH,UAAU,IAAI,IAAI;CAOnB"}
package/dist/Channel.js CHANGED
@@ -1,50 +1,77 @@
1
- import { Message } from './Message.js';
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Channel = void 0;
4
+ const Message_1 = require("./Message");
2
5
  /**
3
6
  * Represents a connected channel with messaging capabilities
4
7
  */
5
- export class Channel {
8
+ class Channel {
6
9
  id;
7
10
  platform;
8
11
  operations;
9
- reactionCallbacks = new Set();
12
+ messageReactionCallbacks = new Map();
10
13
  unsubscribeFromPlatform = null;
11
14
  constructor(id, platform, operations) {
12
15
  this.id = id;
13
16
  this.platform = platform;
14
17
  this.operations = operations;
15
- // Subscribe to platform reactions and forward to our callbacks
18
+ // Subscribe to platform reactions and forward to message-specific callbacks
16
19
  this.unsubscribeFromPlatform = this.operations.subscribeToReactions(id, (event) => this.emitReaction(event));
17
20
  }
18
21
  /**
19
22
  * Post a message to this channel
20
- * @param text - Message content
23
+ * @param content - Message content (string or Document)
24
+ * @param options - Optional message options (e.g., threadTs for threading)
21
25
  * @returns Message object with chainable reaction methods
22
26
  */
23
- postMessage(text) {
24
- const messagePromise = this.operations.postMessage(this.id, text);
27
+ postMessage(content, options) {
28
+ const messagePromise = this.operations.postMessage(this.id, content, options);
25
29
  // Create a Message that will resolve once the post completes
26
- const pendingMessage = new PendingMessage(messagePromise, this.operations);
30
+ const pendingMessage = new PendingMessage(messagePromise, this.createMessageOperations(), this.platform);
27
31
  return pendingMessage;
28
32
  }
29
33
  /**
30
- * Register a callback for reaction events on this channel
31
- * @param callback - Function called when users add reactions
32
- * @returns Unsubscribe function
34
+ * Emit a reaction event to registered message-specific callbacks
33
35
  */
34
- onReaction(callback) {
35
- this.reactionCallbacks.add(callback);
36
+ async emitReaction(event) {
37
+ const callbacks = this.messageReactionCallbacks.get(event.messageId);
38
+ if (!callbacks) {
39
+ return;
40
+ }
41
+ const promises = Array.from(callbacks).map((cb) => Promise.resolve(cb(event)).catch((err) => {
42
+ console.error('Reaction callback error:', err);
43
+ }));
44
+ await Promise.all(promises);
45
+ }
46
+ /**
47
+ * Subscribe to reactions for a specific message
48
+ * @internal Used by Message.onReaction
49
+ */
50
+ subscribeToMessageReactions(messageId, callback) {
51
+ let callbacks = this.messageReactionCallbacks.get(messageId);
52
+ if (!callbacks) {
53
+ callbacks = new Set();
54
+ this.messageReactionCallbacks.set(messageId, callbacks);
55
+ }
56
+ callbacks.add(callback);
36
57
  return () => {
37
- this.reactionCallbacks.delete(callback);
58
+ callbacks.delete(callback);
59
+ if (callbacks.size === 0) {
60
+ this.messageReactionCallbacks.delete(messageId);
61
+ }
38
62
  };
39
63
  }
40
64
  /**
41
- * Emit a reaction event to all registered callbacks
65
+ * Create MessageOperations from ChannelOperations
42
66
  */
43
- async emitReaction(event) {
44
- const promises = Array.from(this.reactionCallbacks).map((cb) => Promise.resolve(cb(event)).catch((err) => {
45
- console.error('Reaction callback error:', err);
46
- }));
47
- await Promise.all(promises);
67
+ createMessageOperations() {
68
+ return {
69
+ addReaction: (messageId, channelId, emoji) => this.operations.addReaction(messageId, channelId, emoji),
70
+ updateMessage: (messageId, channelId, content) => this.operations.updateMessage(messageId, channelId, content),
71
+ deleteMessage: (messageId, channelId) => this.operations.deleteMessage(messageId, channelId),
72
+ postReply: async (channelId, threadTs, content) => this.operations.postMessage(channelId, content, { threadTs }),
73
+ subscribeToReactions: (messageId, callback) => this.subscribeToMessageReactions(messageId, callback),
74
+ };
48
75
  }
49
76
  /**
50
77
  * Disconnect from this channel (cleanup)
@@ -54,52 +81,78 @@ export class Channel {
54
81
  this.unsubscribeFromPlatform();
55
82
  this.unsubscribeFromPlatform = null;
56
83
  }
57
- this.reactionCallbacks.clear();
84
+ this.messageReactionCallbacks.clear();
58
85
  }
59
86
  }
87
+ exports.Channel = Channel;
60
88
  /**
61
- * A Message that is still being posted - supports the same chainable API
89
+ * A Message that is still being posted.
90
+ * Use `.wait()` to await completion and handle errors.
62
91
  */
63
- class PendingMessage extends Message {
92
+ class PendingMessage extends Message_1.Message {
64
93
  postPromise;
65
- resolvedData = null;
66
- constructor(postPromise, reactionAdder) {
67
- // Initialize with placeholder data
68
- super({ id: '', channelId: '', platform: 'discord' }, reactionAdder);
94
+ deferredReactionCallbacks = [];
95
+ constructor(postPromise, operations, platform) {
96
+ // Initialize with placeholder data using the correct platform
97
+ super({ id: '', channelId: '', platform }, operations);
69
98
  this.postPromise = postPromise;
70
- // Update our data when the post resolves
71
- void this.postPromise.then((data) => {
72
- this.resolvedData = data;
99
+ // Update our data when the post resolves and subscribe any deferred listeners
100
+ this.postPromise
101
+ .then((data) => {
73
102
  // Update the readonly properties via Object.defineProperty
74
103
  Object.defineProperty(this, 'id', { value: data.id });
75
104
  Object.defineProperty(this, 'channelId', { value: data.channelId });
76
105
  Object.defineProperty(this, 'platform', { value: data.platform });
106
+ // Subscribe deferred reaction callbacks now that we have the message ID
107
+ for (const callback of this.deferredReactionCallbacks) {
108
+ const unsubscribe = this.operations.subscribeToReactions(data.id, callback);
109
+ this.reactionUnsubscribers.push(unsubscribe);
110
+ }
111
+ })
112
+ .catch(() => {
113
+ // Errors handled via wait()
77
114
  });
78
115
  }
79
116
  /**
80
117
  * Override addReactions to wait for post to complete first
81
118
  */
82
119
  addReactions(emojis) {
83
- // Chain after the post completes
84
- void this.postPromise.then(() => {
85
- super.addReactions(emojis);
86
- });
120
+ // Chain after the post completes, capturing current pendingReactions
121
+ const currentPendingReactions = this.pendingReactions;
122
+ this.pendingReactions = this.postPromise.then(() => currentPendingReactions);
123
+ for (const emoji of emojis) {
124
+ this.pendingReactions = this.pendingReactions.then(() => this.operations.addReaction(this.id, this.channelId, emoji));
125
+ }
87
126
  return this;
88
127
  }
89
128
  /**
90
- * Wait for post and all reactions to complete
129
+ * Override onReaction to defer subscription until post completes
91
130
  */
92
- async then(onFulfilled, onRejected) {
93
- try {
94
- await this.postPromise;
95
- return await super.then(onFulfilled, onRejected);
96
- }
97
- catch (err) {
98
- if (onRejected) {
99
- return onRejected(err);
100
- }
101
- throw err;
102
- }
131
+ onReaction(callback) {
132
+ this.deferredReactionCallbacks.push(callback);
133
+ return this;
134
+ }
135
+ /**
136
+ * Wait for post to complete.
137
+ * Throws if the post fails - allows callers to handle errors.
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * const msg = channel.postMessage('Hello');
142
+ * await msg.wait(); // throws if post fails
143
+ * console.log(msg.id); // now available
144
+ * ```
145
+ */
146
+ async wait() {
147
+ await this.postPromise;
148
+ return this;
149
+ }
150
+ /**
151
+ * Wait for post and all pending reactions to complete.
152
+ */
153
+ async waitForReactions() {
154
+ await this.postPromise;
155
+ await this.pendingReactions;
103
156
  }
104
157
  }
105
158
  //# sourceMappingURL=Channel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Channel.js","sourceRoot":"","sources":["../src/Channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Channel.js","sourceRoot":"","sources":["../src/Channel.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import type { ChatConfig } from './types.js';
2
- import type { Channel } from './Channel.js';
1
+ import type { ChatConfig } from './types';
2
+ import type { Channel } from './Channel';
3
3
  /**
4
4
  * Abstract base class for chat platform clients
5
5
  * Provides a unified API for Discord and Slack
@@ -1 +1 @@
1
- {"version":3,"file":"ChatClient.d.ts","sourceRoot":"","sources":["../src/ChatClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;GAGG;AACH,8BAAsB,UAAU;IAClB,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU;gBAAlB,MAAM,EAAE,UAAU;IAEjD;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAErD;;OAEG;IACH,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CACrC"}
1
+ {"version":3,"file":"ChatClient.d.ts","sourceRoot":"","sources":["../src/ChatClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC;;;GAGG;AACH,8BAAsB,UAAU;IAClB,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU;gBAAlB,MAAM,EAAE,UAAU;IAEjD;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAErD;;OAEG;IACH,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CACrC"}
@@ -1,11 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChatClient = void 0;
1
4
  /**
2
5
  * Abstract base class for chat platform clients
3
6
  * Provides a unified API for Discord and Slack
4
7
  */
5
- export class ChatClient {
8
+ class ChatClient {
6
9
  config;
7
10
  constructor(config) {
8
11
  this.config = config;
9
12
  }
10
13
  }
14
+ exports.ChatClient = ChatClient;
11
15
  //# sourceMappingURL=ChatClient.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatClient.js","sourceRoot":"","sources":["../src/ChatClient.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,OAAgB,UAAU;IACC;IAA/B,YAA+B,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;CAatD"}
1
+ {"version":3,"file":"ChatClient.js","sourceRoot":"","sources":["../src/ChatClient.ts"],"names":[],"mappings":";;;AAGA;;;GAGG;AACH,MAAsB,UAAU;IACC;IAA/B,YAA+B,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;CAatD;AAdD,gCAcC"}