@theholocron/holocron-plugin-slack 3.25.1 → 3.26.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 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.
@@ -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.25.1",
3
+ "version": "3.26.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.25.1"
24
+ "@theholocron/cli": "3.26.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.25.1"
42
+ "@theholocron/cli": "3.26.0"
43
43
  },
44
44
  "publishConfig": {
45
45
  "access": "public"