@urugus/slack-cli 0.2.8 → 0.2.9
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/.claude/settings.local.json +13 -55
- package/.github/workflows/ci.yml +2 -2
- package/dist/commands/unread.d.ts.map +1 -1
- package/dist/commands/unread.js +32 -16
- package/dist/commands/unread.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +1 -5
- package/dist/utils/errors.js.map +1 -1
- package/eslint.config.js +38 -0
- package/package.json +12 -14
- package/src/commands/unread.ts +52 -22
- package/src/utils/errors.ts +1 -5
- package/tests/index.test.ts +2 -2
- package/.eslintrc.json +0 -25
- package/dist/utils/config.d.ts +0 -10
- package/dist/utils/config.d.ts.map +0 -1
- package/dist/utils/config.js +0 -94
- package/dist/utils/config.js.map +0 -1
- package/dist/utils/formatters/output-formatter.d.ts +0 -7
- package/dist/utils/formatters/output-formatter.d.ts.map +0 -1
- package/dist/utils/formatters/output-formatter.js +0 -7
- package/dist/utils/formatters/output-formatter.js.map +0 -1
- package/dist/utils/profile-config-refactored.d.ts +0 -20
- package/dist/utils/profile-config-refactored.d.ts.map +0 -1
- package/dist/utils/profile-config-refactored.js +0 -174
- package/dist/utils/profile-config-refactored.js.map +0 -1
- package/src/utils/formatters/output-formatter.ts +0 -7
- package/tests/utils/slack-operations/channel-operations-refactored.test.ts +0 -179
|
@@ -1,70 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"permissions": {
|
|
3
3
|
"allow": [
|
|
4
|
-
"Bash(mkdir:*)",
|
|
5
|
-
"Bash(ls:*)",
|
|
6
|
-
"Bash(npm install)",
|
|
7
|
-
"Bash(npm run test:*)",
|
|
8
4
|
"Bash(find:*)",
|
|
5
|
+
"Bash(npm install:*)",
|
|
6
|
+
"Bash(gh issue list:*)",
|
|
7
|
+
"Bash(gh pr list:*)",
|
|
8
|
+
"Bash(gh pr checkout:*)",
|
|
9
9
|
"Bash(npm test)",
|
|
10
|
-
"Bash(npm run build:*)",
|
|
11
10
|
"Bash(npm run lint)",
|
|
12
|
-
"Bash(npm run
|
|
13
|
-
"Bash(npm run format:*)",
|
|
14
|
-
"Bash(npm test:*)",
|
|
15
|
-
"Bash(node:*)",
|
|
11
|
+
"Bash(npm run build:*)",
|
|
16
12
|
"Bash(git add:*)",
|
|
17
13
|
"Bash(git commit:*)",
|
|
18
|
-
"Bash(grep:*)",
|
|
19
|
-
"Bash(true)",
|
|
20
|
-
"Bash(npx vitest run:*)",
|
|
21
|
-
"Bash(NODE_ENV=test npx vitest run --reporter=tap 2 >& 1)",
|
|
22
|
-
"Bash(npm ls:*)",
|
|
23
|
-
"Bash(/opt/homebrew/bin/slack-cli config:*)",
|
|
24
|
-
"Bash(npm bin:*)",
|
|
25
|
-
"Bash(npm root:*)",
|
|
26
|
-
"Bash(strace:*)",
|
|
27
|
-
"Bash(npx vitest list:*)",
|
|
28
|
-
"Bash(NODE_OPTIONS=\"--trace-warnings\" npx vitest run --no-threads 2 >& 1)",
|
|
29
|
-
"Bash(NODE_ENV=test npx vitest run --reporter=tap tests/commands/config.test.ts 2 >& 1)",
|
|
30
|
-
"Bash(echo:*)",
|
|
31
|
-
"Bash(git reset:*)",
|
|
32
|
-
"Bash(npm uninstall:*)",
|
|
33
|
-
"Bash(pkill:*)",
|
|
34
|
-
"Bash(/opt/homebrew/bin/slack:*)",
|
|
35
|
-
"Bash(brew list:*)",
|
|
36
|
-
"Bash(brew info:*)",
|
|
37
|
-
"Bash(npm link:*)",
|
|
38
|
-
"Bash(slack-cli:*)",
|
|
39
14
|
"Bash(git push:*)",
|
|
40
|
-
"Bash(
|
|
15
|
+
"Bash(git config:*)",
|
|
16
|
+
"Bash(gh pr view:*)",
|
|
41
17
|
"Bash(gh run view:*)",
|
|
42
|
-
"Bash(gh run watch:*)",
|
|
43
|
-
"Bash(cat:*)",
|
|
44
|
-
"Bash(mv:*)",
|
|
45
|
-
"Bash(rm:*)",
|
|
46
|
-
"WebFetch(domain:api.slack.com)",
|
|
47
|
-
"Bash(npm run typecheck:*)",
|
|
48
|
-
"Bash(npm run:*)",
|
|
49
|
-
"Bash(npm whoami:*)",
|
|
50
|
-
"Bash(npm unlink:*)",
|
|
51
|
-
"Bash(npm update:*)",
|
|
52
|
-
"Bash(npm install:*)",
|
|
53
|
-
"Bash(npm view:*)",
|
|
54
|
-
"Bash(npm publish:*)",
|
|
55
|
-
"Bash(rg:*)",
|
|
56
|
-
"Bash(npm version:*)",
|
|
57
|
-
"Bash(npx tsx:*)",
|
|
58
|
-
"Bash(gh workflow view:*)",
|
|
59
|
-
"Bash(git tag:*)",
|
|
60
|
-
"Bash(./bin/dev:*)",
|
|
61
18
|
"Bash(git checkout:*)",
|
|
62
|
-
"Bash(gh pr create:*)",
|
|
63
|
-
"Bash(gh pr checks:*)",
|
|
64
|
-
"Bash(gh pr view:*)",
|
|
65
|
-
"Bash(gh pr merge:*)",
|
|
66
19
|
"Bash(git pull:*)",
|
|
67
|
-
"Bash(
|
|
20
|
+
"Bash(git rebase:*)",
|
|
21
|
+
"WebFetch(domain:github.com)",
|
|
22
|
+
"Bash(rm:*)",
|
|
23
|
+
"Bash(gh pr comment:*)",
|
|
24
|
+
"Bash(gh pr close:*)",
|
|
25
|
+
"Bash(npm publish:*)"
|
|
68
26
|
],
|
|
69
27
|
"deny": []
|
|
70
28
|
}
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -12,7 +12,7 @@ jobs:
|
|
|
12
12
|
|
|
13
13
|
strategy:
|
|
14
14
|
matrix:
|
|
15
|
-
node-version: [
|
|
15
|
+
node-version: [20.x]
|
|
16
16
|
|
|
17
17
|
steps:
|
|
18
18
|
- uses: actions/checkout@v4
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
run: npm run test:coverage
|
|
43
43
|
|
|
44
44
|
- name: Upload coverage reports
|
|
45
|
-
uses: codecov/codecov-action@
|
|
45
|
+
uses: codecov/codecov-action@v5
|
|
46
46
|
if: matrix.node-version == '20.x'
|
|
47
47
|
with:
|
|
48
48
|
files: ./coverage/coverage-final.json
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unread.d.ts","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"unread.d.ts","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+FpC,wBAAgB,kBAAkB,IAAI,OAAO,CA0B5C"}
|
package/dist/commands/unread.js
CHANGED
|
@@ -12,10 +12,10 @@ const channel_formatters_1 = require("../utils/formatters/channel-formatters");
|
|
|
12
12
|
const message_formatters_1 = require("../utils/formatters/message-formatters");
|
|
13
13
|
const constants_1 = require("../utils/constants");
|
|
14
14
|
const option_parsers_1 = require("../utils/option-parsers");
|
|
15
|
-
async function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
async function fetchChannelUnreadData(client, channelName) {
|
|
16
|
+
return await client.getChannelUnread(channelName);
|
|
17
|
+
}
|
|
18
|
+
function formatChannelUnreadOutput(result, format, countOnly) {
|
|
19
19
|
const formatter = (0, message_formatters_1.createMessageFormatter)(format);
|
|
20
20
|
formatter.format({
|
|
21
21
|
channel: result.channel,
|
|
@@ -24,30 +24,46 @@ async function handleSpecificChannelUnread(client, options) {
|
|
|
24
24
|
countOnly: countOnly,
|
|
25
25
|
format: format,
|
|
26
26
|
});
|
|
27
|
+
}
|
|
28
|
+
async function markChannelAsRead(client, channel) {
|
|
29
|
+
await client.markAsRead(channel.id);
|
|
30
|
+
console.log(chalk_1.default.green(`✓ Marked messages in #${channel.name} as read`));
|
|
31
|
+
}
|
|
32
|
+
async function handleSpecificChannelUnread(client, options) {
|
|
33
|
+
const result = await fetchChannelUnreadData(client, options.channel);
|
|
34
|
+
const format = (0, option_parsers_1.parseFormat)(options.format);
|
|
35
|
+
const countOnly = (0, option_parsers_1.parseBoolean)(options.countOnly);
|
|
36
|
+
formatChannelUnreadOutput(result, format, countOnly);
|
|
27
37
|
if ((0, option_parsers_1.parseBoolean)(options.markRead)) {
|
|
28
|
-
await client
|
|
29
|
-
|
|
38
|
+
await markChannelAsRead(client, result.channel);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function fetchAllUnreadChannels(client) {
|
|
42
|
+
return await client.listUnreadChannels();
|
|
43
|
+
}
|
|
44
|
+
function formatAllChannelsOutput(channels, format, countOnly, limit) {
|
|
45
|
+
const displayChannels = channels.slice(0, limit);
|
|
46
|
+
const formatter = (0, channel_formatters_1.createChannelFormatter)(format, countOnly);
|
|
47
|
+
formatter.format({ channels: displayChannels, countOnly: countOnly });
|
|
48
|
+
}
|
|
49
|
+
async function markAllChannelsAsRead(client, channels) {
|
|
50
|
+
for (const channel of channels) {
|
|
51
|
+
await client.markAsRead(channel.id);
|
|
30
52
|
}
|
|
53
|
+
console.log(chalk_1.default.green('✓ Marked all messages as read'));
|
|
31
54
|
}
|
|
32
55
|
async function handleAllChannelsUnread(client, options) {
|
|
33
|
-
const channels = await client
|
|
56
|
+
const channels = await fetchAllUnreadChannels(client);
|
|
34
57
|
if (channels.length === 0) {
|
|
35
58
|
console.log(chalk_1.default.green('✓ No unread messages'));
|
|
36
59
|
return;
|
|
37
60
|
}
|
|
38
|
-
// Apply limit
|
|
39
61
|
const limit = (0, option_parsers_1.parseLimit)(options.limit, constants_1.DEFAULTS.UNREAD_DISPLAY_LIMIT);
|
|
40
|
-
const displayChannels = channels.slice(0, limit);
|
|
41
62
|
const format = (0, option_parsers_1.parseFormat)(options.format);
|
|
42
63
|
const countOnly = (0, option_parsers_1.parseBoolean)(options.countOnly);
|
|
43
|
-
|
|
44
|
-
formatter.format({ channels: displayChannels, countOnly: countOnly });
|
|
64
|
+
formatAllChannelsOutput(channels, format, countOnly, limit);
|
|
45
65
|
if ((0, option_parsers_1.parseBoolean)(options.markRead)) {
|
|
46
|
-
|
|
47
|
-
for (const channel of channels) {
|
|
48
|
-
await client.markAsRead(channel.id);
|
|
49
|
-
}
|
|
50
|
-
console.log(chalk_1.default.green('✓ Marked all messages as read'));
|
|
66
|
+
await markAllChannelsAsRead(client, channels);
|
|
51
67
|
}
|
|
52
68
|
}
|
|
53
69
|
function setupUnreadCommand() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unread.js","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"unread.js","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;IAG7B,IAAI,CAAC,EAAE,MAAM;gBADpB,OAAO,EAAE,MAAM,EACR,IAAI,CAAC,EAAE,MAAM,YAAA;CAKvB;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,OAAO,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;IAG7B,IAAI,CAAC,EAAE,MAAM;gBADpB,OAAO,EAAE,MAAM,EACR,IAAI,CAAC,EAAE,MAAM,YAAA;CAKvB;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,QAAS,SAAQ,aAAa;gBAC7B,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,SAAU,SAAQ,aAAa;gBAC9B,OAAO,EAAE,MAAM;CAG5B"}
|
package/dist/utils/errors.js
CHANGED
|
@@ -5,35 +5,31 @@ class SlackCliError extends Error {
|
|
|
5
5
|
constructor(message, code) {
|
|
6
6
|
super(message);
|
|
7
7
|
this.code = code;
|
|
8
|
-
this.name =
|
|
8
|
+
this.name = this.constructor.name;
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
exports.SlackCliError = SlackCliError;
|
|
12
12
|
class ConfigurationError extends SlackCliError {
|
|
13
13
|
constructor(message) {
|
|
14
14
|
super(message, 'CONFIGURATION_ERROR');
|
|
15
|
-
this.name = 'ConfigurationError';
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
17
|
exports.ConfigurationError = ConfigurationError;
|
|
19
18
|
class ValidationError extends SlackCliError {
|
|
20
19
|
constructor(message) {
|
|
21
20
|
super(message, 'VALIDATION_ERROR');
|
|
22
|
-
this.name = 'ValidationError';
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
exports.ValidationError = ValidationError;
|
|
26
24
|
class ApiError extends SlackCliError {
|
|
27
25
|
constructor(message) {
|
|
28
26
|
super(message, 'API_ERROR');
|
|
29
|
-
this.name = 'ApiError';
|
|
30
27
|
}
|
|
31
28
|
}
|
|
32
29
|
exports.ApiError = ApiError;
|
|
33
30
|
class FileError extends SlackCliError {
|
|
34
31
|
constructor(message) {
|
|
35
32
|
super(message, 'FILE_ERROR');
|
|
36
|
-
this.name = 'FileError';
|
|
37
33
|
}
|
|
38
34
|
}
|
|
39
35
|
exports.FileError = FileError;
|
package/dist/utils/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,aAAc,SAAQ,KAAK;IACtC,YACE,OAAe,EACR,IAAa;QAEpB,KAAK,CAAC,OAAO,CAAC,CAAC;QAFR,SAAI,GAAJ,IAAI,CAAS;QAGpB,IAAI,CAAC,IAAI,GAAG,
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,aAAc,SAAQ,KAAK;IACtC,YACE,OAAe,EACR,IAAa;QAEpB,KAAK,CAAC,OAAO,CAAC,CAAC;QAFR,SAAI,GAAJ,IAAI,CAAS;QAGpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IACpC,CAAC;CACF;AARD,sCAQC;AAED,MAAa,kBAAmB,SAAQ,aAAa;IACnD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;IACxC,CAAC;CACF;AAJD,gDAIC;AAED,MAAa,eAAgB,SAAQ,aAAa;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;IACrC,CAAC;CACF;AAJD,0CAIC;AAED,MAAa,QAAS,SAAQ,aAAa;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC9B,CAAC;CACF;AAJD,4BAIC;AAED,MAAa,SAAU,SAAQ,aAAa;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC/B,CAAC;CACF;AAJD,8BAIC"}
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import eslint from '@eslint/js';
|
|
2
|
+
import tseslint from 'typescript-eslint';
|
|
3
|
+
import prettierConfig from 'eslint-config-prettier';
|
|
4
|
+
|
|
5
|
+
export default [
|
|
6
|
+
{
|
|
7
|
+
ignores: ['dist/**', 'node_modules/**', 'coverage/**', 'vitest.config.ts']
|
|
8
|
+
},
|
|
9
|
+
eslint.configs.recommended,
|
|
10
|
+
...tseslint.configs.recommended,
|
|
11
|
+
prettierConfig,
|
|
12
|
+
{
|
|
13
|
+
languageOptions: {
|
|
14
|
+
ecmaVersion: 2020,
|
|
15
|
+
sourceType: 'module',
|
|
16
|
+
parserOptions: {
|
|
17
|
+
project: './tsconfig.json'
|
|
18
|
+
},
|
|
19
|
+
globals: {
|
|
20
|
+
console: 'readonly',
|
|
21
|
+
process: 'readonly',
|
|
22
|
+
Buffer: 'readonly',
|
|
23
|
+
__dirname: 'readonly',
|
|
24
|
+
__filename: 'readonly',
|
|
25
|
+
exports: 'readonly',
|
|
26
|
+
module: 'readonly',
|
|
27
|
+
require: 'readonly',
|
|
28
|
+
global: 'readonly'
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
rules: {
|
|
32
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
33
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
34
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
35
|
+
'no-console': 'off'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@urugus/slack-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "A command-line tool for sending messages to Slack",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -31,27 +31,25 @@
|
|
|
31
31
|
},
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@slack/web-api": "^
|
|
35
|
-
"chalk": "^4.1
|
|
36
|
-
"commander": "^
|
|
37
|
-
"dotenv": "^16.3.1",
|
|
38
|
-
"inquirer": "^8.2.6",
|
|
34
|
+
"@slack/web-api": "^7.9.3",
|
|
35
|
+
"chalk": "^5.4.1",
|
|
36
|
+
"commander": "^14.0.0",
|
|
39
37
|
"p-limit": "^3.1.0"
|
|
40
38
|
},
|
|
41
39
|
"devDependencies": {
|
|
42
|
-
"@types/inquirer": "^8.2.10",
|
|
43
40
|
"@types/node": "^20.10.0",
|
|
44
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
45
|
-
"@typescript-eslint/parser": "^
|
|
46
|
-
"@vitest/coverage-v8": "^
|
|
47
|
-
"eslint": "^
|
|
48
|
-
"eslint-config-prettier": "^
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^8.34.1",
|
|
42
|
+
"@typescript-eslint/parser": "^8.34.1",
|
|
43
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
44
|
+
"eslint": "^9.30.0",
|
|
45
|
+
"eslint-config-prettier": "^10.1.5",
|
|
49
46
|
"prettier": "^3.1.1",
|
|
50
47
|
"ts-node": "^10.9.1",
|
|
51
48
|
"typescript": "^5.3.2",
|
|
52
|
-
"
|
|
49
|
+
"typescript-eslint": "^8.35.0",
|
|
50
|
+
"vitest": "^3.2.4"
|
|
53
51
|
},
|
|
54
52
|
"engines": {
|
|
55
|
-
"node": ">=
|
|
53
|
+
"node": ">=20.0.0"
|
|
56
54
|
}
|
|
57
55
|
}
|
package/src/commands/unread.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { wrapCommand } from '../utils/command-wrapper';
|
|
3
3
|
import { createSlackClient } from '../utils/client-factory';
|
|
4
|
-
import { SlackApiClient } from '../utils/slack-api-client';
|
|
4
|
+
import { SlackApiClient, ChannelUnreadResult, Channel } from '../utils/slack-api-client';
|
|
5
5
|
import { UnreadOptions } from '../types/commands';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import { createChannelFormatter } from '../utils/formatters/channel-formatters';
|
|
@@ -9,15 +9,15 @@ import { createMessageFormatter } from '../utils/formatters/message-formatters';
|
|
|
9
9
|
import { DEFAULTS } from '../utils/constants';
|
|
10
10
|
import { parseLimit, parseFormat, parseBoolean } from '../utils/option-parsers';
|
|
11
11
|
|
|
12
|
-
async function
|
|
13
|
-
client
|
|
14
|
-
|
|
15
|
-
): Promise<void> {
|
|
16
|
-
const result = await client.getChannelUnread(options.channel!);
|
|
17
|
-
|
|
18
|
-
const format = parseFormat(options.format);
|
|
19
|
-
const countOnly = parseBoolean(options.countOnly);
|
|
12
|
+
async function fetchChannelUnreadData(client: SlackApiClient, channelName: string) {
|
|
13
|
+
return await client.getChannelUnread(channelName);
|
|
14
|
+
}
|
|
20
15
|
|
|
16
|
+
function formatChannelUnreadOutput(
|
|
17
|
+
result: ChannelUnreadResult,
|
|
18
|
+
format: string,
|
|
19
|
+
countOnly: boolean
|
|
20
|
+
): void {
|
|
21
21
|
const formatter = createMessageFormatter(format);
|
|
22
22
|
formatter.format({
|
|
23
23
|
channel: result.channel,
|
|
@@ -26,40 +26,70 @@ async function handleSpecificChannelUnread(
|
|
|
26
26
|
countOnly: countOnly,
|
|
27
27
|
format: format,
|
|
28
28
|
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function markChannelAsRead(client: SlackApiClient, channel: Channel): Promise<void> {
|
|
32
|
+
await client.markAsRead(channel.id);
|
|
33
|
+
console.log(chalk.green(`✓ Marked messages in #${channel.name} as read`));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function handleSpecificChannelUnread(
|
|
37
|
+
client: SlackApiClient,
|
|
38
|
+
options: UnreadOptions
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
const result = await fetchChannelUnreadData(client, options.channel!);
|
|
41
|
+
|
|
42
|
+
const format = parseFormat(options.format);
|
|
43
|
+
const countOnly = parseBoolean(options.countOnly);
|
|
44
|
+
|
|
45
|
+
formatChannelUnreadOutput(result, format, countOnly);
|
|
29
46
|
|
|
30
47
|
if (parseBoolean(options.markRead)) {
|
|
31
|
-
await client
|
|
32
|
-
console.log(chalk.green(`✓ Marked messages in #${result.channel.name} as read`));
|
|
48
|
+
await markChannelAsRead(client, result.channel);
|
|
33
49
|
}
|
|
34
50
|
}
|
|
35
51
|
|
|
52
|
+
async function fetchAllUnreadChannels(client: SlackApiClient) {
|
|
53
|
+
return await client.listUnreadChannels();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function formatAllChannelsOutput(
|
|
57
|
+
channels: Channel[],
|
|
58
|
+
format: string,
|
|
59
|
+
countOnly: boolean,
|
|
60
|
+
limit: number
|
|
61
|
+
): void {
|
|
62
|
+
const displayChannels = channels.slice(0, limit);
|
|
63
|
+
const formatter = createChannelFormatter(format, countOnly);
|
|
64
|
+
formatter.format({ channels: displayChannels, countOnly: countOnly });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function markAllChannelsAsRead(client: SlackApiClient, channels: Channel[]): Promise<void> {
|
|
68
|
+
for (const channel of channels) {
|
|
69
|
+
await client.markAsRead(channel.id);
|
|
70
|
+
}
|
|
71
|
+
console.log(chalk.green('✓ Marked all messages as read'));
|
|
72
|
+
}
|
|
73
|
+
|
|
36
74
|
async function handleAllChannelsUnread(
|
|
37
75
|
client: SlackApiClient,
|
|
38
76
|
options: UnreadOptions
|
|
39
77
|
): Promise<void> {
|
|
40
|
-
const channels = await client
|
|
78
|
+
const channels = await fetchAllUnreadChannels(client);
|
|
41
79
|
|
|
42
80
|
if (channels.length === 0) {
|
|
43
81
|
console.log(chalk.green('✓ No unread messages'));
|
|
44
82
|
return;
|
|
45
83
|
}
|
|
46
84
|
|
|
47
|
-
// Apply limit
|
|
48
85
|
const limit = parseLimit(options.limit, DEFAULTS.UNREAD_DISPLAY_LIMIT);
|
|
49
|
-
const displayChannels = channels.slice(0, limit);
|
|
50
|
-
|
|
51
86
|
const format = parseFormat(options.format);
|
|
52
87
|
const countOnly = parseBoolean(options.countOnly);
|
|
53
88
|
|
|
54
|
-
|
|
55
|
-
formatter.format({ channels: displayChannels, countOnly: countOnly });
|
|
89
|
+
formatAllChannelsOutput(channels, format, countOnly, limit);
|
|
56
90
|
|
|
57
91
|
if (parseBoolean(options.markRead)) {
|
|
58
|
-
|
|
59
|
-
for (const channel of channels) {
|
|
60
|
-
await client.markAsRead(channel.id);
|
|
61
|
-
}
|
|
62
|
-
console.log(chalk.green('✓ Marked all messages as read'));
|
|
92
|
+
await markAllChannelsAsRead(client, channels);
|
|
63
93
|
}
|
|
64
94
|
}
|
|
65
95
|
|
package/src/utils/errors.ts
CHANGED
|
@@ -4,34 +4,30 @@ export class SlackCliError extends Error {
|
|
|
4
4
|
public code?: string
|
|
5
5
|
) {
|
|
6
6
|
super(message);
|
|
7
|
-
this.name =
|
|
7
|
+
this.name = this.constructor.name;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export class ConfigurationError extends SlackCliError {
|
|
12
12
|
constructor(message: string) {
|
|
13
13
|
super(message, 'CONFIGURATION_ERROR');
|
|
14
|
-
this.name = 'ConfigurationError';
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
export class ValidationError extends SlackCliError {
|
|
19
18
|
constructor(message: string) {
|
|
20
19
|
super(message, 'VALIDATION_ERROR');
|
|
21
|
-
this.name = 'ValidationError';
|
|
22
20
|
}
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
export class ApiError extends SlackCliError {
|
|
26
24
|
constructor(message: string) {
|
|
27
25
|
super(message, 'API_ERROR');
|
|
28
|
-
this.name = 'ApiError';
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
export class FileError extends SlackCliError {
|
|
33
30
|
constructor(message: string) {
|
|
34
31
|
super(message, 'FILE_ERROR');
|
|
35
|
-
this.name = 'FileError';
|
|
36
32
|
}
|
|
37
33
|
}
|
package/tests/index.test.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { readFileSync } from 'fs';
|
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
|
|
6
6
|
describe('slack-cli version', () => {
|
|
7
|
-
it('should display the correct version from package.json', () => {
|
|
7
|
+
it('should display the correct version from package.json', { timeout: 20000 }, () => {
|
|
8
8
|
// Read the expected version from package.json
|
|
9
9
|
const packageJson = JSON.parse(
|
|
10
10
|
readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')
|
|
@@ -21,7 +21,7 @@ describe('slack-cli version', () => {
|
|
|
21
21
|
expect(output).toBe(expectedVersion);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
it('should display version with -V flag', () => {
|
|
24
|
+
it('should display version with -V flag', { timeout: 20000 }, () => {
|
|
25
25
|
// Read the expected version from package.json
|
|
26
26
|
const packageJson = JSON.parse(
|
|
27
27
|
readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')
|
package/.eslintrc.json
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"parser": "@typescript-eslint/parser",
|
|
3
|
-
"extends": [
|
|
4
|
-
"eslint:recommended",
|
|
5
|
-
"plugin:@typescript-eslint/recommended",
|
|
6
|
-
"prettier"
|
|
7
|
-
],
|
|
8
|
-
"plugins": ["@typescript-eslint"],
|
|
9
|
-
"parserOptions": {
|
|
10
|
-
"ecmaVersion": 2020,
|
|
11
|
-
"sourceType": "module",
|
|
12
|
-
"project": "./tsconfig.json"
|
|
13
|
-
},
|
|
14
|
-
"env": {
|
|
15
|
-
"node": true,
|
|
16
|
-
"es2020": true
|
|
17
|
-
},
|
|
18
|
-
"rules": {
|
|
19
|
-
"@typescript-eslint/explicit-function-return-type": "off",
|
|
20
|
-
"@typescript-eslint/no-explicit-any": "warn",
|
|
21
|
-
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
|
22
|
-
"no-console": "off"
|
|
23
|
-
},
|
|
24
|
-
"ignorePatterns": ["dist", "node_modules", "coverage", "vitest.config.ts"]
|
|
25
|
-
}
|
package/dist/utils/config.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Config, ConfigOptions } from '../types/config';
|
|
2
|
-
export declare class ConfigManager {
|
|
3
|
-
private configPath;
|
|
4
|
-
constructor(options?: ConfigOptions);
|
|
5
|
-
setToken(token: string): Promise<void>;
|
|
6
|
-
getConfig(): Promise<Config | null>;
|
|
7
|
-
clearConfig(): Promise<void>;
|
|
8
|
-
maskToken(token: string): string;
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE7D,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,GAAE,aAAkB;IAKjC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAatC,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAqBnC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAUlC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAUjC"}
|
package/dist/utils/config.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.ConfigManager = void 0;
|
|
37
|
-
const fs = __importStar(require("fs/promises"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
const os = __importStar(require("os"));
|
|
40
|
-
class ConfigManager {
|
|
41
|
-
constructor(options = {}) {
|
|
42
|
-
const configDir = options.configDir || path.join(os.homedir(), '.slack-cli');
|
|
43
|
-
this.configPath = path.join(configDir, 'config.json');
|
|
44
|
-
}
|
|
45
|
-
async setToken(token) {
|
|
46
|
-
const config = {
|
|
47
|
-
token,
|
|
48
|
-
updatedAt: new Date().toISOString(),
|
|
49
|
-
};
|
|
50
|
-
const configDir = path.dirname(this.configPath);
|
|
51
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
52
|
-
await fs.writeFile(this.configPath, JSON.stringify(config, null, 2));
|
|
53
|
-
await fs.chmod(this.configPath, 0o600);
|
|
54
|
-
}
|
|
55
|
-
async getConfig() {
|
|
56
|
-
try {
|
|
57
|
-
const data = await fs.readFile(this.configPath, 'utf-8');
|
|
58
|
-
const config = JSON.parse(data);
|
|
59
|
-
if (!config.token || !config.updatedAt) {
|
|
60
|
-
throw new Error('Invalid config file format');
|
|
61
|
-
}
|
|
62
|
-
return config;
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
if (error instanceof SyntaxError) {
|
|
69
|
-
throw new Error('Invalid config file format');
|
|
70
|
-
}
|
|
71
|
-
throw error;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
async clearConfig() {
|
|
75
|
-
try {
|
|
76
|
-
await fs.unlink(this.configPath);
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
if (error && typeof error === 'object' && 'code' in error && error.code !== 'ENOENT') {
|
|
80
|
-
throw error;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
maskToken(token) {
|
|
85
|
-
if (token.length <= 9) {
|
|
86
|
-
return '****';
|
|
87
|
-
}
|
|
88
|
-
const prefix = token.substring(0, 4);
|
|
89
|
-
const suffix = token.substring(token.length - 4);
|
|
90
|
-
return `${prefix}-****-****-${suffix}`;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
exports.ConfigManager = ConfigManager;
|
|
94
|
-
//# sourceMappingURL=config.js.map
|
package/dist/utils/config.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAkC;AAClC,2CAA6B;AAC7B,uCAAyB;AAGzB,MAAa,aAAa;IAGxB,YAAY,UAAyB,EAAE;QACrC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;QAC7E,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAa;QAC1B,MAAM,MAAM,GAAW;YACrB,KAAK;YACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,SAAS;QACb,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAEhC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBACvC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChD,CAAC;YAED,OAAO,MAAgB,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrF,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;gBACjC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChD,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrF,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,CAAC,KAAa;QACrB,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEjD,OAAO,GAAG,MAAM,cAAc,MAAM,EAAE,CAAC;IACzC,CAAC;CACF;AA9DD,sCA8DC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"output-formatter.d.ts","sourceRoot":"","sources":["../../../src/utils/formatters/output-formatter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC;CACzB;AAED,8BAAsB,aAAa,CAAC,CAAC,CAAE,YAAW,eAAe,CAAC,CAAC,CAAC;IAClE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI;CACjC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"output-formatter.js","sourceRoot":"","sources":["../../../src/utils/formatters/output-formatter.ts"],"names":[],"mappings":";;;AAIA,MAAsB,aAAa;CAElC;AAFD,sCAEC"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { Config, ConfigOptions, Profile } from '../types/config';
|
|
2
|
-
export declare class ProfileConfigManager {
|
|
3
|
-
private fileManager;
|
|
4
|
-
private cryptoService;
|
|
5
|
-
private profileManager;
|
|
6
|
-
constructor(_options?: ConfigOptions);
|
|
7
|
-
setToken(token: string, profile?: string): Promise<void>;
|
|
8
|
-
getConfig(profile?: string): Promise<Config | null>;
|
|
9
|
-
listProfiles(): Promise<Profile[]>;
|
|
10
|
-
useProfile(profile: string): Promise<void>;
|
|
11
|
-
getCurrentProfile(): Promise<string>;
|
|
12
|
-
clearConfig(profile?: string): Promise<void>;
|
|
13
|
-
maskToken(token: string): string;
|
|
14
|
-
migrateIfNeeded(): Promise<void>;
|
|
15
|
-
}
|
|
16
|
-
export declare const profileConfig: {
|
|
17
|
-
getCurrentProfile: () => string;
|
|
18
|
-
getToken: (_profile?: string) => string | undefined;
|
|
19
|
-
};
|
|
20
|
-
//# sourceMappingURL=profile-config-refactored.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"profile-config-refactored.d.ts","sourceRoot":"","sources":["../../src/utils/profile-config-refactored.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAOtE,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,cAAc,CAAiB;gBAE3B,QAAQ,GAAE,aAAkB;IAQlC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBxD,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAcnD,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAiBlC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1C,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIpC,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgClD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAY1B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAwBvC;AAGD,eAAO,MAAM,aAAa;6BACD,MAAM;0BAGP,MAAM,KAAG,MAAM,GAAG,SAAS;CAKlD,CAAC"}
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.profileConfig = exports.ProfileConfigManager = void 0;
|
|
37
|
-
const constants_1 = require("./constants");
|
|
38
|
-
const config_file_manager_1 = require("./config/config-file-manager");
|
|
39
|
-
const token_crypto_service_1 = require("./config/token-crypto-service");
|
|
40
|
-
const profile_manager_1 = require("./config/profile-manager");
|
|
41
|
-
const fs = __importStar(require("fs/promises"));
|
|
42
|
-
class ProfileConfigManager {
|
|
43
|
-
constructor(_options = {}) {
|
|
44
|
-
// Note: ConfigFileManager currently doesn't support custom configDir
|
|
45
|
-
// This would need to be added if required
|
|
46
|
-
this.fileManager = new config_file_manager_1.ConfigFileManager();
|
|
47
|
-
this.cryptoService = new token_crypto_service_1.TokenCryptoService();
|
|
48
|
-
this.profileManager = new profile_manager_1.ProfileManager(this.fileManager, this.cryptoService);
|
|
49
|
-
}
|
|
50
|
-
async setToken(token, profile) {
|
|
51
|
-
const profileName = profile || (await this.profileManager.getCurrentProfile());
|
|
52
|
-
const config = {
|
|
53
|
-
token,
|
|
54
|
-
updatedAt: new Date().toISOString(),
|
|
55
|
-
};
|
|
56
|
-
await this.profileManager.setProfile(profileName, config);
|
|
57
|
-
// Set as default profile if it's the first one or explicitly setting default
|
|
58
|
-
const profiles = await this.profileManager.listProfiles();
|
|
59
|
-
if (profiles.length === 1 || profileName === constants_1.DEFAULT_PROFILE_NAME) {
|
|
60
|
-
await this.profileManager.setCurrentProfile(profileName);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
async getConfig(profile) {
|
|
64
|
-
const profileName = profile || (await this.profileManager.getCurrentProfile());
|
|
65
|
-
try {
|
|
66
|
-
return await this.profileManager.getProfile(profileName);
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
// Return null if profile not found
|
|
70
|
-
if (error instanceof Error && error.message.includes('not found')) {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
throw error;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
async listProfiles() {
|
|
77
|
-
const profileNames = await this.profileManager.listProfiles();
|
|
78
|
-
const currentProfile = await this.profileManager.getCurrentProfile();
|
|
79
|
-
const profiles = [];
|
|
80
|
-
for (const name of profileNames) {
|
|
81
|
-
const config = await this.profileManager.getProfile(name);
|
|
82
|
-
profiles.push({
|
|
83
|
-
name,
|
|
84
|
-
config,
|
|
85
|
-
isDefault: name === currentProfile,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
return profiles;
|
|
89
|
-
}
|
|
90
|
-
async useProfile(profile) {
|
|
91
|
-
const exists = await this.profileManager.profileExists(profile);
|
|
92
|
-
if (!exists) {
|
|
93
|
-
throw new Error(`Profile "${profile}" does not exist`);
|
|
94
|
-
}
|
|
95
|
-
await this.profileManager.setCurrentProfile(profile);
|
|
96
|
-
}
|
|
97
|
-
async getCurrentProfile() {
|
|
98
|
-
return await this.profileManager.getCurrentProfile();
|
|
99
|
-
}
|
|
100
|
-
async clearConfig(profile) {
|
|
101
|
-
const profileName = profile || (await this.profileManager.getCurrentProfile());
|
|
102
|
-
try {
|
|
103
|
-
await this.profileManager.deleteProfile(profileName);
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
// If profile doesn't exist, do nothing
|
|
107
|
-
if (error instanceof Error && error.message.includes('not found')) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
throw error;
|
|
111
|
-
}
|
|
112
|
-
// If we deleted the current profile, set a new default
|
|
113
|
-
const currentProfile = await this.profileManager.getCurrentProfile();
|
|
114
|
-
if (currentProfile === profileName) {
|
|
115
|
-
const remainingProfiles = await this.profileManager.listProfiles();
|
|
116
|
-
if (remainingProfiles.length > 0) {
|
|
117
|
-
await this.profileManager.setCurrentProfile(remainingProfiles[0]);
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
// No profiles left, delete the config file
|
|
121
|
-
try {
|
|
122
|
-
await fs.unlink(this.fileManager.getConfigPath());
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
if (error && typeof error === 'object' && 'code' in error && error.code !== 'ENOENT') {
|
|
126
|
-
throw error;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
maskToken(token) {
|
|
133
|
-
if (token.length <= constants_1.TOKEN_MIN_LENGTH) {
|
|
134
|
-
return '****';
|
|
135
|
-
}
|
|
136
|
-
const prefix = token.substring(0, constants_1.TOKEN_MASK_LENGTH);
|
|
137
|
-
const suffix = token.substring(token.length - constants_1.TOKEN_MASK_LENGTH);
|
|
138
|
-
return `${prefix}-****-****-${suffix}`;
|
|
139
|
-
}
|
|
140
|
-
// Migration support - to be called separately if needed
|
|
141
|
-
async migrateIfNeeded() {
|
|
142
|
-
const data = await this.fileManager.read();
|
|
143
|
-
// Check if migration is needed (old format detection)
|
|
144
|
-
const anyData = data;
|
|
145
|
-
if (anyData.token && !anyData.profiles) {
|
|
146
|
-
// Old format detected, migrate
|
|
147
|
-
const oldConfig = {
|
|
148
|
-
token: anyData.token,
|
|
149
|
-
updatedAt: anyData.updatedAt || new Date().toISOString(),
|
|
150
|
-
};
|
|
151
|
-
// Create new format
|
|
152
|
-
const newData = {
|
|
153
|
-
profiles: { [constants_1.DEFAULT_PROFILE_NAME]: oldConfig },
|
|
154
|
-
currentProfile: constants_1.DEFAULT_PROFILE_NAME,
|
|
155
|
-
};
|
|
156
|
-
await this.fileManager.write(newData);
|
|
157
|
-
// Re-encrypt token using new service
|
|
158
|
-
await this.setToken(oldConfig.token, constants_1.DEFAULT_PROFILE_NAME);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
exports.ProfileConfigManager = ProfileConfigManager;
|
|
163
|
-
// Export a simplified version for backward compatibility
|
|
164
|
-
exports.profileConfig = {
|
|
165
|
-
getCurrentProfile: () => {
|
|
166
|
-
return constants_1.DEFAULT_PROFILE_NAME;
|
|
167
|
-
},
|
|
168
|
-
getToken: (_profile) => {
|
|
169
|
-
// This is a simplified version for testing
|
|
170
|
-
// In real usage, it would need to be async
|
|
171
|
-
return undefined;
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
//# sourceMappingURL=profile-config-refactored.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"profile-config-refactored.js","sourceRoot":"","sources":["../../src/utils/profile-config-refactored.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,2CAAwF;AACxF,sEAAiE;AACjE,wEAAmE;AACnE,8DAA0D;AAC1D,gDAAkC;AAElC,MAAa,oBAAoB;IAK/B,YAAY,WAA0B,EAAE;QACtC,qEAAqE;QACrE,0CAA0C;QAC1C,IAAI,CAAC,WAAW,GAAG,IAAI,uCAAiB,EAAE,CAAC;QAC3C,IAAI,CAAC,aAAa,GAAG,IAAI,yCAAkB,EAAE,CAAC;QAC9C,IAAI,CAAC,cAAc,GAAG,IAAI,gCAAc,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACjF,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,OAAgB;QAC5C,MAAM,WAAW,GAAG,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAC/E,MAAM,MAAM,GAAW;YACrB,KAAK;YACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAE1D,6EAA6E;QAC7E,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC;QAC1D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,WAAW,KAAK,gCAAoB,EAAE,CAAC;YAClE,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAgB;QAC9B,MAAM,WAAW,GAAG,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAE/E,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,mCAAmC;YACnC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBAClE,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC;QAC9D,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,EAAE,CAAC;QAErE,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAC1D,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI;gBACJ,MAAM;gBACN,SAAS,EAAE,IAAI,KAAK,cAAc;aACnC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAe;QAC9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,kBAAkB,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,iBAAiB;QACrB,OAAO,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,EAAE,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAgB;QAChC,MAAM,WAAW,GAAG,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAE/E,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,uCAAuC;YACvC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBAClE,OAAO;YACT,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,uDAAuD;QACvD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,EAAE,CAAC;QACrE,IAAI,cAAc,KAAK,WAAW,EAAE,CAAC;YACnC,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC;YACnE,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjC,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;YACpE,CAAC;iBAAM,CAAC;gBACN,2CAA2C;gBAC3C,IAAI,CAAC;oBACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC;gBACpD,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACxB,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;wBACrF,MAAM,KAAK,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,CAAC,KAAa;QACrB,IAAI,KAAK,CAAC,MAAM,IAAI,4BAAgB,EAAE,CAAC;YACrC,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,6BAAiB,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,6BAAiB,CAAC,CAAC;QAEjE,OAAO,GAAG,MAAM,cAAc,MAAM,EAAE,CAAC;IACzC,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QAE3C,sDAAsD;QACtD,MAAM,OAAO,GAAG,IAA0C,CAAC;QAC3D,IAAI,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvC,+BAA+B;YAC/B,MAAM,SAAS,GAAW;gBACxB,KAAK,EAAE,OAAO,CAAC,KAAe;gBAC9B,SAAS,EAAG,OAAO,CAAC,SAAoB,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACrE,CAAC;YAEF,oBAAoB;YACpB,MAAM,OAAO,GAAG;gBACd,QAAQ,EAAE,EAAE,CAAC,gCAAoB,CAAC,EAAE,SAAS,EAAE;gBAC/C,cAAc,EAAE,gCAAoB;aACrC,CAAC;YAEF,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAEtC,qCAAqC;YACrC,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,gCAAoB,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;CACF;AA7ID,oDA6IC;AAED,yDAAyD;AAC5C,QAAA,aAAa,GAAG;IAC3B,iBAAiB,EAAE,GAAW,EAAE;QAC9B,OAAO,gCAAoB,CAAC;IAC9B,CAAC;IACD,QAAQ,EAAE,CAAC,QAAiB,EAAsB,EAAE;QAClD,2CAA2C;QAC3C,2CAA2C;QAC3C,OAAO,SAAS,CAAC;IACnB,CAAC;CACF,CAAC"}
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import { ChannelOperations } from '../../../src/utils/slack-operations/channel-operations';
|
|
3
|
-
import { WebClient } from '@slack/web-api';
|
|
4
|
-
|
|
5
|
-
vi.mock('@slack/web-api');
|
|
6
|
-
|
|
7
|
-
describe('ChannelOperations - refactored listUnreadChannels', () => {
|
|
8
|
-
let channelOps: ChannelOperations;
|
|
9
|
-
let mockClient: any;
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
vi.resetAllMocks();
|
|
13
|
-
mockClient = {
|
|
14
|
-
conversations: {
|
|
15
|
-
list: vi.fn(),
|
|
16
|
-
info: vi.fn(),
|
|
17
|
-
history: vi.fn(),
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
channelOps = new ChannelOperations(mockClient as WebClient);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
describe('listUnreadChannels', () => {
|
|
24
|
-
it('should fetch unread channels with proper separation of concerns', async () => {
|
|
25
|
-
const mockChannels = [
|
|
26
|
-
{ id: 'C1', name: 'general' },
|
|
27
|
-
{ id: 'C2', name: 'random' },
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
mockClient.conversations.list.mockResolvedValueOnce({
|
|
31
|
-
channels: mockChannels,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Channel 1 - has unread messages
|
|
35
|
-
mockClient.conversations.info.mockResolvedValueOnce({
|
|
36
|
-
channel: { id: 'C1', last_read: '1234567890.000000' },
|
|
37
|
-
});
|
|
38
|
-
mockClient.conversations.history
|
|
39
|
-
.mockResolvedValueOnce({ messages: [{ ts: '1234567900.000000' }] }) // latest message
|
|
40
|
-
.mockResolvedValueOnce({ messages: [{ ts: '1234567900.000000' }, { ts: '1234567895.000000' }] }); // messages after last_read
|
|
41
|
-
|
|
42
|
-
// Channel 2 - no unread messages
|
|
43
|
-
mockClient.conversations.info.mockResolvedValueOnce({
|
|
44
|
-
channel: { id: 'C2', last_read: '1234567900.000000' },
|
|
45
|
-
});
|
|
46
|
-
mockClient.conversations.history
|
|
47
|
-
.mockResolvedValueOnce({ messages: [{ ts: '1234567890.000000' }] }) // latest message
|
|
48
|
-
.mockResolvedValueOnce({ messages: [] }); // no messages after last_read
|
|
49
|
-
|
|
50
|
-
const result = await channelOps.listUnreadChannels();
|
|
51
|
-
|
|
52
|
-
expect(result).toHaveLength(1);
|
|
53
|
-
expect(result[0]).toMatchObject({
|
|
54
|
-
id: 'C1',
|
|
55
|
-
name: 'general',
|
|
56
|
-
unread_count: 2,
|
|
57
|
-
unread_count_display: 2,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Verify the separation of concerns - each method is called appropriately
|
|
61
|
-
expect(mockClient.conversations.list).toHaveBeenCalledOnce();
|
|
62
|
-
expect(mockClient.conversations.info).toHaveBeenCalledTimes(2);
|
|
63
|
-
expect(mockClient.conversations.history).toHaveBeenCalledTimes(4);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should handle channels with no last_read timestamp', async () => {
|
|
67
|
-
const mockChannels = [
|
|
68
|
-
{ id: 'C1', name: 'general' },
|
|
69
|
-
];
|
|
70
|
-
|
|
71
|
-
mockClient.conversations.list.mockResolvedValueOnce({
|
|
72
|
-
channels: mockChannels,
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
mockClient.conversations.info.mockResolvedValueOnce({
|
|
76
|
-
channel: { id: 'C1' }, // no last_read
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
mockClient.conversations.history
|
|
80
|
-
.mockResolvedValueOnce({ messages: [{ ts: '1234567900.000000' }] }) // check if has messages
|
|
81
|
-
.mockResolvedValueOnce({
|
|
82
|
-
messages: [
|
|
83
|
-
{ ts: '1234567900.000000' },
|
|
84
|
-
{ ts: '1234567895.000000' },
|
|
85
|
-
{ ts: '1234567890.000000' },
|
|
86
|
-
]
|
|
87
|
-
}); // all messages are unread
|
|
88
|
-
|
|
89
|
-
const result = await channelOps.listUnreadChannels();
|
|
90
|
-
|
|
91
|
-
expect(result).toHaveLength(1);
|
|
92
|
-
expect(result[0]).toMatchObject({
|
|
93
|
-
id: 'C1',
|
|
94
|
-
name: 'general',
|
|
95
|
-
unread_count: 3,
|
|
96
|
-
unread_count_display: 3,
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('should skip channels with no messages', async () => {
|
|
101
|
-
const mockChannels = [
|
|
102
|
-
{ id: 'C1', name: 'general' },
|
|
103
|
-
];
|
|
104
|
-
|
|
105
|
-
mockClient.conversations.list.mockResolvedValueOnce({
|
|
106
|
-
channels: mockChannels,
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
mockClient.conversations.info.mockResolvedValueOnce({
|
|
110
|
-
channel: { id: 'C1', last_read: '1234567890.000000' },
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
mockClient.conversations.history
|
|
114
|
-
.mockResolvedValueOnce({ messages: [] }); // no messages at all
|
|
115
|
-
|
|
116
|
-
const result = await channelOps.listUnreadChannels();
|
|
117
|
-
|
|
118
|
-
expect(result).toHaveLength(0);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('should handle rate limit errors gracefully', async () => {
|
|
122
|
-
const mockChannels = [
|
|
123
|
-
{ id: 'C1', name: 'general' },
|
|
124
|
-
{ id: 'C2', name: 'random' },
|
|
125
|
-
];
|
|
126
|
-
|
|
127
|
-
mockClient.conversations.list.mockResolvedValueOnce({
|
|
128
|
-
channels: mockChannels,
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// Channel 1 - rate limited
|
|
132
|
-
mockClient.conversations.info.mockRejectedValueOnce(new Error('rate_limited'));
|
|
133
|
-
|
|
134
|
-
// Channel 2 - successful
|
|
135
|
-
mockClient.conversations.info.mockResolvedValueOnce({
|
|
136
|
-
channel: { id: 'C2', last_read: '1234567890.000000' },
|
|
137
|
-
});
|
|
138
|
-
mockClient.conversations.history
|
|
139
|
-
.mockResolvedValueOnce({ messages: [{ ts: '1234567900.000000' }] })
|
|
140
|
-
.mockResolvedValueOnce({ messages: [{ ts: '1234567900.000000' }] });
|
|
141
|
-
|
|
142
|
-
const result = await channelOps.listUnreadChannels();
|
|
143
|
-
|
|
144
|
-
expect(result).toHaveLength(1);
|
|
145
|
-
expect(result[0].id).toBe('C2');
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
describe('private methods (indirectly tested)', () => {
|
|
150
|
-
it('fetchAllChannels should handle large channel lists', async () => {
|
|
151
|
-
const mockChannels = [
|
|
152
|
-
{ id: 'C1', name: 'channel-1' },
|
|
153
|
-
{ id: 'C2', name: 'channel-2' },
|
|
154
|
-
{ id: 'C3', name: 'channel-3' },
|
|
155
|
-
];
|
|
156
|
-
|
|
157
|
-
mockClient.conversations.list.mockResolvedValueOnce({
|
|
158
|
-
channels: mockChannels,
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// Mock all channels having no unread messages for simplicity
|
|
162
|
-
mockChannels.forEach(() => {
|
|
163
|
-
mockClient.conversations.info.mockResolvedValueOnce({
|
|
164
|
-
channel: { last_read: '9999999999.000000' },
|
|
165
|
-
});
|
|
166
|
-
mockClient.conversations.history.mockResolvedValueOnce({ messages: [] });
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
const result = await channelOps.listUnreadChannels();
|
|
170
|
-
|
|
171
|
-
expect(result).toHaveLength(0);
|
|
172
|
-
expect(mockClient.conversations.list).toHaveBeenCalledWith({
|
|
173
|
-
types: 'public_channel,private_channel,im,mpim',
|
|
174
|
-
exclude_archived: true,
|
|
175
|
-
limit: 1000,
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
});
|