@theholocron/holocron-plugin-slack 3.25.1 → 3.27.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 +51 -0
- package/dist/index.d.mts +76 -0
- package/dist/index.mjs +99 -0
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!-- editorconfig-checker-disable-file -->
|
|
2
|
+
|
|
3
|
+
# `@theholocron/holocron-plugin-slack`
|
|
4
|
+
|
|
5
|
+
Slack plugin for [Holocron](../cli). Implements the `notifications`
|
|
6
|
+
capability via the [Slack Web API](https://api.slack.com/web).
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
<!-- prettier-ignore -->
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add -D @theholocron/holocron-plugin-slack
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Auth
|
|
17
|
+
|
|
18
|
+
Token resolution order:
|
|
19
|
+
|
|
20
|
+
1. `--token <TOKEN>` flag on the holocron invocation
|
|
21
|
+
2. `HOLOCRON_SLACK_TOKEN` env var
|
|
22
|
+
3. `SLACK_BOT_TOKEN` env var (the standard Slack variable name)
|
|
23
|
+
|
|
24
|
+
Create a Slack app at **api.slack.com/apps**, add the `chat:write` bot
|
|
25
|
+
scope, install it to your workspace, and copy the **Bot User OAuth Token**
|
|
26
|
+
(`xoxb-…`). The bot must be invited to any channel it will post to
|
|
27
|
+
(`/invite @YourBotName`).
|
|
28
|
+
|
|
29
|
+
## Config
|
|
30
|
+
|
|
31
|
+
<!-- prettier-ignore -->
|
|
32
|
+
```jsonc
|
|
33
|
+
{
|
|
34
|
+
"providers": {
|
|
35
|
+
"notifications": ["slack", { "defaultChannel": "C0123456789" }],
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- `defaultChannel` (optional) — Slack channel id used when `send()` is
|
|
42
|
+
called with an empty string.
|
|
43
|
+
|
|
44
|
+
## What's implemented
|
|
45
|
+
|
|
46
|
+
| Method | What it does |
|
|
47
|
+
| ------ | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
48
|
+
| `send` | Posts a plain-text message to the given channel id via `chat.postMessage`. Falls back to `defaultChannel` when `channel` is empty. |
|
|
49
|
+
|
|
50
|
+
Slack always returns HTTP 200 with an `ok` field — errors are surfaced as
|
|
51
|
+
`ProviderApiError` from the response body rather than from the HTTP status.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { AuthError, Notifications, ResolveTokenInput } from "@theholocron/cli";
|
|
2
|
+
//#region src/auth.d.ts
|
|
3
|
+
declare const resolveToken: (input?: ResolveTokenInput) => string;
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/rest.d.ts
|
|
6
|
+
interface SlackClientOptions {
|
|
7
|
+
token: string;
|
|
8
|
+
/** Override base URL for tests. Default: https://slack.com/api */
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
fetch?: typeof fetch;
|
|
11
|
+
}
|
|
12
|
+
interface SlackClient {
|
|
13
|
+
auth: {
|
|
14
|
+
test(): Promise<{
|
|
15
|
+
ok: true;
|
|
16
|
+
team: string;
|
|
17
|
+
user: string;
|
|
18
|
+
}>;
|
|
19
|
+
};
|
|
20
|
+
chat: {
|
|
21
|
+
postMessage(channel: string, text: string): Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
declare function createSlackClient({ token, baseUrl, fetch: fetchImpl }: SlackClientOptions): SlackClient;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/capabilities/notifications.d.ts
|
|
27
|
+
interface SlackNotificationsOptions {
|
|
28
|
+
/** Default channel id used when `send()` is called without an explicit channel. */
|
|
29
|
+
defaultChannel?: string;
|
|
30
|
+
}
|
|
31
|
+
declare class SlackNotifications implements Notifications {
|
|
32
|
+
private readonly client;
|
|
33
|
+
private readonly opts;
|
|
34
|
+
readonly key: "notifications";
|
|
35
|
+
readonly providerName = "slack";
|
|
36
|
+
constructor(client: SlackClient, opts: SlackNotificationsOptions);
|
|
37
|
+
send(channel: string, message: string): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/verify-token.d.ts
|
|
41
|
+
interface VerifyTokenSuccess {
|
|
42
|
+
ok: true;
|
|
43
|
+
subject: string;
|
|
44
|
+
}
|
|
45
|
+
interface VerifyTokenFailure {
|
|
46
|
+
ok: false;
|
|
47
|
+
message: string;
|
|
48
|
+
}
|
|
49
|
+
type VerifyTokenResult = VerifyTokenSuccess | VerifyTokenFailure;
|
|
50
|
+
interface VerifyTokenOptions {
|
|
51
|
+
baseUrl?: string;
|
|
52
|
+
fetch?: typeof fetch;
|
|
53
|
+
}
|
|
54
|
+
declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult>;
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/index.d.ts
|
|
57
|
+
interface SlackPluginOptions extends ResolveTokenInput, SlackNotificationsOptions {
|
|
58
|
+
/** Override base URL for tests. Default: https://slack.com/api */
|
|
59
|
+
baseUrl?: string;
|
|
60
|
+
fetch?: typeof fetch;
|
|
61
|
+
}
|
|
62
|
+
interface PluginContext {
|
|
63
|
+
options: SlackPluginOptions;
|
|
64
|
+
client: SlackClient;
|
|
65
|
+
}
|
|
66
|
+
declare function createContext(options?: SlackPluginOptions): PluginContext;
|
|
67
|
+
declare function notifications(ctx: PluginContext): Notifications;
|
|
68
|
+
declare function createPlugin(options?: SlackPluginOptions): {
|
|
69
|
+
name: string;
|
|
70
|
+
capabilities: {
|
|
71
|
+
notifications: () => Notifications;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
declare const AUTH_HINT: string;
|
|
75
|
+
//#endregion
|
|
76
|
+
export { AUTH_HINT, AuthError, PluginContext, type ResolveTokenInput, type SlackClient, type SlackClientOptions, SlackNotifications, type SlackNotificationsOptions, SlackPluginOptions, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, createContext, createPlugin, createSlackClient, notifications, resolveToken, verifyToken };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { AuthError, ProviderApiError, createResolveToken } from "@theholocron/cli";
|
|
2
|
+
//#region src/auth.ts
|
|
3
|
+
const resolveToken = createResolveToken({
|
|
4
|
+
envName: "HOLOCRON_SLACK_TOKEN",
|
|
5
|
+
vendorEnvName: "SLACK_BOT_TOKEN",
|
|
6
|
+
keyringService: "slack",
|
|
7
|
+
errorMessage: "no Slack bot token found. Pass --token <TOKEN>, set HOLOCRON_SLACK_TOKEN / SLACK_BOT_TOKEN, or run: holocron auth set slack <xoxb-TOKEN>"
|
|
8
|
+
});
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/capabilities/notifications.ts
|
|
11
|
+
var SlackNotifications = class {
|
|
12
|
+
client;
|
|
13
|
+
opts;
|
|
14
|
+
key = "notifications";
|
|
15
|
+
providerName = "slack";
|
|
16
|
+
constructor(client, opts) {
|
|
17
|
+
this.client = client;
|
|
18
|
+
this.opts = opts;
|
|
19
|
+
}
|
|
20
|
+
async send(channel, message) {
|
|
21
|
+
const ch = channel || this.opts.defaultChannel;
|
|
22
|
+
if (!ch) throw new Error("SlackNotifications.send: channel required (pass a channel id or set defaultChannel)");
|
|
23
|
+
await this.client.chat.postMessage(ch, message);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/rest.ts
|
|
28
|
+
function createSlackClient({ token, baseUrl, fetch: fetchImpl }) {
|
|
29
|
+
const base = baseUrl ?? "https://slack.com/api";
|
|
30
|
+
const f = fetchImpl ?? globalThis.fetch;
|
|
31
|
+
async function call(method, body) {
|
|
32
|
+
const res = await f(`${base}/${method}`, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: {
|
|
35
|
+
"content-type": "application/json; charset=utf-8",
|
|
36
|
+
authorization: `Bearer ${token}`
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify(body)
|
|
39
|
+
});
|
|
40
|
+
const data = await res.json();
|
|
41
|
+
if (!data.ok) throw new ProviderApiError(data.error ?? "unknown Slack error", res.status, data);
|
|
42
|
+
return data;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
auth: { test: () => call("auth.test", {}) },
|
|
46
|
+
chat: { postMessage: async (channel, text) => {
|
|
47
|
+
await call("chat.postMessage", {
|
|
48
|
+
channel,
|
|
49
|
+
text
|
|
50
|
+
});
|
|
51
|
+
} }
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/verify-token.ts
|
|
56
|
+
async function verifyToken(token, opts = {}) {
|
|
57
|
+
const client = createSlackClient({
|
|
58
|
+
token,
|
|
59
|
+
baseUrl: opts.baseUrl,
|
|
60
|
+
fetch: opts.fetch
|
|
61
|
+
});
|
|
62
|
+
try {
|
|
63
|
+
const res = await client.auth.test();
|
|
64
|
+
return {
|
|
65
|
+
ok: true,
|
|
66
|
+
subject: `${res.user} @ ${res.team}`
|
|
67
|
+
};
|
|
68
|
+
} catch (err) {
|
|
69
|
+
return {
|
|
70
|
+
ok: false,
|
|
71
|
+
message: err instanceof Error ? err.message : String(err)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/index.ts
|
|
77
|
+
function createContext(options = {}) {
|
|
78
|
+
return {
|
|
79
|
+
options,
|
|
80
|
+
client: createSlackClient({
|
|
81
|
+
token: resolveToken(options),
|
|
82
|
+
baseUrl: options.baseUrl,
|
|
83
|
+
fetch: options.fetch
|
|
84
|
+
})
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function notifications(ctx) {
|
|
88
|
+
return new SlackNotifications(ctx.client, ctx.options);
|
|
89
|
+
}
|
|
90
|
+
function createPlugin(options = {}) {
|
|
91
|
+
const ctx = createContext(options);
|
|
92
|
+
return {
|
|
93
|
+
name: "@theholocron/holocron-plugin-slack",
|
|
94
|
+
capabilities: { notifications: () => notifications(ctx) }
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const AUTH_HINT = "create a Slack app at https://api.slack.com/apps, add the chat:write bot scope, install it to your workspace, copy the Bot User OAuth Token (xoxb-...), then run: holocron auth set slack <xoxb-TOKEN>";
|
|
98
|
+
//#endregion
|
|
99
|
+
export { AUTH_HINT, AuthError, SlackNotifications, createContext, createPlugin, createSlackClient, notifications, resolveToken, verifyToken };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theholocron/holocron-plugin-slack",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.27.0",
|
|
4
4
|
"description": "Holocron plugin for Slack. Implements the notifications capability via Slack's bot API.",
|
|
5
5
|
"homepage": "https://github.com/theholocron/holocron/tree/main/packages/holocron-plugin-slack#readme",
|
|
6
6
|
"bugs": "https://github.com/theholocron/holocron/issues",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"@theholocron/cli": "3.
|
|
24
|
+
"@theholocron/cli": "3.27.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@theholocron/eslint-config": "^7.19.1",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"tsx": "4.22.4",
|
|
40
40
|
"typescript": "^5.9.3",
|
|
41
41
|
"vitest": "^4.1.10",
|
|
42
|
-
"@theholocron/cli": "3.
|
|
42
|
+
"@theholocron/cli": "3.27.0"
|
|
43
43
|
},
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|