@urugus/slack-cli 0.2.12 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/dist/commands/history-display.d.ts +5 -1
- package/dist/commands/history-display.d.ts.map +1 -1
- package/dist/commands/history-display.js +3 -3
- package/dist/commands/history-display.js.map +1 -1
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +28 -11
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/search.d.ts +3 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +51 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/types/commands.d.ts +10 -0
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +5 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/formatters/search-formatters.d.ts +10 -0
- package/dist/utils/formatters/search-formatters.d.ts.map +1 -0
- package/dist/utils/formatters/search-formatters.js +91 -0
- package/dist/utils/formatters/search-formatters.js.map +1 -0
- package/dist/utils/slack-api-client.d.ts +5 -0
- package/dist/utils/slack-api-client.d.ts.map +1 -1
- package/dist/utils/slack-api-client.js +8 -0
- package/dist/utils/slack-api-client.js.map +1 -1
- package/dist/utils/slack-operations/index.d.ts +1 -0
- package/dist/utils/slack-operations/index.d.ts.map +1 -1
- package/dist/utils/slack-operations/index.js +3 -1
- package/dist/utils/slack-operations/index.js.map +1 -1
- package/dist/utils/slack-operations/message-operations.d.ts +1 -0
- package/dist/utils/slack-operations/message-operations.d.ts.map +1 -1
- package/dist/utils/slack-operations/message-operations.js +21 -0
- package/dist/utils/slack-operations/message-operations.js.map +1 -1
- package/dist/utils/slack-operations/search-operations.d.ts +29 -0
- package/dist/utils/slack-operations/search-operations.d.ts.map +1 -0
- package/dist/utils/slack-operations/search-operations.js +37 -0
- package/dist/utils/slack-operations/search-operations.js.map +1 -0
- package/dist/utils/validators.d.ts +16 -0
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/utils/validators.js +50 -0
- package/dist/utils/validators.js.map +1 -1
- package/package.json +5 -2
- package/.claude/settings.local.json +0 -75
- package/.github/dependabot.yml +0 -18
- package/.github/workflows/ci.yml +0 -70
- package/.github/workflows/pr-validation.yml +0 -41
- package/.prettierignore +0 -11
- package/.prettierrc +0 -10
- package/CHANGELOG.md +0 -61
- package/CLAUDE.md +0 -16
- package/eslint.config.js +0 -38
- package/src/commands/channels.ts +0 -50
- package/src/commands/config-subcommands.ts +0 -63
- package/src/commands/config.ts +0 -50
- package/src/commands/history-display.ts +0 -19
- package/src/commands/history-validators.ts +0 -46
- package/src/commands/history.ts +0 -61
- package/src/commands/scheduled.ts +0 -71
- package/src/commands/send.ts +0 -69
- package/src/commands/unread.ts +0 -122
- package/src/index.ts +0 -27
- package/src/types/commands.ts +0 -58
- package/src/types/config.ts +0 -20
- package/src/utils/channel-formatter.ts +0 -45
- package/src/utils/channel-resolver.ts +0 -82
- package/src/utils/client-factory.ts +0 -10
- package/src/utils/command-wrapper.ts +0 -27
- package/src/utils/config/config-file-manager.ts +0 -56
- package/src/utils/config/profile-manager.ts +0 -79
- package/src/utils/config/token-crypto-service.ts +0 -80
- package/src/utils/config-helper.ts +0 -21
- package/src/utils/constants.ts +0 -78
- package/src/utils/date-utils.ts +0 -8
- package/src/utils/error-utils.ts +0 -6
- package/src/utils/errors.ts +0 -33
- package/src/utils/format-utils.ts +0 -9
- package/src/utils/formatters/base-formatter.ts +0 -34
- package/src/utils/formatters/channel-formatters.ts +0 -71
- package/src/utils/formatters/channels-list-formatters.ts +0 -55
- package/src/utils/formatters/history-formatters.ts +0 -123
- package/src/utils/formatters/message-formatters.ts +0 -85
- package/src/utils/mention-utils.ts +0 -47
- package/src/utils/option-parsers.ts +0 -100
- package/src/utils/profile-config.ts +0 -161
- package/src/utils/schedule-utils.ts +0 -41
- package/src/utils/slack-api-client.ts +0 -135
- package/src/utils/slack-operations/base-client.ts +0 -30
- package/src/utils/slack-operations/channel-operations.ts +0 -161
- package/src/utils/slack-operations/index.ts +0 -3
- package/src/utils/slack-operations/message-operations.ts +0 -176
- package/src/utils/slack-patterns.ts +0 -9
- package/src/utils/token-utils.ts +0 -17
- package/src/utils/validators.ts +0 -263
- package/tests/commands/channels.test.ts +0 -250
- package/tests/commands/config.test.ts +0 -158
- package/tests/commands/history.test.ts +0 -403
- package/tests/commands/scheduled.test.ts +0 -131
- package/tests/commands/send.test.ts +0 -414
- package/tests/commands/unread.test.ts +0 -492
- package/tests/index.test.ts +0 -40
- package/tests/test-utils.ts +0 -28
- package/tests/utils/channel-resolver.test.ts +0 -161
- package/tests/utils/config/config-file-manager.test.ts +0 -118
- package/tests/utils/config/profile-manager.test.ts +0 -266
- package/tests/utils/config/token-crypto-service.test.ts +0 -98
- package/tests/utils/config.test.ts +0 -400
- package/tests/utils/date-utils.test.ts +0 -30
- package/tests/utils/error-utils.test.ts +0 -34
- package/tests/utils/format-utils.test.ts +0 -61
- package/tests/utils/mention-utils.test.ts +0 -100
- package/tests/utils/option-parsers.test.ts +0 -173
- package/tests/utils/profile-config.test.ts +0 -282
- package/tests/utils/schedule-utils.test.ts +0 -63
- package/tests/utils/slack-api-client.test.ts +0 -313
- package/tests/utils/slack-operations/channel-operations.test.ts +0 -248
- package/tests/utils/slack-operations/message-operations.test.ts +0 -163
- package/tests/utils/token-utils.test.ts +0 -33
- package/tests/utils/validators.test.ts +0 -307
- package/tsconfig.json +0 -22
- package/vitest.config.ts +0 -27
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { ChatPostMessageResponse, ChatScheduleMessageResponse } from '@slack/web-api';
|
|
2
|
-
import { ChannelOperations } from './slack-operations/channel-operations';
|
|
3
|
-
import { MessageOperations } from './slack-operations/message-operations';
|
|
4
|
-
|
|
5
|
-
export interface Channel {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
is_channel?: boolean;
|
|
9
|
-
is_group?: boolean;
|
|
10
|
-
is_im?: boolean;
|
|
11
|
-
is_mpim?: boolean;
|
|
12
|
-
is_private: boolean;
|
|
13
|
-
created: number;
|
|
14
|
-
is_archived?: boolean;
|
|
15
|
-
is_general?: boolean;
|
|
16
|
-
unlinked?: number;
|
|
17
|
-
name_normalized?: string;
|
|
18
|
-
is_shared?: boolean;
|
|
19
|
-
is_ext_shared?: boolean;
|
|
20
|
-
is_org_shared?: boolean;
|
|
21
|
-
is_member?: boolean;
|
|
22
|
-
num_members?: number;
|
|
23
|
-
unread_count?: number;
|
|
24
|
-
unread_count_display?: number;
|
|
25
|
-
last_read?: string;
|
|
26
|
-
topic?: {
|
|
27
|
-
value: string;
|
|
28
|
-
creator?: string;
|
|
29
|
-
last_set?: number;
|
|
30
|
-
};
|
|
31
|
-
purpose?: {
|
|
32
|
-
value: string;
|
|
33
|
-
creator?: string;
|
|
34
|
-
last_set?: number;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ListChannelsOptions {
|
|
39
|
-
types: string;
|
|
40
|
-
exclude_archived: boolean;
|
|
41
|
-
limit: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface HistoryOptions {
|
|
45
|
-
limit: number;
|
|
46
|
-
oldest?: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface Message {
|
|
50
|
-
type: string;
|
|
51
|
-
text?: string;
|
|
52
|
-
user?: string;
|
|
53
|
-
bot_id?: string;
|
|
54
|
-
ts: string;
|
|
55
|
-
thread_ts?: string;
|
|
56
|
-
attachments?: unknown[];
|
|
57
|
-
blocks?: unknown[];
|
|
58
|
-
}
|
|
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
|
-
|
|
68
|
-
export interface HistoryResult {
|
|
69
|
-
messages: Message[];
|
|
70
|
-
users: Map<string, string>;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface ChannelUnreadResult {
|
|
74
|
-
channel: Channel;
|
|
75
|
-
messages: Message[];
|
|
76
|
-
users: Map<string, string>;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export class SlackApiClient {
|
|
80
|
-
private channelOps: ChannelOperations;
|
|
81
|
-
private messageOps: MessageOperations;
|
|
82
|
-
|
|
83
|
-
constructor(token: string) {
|
|
84
|
-
this.channelOps = new ChannelOperations(token);
|
|
85
|
-
this.messageOps = new MessageOperations(token);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async sendMessage(
|
|
89
|
-
channel: string,
|
|
90
|
-
text: string,
|
|
91
|
-
thread_ts?: string
|
|
92
|
-
): Promise<ChatPostMessageResponse> {
|
|
93
|
-
return this.messageOps.sendMessage(channel, text, thread_ts);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async scheduleMessage(
|
|
97
|
-
channel: string,
|
|
98
|
-
text: string,
|
|
99
|
-
post_at: number,
|
|
100
|
-
thread_ts?: string
|
|
101
|
-
): Promise<ChatScheduleMessageResponse> {
|
|
102
|
-
return this.messageOps.scheduleMessage(channel, text, post_at, thread_ts);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async listScheduledMessages(channel?: string, limit = 50): Promise<ScheduledMessage[]> {
|
|
106
|
-
return this.messageOps.listScheduledMessages(channel, limit);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async listChannels(options: ListChannelsOptions): Promise<Channel[]> {
|
|
110
|
-
return this.channelOps.listChannels(options);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async getHistory(channel: string, options: HistoryOptions): Promise<HistoryResult> {
|
|
114
|
-
return this.messageOps.getHistory(channel, options);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async listUnreadChannels(): Promise<Channel[]> {
|
|
118
|
-
return this.channelOps.listUnreadChannels();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async getChannelUnread(channelNameOrId: string): Promise<ChannelUnreadResult> {
|
|
122
|
-
return this.messageOps.getChannelUnread(channelNameOrId);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async markAsRead(channelId: string): Promise<void> {
|
|
126
|
-
return this.messageOps.markAsRead(channelId);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export const slackApiClient = {
|
|
131
|
-
listChannels: async (token: string, options: ListChannelsOptions): Promise<Channel[]> => {
|
|
132
|
-
const client = new SlackApiClient(token);
|
|
133
|
-
return client.listChannels(options);
|
|
134
|
-
},
|
|
135
|
-
};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { WebClient, LogLevel } from '@slack/web-api';
|
|
2
|
-
import pLimit from 'p-limit';
|
|
3
|
-
import { RATE_LIMIT } from '../constants';
|
|
4
|
-
|
|
5
|
-
export class BaseSlackClient {
|
|
6
|
-
protected client: WebClient;
|
|
7
|
-
protected rateLimiter: ReturnType<typeof pLimit>;
|
|
8
|
-
|
|
9
|
-
constructor(token: string) {
|
|
10
|
-
this.client = new WebClient(token, {
|
|
11
|
-
retryConfig: {
|
|
12
|
-
retries: 0, // Disable automatic retries to handle rate limits manually
|
|
13
|
-
},
|
|
14
|
-
logLevel: LogLevel.ERROR, // Reduce noise from WebClient logs
|
|
15
|
-
});
|
|
16
|
-
// Limit concurrent API calls to avoid rate limiting
|
|
17
|
-
this.rateLimiter = pLimit(RATE_LIMIT.CONCURRENT_REQUESTS);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
protected async handleRateLimit(error: unknown): Promise<void> {
|
|
21
|
-
if (error instanceof Error && error.message?.includes('rate limit')) {
|
|
22
|
-
// If we hit rate limit, wait longer
|
|
23
|
-
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
protected async delay(ms: number): Promise<void> {
|
|
28
|
-
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { BaseSlackClient } from './base-client';
|
|
2
|
-
import { channelResolver } from '../channel-resolver';
|
|
3
|
-
import { DEFAULTS } from '../constants';
|
|
4
|
-
import { Channel, ListChannelsOptions } from '../slack-api-client';
|
|
5
|
-
import { WebClient } from '@slack/web-api';
|
|
6
|
-
|
|
7
|
-
interface ChannelWithUnreadInfo extends Channel {
|
|
8
|
-
unread_count: number;
|
|
9
|
-
unread_count_display: number;
|
|
10
|
-
last_read?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class ChannelOperations extends BaseSlackClient {
|
|
14
|
-
constructor(tokenOrClient: string | WebClient) {
|
|
15
|
-
if (typeof tokenOrClient === 'string') {
|
|
16
|
-
super(tokenOrClient);
|
|
17
|
-
} else {
|
|
18
|
-
super('dummy-token'); // Call parent constructor
|
|
19
|
-
this.client = tokenOrClient; // Override the client for testing
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async listChannels(options: ListChannelsOptions): Promise<Channel[]> {
|
|
24
|
-
const channels: Channel[] = [];
|
|
25
|
-
let cursor: string | undefined;
|
|
26
|
-
|
|
27
|
-
// Paginate through all channels
|
|
28
|
-
do {
|
|
29
|
-
const response = await this.client.conversations.list({
|
|
30
|
-
types: options.types,
|
|
31
|
-
exclude_archived: options.exclude_archived,
|
|
32
|
-
limit: options.limit,
|
|
33
|
-
cursor,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
if (response.channels) {
|
|
37
|
-
channels.push(...(response.channels as Channel[]));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
cursor = response.response_metadata?.next_cursor;
|
|
41
|
-
} while (cursor);
|
|
42
|
-
|
|
43
|
-
return channels;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async listUnreadChannels(): Promise<Channel[]> {
|
|
47
|
-
const channels = await this.fetchAllChannels();
|
|
48
|
-
const channelsWithUnread: Channel[] = [];
|
|
49
|
-
|
|
50
|
-
// Process channels one by one with delay to avoid rate limits
|
|
51
|
-
for (const channel of channels) {
|
|
52
|
-
try {
|
|
53
|
-
const unreadInfo = await this.getChannelUnreadInfo(channel);
|
|
54
|
-
if (unreadInfo) {
|
|
55
|
-
channelsWithUnread.push(unreadInfo);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Add delay between API calls to avoid rate limiting
|
|
59
|
-
await this.delay(100);
|
|
60
|
-
} catch (error) {
|
|
61
|
-
// Skip channels that fail
|
|
62
|
-
await this.handleRateLimit(error);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return channelsWithUnread;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private async fetchAllChannels(): Promise<Channel[]> {
|
|
70
|
-
const response = await this.client.conversations.list({
|
|
71
|
-
types: 'public_channel,private_channel,im,mpim',
|
|
72
|
-
exclude_archived: true,
|
|
73
|
-
limit: 1000,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
return response.channels as Channel[];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
private async getChannelUnreadInfo(channel: Channel): Promise<Channel | null> {
|
|
80
|
-
const channelInfo = await this.fetchChannelInfo(channel.id);
|
|
81
|
-
const unreadCount = await this.calculateUnreadCount(channel.id, channelInfo);
|
|
82
|
-
|
|
83
|
-
if (unreadCount > 0) {
|
|
84
|
-
return {
|
|
85
|
-
...channel,
|
|
86
|
-
unread_count: unreadCount,
|
|
87
|
-
unread_count_display: unreadCount,
|
|
88
|
-
last_read: channelInfo.last_read,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
private async fetchChannelInfo(channelId: string): Promise<ChannelWithUnreadInfo> {
|
|
96
|
-
const info = await this.client.conversations.info({
|
|
97
|
-
channel: channelId,
|
|
98
|
-
include_num_members: false,
|
|
99
|
-
});
|
|
100
|
-
return info.channel as ChannelWithUnreadInfo;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private async calculateUnreadCount(
|
|
104
|
-
channelId: string,
|
|
105
|
-
channelInfo: ChannelWithUnreadInfo
|
|
106
|
-
): Promise<number> {
|
|
107
|
-
// Get the latest message to check if channel has any messages
|
|
108
|
-
const latestMessage = await this.fetchLatestMessage(channelId);
|
|
109
|
-
if (!latestMessage) {
|
|
110
|
-
return 0;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (channelInfo.last_read) {
|
|
114
|
-
return await this.fetchUnreadMessageCount(channelId, channelInfo.last_read);
|
|
115
|
-
} else {
|
|
116
|
-
// If no last_read, all messages are unread
|
|
117
|
-
return await this.fetchAllMessageCount(channelId);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private async fetchLatestMessage(channelId: string): Promise<any> {
|
|
122
|
-
const history = await this.client.conversations.history({
|
|
123
|
-
channel: channelId,
|
|
124
|
-
limit: 1,
|
|
125
|
-
});
|
|
126
|
-
return history.messages && history.messages.length > 0 ? history.messages[0] : null;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private async fetchUnreadMessageCount(channelId: string, lastRead: string): Promise<number> {
|
|
130
|
-
const unreadHistory = await this.client.conversations.history({
|
|
131
|
-
channel: channelId,
|
|
132
|
-
oldest: lastRead,
|
|
133
|
-
limit: 100, // Get up to 100 unread messages
|
|
134
|
-
});
|
|
135
|
-
return unreadHistory.messages?.length || 0;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private async fetchAllMessageCount(channelId: string): Promise<number> {
|
|
139
|
-
const allHistory = await this.client.conversations.history({
|
|
140
|
-
channel: channelId,
|
|
141
|
-
limit: 100,
|
|
142
|
-
});
|
|
143
|
-
return allHistory.messages?.length || 0;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async getChannelInfo(channelNameOrId: string): Promise<ChannelWithUnreadInfo> {
|
|
147
|
-
const channelId = await channelResolver.resolveChannelId(channelNameOrId, () =>
|
|
148
|
-
this.listChannels({
|
|
149
|
-
types: 'public_channel,private_channel,im,mpim',
|
|
150
|
-
exclude_archived: true,
|
|
151
|
-
limit: DEFAULTS.CHANNELS_LIMIT,
|
|
152
|
-
})
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
const info = await this.client.conversations.info({
|
|
156
|
-
channel: channelId,
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
return info.channel as ChannelWithUnreadInfo;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ChatPostMessageResponse,
|
|
3
|
-
ChatPostMessageArguments,
|
|
4
|
-
ChatScheduleMessageArguments,
|
|
5
|
-
ChatScheduleMessageResponse,
|
|
6
|
-
} from '@slack/web-api';
|
|
7
|
-
import { BaseSlackClient } from './base-client';
|
|
8
|
-
import { channelResolver } from '../channel-resolver';
|
|
9
|
-
import { DEFAULTS } from '../constants';
|
|
10
|
-
import {
|
|
11
|
-
Message,
|
|
12
|
-
HistoryOptions,
|
|
13
|
-
HistoryResult,
|
|
14
|
-
ChannelUnreadResult,
|
|
15
|
-
ScheduledMessage,
|
|
16
|
-
} from '../slack-api-client';
|
|
17
|
-
import { ChannelOperations } from './channel-operations';
|
|
18
|
-
import { extractAllUserIds } from '../mention-utils';
|
|
19
|
-
|
|
20
|
-
export class MessageOperations extends BaseSlackClient {
|
|
21
|
-
private channelOps: ChannelOperations;
|
|
22
|
-
|
|
23
|
-
constructor(token: string) {
|
|
24
|
-
super(token);
|
|
25
|
-
this.channelOps = new ChannelOperations(token);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async sendMessage(
|
|
29
|
-
channel: string,
|
|
30
|
-
text: string,
|
|
31
|
-
thread_ts?: string
|
|
32
|
-
): Promise<ChatPostMessageResponse> {
|
|
33
|
-
const params: ChatPostMessageArguments = {
|
|
34
|
-
channel,
|
|
35
|
-
text,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
if (thread_ts) {
|
|
39
|
-
params.thread_ts = thread_ts;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return await this.client.chat.postMessage(params);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async scheduleMessage(
|
|
46
|
-
channel: string,
|
|
47
|
-
text: string,
|
|
48
|
-
post_at: number,
|
|
49
|
-
thread_ts?: string
|
|
50
|
-
): Promise<ChatScheduleMessageResponse> {
|
|
51
|
-
const params: ChatScheduleMessageArguments = {
|
|
52
|
-
channel,
|
|
53
|
-
text,
|
|
54
|
-
post_at,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
if (thread_ts) {
|
|
58
|
-
params.thread_ts = thread_ts;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return await this.client.chat.scheduleMessage(params);
|
|
62
|
-
}
|
|
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
|
-
|
|
87
|
-
async getHistory(channel: string, options: HistoryOptions): Promise<HistoryResult> {
|
|
88
|
-
// Resolve channel name to ID if needed
|
|
89
|
-
const channelId = await channelResolver.resolveChannelId(channel, () =>
|
|
90
|
-
this.channelOps.listChannels({
|
|
91
|
-
types: 'public_channel,private_channel,im,mpim',
|
|
92
|
-
exclude_archived: true,
|
|
93
|
-
limit: DEFAULTS.CHANNELS_LIMIT,
|
|
94
|
-
})
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
const response = await this.client.conversations.history({
|
|
98
|
-
channel: channelId,
|
|
99
|
-
limit: options.limit,
|
|
100
|
-
oldest: options.oldest,
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const messages = response.messages as Message[];
|
|
104
|
-
|
|
105
|
-
// Extract all unique user IDs (authors and mentioned users)
|
|
106
|
-
const userIds = extractAllUserIds(messages);
|
|
107
|
-
const users = await this.fetchUserInfo(userIds);
|
|
108
|
-
|
|
109
|
-
return { messages, users };
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async getChannelUnread(channelNameOrId: string): Promise<ChannelUnreadResult> {
|
|
113
|
-
const channel = await this.channelOps.getChannelInfo(channelNameOrId);
|
|
114
|
-
|
|
115
|
-
// Get unread messages
|
|
116
|
-
let messages: Message[] = [];
|
|
117
|
-
let users = new Map<string, string>();
|
|
118
|
-
let actualUnreadCount = 0;
|
|
119
|
-
|
|
120
|
-
if (channel.last_read) {
|
|
121
|
-
// Always fetch messages after last_read to get accurate unread count
|
|
122
|
-
const historyResult = await this.getHistory(channel.id, {
|
|
123
|
-
limit: 100, // Fetch up to 100 messages after last_read
|
|
124
|
-
oldest: channel.last_read,
|
|
125
|
-
});
|
|
126
|
-
messages = historyResult.messages;
|
|
127
|
-
users = historyResult.users;
|
|
128
|
-
actualUnreadCount = messages.length;
|
|
129
|
-
} else if (!channel.last_read) {
|
|
130
|
-
// If no last_read, all messages are unread
|
|
131
|
-
const historyResult = await this.getHistory(channel.id, {
|
|
132
|
-
limit: 100,
|
|
133
|
-
});
|
|
134
|
-
messages = historyResult.messages;
|
|
135
|
-
users = historyResult.users;
|
|
136
|
-
actualUnreadCount = messages.length;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
channel: {
|
|
141
|
-
...channel,
|
|
142
|
-
unread_count: actualUnreadCount,
|
|
143
|
-
unread_count_display: actualUnreadCount,
|
|
144
|
-
},
|
|
145
|
-
messages,
|
|
146
|
-
users,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private async fetchUserInfo(userIds: string[]): Promise<Map<string, string>> {
|
|
151
|
-
const users = new Map<string, string>();
|
|
152
|
-
|
|
153
|
-
if (userIds.length > 0) {
|
|
154
|
-
for (const userId of userIds) {
|
|
155
|
-
try {
|
|
156
|
-
const userInfo = await this.client.users.info({ user: userId });
|
|
157
|
-
if (userInfo.user?.name) {
|
|
158
|
-
users.set(userId, userInfo.user.name);
|
|
159
|
-
}
|
|
160
|
-
} catch (error) {
|
|
161
|
-
// If we can't get user info, we'll use the ID
|
|
162
|
-
users.set(userId, userId);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return users;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async markAsRead(channelId: string): Promise<void> {
|
|
171
|
-
await this.client.conversations.mark({
|
|
172
|
-
channel: channelId,
|
|
173
|
-
ts: Date.now() / 1000 + '',
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Common regex patterns for Slack message parsing
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
// Matches Slack user mentions in the format <@USERID>
|
|
6
|
-
export const USER_MENTION_PATTERN = /<@([A-Z0-9]+)>/g;
|
|
7
|
-
|
|
8
|
-
// Matches a single user mention (non-global)
|
|
9
|
-
export const SINGLE_USER_MENTION_PATTERN = /<@([A-Z0-9]+)>/;
|
package/src/utils/token-utils.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { TOKEN_MASK_LENGTH, TOKEN_MIN_LENGTH } from './constants';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Masks a token for display purposes, showing only first and last few characters
|
|
5
|
-
* @param token The token to mask
|
|
6
|
-
* @returns Masked token in format "xoxb-****-****-abcd"
|
|
7
|
-
*/
|
|
8
|
-
export function maskToken(token: string): string {
|
|
9
|
-
if (token.length <= TOKEN_MIN_LENGTH) {
|
|
10
|
-
return '****';
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const prefix = token.substring(0, TOKEN_MASK_LENGTH);
|
|
14
|
-
const suffix = token.substring(token.length - TOKEN_MASK_LENGTH);
|
|
15
|
-
|
|
16
|
-
return `${prefix}-****-****-${suffix}`;
|
|
17
|
-
}
|