@urugus/slack-cli 0.2.10 → 0.2.11
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 +65 -30
- package/dist/commands/scheduled.d.ts +3 -0
- package/dist/commands/scheduled.d.ts.map +1 -0
- package/dist/commands/scheduled.js +55 -0
- package/dist/commands/scheduled.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/types/commands.d.ts +6 -0
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/utils/channel-resolver.d.ts.map +1 -1
- package/dist/utils/channel-resolver.js +1 -3
- package/dist/utils/channel-resolver.js.map +1 -1
- package/dist/utils/slack-api-client.d.ts +8 -0
- package/dist/utils/slack-api-client.d.ts.map +1 -1
- package/dist/utils/slack-api-client.js +3 -0
- package/dist/utils/slack-api-client.js.map +1 -1
- package/dist/utils/slack-operations/message-operations.d.ts +2 -1
- package/dist/utils/slack-operations/message-operations.d.ts.map +1 -1
- package/dist/utils/slack-operations/message-operations.js +17 -0
- package/dist/utils/slack-operations/message-operations.js.map +1 -1
- package/package.json +2 -2
- package/src/commands/scheduled.ts +71 -0
- package/src/index.ts +2 -0
- package/src/types/commands.ts +7 -0
- package/src/utils/channel-resolver.ts +1 -5
- package/src/utils/slack-api-client.ts +12 -0
- package/src/utils/slack-operations/message-operations.ts +30 -1
- package/tests/commands/scheduled.test.ts +131 -0
- package/tests/utils/channel-resolver.test.ts +25 -21
- package/tests/utils/slack-api-client.test.ts +65 -47
- package/tests/utils/slack-operations/message-operations.test.ts +19 -0
package/README.md
CHANGED
|
@@ -143,6 +143,23 @@ slack-cli unread --format json
|
|
|
143
143
|
slack-cli unread --format simple
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
+
### List Scheduled Messages
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# List scheduled messages
|
|
150
|
+
slack-cli scheduled
|
|
151
|
+
|
|
152
|
+
# Filter by channel
|
|
153
|
+
slack-cli scheduled -c general
|
|
154
|
+
|
|
155
|
+
# Limit results
|
|
156
|
+
slack-cli scheduled --limit 20
|
|
157
|
+
|
|
158
|
+
# Output in different formats
|
|
159
|
+
slack-cli scheduled --format json
|
|
160
|
+
slack-cli scheduled --format simple
|
|
161
|
+
```
|
|
162
|
+
|
|
146
163
|
### Other Commands
|
|
147
164
|
|
|
148
165
|
```bash
|
|
@@ -162,44 +179,56 @@ slack-cli config set --token NEW_TOKEN
|
|
|
162
179
|
## Options
|
|
163
180
|
|
|
164
181
|
### Global Options
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
|
182
|
+
|
|
183
|
+
| Option | Short | Description |
|
|
184
|
+
| --------- | ----- | ------------------------------ |
|
|
185
|
+
| --profile | -p | Use specific workspace profile |
|
|
168
186
|
|
|
169
187
|
### send command
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
|
173
|
-
| --
|
|
174
|
-
| --
|
|
175
|
-
| --
|
|
176
|
-
| --
|
|
177
|
-
| --
|
|
188
|
+
|
|
189
|
+
| Option | Short | Description |
|
|
190
|
+
| --------- | ----- | ---------------------------------------- |
|
|
191
|
+
| --channel | -c | Target channel name or ID (required) |
|
|
192
|
+
| --message | -m | Message to send |
|
|
193
|
+
| --file | -f | File containing message content |
|
|
194
|
+
| --thread | -t | Thread timestamp to reply to |
|
|
195
|
+
| --at | | Schedule time (Unix seconds or ISO 8601) |
|
|
196
|
+
| --after | | Schedule message after N minutes |
|
|
178
197
|
|
|
179
198
|
### channels command
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
|
183
|
-
| --
|
|
184
|
-
| --
|
|
185
|
-
| --
|
|
199
|
+
|
|
200
|
+
| Option | Short | Description |
|
|
201
|
+
| ------------------ | ----- | -------------------------------------------------------------- |
|
|
202
|
+
| --type | | Channel type: public, private, im, mpim, all (default: public) |
|
|
203
|
+
| --include-archived | | Include archived channels |
|
|
204
|
+
| --format | | Output format: table, simple, json (default: table) |
|
|
205
|
+
| --limit | | Maximum number of channels to list (default: 100) |
|
|
186
206
|
|
|
187
207
|
### history command
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
|
191
|
-
| --
|
|
192
|
-
| --
|
|
208
|
+
|
|
209
|
+
| Option | Short | Description |
|
|
210
|
+
| --------- | ----- | ------------------------------------------------------ |
|
|
211
|
+
| --channel | -c | Target channel name or ID (required) |
|
|
212
|
+
| --number | -n | Number of messages to retrieve (default: 10) |
|
|
213
|
+
| --since | | Get messages since specific date (YYYY-MM-DD HH:MM:SS) |
|
|
193
214
|
|
|
194
215
|
### unread command
|
|
195
|
-
| Option | Short | Description |
|
|
196
|
-
|--------|-------|-------------|
|
|
197
|
-
| --channel | -c | Get unread for specific channel |
|
|
198
|
-
| --format | | Output format: table, simple, json (default: table) |
|
|
199
|
-
| --count-only | | Show only unread counts |
|
|
200
|
-
| --limit | | Maximum number of channels to display (default: 50) |
|
|
201
|
-
| --mark-read | | Mark messages as read after fetching |
|
|
202
216
|
|
|
217
|
+
| Option | Short | Description |
|
|
218
|
+
| ------------ | ----- | --------------------------------------------------- |
|
|
219
|
+
| --channel | -c | Get unread for specific channel |
|
|
220
|
+
| --format | | Output format: table, simple, json (default: table) |
|
|
221
|
+
| --count-only | | Show only unread counts |
|
|
222
|
+
| --limit | | Maximum number of channels to display (default: 50) |
|
|
223
|
+
| --mark-read | | Mark messages as read after fetching |
|
|
224
|
+
|
|
225
|
+
### scheduled command
|
|
226
|
+
|
|
227
|
+
| Option | Short | Description |
|
|
228
|
+
| --------- | ----- | ---------------------------------------------------------- |
|
|
229
|
+
| --channel | -c | Filter by channel name or ID |
|
|
230
|
+
| --limit | | Maximum number of scheduled messages to list (default: 50) |
|
|
231
|
+
| --format | | Output format: table, simple, json (default: table) |
|
|
203
232
|
|
|
204
233
|
## Required Permissions
|
|
205
234
|
|
|
@@ -216,19 +245,25 @@ Your Slack API token needs the following scopes:
|
|
|
216
245
|
## Advanced Features
|
|
217
246
|
|
|
218
247
|
### Rate Limiting
|
|
248
|
+
|
|
219
249
|
The CLI includes built-in rate limiting to handle Slack API limits:
|
|
250
|
+
|
|
220
251
|
- Concurrent requests: 3
|
|
221
252
|
- Automatic retry with exponential backoff (max 3 retries)
|
|
222
253
|
- Graceful error handling for rate limit errors
|
|
223
254
|
|
|
224
255
|
### Output Formats
|
|
256
|
+
|
|
225
257
|
Most commands support multiple output formats:
|
|
258
|
+
|
|
226
259
|
- `table` (default) - Human-readable table format
|
|
227
260
|
- `simple` - Simplified text output
|
|
228
261
|
- `json` - Machine-readable JSON format
|
|
229
262
|
|
|
230
263
|
### Markdown Support
|
|
264
|
+
|
|
231
265
|
Messages sent via the `send` command automatically support Slack's mrkdwn formatting:
|
|
266
|
+
|
|
232
267
|
- `*bold*` for bold text
|
|
233
268
|
- `_italic_` for italic text
|
|
234
269
|
- `~strikethrough~` for strikethrough
|
|
@@ -240,4 +275,4 @@ Messages sent via the `send` command automatically support Slack's mrkdwn format
|
|
|
240
275
|
|
|
241
276
|
## License
|
|
242
277
|
|
|
243
|
-
MIT
|
|
278
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled.d.ts","sourceRoot":"","sources":["../../src/commands/scheduled.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkCpC,wBAAgB,qBAAqB,IAAI,OAAO,CAoC/C"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setupScheduledCommand = setupScheduledCommand;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const command_wrapper_1 = require("../utils/command-wrapper");
|
|
6
|
+
const client_factory_1 = require("../utils/client-factory");
|
|
7
|
+
const option_parsers_1 = require("../utils/option-parsers");
|
|
8
|
+
const validators_1 = require("../utils/validators");
|
|
9
|
+
function formatPostAt(postAt) {
|
|
10
|
+
return new Date(postAt * 1000).toISOString();
|
|
11
|
+
}
|
|
12
|
+
function renderTable(messages) {
|
|
13
|
+
const rows = messages.map((message) => ({
|
|
14
|
+
id: message.id,
|
|
15
|
+
channel: message.channel_id,
|
|
16
|
+
post_at: formatPostAt(message.post_at),
|
|
17
|
+
text: message.text || '',
|
|
18
|
+
}));
|
|
19
|
+
console.table(rows);
|
|
20
|
+
}
|
|
21
|
+
function renderSimple(messages) {
|
|
22
|
+
for (const message of messages) {
|
|
23
|
+
console.log(`${formatPostAt(message.post_at)} ${message.channel_id} ${message.id} ${message.text || ''}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function setupScheduledCommand() {
|
|
27
|
+
const scheduledCommand = new commander_1.Command('scheduled')
|
|
28
|
+
.description('List scheduled messages')
|
|
29
|
+
.option('-c, --channel <channel>', 'Filter by channel name or ID')
|
|
30
|
+
.option('--limit <number>', 'Maximum number of scheduled messages to list', '50')
|
|
31
|
+
.option('--format <format>', 'Output format: table, simple, json', 'table')
|
|
32
|
+
.option('--profile <profile>', 'Use specific workspace profile')
|
|
33
|
+
.hook('preAction', (0, validators_1.createValidationHook)([validators_1.optionValidators.format]))
|
|
34
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
35
|
+
const client = await (0, client_factory_1.createSlackClient)(options.profile);
|
|
36
|
+
const limit = (0, option_parsers_1.parseLimit)(options.limit, 50);
|
|
37
|
+
const messages = await client.listScheduledMessages(options.channel, limit);
|
|
38
|
+
if (messages.length === 0) {
|
|
39
|
+
console.log('No scheduled messages found');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const format = (0, option_parsers_1.parseFormat)(options.format);
|
|
43
|
+
if (format === 'json') {
|
|
44
|
+
console.log(JSON.stringify(messages, null, 2));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (format === 'simple') {
|
|
48
|
+
renderSimple(messages);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
renderTable(messages);
|
|
52
|
+
}));
|
|
53
|
+
return scheduledCommand;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=scheduled.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled.js","sourceRoot":"","sources":["../../src/commands/scheduled.ts"],"names":[],"mappings":";;AAkCA,sDAoCC;AAtED,yCAAoC;AACpC,8DAAuD;AACvD,4DAA4D;AAE5D,4DAAkE;AAClE,oDAA6E;AAE7E,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,WAAW,CAClB,QAAmF;IAEnF,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACtC,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,OAAO,EAAE,OAAO,CAAC,UAAU;QAC3B,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC;QACtC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE;KACzB,CAAC,CAAC,CAAC;IAEJ,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,SAAS,YAAY,CACnB,QAAmF;IAEnF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CACT,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,EAAE,IAAI,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,CAC7F,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAgB,qBAAqB;IACnC,MAAM,gBAAgB,GAAG,IAAI,mBAAO,CAAC,WAAW,CAAC;SAC9C,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CAAC,yBAAyB,EAAE,8BAA8B,CAAC;SACjE,MAAM,CAAC,kBAAkB,EAAE,8CAA8C,EAAE,IAAI,CAAC;SAChF,MAAM,CAAC,mBAAmB,EAAE,oCAAoC,EAAE,OAAO,CAAC;SAC1E,MAAM,CAAC,qBAAqB,EAAE,gCAAgC,CAAC;SAC/D,IAAI,CAAC,WAAW,EAAE,IAAA,iCAAoB,EAAC,CAAC,6BAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;SAClE,MAAM,CACL,IAAA,6BAAW,EAAC,KAAK,EAAE,OAAyB,EAAE,EAAE;QAC9C,MAAM,MAAM,GAAG,MAAM,IAAA,kCAAiB,EAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,IAAA,2BAAU,EAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAE5E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;YAC3C,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,4BAAW,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAE3C,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/C,OAAO;QACT,CAAC;QAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,YAAY,CAAC,QAAQ,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QAED,WAAW,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC,CAAC,CACH,CAAC;IAEJ,OAAO,gBAAgB,CAAC;AAC1B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const send_1 = require("./commands/send");
|
|
|
7
7
|
const channels_1 = require("./commands/channels");
|
|
8
8
|
const history_1 = require("./commands/history");
|
|
9
9
|
const unread_1 = require("./commands/unread");
|
|
10
|
+
const scheduled_1 = require("./commands/scheduled");
|
|
10
11
|
const fs_1 = require("fs");
|
|
11
12
|
const path_1 = require("path");
|
|
12
13
|
const program = new commander_1.Command();
|
|
@@ -19,5 +20,6 @@ program.addCommand((0, send_1.setupSendCommand)());
|
|
|
19
20
|
program.addCommand((0, channels_1.setupChannelsCommand)());
|
|
20
21
|
program.addCommand((0, history_1.setupHistoryCommand)());
|
|
21
22
|
program.addCommand((0, unread_1.setupUnreadCommand)());
|
|
23
|
+
program.addCommand((0, scheduled_1.setupScheduledCommand)());
|
|
22
24
|
program.parse();
|
|
23
25
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,yCAAoC;AACpC,8CAAuD;AACvD,0CAAmD;AACnD,kDAA2D;AAC3D,gDAAyD;AACzD,8CAAuD;AACvD,2BAAkC;AAClC,+BAA4B;AAE5B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,iCAAiC;AACjC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAC7F,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AAEpC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,yCAAyC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAElG,OAAO,CAAC,UAAU,CAAC,IAAA,2BAAkB,GAAE,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,IAAA,uBAAgB,GAAE,CAAC,CAAC;AACvC,OAAO,CAAC,UAAU,CAAC,IAAA,+BAAoB,GAAE,CAAC,CAAC;AAC3C,OAAO,CAAC,UAAU,CAAC,IAAA,6BAAmB,GAAE,CAAC,CAAC;AAC1C,OAAO,CAAC,UAAU,CAAC,IAAA,2BAAkB,GAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,yCAAoC;AACpC,8CAAuD;AACvD,0CAAmD;AACnD,kDAA2D;AAC3D,gDAAyD;AACzD,8CAAuD;AACvD,oDAA6D;AAC7D,2BAAkC;AAClC,+BAA4B;AAE5B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,iCAAiC;AACjC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAC7F,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AAEpC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,yCAAyC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAElG,OAAO,CAAC,UAAU,CAAC,IAAA,2BAAkB,GAAE,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,IAAA,uBAAgB,GAAE,CAAC,CAAC;AACvC,OAAO,CAAC,UAAU,CAAC,IAAA,+BAAoB,GAAE,CAAC,CAAC;AAC3C,OAAO,CAAC,UAAU,CAAC,IAAA,6BAAmB,GAAE,CAAC,CAAC;AAC1C,OAAO,CAAC,UAAU,CAAC,IAAA,2BAAkB,GAAE,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,IAAA,iCAAqB,GAAE,CAAC,CAAC;AAE5C,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
package/dist/types/commands.d.ts
CHANGED
|
@@ -20,6 +20,12 @@ export interface SendOptions {
|
|
|
20
20
|
after?: string;
|
|
21
21
|
profile?: string;
|
|
22
22
|
}
|
|
23
|
+
export interface ScheduledOptions {
|
|
24
|
+
channel?: string;
|
|
25
|
+
limit?: string;
|
|
26
|
+
format?: 'table' | 'simple' | 'json';
|
|
27
|
+
profile?: string;
|
|
28
|
+
}
|
|
23
29
|
export interface ChannelsOptions {
|
|
24
30
|
type: 'public' | 'private' | 'im' | 'mpim' | 'all';
|
|
25
31
|
includeArchived: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/types/commands.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;IACnD,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/types/commands.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;IACnD,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/channel-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AAE3D,qBAAa,eAAe;IAC1B;;OAEG;IACH,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"channel-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/channel-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AAE3D,qBAAa,eAAe;IAC1B;;OAEG;IACH,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO;IAI7C;;OAEG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,GAAG,SAAS;IAc1E;;OAEG;IACH,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE;IAOjF;;OAEG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK;IAcpE;;OAEG;IACG,gBAAgB,CACpB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,mBAAmB,GAC/B,OAAO,CAAC,MAAM,CAAC;CAgBnB;AAGD,eAAO,MAAM,eAAe,iBAAwB,CAAC"}
|
|
@@ -6,9 +6,7 @@ class ChannelResolver {
|
|
|
6
6
|
* Check if the given string is a channel ID
|
|
7
7
|
*/
|
|
8
8
|
isChannelId(channelNameOrId) {
|
|
9
|
-
return (channelNameOrId
|
|
10
|
-
channelNameOrId.startsWith('D') ||
|
|
11
|
-
channelNameOrId.startsWith('G'));
|
|
9
|
+
return /^[CDG][A-Z0-9]{8,}$/.test(channelNameOrId);
|
|
12
10
|
}
|
|
13
11
|
/**
|
|
14
12
|
* Find a channel by name from the given list
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-resolver.js","sourceRoot":"","sources":["../../src/utils/channel-resolver.ts"],"names":[],"mappings":";;;AAIA,MAAa,eAAe;IAC1B;;OAEG;IACH,WAAW,CAAC,eAAuB;QACjC,OAAO,
|
|
1
|
+
{"version":3,"file":"channel-resolver.js","sourceRoot":"","sources":["../../src/utils/channel-resolver.ts"],"names":[],"mappings":";;;AAIA,MAAa,eAAe;IAC1B;;OAEG;IACH,WAAW,CAAC,eAAuB;QACjC,OAAO,qBAAqB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,WAAmB,EAAE,QAAmB;QAClD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YACzB,oBAAoB;YACpB,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;gBAAE,OAAO,IAAI,CAAC;YACxC,yBAAyB;YACzB,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;gBAAE,OAAO,IAAI,CAAC;YACzD,yBAAyB;YACzB,IAAI,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE;gBAAE,OAAO,IAAI,CAAC;YACrE,6BAA6B;YAC7B,IAAI,CAAC,CAAC,eAAe,KAAK,WAAW;gBAAE,OAAO,IAAI,CAAC;YACnD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAC,WAAmB,EAAE,QAAmB,EAAE,KAAK,GAAG,CAAC;QACpE,OAAO,QAAQ;aACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC;aACxE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;aACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAc,CAAC,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,mBAAmB,CAAC,WAAmB,EAAE,QAAmB;QAC1D,MAAM,eAAe,GAAG,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAEvE,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,KAAK,CACd,YAAY,WAAW,2CAA2C,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/F,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,KAAK,CACd,YAAY,WAAW,0DAA0D,CAClF,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CACpB,eAAuB,EACvB,WAAgC;QAEhC,mCAAmC;QACnC,IAAI,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,EAAE,CAAC;YACtC,OAAO,eAAe,CAAC;QACzB,CAAC;QAED,iDAAiD;QACjD,MAAM,QAAQ,GAAG,MAAM,WAAW,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;QAE5D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,CAAC,mBAAmB,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;QAC5D,CAAC;QAED,OAAO,OAAO,CAAC,EAAE,CAAC;IACpB,CAAC;CACF;AA1ED,0CA0EC;AAED,8BAA8B;AACjB,QAAA,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC"}
|
|
@@ -50,6 +50,13 @@ export interface Message {
|
|
|
50
50
|
attachments?: unknown[];
|
|
51
51
|
blocks?: unknown[];
|
|
52
52
|
}
|
|
53
|
+
export interface ScheduledMessage {
|
|
54
|
+
id: string;
|
|
55
|
+
channel_id: string;
|
|
56
|
+
post_at: number;
|
|
57
|
+
date_created: number;
|
|
58
|
+
text?: string;
|
|
59
|
+
}
|
|
53
60
|
export interface HistoryResult {
|
|
54
61
|
messages: Message[];
|
|
55
62
|
users: Map<string, string>;
|
|
@@ -65,6 +72,7 @@ export declare class SlackApiClient {
|
|
|
65
72
|
constructor(token: string);
|
|
66
73
|
sendMessage(channel: string, text: string, thread_ts?: string): Promise<ChatPostMessageResponse>;
|
|
67
74
|
scheduleMessage(channel: string, text: string, post_at: number, thread_ts?: string): Promise<ChatScheduleMessageResponse>;
|
|
75
|
+
listScheduledMessages(channel?: string, limit?: number): Promise<ScheduledMessage[]>;
|
|
68
76
|
listChannels(options: ListChannelsOptions): Promise<Channel[]>;
|
|
69
77
|
getHistory(channel: string, options: HistoryOptions): Promise<HistoryResult>;
|
|
70
78
|
listUnreadChannels(): Promise<Channel[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-api-client.d.ts","sourceRoot":"","sources":["../../src/utils/slack-api-client.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"slack-api-client.d.ts","sourceRoot":"","sources":["../../src/utils/slack-api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,9 @@ class SlackApiClient {
|
|
|
14
14
|
async scheduleMessage(channel, text, post_at, thread_ts) {
|
|
15
15
|
return this.messageOps.scheduleMessage(channel, text, post_at, thread_ts);
|
|
16
16
|
}
|
|
17
|
+
async listScheduledMessages(channel, limit = 50) {
|
|
18
|
+
return this.messageOps.listScheduledMessages(channel, limit);
|
|
19
|
+
}
|
|
17
20
|
async listChannels(options) {
|
|
18
21
|
return this.channelOps.listChannels(options);
|
|
19
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-api-client.js","sourceRoot":"","sources":["../../src/utils/slack-api-client.ts"],"names":[],"mappings":";;;AACA,8EAA0E;AAC1E,8EAA0E;
|
|
1
|
+
{"version":3,"file":"slack-api-client.js","sourceRoot":"","sources":["../../src/utils/slack-api-client.ts"],"names":[],"mappings":";;;AACA,8EAA0E;AAC1E,8EAA0E;AA4E1E,MAAa,cAAc;IAIzB,YAAY,KAAa;QACvB,IAAI,CAAC,UAAU,GAAG,IAAI,sCAAiB,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,IAAI,sCAAiB,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,WAAW,CACf,OAAe,EACf,IAAY,EACZ,SAAkB;QAElB,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,OAAe,EACf,IAAY,EACZ,OAAe,EACf,SAAkB;QAElB,OAAO,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,OAAgB,EAAE,KAAK,GAAG,EAAE;QACtD,OAAO,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAA4B;QAC7C,OAAO,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAe,EAAE,OAAuB;QACvD,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,OAAO,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,eAAuB;QAC5C,OAAO,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;CACF;AAjDD,wCAiDC;AAEY,QAAA,cAAc,GAAG;IAC5B,YAAY,EAAE,KAAK,EAAE,KAAa,EAAE,OAA4B,EAAsB,EAAE;QACtF,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;CACF,CAAC"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { ChatPostMessageResponse, ChatScheduleMessageResponse } from '@slack/web-api';
|
|
2
2
|
import { BaseSlackClient } from './base-client';
|
|
3
|
-
import { HistoryOptions, HistoryResult, ChannelUnreadResult } from '../slack-api-client';
|
|
3
|
+
import { HistoryOptions, HistoryResult, ChannelUnreadResult, ScheduledMessage } from '../slack-api-client';
|
|
4
4
|
export declare class MessageOperations extends BaseSlackClient {
|
|
5
5
|
private channelOps;
|
|
6
6
|
constructor(token: string);
|
|
7
7
|
sendMessage(channel: string, text: string, thread_ts?: string): Promise<ChatPostMessageResponse>;
|
|
8
8
|
scheduleMessage(channel: string, text: string, post_at: number, thread_ts?: string): Promise<ChatScheduleMessageResponse>;
|
|
9
|
+
listScheduledMessages(channel?: string, limit?: number): Promise<ScheduledMessage[]>;
|
|
9
10
|
getHistory(channel: string, options: HistoryOptions): Promise<HistoryResult>;
|
|
10
11
|
getChannelUnread(channelNameOrId: string): Promise<ChannelUnreadResult>;
|
|
11
12
|
private fetchUserInfo;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-operations.d.ts","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EAGvB,2BAA2B,EAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,
|
|
1
|
+
{"version":3,"file":"message-operations.d.ts","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EAGvB,2BAA2B,EAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAEL,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,qBAAqB,CAAC;AAI7B,qBAAa,iBAAkB,SAAQ,eAAe;IACpD,OAAO,CAAC,UAAU,CAAoB;gBAE1B,KAAK,EAAE,MAAM;IAKnB,WAAW,CACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,uBAAuB,CAAC;IAa7B,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,2BAA2B,CAAC;IAcjC,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAuBhF,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAyB5E,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAsC/D,aAAa;IAoBrB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMnD"}
|
|
@@ -32,6 +32,23 @@ class MessageOperations extends base_client_1.BaseSlackClient {
|
|
|
32
32
|
}
|
|
33
33
|
return await this.client.chat.scheduleMessage(params);
|
|
34
34
|
}
|
|
35
|
+
async listScheduledMessages(channel, limit = 50) {
|
|
36
|
+
const channelId = channel
|
|
37
|
+
? await channel_resolver_1.channelResolver.resolveChannelId(channel, () => this.channelOps.listChannels({
|
|
38
|
+
types: 'public_channel,private_channel,im,mpim',
|
|
39
|
+
exclude_archived: true,
|
|
40
|
+
limit: constants_1.DEFAULTS.CHANNELS_LIMIT,
|
|
41
|
+
}))
|
|
42
|
+
: undefined;
|
|
43
|
+
const params = {
|
|
44
|
+
limit,
|
|
45
|
+
};
|
|
46
|
+
if (channelId) {
|
|
47
|
+
params.channel = channelId;
|
|
48
|
+
}
|
|
49
|
+
const response = await this.client.chat.scheduledMessages.list(params);
|
|
50
|
+
return (response.scheduled_messages || []);
|
|
51
|
+
}
|
|
35
52
|
async getHistory(channel, options) {
|
|
36
53
|
// Resolve channel name to ID if needed
|
|
37
54
|
const channelId = await channel_resolver_1.channelResolver.resolveChannelId(channel, () => this.channelOps.listChannels({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-operations.js","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":";;;AAMA,+CAAgD;AAChD,0DAAsD;AACtD,4CAAwC;
|
|
1
|
+
{"version":3,"file":"message-operations.js","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@urugus/slack-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
4
4
|
"description": "A command-line tool for sending messages to Slack",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"slack-cli": "dist/index.js"
|
|
7
|
+
"slack-cli": "./dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { wrapCommand } from '../utils/command-wrapper';
|
|
3
|
+
import { createSlackClient } from '../utils/client-factory';
|
|
4
|
+
import { ScheduledOptions } from '../types/commands';
|
|
5
|
+
import { parseFormat, parseLimit } from '../utils/option-parsers';
|
|
6
|
+
import { createValidationHook, optionValidators } from '../utils/validators';
|
|
7
|
+
|
|
8
|
+
function formatPostAt(postAt: number): string {
|
|
9
|
+
return new Date(postAt * 1000).toISOString();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function renderTable(
|
|
13
|
+
messages: Array<{ id: string; channel_id: string; post_at: number; text?: string }>
|
|
14
|
+
) {
|
|
15
|
+
const rows = messages.map((message) => ({
|
|
16
|
+
id: message.id,
|
|
17
|
+
channel: message.channel_id,
|
|
18
|
+
post_at: formatPostAt(message.post_at),
|
|
19
|
+
text: message.text || '',
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
console.table(rows);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function renderSimple(
|
|
26
|
+
messages: Array<{ id: string; channel_id: string; post_at: number; text?: string }>
|
|
27
|
+
) {
|
|
28
|
+
for (const message of messages) {
|
|
29
|
+
console.log(
|
|
30
|
+
`${formatPostAt(message.post_at)} ${message.channel_id} ${message.id} ${message.text || ''}`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function setupScheduledCommand(): Command {
|
|
36
|
+
const scheduledCommand = new Command('scheduled')
|
|
37
|
+
.description('List scheduled messages')
|
|
38
|
+
.option('-c, --channel <channel>', 'Filter by channel name or ID')
|
|
39
|
+
.option('--limit <number>', 'Maximum number of scheduled messages to list', '50')
|
|
40
|
+
.option('--format <format>', 'Output format: table, simple, json', 'table')
|
|
41
|
+
.option('--profile <profile>', 'Use specific workspace profile')
|
|
42
|
+
.hook('preAction', createValidationHook([optionValidators.format]))
|
|
43
|
+
.action(
|
|
44
|
+
wrapCommand(async (options: ScheduledOptions) => {
|
|
45
|
+
const client = await createSlackClient(options.profile);
|
|
46
|
+
const limit = parseLimit(options.limit, 50);
|
|
47
|
+
const messages = await client.listScheduledMessages(options.channel, limit);
|
|
48
|
+
|
|
49
|
+
if (messages.length === 0) {
|
|
50
|
+
console.log('No scheduled messages found');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const format = parseFormat(options.format);
|
|
55
|
+
|
|
56
|
+
if (format === 'json') {
|
|
57
|
+
console.log(JSON.stringify(messages, null, 2));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (format === 'simple') {
|
|
62
|
+
renderSimple(messages);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
renderTable(messages);
|
|
67
|
+
})
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return scheduledCommand;
|
|
71
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { setupSendCommand } from './commands/send';
|
|
|
5
5
|
import { setupChannelsCommand } from './commands/channels';
|
|
6
6
|
import { setupHistoryCommand } from './commands/history';
|
|
7
7
|
import { setupUnreadCommand } from './commands/unread';
|
|
8
|
+
import { setupScheduledCommand } from './commands/scheduled';
|
|
8
9
|
import { readFileSync } from 'fs';
|
|
9
10
|
import { join } from 'path';
|
|
10
11
|
|
|
@@ -21,5 +22,6 @@ program.addCommand(setupSendCommand());
|
|
|
21
22
|
program.addCommand(setupChannelsCommand());
|
|
22
23
|
program.addCommand(setupHistoryCommand());
|
|
23
24
|
program.addCommand(setupUnreadCommand());
|
|
25
|
+
program.addCommand(setupScheduledCommand());
|
|
24
26
|
|
|
25
27
|
program.parse();
|
package/src/types/commands.ts
CHANGED
|
@@ -25,6 +25,13 @@ export interface SendOptions {
|
|
|
25
25
|
profile?: string;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
export interface ScheduledOptions {
|
|
29
|
+
channel?: string;
|
|
30
|
+
limit?: string;
|
|
31
|
+
format?: 'table' | 'simple' | 'json';
|
|
32
|
+
profile?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
28
35
|
export interface ChannelsOptions {
|
|
29
36
|
type: 'public' | 'private' | 'im' | 'mpim' | 'all';
|
|
30
37
|
includeArchived: boolean;
|
|
@@ -7,11 +7,7 @@ export class ChannelResolver {
|
|
|
7
7
|
* Check if the given string is a channel ID
|
|
8
8
|
*/
|
|
9
9
|
isChannelId(channelNameOrId: string): boolean {
|
|
10
|
-
return (
|
|
11
|
-
channelNameOrId.startsWith('C') ||
|
|
12
|
-
channelNameOrId.startsWith('D') ||
|
|
13
|
-
channelNameOrId.startsWith('G')
|
|
14
|
-
);
|
|
10
|
+
return /^[CDG][A-Z0-9]{8,}$/.test(channelNameOrId);
|
|
15
11
|
}
|
|
16
12
|
|
|
17
13
|
/**
|
|
@@ -57,6 +57,14 @@ export interface Message {
|
|
|
57
57
|
blocks?: unknown[];
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
export interface ScheduledMessage {
|
|
61
|
+
id: string;
|
|
62
|
+
channel_id: string;
|
|
63
|
+
post_at: number;
|
|
64
|
+
date_created: number;
|
|
65
|
+
text?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
60
68
|
export interface HistoryResult {
|
|
61
69
|
messages: Message[];
|
|
62
70
|
users: Map<string, string>;
|
|
@@ -94,6 +102,10 @@ export class SlackApiClient {
|
|
|
94
102
|
return this.messageOps.scheduleMessage(channel, text, post_at, thread_ts);
|
|
95
103
|
}
|
|
96
104
|
|
|
105
|
+
async listScheduledMessages(channel?: string, limit = 50): Promise<ScheduledMessage[]> {
|
|
106
|
+
return this.messageOps.listScheduledMessages(channel, limit);
|
|
107
|
+
}
|
|
108
|
+
|
|
97
109
|
async listChannels(options: ListChannelsOptions): Promise<Channel[]> {
|
|
98
110
|
return this.channelOps.listChannels(options);
|
|
99
111
|
}
|
|
@@ -7,7 +7,13 @@ import {
|
|
|
7
7
|
import { BaseSlackClient } from './base-client';
|
|
8
8
|
import { channelResolver } from '../channel-resolver';
|
|
9
9
|
import { DEFAULTS } from '../constants';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
Message,
|
|
12
|
+
HistoryOptions,
|
|
13
|
+
HistoryResult,
|
|
14
|
+
ChannelUnreadResult,
|
|
15
|
+
ScheduledMessage,
|
|
16
|
+
} from '../slack-api-client';
|
|
11
17
|
import { ChannelOperations } from './channel-operations';
|
|
12
18
|
import { extractAllUserIds } from '../mention-utils';
|
|
13
19
|
|
|
@@ -55,6 +61,29 @@ export class MessageOperations extends BaseSlackClient {
|
|
|
55
61
|
return await this.client.chat.scheduleMessage(params);
|
|
56
62
|
}
|
|
57
63
|
|
|
64
|
+
async listScheduledMessages(channel?: string, limit = 50): Promise<ScheduledMessage[]> {
|
|
65
|
+
const channelId = channel
|
|
66
|
+
? await channelResolver.resolveChannelId(channel, () =>
|
|
67
|
+
this.channelOps.listChannels({
|
|
68
|
+
types: 'public_channel,private_channel,im,mpim',
|
|
69
|
+
exclude_archived: true,
|
|
70
|
+
limit: DEFAULTS.CHANNELS_LIMIT,
|
|
71
|
+
})
|
|
72
|
+
)
|
|
73
|
+
: undefined;
|
|
74
|
+
|
|
75
|
+
const params: { channel?: string; limit: number } = {
|
|
76
|
+
limit,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
if (channelId) {
|
|
80
|
+
params.channel = channelId;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const response = await this.client.chat.scheduledMessages.list(params as any);
|
|
84
|
+
return (response.scheduled_messages || []) as ScheduledMessage[];
|
|
85
|
+
}
|
|
86
|
+
|
|
58
87
|
async getHistory(channel: string, options: HistoryOptions): Promise<HistoryResult> {
|
|
59
88
|
// Resolve channel name to ID if needed
|
|
60
89
|
const channelId = await channelResolver.resolveChannelId(channel, () =>
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { setupScheduledCommand } from '../../src/commands/scheduled';
|
|
3
|
+
import { SlackApiClient } from '../../src/utils/slack-api-client';
|
|
4
|
+
import { ProfileConfigManager } from '../../src/utils/profile-config';
|
|
5
|
+
import { setupMockConsole, createTestProgram, restoreMocks } from '../test-utils';
|
|
6
|
+
|
|
7
|
+
vi.mock('../../src/utils/slack-api-client');
|
|
8
|
+
vi.mock('../../src/utils/profile-config');
|
|
9
|
+
|
|
10
|
+
describe('scheduled command', () => {
|
|
11
|
+
let program: any;
|
|
12
|
+
let mockSlackClient: SlackApiClient;
|
|
13
|
+
let mockConfigManager: ProfileConfigManager;
|
|
14
|
+
let mockConsole: any;
|
|
15
|
+
let tableSpy: any;
|
|
16
|
+
|
|
17
|
+
const mockScheduledMessages = [
|
|
18
|
+
{
|
|
19
|
+
id: 'Q123',
|
|
20
|
+
channel_id: 'C1234567890',
|
|
21
|
+
post_at: 1770855000,
|
|
22
|
+
date_created: 1770854400,
|
|
23
|
+
text: 'Scheduled message 1',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: 'Q456',
|
|
27
|
+
channel_id: 'C0987654321',
|
|
28
|
+
post_at: 1770858600,
|
|
29
|
+
date_created: 1770854400,
|
|
30
|
+
text: 'Scheduled message 2',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
vi.clearAllMocks();
|
|
36
|
+
|
|
37
|
+
mockConfigManager = new ProfileConfigManager();
|
|
38
|
+
vi.mocked(ProfileConfigManager).mockReturnValue(mockConfigManager);
|
|
39
|
+
|
|
40
|
+
mockSlackClient = new SlackApiClient('test-token');
|
|
41
|
+
vi.mocked(SlackApiClient).mockReturnValue(mockSlackClient);
|
|
42
|
+
|
|
43
|
+
mockConsole = setupMockConsole();
|
|
44
|
+
tableSpy = vi.spyOn(console, 'table').mockImplementation(() => {});
|
|
45
|
+
|
|
46
|
+
program = createTestProgram();
|
|
47
|
+
program.addCommand(setupScheduledCommand());
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
restoreMocks();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should list scheduled messages in table format by default', async () => {
|
|
55
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
56
|
+
token: 'test-token',
|
|
57
|
+
updatedAt: new Date().toISOString(),
|
|
58
|
+
});
|
|
59
|
+
vi.mocked(mockSlackClient.listScheduledMessages).mockResolvedValue(
|
|
60
|
+
mockScheduledMessages as any
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
await program.parseAsync(['node', 'slack-cli', 'scheduled']);
|
|
64
|
+
|
|
65
|
+
expect(mockSlackClient.listScheduledMessages).toHaveBeenCalledWith(undefined, 50);
|
|
66
|
+
expect(tableSpy).toHaveBeenCalled();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should filter by channel and limit', async () => {
|
|
70
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
71
|
+
token: 'test-token',
|
|
72
|
+
updatedAt: new Date().toISOString(),
|
|
73
|
+
});
|
|
74
|
+
vi.mocked(mockSlackClient.listScheduledMessages).mockResolvedValue(
|
|
75
|
+
mockScheduledMessages as any
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
await program.parseAsync([
|
|
79
|
+
'node',
|
|
80
|
+
'slack-cli',
|
|
81
|
+
'scheduled',
|
|
82
|
+
'--channel',
|
|
83
|
+
'general',
|
|
84
|
+
'--limit',
|
|
85
|
+
'10',
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
expect(mockSlackClient.listScheduledMessages).toHaveBeenCalledWith('general', 10);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should output json format', async () => {
|
|
92
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
93
|
+
token: 'test-token',
|
|
94
|
+
updatedAt: new Date().toISOString(),
|
|
95
|
+
});
|
|
96
|
+
vi.mocked(mockSlackClient.listScheduledMessages).mockResolvedValue(
|
|
97
|
+
mockScheduledMessages as any
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
await program.parseAsync(['node', 'slack-cli', 'scheduled', '--format', 'json']);
|
|
101
|
+
|
|
102
|
+
expect(mockConsole.logSpy).toHaveBeenCalledWith(expect.stringContaining('"id": "Q123"'));
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should output simple format', async () => {
|
|
106
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
107
|
+
token: 'test-token',
|
|
108
|
+
updatedAt: new Date().toISOString(),
|
|
109
|
+
});
|
|
110
|
+
vi.mocked(mockSlackClient.listScheduledMessages).mockResolvedValue(
|
|
111
|
+
mockScheduledMessages as any
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
await program.parseAsync(['node', 'slack-cli', 'scheduled', '--format', 'simple']);
|
|
115
|
+
|
|
116
|
+
expect(mockConsole.logSpy).toHaveBeenCalledWith(expect.stringContaining('Q123'));
|
|
117
|
+
expect(mockConsole.logSpy).toHaveBeenCalledWith(expect.stringContaining('Q456'));
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should show empty message when no scheduled messages', async () => {
|
|
121
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
122
|
+
token: 'test-token',
|
|
123
|
+
updatedAt: new Date().toISOString(),
|
|
124
|
+
});
|
|
125
|
+
vi.mocked(mockSlackClient.listScheduledMessages).mockResolvedValue([] as any);
|
|
126
|
+
|
|
127
|
+
await program.parseAsync(['node', 'slack-cli', 'scheduled']);
|
|
128
|
+
|
|
129
|
+
expect(mockConsole.logSpy).toHaveBeenCalledWith('No scheduled messages found');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -10,21 +10,21 @@ describe('ChannelResolver', () => {
|
|
|
10
10
|
resolver = new ChannelResolver();
|
|
11
11
|
mockChannels = [
|
|
12
12
|
{
|
|
13
|
-
id: '
|
|
13
|
+
id: 'C1234567890',
|
|
14
14
|
name: 'general',
|
|
15
15
|
is_private: false,
|
|
16
16
|
created: 1234567890,
|
|
17
17
|
is_member: true,
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
id: '
|
|
20
|
+
id: 'C0987654321',
|
|
21
21
|
name: 'random',
|
|
22
22
|
is_private: false,
|
|
23
23
|
created: 1234567890,
|
|
24
24
|
is_member: true,
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
id: '
|
|
27
|
+
id: 'C1111111111',
|
|
28
28
|
name: 'dev-team',
|
|
29
29
|
is_private: false,
|
|
30
30
|
created: 1234567890,
|
|
@@ -32,7 +32,7 @@ describe('ChannelResolver', () => {
|
|
|
32
32
|
name_normalized: 'dev-team',
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
|
-
id: '
|
|
35
|
+
id: 'G1234567890',
|
|
36
36
|
name: 'private-channel',
|
|
37
37
|
is_private: true,
|
|
38
38
|
created: 1234567890,
|
|
@@ -42,21 +42,18 @@ describe('ChannelResolver', () => {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
describe('isChannelId', () => {
|
|
45
|
-
it('should identify channel IDs
|
|
46
|
-
expect(resolver.isChannelId('
|
|
45
|
+
it('should identify channel IDs with valid format', () => {
|
|
46
|
+
expect(resolver.isChannelId('C1234567890')).toBe(true);
|
|
47
|
+
expect(resolver.isChannelId('D1234567890')).toBe(true);
|
|
48
|
+
expect(resolver.isChannelId('G1234567890')).toBe(true);
|
|
47
49
|
});
|
|
48
50
|
|
|
49
|
-
it('should
|
|
50
|
-
expect(resolver.isChannelId('D123456')).toBe(true);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should identify group IDs starting with G', () => {
|
|
54
|
-
expect(resolver.isChannelId('G123456')).toBe(true);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should return false for channel names', () => {
|
|
51
|
+
it('should return false for channel names or malformed IDs', () => {
|
|
58
52
|
expect(resolver.isChannelId('general')).toBe(false);
|
|
59
53
|
expect(resolver.isChannelId('#general')).toBe(false);
|
|
54
|
+
expect(resolver.isChannelId('General')).toBe(false);
|
|
55
|
+
expect(resolver.isChannelId('Dev')).toBe(false);
|
|
56
|
+
expect(resolver.isChannelId('C123')).toBe(false);
|
|
60
57
|
});
|
|
61
58
|
});
|
|
62
59
|
|
|
@@ -96,8 +93,8 @@ describe('ChannelResolver', () => {
|
|
|
96
93
|
it('should limit results to specified count', () => {
|
|
97
94
|
const manyChannels = [
|
|
98
95
|
...mockChannels,
|
|
99
|
-
{ id: '
|
|
100
|
-
{ id: '
|
|
96
|
+
{ id: 'C9999999999', name: 'general-2', is_private: false, created: 0 },
|
|
97
|
+
{ id: 'C8888888888', name: 'general-3', is_private: false, created: 0 },
|
|
101
98
|
];
|
|
102
99
|
const result = resolver.getSimilarChannels('general', manyChannels, 2);
|
|
103
100
|
expect(result).toHaveLength(2);
|
|
@@ -128,15 +125,22 @@ describe('ChannelResolver', () => {
|
|
|
128
125
|
describe('resolveChannelId', () => {
|
|
129
126
|
it('should return ID directly if already an ID', async () => {
|
|
130
127
|
const getChannelsFn = vi.fn();
|
|
131
|
-
const result = await resolver.resolveChannelId('
|
|
132
|
-
expect(result).toBe('
|
|
128
|
+
const result = await resolver.resolveChannelId('C1234567890', getChannelsFn);
|
|
129
|
+
expect(result).toBe('C1234567890');
|
|
133
130
|
expect(getChannelsFn).not.toHaveBeenCalled();
|
|
134
131
|
});
|
|
135
132
|
|
|
136
133
|
it('should resolve channel name to ID', async () => {
|
|
137
134
|
const getChannelsFn = vi.fn().mockResolvedValue(mockChannels);
|
|
138
135
|
const result = await resolver.resolveChannelId('general', getChannelsFn);
|
|
139
|
-
expect(result).toBe('
|
|
136
|
+
expect(result).toBe('C1234567890');
|
|
137
|
+
expect(getChannelsFn).toHaveBeenCalled();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should resolve mixed-case channel names to ID', async () => {
|
|
141
|
+
const getChannelsFn = vi.fn().mockResolvedValue(mockChannels);
|
|
142
|
+
const result = await resolver.resolveChannelId('General', getChannelsFn);
|
|
143
|
+
expect(result).toBe('C1234567890');
|
|
140
144
|
expect(getChannelsFn).toHaveBeenCalled();
|
|
141
145
|
});
|
|
142
146
|
|
|
@@ -154,4 +158,4 @@ describe('ChannelResolver', () => {
|
|
|
154
158
|
);
|
|
155
159
|
});
|
|
156
160
|
});
|
|
157
|
-
});
|
|
161
|
+
});
|
|
@@ -13,15 +13,18 @@ describe('SlackApiClient', () => {
|
|
|
13
13
|
mockWebClient = {
|
|
14
14
|
chat: {
|
|
15
15
|
postMessage: vi.fn(),
|
|
16
|
-
scheduleMessage: vi.fn()
|
|
16
|
+
scheduleMessage: vi.fn(),
|
|
17
|
+
scheduledMessages: {
|
|
18
|
+
list: vi.fn(),
|
|
19
|
+
},
|
|
17
20
|
},
|
|
18
21
|
conversations: {
|
|
19
22
|
list: vi.fn(),
|
|
20
|
-
info: vi.fn()
|
|
23
|
+
info: vi.fn(),
|
|
21
24
|
},
|
|
22
25
|
users: {
|
|
23
|
-
conversations: vi.fn()
|
|
24
|
-
}
|
|
26
|
+
conversations: vi.fn(),
|
|
27
|
+
},
|
|
25
28
|
};
|
|
26
29
|
vi.mocked(WebClient).mockReturnValue(mockWebClient);
|
|
27
30
|
client = new SlackApiClient('test-token');
|
|
@@ -47,7 +50,7 @@ describe('SlackApiClient', () => {
|
|
|
47
50
|
|
|
48
51
|
expect(mockWebClient.chat.postMessage).toHaveBeenCalledWith({
|
|
49
52
|
channel: 'general',
|
|
50
|
-
text: 'Hello, World!'
|
|
53
|
+
text: 'Hello, World!',
|
|
51
54
|
});
|
|
52
55
|
expect(result).toEqual(mockResponse);
|
|
53
56
|
});
|
|
@@ -60,7 +63,7 @@ describe('SlackApiClient', () => {
|
|
|
60
63
|
|
|
61
64
|
expect(mockWebClient.chat.postMessage).toHaveBeenCalledWith({
|
|
62
65
|
channel: 'C1234567890',
|
|
63
|
-
text: 'Hello!'
|
|
66
|
+
text: 'Hello!',
|
|
64
67
|
});
|
|
65
68
|
});
|
|
66
69
|
|
|
@@ -73,7 +76,7 @@ describe('SlackApiClient', () => {
|
|
|
73
76
|
|
|
74
77
|
expect(mockWebClient.chat.postMessage).toHaveBeenCalledWith({
|
|
75
78
|
channel: 'general',
|
|
76
|
-
text: multiLineMessage
|
|
79
|
+
text: multiLineMessage,
|
|
77
80
|
});
|
|
78
81
|
});
|
|
79
82
|
|
|
@@ -95,12 +98,29 @@ describe('SlackApiClient', () => {
|
|
|
95
98
|
expect(mockWebClient.chat.scheduleMessage).toHaveBeenCalledWith({
|
|
96
99
|
channel: 'general',
|
|
97
100
|
text: 'Hello, future!',
|
|
98
|
-
post_at: 1770855000
|
|
101
|
+
post_at: 1770855000,
|
|
99
102
|
});
|
|
100
103
|
expect(result).toEqual(mockResponse);
|
|
101
104
|
});
|
|
102
105
|
});
|
|
103
106
|
|
|
107
|
+
describe('listScheduledMessages', () => {
|
|
108
|
+
it('should list scheduled messages', async () => {
|
|
109
|
+
const mockResponse = {
|
|
110
|
+
ok: true,
|
|
111
|
+
scheduled_messages: [
|
|
112
|
+
{ id: 'Q123', channel_id: 'C123', post_at: 1770855000, date_created: 1770854400 },
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
vi.mocked(mockWebClient.chat.scheduledMessages.list).mockResolvedValue(mockResponse as any);
|
|
116
|
+
|
|
117
|
+
const result = await client.listScheduledMessages();
|
|
118
|
+
|
|
119
|
+
expect(mockWebClient.chat.scheduledMessages.list).toHaveBeenCalledWith({ limit: 50 });
|
|
120
|
+
expect(result).toEqual(mockResponse.scheduled_messages);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
104
124
|
describe('listChannels', () => {
|
|
105
125
|
it('should list channels with default options', async () => {
|
|
106
126
|
const mockChannels = [
|
|
@@ -111,24 +131,24 @@ describe('SlackApiClient', () => {
|
|
|
111
131
|
is_private: false,
|
|
112
132
|
num_members: 150,
|
|
113
133
|
created: 1579075200,
|
|
114
|
-
purpose: { value: 'Company announcements' }
|
|
115
|
-
}
|
|
134
|
+
purpose: { value: 'Company announcements' },
|
|
135
|
+
},
|
|
116
136
|
];
|
|
117
137
|
vi.mocked(mockWebClient.conversations.list).mockResolvedValue({
|
|
118
138
|
ok: true,
|
|
119
|
-
channels: mockChannels
|
|
139
|
+
channels: mockChannels,
|
|
120
140
|
} as any);
|
|
121
141
|
|
|
122
142
|
const result = await client.listChannels({
|
|
123
143
|
types: 'public_channel',
|
|
124
144
|
exclude_archived: true,
|
|
125
|
-
limit: 100
|
|
145
|
+
limit: 100,
|
|
126
146
|
});
|
|
127
147
|
|
|
128
148
|
expect(mockWebClient.conversations.list).toHaveBeenCalledWith({
|
|
129
149
|
types: 'public_channel',
|
|
130
150
|
exclude_archived: true,
|
|
131
|
-
limit: 100
|
|
151
|
+
limit: 100,
|
|
132
152
|
});
|
|
133
153
|
expect(result).toEqual(mockChannels);
|
|
134
154
|
});
|
|
@@ -142,24 +162,24 @@ describe('SlackApiClient', () => {
|
|
|
142
162
|
is_private: true,
|
|
143
163
|
num_members: 10,
|
|
144
164
|
created: 1579075200,
|
|
145
|
-
purpose: { value: 'Private discussions' }
|
|
146
|
-
}
|
|
165
|
+
purpose: { value: 'Private discussions' },
|
|
166
|
+
},
|
|
147
167
|
];
|
|
148
168
|
vi.mocked(mockWebClient.conversations.list).mockResolvedValue({
|
|
149
169
|
ok: true,
|
|
150
|
-
channels: mockChannels
|
|
170
|
+
channels: mockChannels,
|
|
151
171
|
} as any);
|
|
152
172
|
|
|
153
173
|
const result = await client.listChannels({
|
|
154
174
|
types: 'private_channel',
|
|
155
175
|
exclude_archived: true,
|
|
156
|
-
limit: 50
|
|
176
|
+
limit: 50,
|
|
157
177
|
});
|
|
158
178
|
|
|
159
179
|
expect(mockWebClient.conversations.list).toHaveBeenCalledWith({
|
|
160
180
|
types: 'private_channel',
|
|
161
181
|
exclude_archived: true,
|
|
162
|
-
limit: 50
|
|
182
|
+
limit: 50,
|
|
163
183
|
});
|
|
164
184
|
expect(result).toEqual(mockChannels);
|
|
165
185
|
});
|
|
@@ -167,30 +187,32 @@ describe('SlackApiClient', () => {
|
|
|
167
187
|
it('should handle multiple channel types', async () => {
|
|
168
188
|
vi.mocked(mockWebClient.conversations.list).mockResolvedValue({
|
|
169
189
|
ok: true,
|
|
170
|
-
channels: []
|
|
190
|
+
channels: [],
|
|
171
191
|
} as any);
|
|
172
192
|
|
|
173
193
|
await client.listChannels({
|
|
174
194
|
types: 'public_channel,private_channel,im',
|
|
175
195
|
exclude_archived: false,
|
|
176
|
-
limit: 200
|
|
196
|
+
limit: 200,
|
|
177
197
|
});
|
|
178
198
|
|
|
179
199
|
expect(mockWebClient.conversations.list).toHaveBeenCalledWith({
|
|
180
200
|
types: 'public_channel,private_channel,im',
|
|
181
201
|
exclude_archived: false,
|
|
182
|
-
limit: 200
|
|
202
|
+
limit: 200,
|
|
183
203
|
});
|
|
184
204
|
});
|
|
185
205
|
|
|
186
206
|
it('should handle API errors', async () => {
|
|
187
207
|
vi.mocked(mockWebClient.conversations.list).mockRejectedValue(new Error('invalid_auth'));
|
|
188
208
|
|
|
189
|
-
await expect(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
209
|
+
await expect(
|
|
210
|
+
client.listChannels({
|
|
211
|
+
types: 'public_channel',
|
|
212
|
+
exclude_archived: true,
|
|
213
|
+
limit: 100,
|
|
214
|
+
})
|
|
215
|
+
).rejects.toThrow('invalid_auth');
|
|
194
216
|
});
|
|
195
217
|
|
|
196
218
|
it('should handle pagination when listing channels', async () => {
|
|
@@ -199,11 +221,11 @@ describe('SlackApiClient', () => {
|
|
|
199
221
|
ok: true,
|
|
200
222
|
channels: [
|
|
201
223
|
{ id: 'C001', name: 'channel1', is_private: false },
|
|
202
|
-
{ id: 'C002', name: 'channel2', is_private: false }
|
|
224
|
+
{ id: 'C002', name: 'channel2', is_private: false },
|
|
203
225
|
],
|
|
204
226
|
response_metadata: {
|
|
205
|
-
next_cursor: 'cursor123'
|
|
206
|
-
}
|
|
227
|
+
next_cursor: 'cursor123',
|
|
228
|
+
},
|
|
207
229
|
} as any);
|
|
208
230
|
|
|
209
231
|
// Second page
|
|
@@ -211,28 +233,26 @@ describe('SlackApiClient', () => {
|
|
|
211
233
|
ok: true,
|
|
212
234
|
channels: [
|
|
213
235
|
{ id: 'C003', name: 'channel3', is_private: false },
|
|
214
|
-
{ id: 'C004', name: 'channel4', is_private: false }
|
|
236
|
+
{ id: 'C004', name: 'channel4', is_private: false },
|
|
215
237
|
],
|
|
216
238
|
response_metadata: {
|
|
217
|
-
next_cursor: 'cursor456'
|
|
218
|
-
}
|
|
239
|
+
next_cursor: 'cursor456',
|
|
240
|
+
},
|
|
219
241
|
} as any);
|
|
220
242
|
|
|
221
243
|
// Third page (last page)
|
|
222
244
|
vi.mocked(mockWebClient.conversations.list).mockResolvedValueOnce({
|
|
223
245
|
ok: true,
|
|
224
|
-
channels: [
|
|
225
|
-
{ id: 'C005', name: 'channel5', is_private: false }
|
|
226
|
-
],
|
|
246
|
+
channels: [{ id: 'C005', name: 'channel5', is_private: false }],
|
|
227
247
|
response_metadata: {
|
|
228
|
-
next_cursor: ''
|
|
229
|
-
}
|
|
248
|
+
next_cursor: '',
|
|
249
|
+
},
|
|
230
250
|
} as any);
|
|
231
251
|
|
|
232
252
|
const result = await client.listChannels({
|
|
233
253
|
types: 'public_channel',
|
|
234
254
|
exclude_archived: true,
|
|
235
|
-
limit: 2
|
|
255
|
+
limit: 2,
|
|
236
256
|
});
|
|
237
257
|
|
|
238
258
|
// Should have called the API 3 times
|
|
@@ -243,7 +263,7 @@ describe('SlackApiClient', () => {
|
|
|
243
263
|
types: 'public_channel',
|
|
244
264
|
exclude_archived: true,
|
|
245
265
|
limit: 2,
|
|
246
|
-
cursor: undefined
|
|
266
|
+
cursor: undefined,
|
|
247
267
|
});
|
|
248
268
|
|
|
249
269
|
// Second call
|
|
@@ -251,7 +271,7 @@ describe('SlackApiClient', () => {
|
|
|
251
271
|
types: 'public_channel',
|
|
252
272
|
exclude_archived: true,
|
|
253
273
|
limit: 2,
|
|
254
|
-
cursor: 'cursor123'
|
|
274
|
+
cursor: 'cursor123',
|
|
255
275
|
});
|
|
256
276
|
|
|
257
277
|
// Third call
|
|
@@ -259,7 +279,7 @@ describe('SlackApiClient', () => {
|
|
|
259
279
|
types: 'public_channel',
|
|
260
280
|
exclude_archived: true,
|
|
261
281
|
limit: 2,
|
|
262
|
-
cursor: 'cursor456'
|
|
282
|
+
cursor: 'cursor456',
|
|
263
283
|
});
|
|
264
284
|
|
|
265
285
|
// Should return all channels
|
|
@@ -274,22 +294,20 @@ describe('SlackApiClient', () => {
|
|
|
274
294
|
it('should handle empty cursor in pagination', async () => {
|
|
275
295
|
vi.mocked(mockWebClient.conversations.list).mockResolvedValueOnce({
|
|
276
296
|
ok: true,
|
|
277
|
-
channels: [
|
|
278
|
-
{ id: 'C001', name: 'channel1', is_private: false }
|
|
279
|
-
],
|
|
297
|
+
channels: [{ id: 'C001', name: 'channel1', is_private: false }],
|
|
280
298
|
response_metadata: {
|
|
281
299
|
// No next_cursor field
|
|
282
|
-
}
|
|
300
|
+
},
|
|
283
301
|
} as any);
|
|
284
302
|
|
|
285
303
|
const result = await client.listChannels({
|
|
286
304
|
types: 'public_channel',
|
|
287
305
|
exclude_archived: true,
|
|
288
|
-
limit: 100
|
|
306
|
+
limit: 100,
|
|
289
307
|
});
|
|
290
308
|
|
|
291
309
|
expect(mockWebClient.conversations.list).toHaveBeenCalledTimes(1);
|
|
292
310
|
expect(result).toHaveLength(1);
|
|
293
311
|
});
|
|
294
312
|
});
|
|
295
|
-
});
|
|
313
|
+
});
|
|
@@ -13,6 +13,9 @@ vi.mock('@slack/web-api', () => ({
|
|
|
13
13
|
chat: {
|
|
14
14
|
postMessage: vi.fn(),
|
|
15
15
|
scheduleMessage: vi.fn(),
|
|
16
|
+
scheduledMessages: {
|
|
17
|
+
list: vi.fn(),
|
|
18
|
+
},
|
|
16
19
|
},
|
|
17
20
|
})),
|
|
18
21
|
LogLevel: {
|
|
@@ -49,6 +52,22 @@ describe('MessageOperations', () => {
|
|
|
49
52
|
});
|
|
50
53
|
});
|
|
51
54
|
|
|
55
|
+
describe('listScheduledMessages', () => {
|
|
56
|
+
it('should call chat.scheduledMessages.list', async () => {
|
|
57
|
+
mockClient.chat.scheduledMessages.list.mockResolvedValue({
|
|
58
|
+
ok: true,
|
|
59
|
+
scheduled_messages: [
|
|
60
|
+
{ id: 'Q123', channel_id: 'C123', post_at: 1770855000, date_created: 1770854400 },
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const result = await messageOps.listScheduledMessages(undefined, 20);
|
|
65
|
+
|
|
66
|
+
expect(mockClient.chat.scheduledMessages.list).toHaveBeenCalledWith({ limit: 20 });
|
|
67
|
+
expect(result).toHaveLength(1);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
52
71
|
describe('getHistory with mentions', () => {
|
|
53
72
|
it('should fetch user info for mentioned users in message text', async () => {
|
|
54
73
|
const mockMessages = [
|