@aigne/afs-slack 1.11.0-beta.12

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/LICENSE.md ADDED
@@ -0,0 +1,26 @@
1
+ # Proprietary License
2
+
3
+ Copyright (c) 2024-2025 ArcBlock, Inc. All Rights Reserved.
4
+
5
+ This software and associated documentation files (the "Software") are proprietary
6
+ and confidential. Unauthorized copying, modification, distribution, or use of
7
+ this Software, via any medium, is strictly prohibited.
8
+
9
+ The Software is provided for internal use only within ArcBlock, Inc. and its
10
+ authorized affiliates.
11
+
12
+ ## No License Granted
13
+
14
+ No license, express or implied, is granted to any party for any purpose.
15
+ All rights are reserved by ArcBlock, Inc.
16
+
17
+ ## Public Artifact Distribution
18
+
19
+ Portions of this Software may be released publicly under separate open-source
20
+ licenses (such as MIT License) through designated public repositories. Such
21
+ public releases are governed by their respective licenses and do not affect
22
+ the proprietary nature of this repository.
23
+
24
+ ## Contact
25
+
26
+ For licensing inquiries, contact: legal@arcblock.io
@@ -0,0 +1,11 @@
1
+
2
+ //#region \0@oxc-project+runtime@0.108.0/helpers/decorate.js
3
+ function __decorate(decorators, target, key, desc) {
4
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
5
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
6
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
7
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
8
+ }
9
+
10
+ //#endregion
11
+ exports.__decorate = __decorate;
@@ -0,0 +1,10 @@
1
+ //#region \0@oxc-project+runtime@0.108.0/helpers/decorate.js
2
+ function __decorate(decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ }
8
+
9
+ //#endregion
10
+ export { __decorate };
@@ -0,0 +1,120 @@
1
+
2
+ //#region src/client.ts
3
+ /**
4
+ * SlackClient — pure Slack API wrapper.
5
+ *
6
+ * Two modes:
7
+ * - Webhook: outbound-only, POST to Incoming Webhook URL
8
+ * - Bot: bidirectional, chat.postMessage with Bearer token
9
+ *
10
+ * Zero external dependencies (uses native fetch).
11
+ * No AFS or application-specific concepts.
12
+ */
13
+ const DEFAULT_API_BASE = "https://slack.com/api";
14
+ const DEFAULT_TIMEOUT = 3e4;
15
+ var SlackClient = class SlackClient {
16
+ mode;
17
+ _webhookUrl;
18
+ _botToken;
19
+ _apiBase;
20
+ _timeout;
21
+ constructor(opts) {
22
+ this.mode = opts.mode;
23
+ this._webhookUrl = opts.webhookUrl ?? null;
24
+ this._botToken = opts.botToken ?? null;
25
+ this._apiBase = opts.apiBase ?? DEFAULT_API_BASE;
26
+ this._timeout = opts.timeout ?? DEFAULT_TIMEOUT;
27
+ }
28
+ static webhook(url, options) {
29
+ if (!url) throw new Error("SlackClient.webhook requires a webhook URL");
30
+ let parsed;
31
+ try {
32
+ parsed = new URL(url);
33
+ } catch {
34
+ throw new Error("SlackClient.webhook: invalid webhook URL");
35
+ }
36
+ const isLocal = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
37
+ if (parsed.protocol !== "https:" && !isLocal) throw new Error("SlackClient.webhook: webhook URL must use HTTPS (or localhost for testing)");
38
+ return new SlackClient({
39
+ mode: "webhook",
40
+ webhookUrl: url,
41
+ timeout: options?.timeout
42
+ });
43
+ }
44
+ static bot(options) {
45
+ if (!options.botToken) throw new Error("SlackClient.bot requires a botToken");
46
+ return new SlackClient({
47
+ mode: "bot",
48
+ botToken: options.botToken,
49
+ apiBase: options.apiBase,
50
+ timeout: options.timeout
51
+ });
52
+ }
53
+ async sendWebhook(text, options) {
54
+ if (!this._webhookUrl) throw new Error("sendWebhook requires webhook mode");
55
+ const payload = { text };
56
+ if (options?.blocks) payload.blocks = options.blocks;
57
+ await fetch(this._webhookUrl, {
58
+ method: "POST",
59
+ headers: { "Content-Type": "application/json" },
60
+ body: JSON.stringify(payload),
61
+ signal: AbortSignal.timeout(this._timeout)
62
+ });
63
+ }
64
+ async postMessage(channel, text, options) {
65
+ const body = {
66
+ channel,
67
+ text
68
+ };
69
+ if (options?.blocks) body.blocks = options.blocks;
70
+ if (options?.threadTs) body.thread_ts = options.threadTs;
71
+ return this._call("chat.postMessage", body);
72
+ }
73
+ static parseEvent(payload) {
74
+ if (!payload) return null;
75
+ if (payload.type === "url_verification" && payload.challenge) return {
76
+ type: "url_verification",
77
+ challenge: payload.challenge
78
+ };
79
+ if (payload.type !== "event_callback") return null;
80
+ const event = payload.event;
81
+ if (!event || event.type !== "message") return null;
82
+ if (event.bot_id) return null;
83
+ if (event.subtype) return null;
84
+ const text = (event.text || "").trim();
85
+ const userId = event.user;
86
+ const channelId = event.channel;
87
+ const ts = event.ts;
88
+ if (!text || !userId) return null;
89
+ return {
90
+ type: "message",
91
+ text,
92
+ userId,
93
+ channelId,
94
+ ts
95
+ };
96
+ }
97
+ static escapeSlack(text) {
98
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
99
+ }
100
+ async _call(method, body) {
101
+ if (!this._botToken) throw new Error(`${method} requires bot mode`);
102
+ const data = await (await fetch(`${this._apiBase}/${method}`, {
103
+ method: "POST",
104
+ headers: {
105
+ "Content-Type": "application/json",
106
+ Authorization: `Bearer ${this._botToken}`
107
+ },
108
+ body: JSON.stringify(body),
109
+ signal: AbortSignal.timeout(this._timeout)
110
+ })).json();
111
+ if (!data.ok) {
112
+ const desc = (data.error || "Unknown error").replace(this._botToken, "***");
113
+ throw new Error(`Slack API error: ${desc}`);
114
+ }
115
+ return data;
116
+ }
117
+ };
118
+
119
+ //#endregion
120
+ exports.SlackClient = SlackClient;
@@ -0,0 +1,56 @@
1
+ //#region src/client.d.ts
2
+ /**
3
+ * SlackClient — pure Slack API wrapper.
4
+ *
5
+ * Two modes:
6
+ * - Webhook: outbound-only, POST to Incoming Webhook URL
7
+ * - Bot: bidirectional, chat.postMessage with Bearer token
8
+ *
9
+ * Zero external dependencies (uses native fetch).
10
+ * No AFS or application-specific concepts.
11
+ */
12
+ interface SlackBotOptions {
13
+ botToken: string;
14
+ apiBase?: string;
15
+ timeout?: number;
16
+ }
17
+ interface PostMessageOptions {
18
+ blocks?: unknown[];
19
+ threadTs?: string;
20
+ }
21
+ interface SendWebhookOptions {
22
+ blocks?: unknown[];
23
+ }
24
+ /** Parsed Slack Events API event. */
25
+ type SlackParsedEvent = {
26
+ type: "url_verification";
27
+ challenge: string;
28
+ } | {
29
+ type: "message";
30
+ text: string;
31
+ userId: string;
32
+ channelId: string;
33
+ ts: string;
34
+ } | null;
35
+ declare class SlackClient {
36
+ readonly mode: "webhook" | "bot";
37
+ private readonly _webhookUrl;
38
+ private readonly _botToken;
39
+ private readonly _apiBase;
40
+ private readonly _timeout;
41
+ private constructor();
42
+ static webhook(url: string, options?: {
43
+ timeout?: number;
44
+ }): SlackClient;
45
+ static bot(options: SlackBotOptions): SlackClient;
46
+ sendWebhook(text: string, options?: SendWebhookOptions): Promise<void>;
47
+ postMessage(channel: string, text: string, options?: PostMessageOptions): Promise<{
48
+ ts: string;
49
+ }>;
50
+ static parseEvent(payload: any): SlackParsedEvent;
51
+ static escapeSlack(text: string): string;
52
+ private _call;
53
+ }
54
+ //#endregion
55
+ export { SlackClient };
56
+ //# sourceMappingURL=client.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.cts","names":[],"sources":["../src/client.ts"],"mappings":";;AAcA;;;;;;;;;UAAiB,eAAA;EACf,QAAA;EACA,OAAA;EACA,OAAA;AAAA;AAAA,UAGe,kBAAA;EACf,MAAA;EACA,QAAA;AAAA;AAAA,UAGe,kBAAA;EACf,MAAA;AAAA;;KAIU,gBAAA;EACN,IAAA;EAA0B,SAAA;AAAA;EAC1B,IAAA;EAAiB,IAAA;EAAc,MAAA;EAAgB,SAAA;EAAmB,EAAA;AAAA;AAAA,cAG3D,WAAA;EAAA,SACF,IAAA;EAAA,iBACQ,WAAA;EAAA,iBACA,SAAA;EAAA,iBACA,QAAA;EAAA,iBACA,QAAA;EAAA,QAEV,WAAA,CAAA;EAAA,OAgBA,OAAA,CAAQ,GAAA,UAAa,OAAA;IAAY,OAAA;EAAA,IAAqB,WAAA;EAAA,OAsBtD,GAAA,CAAI,OAAA,EAAS,eAAA,GAAkB,WAAA;EAYhC,WAAA,CAAY,IAAA,UAAc,OAAA,GAAU,kBAAA,GAAqB,OAAA;EAgBzD,WAAA,CACJ,OAAA,UACA,IAAA,UACA,OAAA,GAAU,kBAAA,GACT,OAAA;IAAU,EAAA;EAAA;EAAA,OASN,UAAA,CAAW,OAAA,QAAe,gBAAA;EAAA,OAyB1B,WAAA,CAAY,IAAA;EAAA,QAML,KAAA;AAAA"}
@@ -0,0 +1,56 @@
1
+ //#region src/client.d.ts
2
+ /**
3
+ * SlackClient — pure Slack API wrapper.
4
+ *
5
+ * Two modes:
6
+ * - Webhook: outbound-only, POST to Incoming Webhook URL
7
+ * - Bot: bidirectional, chat.postMessage with Bearer token
8
+ *
9
+ * Zero external dependencies (uses native fetch).
10
+ * No AFS or application-specific concepts.
11
+ */
12
+ interface SlackBotOptions {
13
+ botToken: string;
14
+ apiBase?: string;
15
+ timeout?: number;
16
+ }
17
+ interface PostMessageOptions {
18
+ blocks?: unknown[];
19
+ threadTs?: string;
20
+ }
21
+ interface SendWebhookOptions {
22
+ blocks?: unknown[];
23
+ }
24
+ /** Parsed Slack Events API event. */
25
+ type SlackParsedEvent = {
26
+ type: "url_verification";
27
+ challenge: string;
28
+ } | {
29
+ type: "message";
30
+ text: string;
31
+ userId: string;
32
+ channelId: string;
33
+ ts: string;
34
+ } | null;
35
+ declare class SlackClient {
36
+ readonly mode: "webhook" | "bot";
37
+ private readonly _webhookUrl;
38
+ private readonly _botToken;
39
+ private readonly _apiBase;
40
+ private readonly _timeout;
41
+ private constructor();
42
+ static webhook(url: string, options?: {
43
+ timeout?: number;
44
+ }): SlackClient;
45
+ static bot(options: SlackBotOptions): SlackClient;
46
+ sendWebhook(text: string, options?: SendWebhookOptions): Promise<void>;
47
+ postMessage(channel: string, text: string, options?: PostMessageOptions): Promise<{
48
+ ts: string;
49
+ }>;
50
+ static parseEvent(payload: any): SlackParsedEvent;
51
+ static escapeSlack(text: string): string;
52
+ private _call;
53
+ }
54
+ //#endregion
55
+ export { SlackClient };
56
+ //# sourceMappingURL=client.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;AAcA;;;;;;;;;UAAiB,eAAA;EACf,QAAA;EACA,OAAA;EACA,OAAA;AAAA;AAAA,UAGe,kBAAA;EACf,MAAA;EACA,QAAA;AAAA;AAAA,UAGe,kBAAA;EACf,MAAA;AAAA;;KAIU,gBAAA;EACN,IAAA;EAA0B,SAAA;AAAA;EAC1B,IAAA;EAAiB,IAAA;EAAc,MAAA;EAAgB,SAAA;EAAmB,EAAA;AAAA;AAAA,cAG3D,WAAA;EAAA,SACF,IAAA;EAAA,iBACQ,WAAA;EAAA,iBACA,SAAA;EAAA,iBACA,QAAA;EAAA,iBACA,QAAA;EAAA,QAEV,WAAA,CAAA;EAAA,OAgBA,OAAA,CAAQ,GAAA,UAAa,OAAA;IAAY,OAAA;EAAA,IAAqB,WAAA;EAAA,OAsBtD,GAAA,CAAI,OAAA,EAAS,eAAA,GAAkB,WAAA;EAYhC,WAAA,CAAY,IAAA,UAAc,OAAA,GAAU,kBAAA,GAAqB,OAAA;EAgBzD,WAAA,CACJ,OAAA,UACA,IAAA,UACA,OAAA,GAAU,kBAAA,GACT,OAAA;IAAU,EAAA;EAAA;EAAA,OASN,UAAA,CAAW,OAAA,QAAe,gBAAA;EAAA,OAyB1B,WAAA,CAAY,IAAA;EAAA,QAML,KAAA;AAAA"}
@@ -0,0 +1,120 @@
1
+ //#region src/client.ts
2
+ /**
3
+ * SlackClient — pure Slack API wrapper.
4
+ *
5
+ * Two modes:
6
+ * - Webhook: outbound-only, POST to Incoming Webhook URL
7
+ * - Bot: bidirectional, chat.postMessage with Bearer token
8
+ *
9
+ * Zero external dependencies (uses native fetch).
10
+ * No AFS or application-specific concepts.
11
+ */
12
+ const DEFAULT_API_BASE = "https://slack.com/api";
13
+ const DEFAULT_TIMEOUT = 3e4;
14
+ var SlackClient = class SlackClient {
15
+ mode;
16
+ _webhookUrl;
17
+ _botToken;
18
+ _apiBase;
19
+ _timeout;
20
+ constructor(opts) {
21
+ this.mode = opts.mode;
22
+ this._webhookUrl = opts.webhookUrl ?? null;
23
+ this._botToken = opts.botToken ?? null;
24
+ this._apiBase = opts.apiBase ?? DEFAULT_API_BASE;
25
+ this._timeout = opts.timeout ?? DEFAULT_TIMEOUT;
26
+ }
27
+ static webhook(url, options) {
28
+ if (!url) throw new Error("SlackClient.webhook requires a webhook URL");
29
+ let parsed;
30
+ try {
31
+ parsed = new URL(url);
32
+ } catch {
33
+ throw new Error("SlackClient.webhook: invalid webhook URL");
34
+ }
35
+ const isLocal = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
36
+ if (parsed.protocol !== "https:" && !isLocal) throw new Error("SlackClient.webhook: webhook URL must use HTTPS (or localhost for testing)");
37
+ return new SlackClient({
38
+ mode: "webhook",
39
+ webhookUrl: url,
40
+ timeout: options?.timeout
41
+ });
42
+ }
43
+ static bot(options) {
44
+ if (!options.botToken) throw new Error("SlackClient.bot requires a botToken");
45
+ return new SlackClient({
46
+ mode: "bot",
47
+ botToken: options.botToken,
48
+ apiBase: options.apiBase,
49
+ timeout: options.timeout
50
+ });
51
+ }
52
+ async sendWebhook(text, options) {
53
+ if (!this._webhookUrl) throw new Error("sendWebhook requires webhook mode");
54
+ const payload = { text };
55
+ if (options?.blocks) payload.blocks = options.blocks;
56
+ await fetch(this._webhookUrl, {
57
+ method: "POST",
58
+ headers: { "Content-Type": "application/json" },
59
+ body: JSON.stringify(payload),
60
+ signal: AbortSignal.timeout(this._timeout)
61
+ });
62
+ }
63
+ async postMessage(channel, text, options) {
64
+ const body = {
65
+ channel,
66
+ text
67
+ };
68
+ if (options?.blocks) body.blocks = options.blocks;
69
+ if (options?.threadTs) body.thread_ts = options.threadTs;
70
+ return this._call("chat.postMessage", body);
71
+ }
72
+ static parseEvent(payload) {
73
+ if (!payload) return null;
74
+ if (payload.type === "url_verification" && payload.challenge) return {
75
+ type: "url_verification",
76
+ challenge: payload.challenge
77
+ };
78
+ if (payload.type !== "event_callback") return null;
79
+ const event = payload.event;
80
+ if (!event || event.type !== "message") return null;
81
+ if (event.bot_id) return null;
82
+ if (event.subtype) return null;
83
+ const text = (event.text || "").trim();
84
+ const userId = event.user;
85
+ const channelId = event.channel;
86
+ const ts = event.ts;
87
+ if (!text || !userId) return null;
88
+ return {
89
+ type: "message",
90
+ text,
91
+ userId,
92
+ channelId,
93
+ ts
94
+ };
95
+ }
96
+ static escapeSlack(text) {
97
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
98
+ }
99
+ async _call(method, body) {
100
+ if (!this._botToken) throw new Error(`${method} requires bot mode`);
101
+ const data = await (await fetch(`${this._apiBase}/${method}`, {
102
+ method: "POST",
103
+ headers: {
104
+ "Content-Type": "application/json",
105
+ Authorization: `Bearer ${this._botToken}`
106
+ },
107
+ body: JSON.stringify(body),
108
+ signal: AbortSignal.timeout(this._timeout)
109
+ })).json();
110
+ if (!data.ok) {
111
+ const desc = (data.error || "Unknown error").replace(this._botToken, "***");
112
+ throw new Error(`Slack API error: ${desc}`);
113
+ }
114
+ return data;
115
+ }
116
+ };
117
+
118
+ //#endregion
119
+ export { SlackClient };
120
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["/**\n * SlackClient — pure Slack API wrapper.\n *\n * Two modes:\n * - Webhook: outbound-only, POST to Incoming Webhook URL\n * - Bot: bidirectional, chat.postMessage with Bearer token\n *\n * Zero external dependencies (uses native fetch).\n * No AFS or application-specific concepts.\n */\n\nconst DEFAULT_API_BASE = \"https://slack.com/api\";\nconst DEFAULT_TIMEOUT = 30_000;\n\nexport interface SlackBotOptions {\n botToken: string;\n apiBase?: string;\n timeout?: number;\n}\n\nexport interface PostMessageOptions {\n blocks?: unknown[];\n threadTs?: string;\n}\n\nexport interface SendWebhookOptions {\n blocks?: unknown[];\n}\n\n/** Parsed Slack Events API event. */\nexport type SlackParsedEvent =\n | { type: \"url_verification\"; challenge: string }\n | { type: \"message\"; text: string; userId: string; channelId: string; ts: string }\n | null;\n\nexport class SlackClient {\n readonly mode: \"webhook\" | \"bot\";\n private readonly _webhookUrl: string | null;\n private readonly _botToken: string | null;\n private readonly _apiBase: string;\n private readonly _timeout: number;\n\n private constructor(opts: {\n mode: \"webhook\" | \"bot\";\n webhookUrl?: string;\n botToken?: string;\n apiBase?: string;\n timeout?: number;\n }) {\n this.mode = opts.mode;\n this._webhookUrl = opts.webhookUrl ?? null;\n this._botToken = opts.botToken ?? null;\n this._apiBase = opts.apiBase ?? DEFAULT_API_BASE;\n this._timeout = opts.timeout ?? DEFAULT_TIMEOUT;\n }\n\n // ─── Factory Methods ──────────────────────────────────────\n\n static webhook(url: string, options?: { timeout?: number }): SlackClient {\n if (!url) throw new Error(\"SlackClient.webhook requires a webhook URL\");\n\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error(\"SlackClient.webhook: invalid webhook URL\");\n }\n\n const isLocal = parsed.hostname === \"localhost\" || parsed.hostname === \"127.0.0.1\";\n if (parsed.protocol !== \"https:\" && !isLocal) {\n throw new Error(\"SlackClient.webhook: webhook URL must use HTTPS (or localhost for testing)\");\n }\n\n return new SlackClient({\n mode: \"webhook\",\n webhookUrl: url,\n timeout: options?.timeout,\n });\n }\n\n static bot(options: SlackBotOptions): SlackClient {\n if (!options.botToken) throw new Error(\"SlackClient.bot requires a botToken\");\n return new SlackClient({\n mode: \"bot\",\n botToken: options.botToken,\n apiBase: options.apiBase,\n timeout: options.timeout,\n });\n }\n\n // ─── Webhook Mode ─────────────────────────────────────────\n\n async sendWebhook(text: string, options?: SendWebhookOptions): Promise<void> {\n if (!this._webhookUrl) throw new Error(\"sendWebhook requires webhook mode\");\n\n const payload: Record<string, unknown> = { text };\n if (options?.blocks) payload.blocks = options.blocks;\n\n await fetch(this._webhookUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: AbortSignal.timeout(this._timeout),\n });\n }\n\n // ─── Bot Mode ─────────────────────────────────────────────\n\n async postMessage(\n channel: string,\n text: string,\n options?: PostMessageOptions,\n ): Promise<{ ts: string }> {\n const body: Record<string, unknown> = { channel, text };\n if (options?.blocks) body.blocks = options.blocks;\n if (options?.threadTs) body.thread_ts = options.threadTs;\n return this._call(\"chat.postMessage\", body);\n }\n\n // ─── Events API Parsing ───────────────────────────────────\n\n static parseEvent(payload: any): SlackParsedEvent {\n if (!payload) return null;\n\n if (payload.type === \"url_verification\" && payload.challenge) {\n return { type: \"url_verification\", challenge: payload.challenge };\n }\n\n if (payload.type !== \"event_callback\") return null;\n\n const event = payload.event;\n if (!event || event.type !== \"message\") return null;\n if (event.bot_id) return null;\n if (event.subtype) return null;\n\n const text = (event.text || \"\").trim();\n const userId = event.user;\n const channelId = event.channel;\n const ts = event.ts;\n if (!text || !userId) return null;\n\n return { type: \"message\", text, userId, channelId, ts };\n }\n\n // ─── Helpers ──────────────────────────────────────────────\n\n static escapeSlack(text: string): string {\n return text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n }\n\n // ─── Internal ─────────────────────────────────────────────\n\n private async _call(method: string, body: Record<string, unknown>): Promise<any> {\n if (!this._botToken) throw new Error(`${method} requires bot mode`);\n\n const response = await fetch(`${this._apiBase}/${method}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this._botToken}`,\n },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(this._timeout),\n });\n\n const data = (await response.json()) as { ok: boolean; error?: string; ts?: string };\n if (!data.ok) {\n const desc = (data.error || \"Unknown error\").replace(this._botToken, \"***\");\n throw new Error(`Slack API error: ${desc}`);\n }\n return data;\n }\n}\n"],"mappings":"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"}
package/dist/index.cjs ADDED
@@ -0,0 +1,288 @@
1
+ const require_client = require('./client.cjs');
2
+ const require_decorate = require('./_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs');
3
+ let _aigne_afs_provider = require("@aigne/afs/provider");
4
+ let _aigne_afs_messaging = require("@aigne/afs-messaging");
5
+
6
+ //#region src/index.ts
7
+ var AFSSlack = class extends _aigne_afs_messaging.BaseMessageProvider {
8
+ static manifest() {
9
+ return {
10
+ name: "slack",
11
+ description: "Slack messaging — webhook (outbound) or Bot API (bidirectional).\n- Incoming Webhook for simple notifications\n- Bot token + Events API for full interaction\n- Path: /:bot/conversations/:channelId/messages/:ts",
12
+ uriTemplate: "slack://{botToken}",
13
+ category: "messaging",
14
+ schema: {
15
+ type: "object",
16
+ properties: {
17
+ botToken: {
18
+ type: "string",
19
+ description: "Slack Bot OAuth token",
20
+ sensitive: true
21
+ },
22
+ webhook: {
23
+ type: "string",
24
+ description: "Incoming Webhook URL",
25
+ sensitive: true
26
+ },
27
+ channels: {
28
+ type: "array",
29
+ items: { type: "string" },
30
+ description: "Channel IDs"
31
+ }
32
+ }
33
+ },
34
+ tags: [
35
+ "slack",
36
+ "messaging",
37
+ "chat",
38
+ "workspace"
39
+ ],
40
+ capabilityTags: [
41
+ "read-write",
42
+ "crud",
43
+ "search",
44
+ "auth:token",
45
+ "remote",
46
+ "http",
47
+ "real-time",
48
+ "rate-limited"
49
+ ],
50
+ security: {
51
+ riskLevel: "external",
52
+ resourceAccess: ["internet"],
53
+ notes: ["Connects to Slack API — requires bot token or webhook URL"]
54
+ },
55
+ capabilities: { network: {
56
+ egress: true,
57
+ allowedDomains: ["slack.com"]
58
+ } }
59
+ };
60
+ }
61
+ static treeSchema() {
62
+ return {
63
+ operations: [
64
+ "list",
65
+ "read",
66
+ "exec",
67
+ "stat",
68
+ "explain"
69
+ ],
70
+ tree: {
71
+ "/": {
72
+ kind: "messaging:root",
73
+ operations: ["list", "exec"],
74
+ actions: [
75
+ "add-bot",
76
+ "remove-bot",
77
+ "process-event"
78
+ ]
79
+ },
80
+ "/{bot}": {
81
+ kind: "messaging:bot",
82
+ operations: ["list", "read"]
83
+ },
84
+ "/{bot}/ctl": {
85
+ kind: "messaging:status",
86
+ operations: ["read"]
87
+ },
88
+ "/{bot}/conversations": {
89
+ kind: "messaging:conversations",
90
+ operations: ["list"]
91
+ },
92
+ "/{bot}/conversations/{convId}": {
93
+ kind: "messaging:conversation",
94
+ operations: ["list"]
95
+ },
96
+ "/{bot}/conversations/{convId}/messages": {
97
+ kind: "messaging:messages",
98
+ operations: ["list", "exec"],
99
+ actions: ["send"]
100
+ },
101
+ "/{bot}/conversations/{convId}/messages/{msgId}": {
102
+ kind: "messaging:message",
103
+ operations: ["read"]
104
+ }
105
+ },
106
+ auth: {
107
+ type: "token",
108
+ env: ["SLACK_BOT_TOKEN"]
109
+ },
110
+ bestFor: [
111
+ "team notifications",
112
+ "workflow alerts",
113
+ "chatops"
114
+ ],
115
+ notFor: ["file storage", "database queries"]
116
+ };
117
+ }
118
+ providerName = "slack";
119
+ eventPrefix = "slack";
120
+ constructor(options) {
121
+ let bots;
122
+ if (options.bots) bots = options.bots.map((b) => ({
123
+ ...b,
124
+ conversations: b.channels
125
+ }));
126
+ else {
127
+ if (!options.botToken && !options.webhook) throw new Error("AFSSlack requires either botToken or webhook");
128
+ bots = [{
129
+ name: "default",
130
+ botToken: options.botToken,
131
+ webhook: options.webhook,
132
+ conversations: options.channels ?? [],
133
+ apiBase: options.apiBase
134
+ }];
135
+ }
136
+ super({
137
+ bots,
138
+ bufferSize: options.bufferSize
139
+ });
140
+ }
141
+ getMessageCapabilities() {
142
+ return {
143
+ formats: {
144
+ send: ["text", "markdown"],
145
+ receive: ["text"]
146
+ },
147
+ maxMessageLength: 4e4,
148
+ features: {
149
+ edit: false,
150
+ delete: false,
151
+ reply: true,
152
+ thread: true,
153
+ reaction: true,
154
+ inlineKeyboard: false
155
+ },
156
+ limits: {
157
+ messagesPerSecond: 1,
158
+ messagesPerMinute: 60
159
+ }
160
+ };
161
+ }
162
+ createBotClient(config) {
163
+ const botToken = config.botToken;
164
+ const webhook = config.webhook;
165
+ const apiBase = config.apiBase;
166
+ if (botToken) return require_client.SlackClient.bot({
167
+ botToken,
168
+ apiBase
169
+ });
170
+ if (webhook) return require_client.SlackClient.webhook(webhook);
171
+ throw new Error(`Slack bot "${config.name}" requires botToken or webhook`);
172
+ }
173
+ async sendMessage(client, convId, text, opts) {
174
+ const sc = client;
175
+ const blocks = opts?.blocks;
176
+ const safeText = require_client.SlackClient.escapeSlack(text);
177
+ if (sc.mode === "bot") return { messageId: (await sc.postMessage(convId, safeText, { blocks })).ts };
178
+ await sc.sendWebhook(safeText, { blocks });
179
+ return { messageId: String(Date.now()) };
180
+ }
181
+ async sendTypingIndicator(_client, _convId) {}
182
+ normalizeMessage(raw) {
183
+ const msg = raw;
184
+ return {
185
+ id: String(msg.ts ?? "0"),
186
+ text: String(msg.text ?? ""),
187
+ from: this.normalizeSender({ id: msg.userId ?? msg.user }),
188
+ timestamp: Math.floor(Number.parseFloat(String(msg.ts ?? "0"))),
189
+ conversationId: String(msg.channelId ?? msg.channel ?? ""),
190
+ platform: { ts: msg.ts }
191
+ };
192
+ }
193
+ normalizeSender(raw) {
194
+ return {
195
+ id: String(raw.id ?? "0"),
196
+ name: String(raw.name ?? raw.id ?? ""),
197
+ isBot: raw.isBot
198
+ };
199
+ }
200
+ async listRootActions(_ctx) {
201
+ return { data: [
202
+ this.buildEntry("/.actions/add-bot", { meta: { description: "Add a bot instance at runtime" } }),
203
+ this.buildEntry("/.actions/remove-bot", { meta: { description: "Remove a bot instance" } }),
204
+ this.buildEntry("/.actions/process-event", { meta: { description: "Process an incoming Slack Events API payload" } })
205
+ ] };
206
+ }
207
+ async execProcessEvent(_ctx, args) {
208
+ this._processEvent(args);
209
+ return {
210
+ success: true,
211
+ data: { ok: true }
212
+ };
213
+ }
214
+ /** Process a Slack Events API payload — delegates to emitMessageReceived(). */
215
+ _processEvent(payload) {
216
+ const parsed = require_client.SlackClient.parseEvent(payload);
217
+ if (!parsed) return;
218
+ if (parsed.type === "url_verification") return;
219
+ const { text, userId, channelId, ts } = parsed;
220
+ const botName = this._botOrder[0] ?? "default";
221
+ this.emitMessageReceived(botName, {
222
+ id: ts,
223
+ text,
224
+ from: {
225
+ id: userId,
226
+ name: userId
227
+ },
228
+ timestamp: Math.floor(Number.parseFloat(ts)),
229
+ conversationId: channelId,
230
+ platform: {
231
+ ts,
232
+ userId
233
+ }
234
+ });
235
+ }
236
+ /** Add a channel to a bot. Defaults to first bot. */
237
+ addChannel(channelId, botName) {
238
+ const name = botName ?? this._botOrder[0];
239
+ if (!name) return;
240
+ const convs = this._botConversations.get(name);
241
+ if (!convs || convs.has(channelId)) return;
242
+ convs.add(channelId);
243
+ const buffers = this._botBuffers.get(name);
244
+ if (buffers && !buffers.has(channelId)) buffers.set(channelId, []);
245
+ }
246
+ /** Remove a channel from a bot. */
247
+ removeChannel(channelId, botName) {
248
+ const name = botName ?? this._botOrder[0];
249
+ if (!name) return;
250
+ const convs = this._botConversations.get(name);
251
+ if (convs) convs.delete(channelId);
252
+ const buffers = this._botBuffers.get(name);
253
+ if (buffers) buffers.delete(channelId);
254
+ }
255
+ /** Add a message to the ring buffer directly. Public for testing/conformance. */
256
+ _addToBuffer(channelId, msg) {
257
+ const botName = this._botOrder[0] ?? "default";
258
+ const convs = this._botConversations.get(botName);
259
+ if (convs && !convs.has(channelId)) convs.add(channelId);
260
+ let botBuffers = this._botBuffers.get(botName);
261
+ if (!botBuffers) {
262
+ botBuffers = /* @__PURE__ */ new Map();
263
+ this._botBuffers.set(botName, botBuffers);
264
+ }
265
+ let buffer = botBuffers.get(channelId);
266
+ if (!buffer) {
267
+ buffer = [];
268
+ botBuffers.set(channelId, buffer);
269
+ }
270
+ buffer.push({
271
+ id: msg.ts,
272
+ text: msg.text,
273
+ from: {
274
+ id: msg.userId,
275
+ name: msg.userId
276
+ },
277
+ timestamp: msg.date,
278
+ conversationId: channelId,
279
+ platform: { ts: msg.ts }
280
+ });
281
+ while (buffer.length > this._bufferSize) buffer.shift();
282
+ }
283
+ };
284
+ require_decorate.__decorate([(0, _aigne_afs_provider.Actions)("/")], AFSSlack.prototype, "listRootActions", null);
285
+ require_decorate.__decorate([_aigne_afs_provider.Actions.Exec("/", "process-event")], AFSSlack.prototype, "execProcessEvent", null);
286
+
287
+ //#endregion
288
+ exports.AFSSlack = AFSSlack;
@@ -0,0 +1,97 @@
1
+ import { SlackClient } from "./client.cjs";
2
+ import { AFSExecResult, AFSListResult, ProviderTreeSchema } from "@aigne/afs";
3
+ import { RouteContext } from "@aigne/afs/provider";
4
+ import { BaseMessageProvider, BotConfig, BufferedMessage, MessageCapabilities, MessageSender, SendOptions } from "@aigne/afs-messaging";
5
+
6
+ //#region src/index.d.ts
7
+ interface AFSSlackOptions {
8
+ /** Multi-bot config */
9
+ bots?: Array<{
10
+ name: string;
11
+ botToken?: string;
12
+ webhook?: string;
13
+ channels?: string[];
14
+ apiBase?: string;
15
+ }>;
16
+ /** Single-bot backward compat: webhook URL */
17
+ webhook?: string;
18
+ /** Single-bot backward compat: bot token */
19
+ botToken?: string;
20
+ /** Single-bot backward compat: channel IDs */
21
+ channels?: string[];
22
+ apiBase?: string;
23
+ bufferSize?: number;
24
+ }
25
+ declare class AFSSlack extends BaseMessageProvider {
26
+ static manifest(): {
27
+ name: string;
28
+ description: string;
29
+ uriTemplate: string;
30
+ category: string;
31
+ schema: {
32
+ type: string;
33
+ properties: {
34
+ botToken: {
35
+ type: string;
36
+ description: string;
37
+ sensitive: boolean;
38
+ };
39
+ webhook: {
40
+ type: string;
41
+ description: string;
42
+ sensitive: boolean;
43
+ };
44
+ channels: {
45
+ type: string;
46
+ items: {
47
+ type: string;
48
+ };
49
+ description: string;
50
+ };
51
+ };
52
+ };
53
+ tags: string[];
54
+ capabilityTags: string[];
55
+ security: {
56
+ riskLevel: string;
57
+ resourceAccess: string[];
58
+ notes: string[];
59
+ };
60
+ capabilities: {
61
+ network: {
62
+ egress: boolean;
63
+ allowedDomains: string[];
64
+ };
65
+ };
66
+ };
67
+ static treeSchema(): ProviderTreeSchema;
68
+ readonly providerName = "slack";
69
+ readonly eventPrefix = "slack";
70
+ constructor(options: AFSSlackOptions);
71
+ getMessageCapabilities(): MessageCapabilities;
72
+ createBotClient(config: BotConfig): SlackClient;
73
+ sendMessage(client: unknown, convId: string, text: string, opts?: SendOptions): Promise<{
74
+ messageId: string;
75
+ }>;
76
+ sendTypingIndicator(_client: unknown, _convId: string): Promise<void>;
77
+ normalizeMessage(raw: Record<string, unknown>): BufferedMessage;
78
+ normalizeSender(raw: Record<string, unknown>): MessageSender;
79
+ listRootActions(_ctx: RouteContext): Promise<AFSListResult>;
80
+ execProcessEvent(_ctx: RouteContext, args: Record<string, unknown>): Promise<AFSExecResult>;
81
+ /** Process a Slack Events API payload — delegates to emitMessageReceived(). */
82
+ _processEvent(payload: any): void;
83
+ /** Add a channel to a bot. Defaults to first bot. */
84
+ addChannel(channelId: string, botName?: string): void;
85
+ /** Remove a channel from a bot. */
86
+ removeChannel(channelId: string, botName?: string): void;
87
+ /** Add a message to the ring buffer directly. Public for testing/conformance. */
88
+ _addToBuffer(channelId: string, msg: {
89
+ ts: string;
90
+ text: string;
91
+ userId: string;
92
+ date: number;
93
+ }): void;
94
+ }
95
+ //#endregion
96
+ export { AFSSlack, AFSSlackOptions, type SlackClient };
97
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;UAoCiB,eAAA;EAyFM;EAvFrB,IAAA,GAAO,KAAA;IACL,IAAA;IACA,QAAA;IACA,OAAA;IACA,QAAA;IACA,OAAA;EAAA;EAwK8C;EArKhD,OAAA;EAiL+C;EA/K/C,QAAA;EA0LmD;EAxLnD,QAAA;EACA,OAAA;EACA,UAAA;AAAA;AAAA,cAGW,QAAA,SAAiB,mBAAA;EAAA,OACrB,QAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAqCA,UAAA,CAAA,GAAc,kBAAA;EAAA,SA6BZ,YAAA;EAAA,SACA,WAAA;cAEG,OAAA,EAAS,eAAA;EA2BrB,sBAAA,CAAA,GAA0B,mBAAA;EAsB1B,eAAA,CAAgB,MAAA,EAAQ,SAAA,GAAY,WAAA;EAc9B,WAAA,CACJ,MAAA,WACA,MAAA,UACA,IAAA,UACA,IAAA,GAAO,WAAA,GACN,OAAA;IAAU,SAAA;EAAA;EAgBP,mBAAA,CAAoB,OAAA,WAAkB,OAAA,WAAkB,OAAA;EAE9D,gBAAA,CAAiB,GAAA,EAAK,MAAA,oBAA0B,eAAA;EAYhD,eAAA,CAAgB,GAAA,EAAK,MAAA,oBAA0B,aAAA;EAWzC,eAAA,CAAgB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,aAAA;EAiB7C,gBAAA,CACJ,IAAA,EAAM,YAAA,EACN,IAAA,EAAM,MAAA,oBACL,OAAA,CAAQ,aAAA;EA7DE;EAqEb,aAAA,CAAc,OAAA;EArDY;EA0E1B,UAAA,CAAW,SAAA,UAAmB,OAAA;EA1EgC;EAuF9D,aAAA,CAAc,SAAA,UAAmB,OAAA;EArFX;EA+FtB,YAAA,CACE,SAAA,UACA,GAAA;IAAO,EAAA;IAAY,IAAA;IAAc,MAAA;IAAgB,IAAA;EAAA;AAAA"}
@@ -0,0 +1,97 @@
1
+ import { SlackClient } from "./client.mjs";
2
+ import { RouteContext } from "@aigne/afs/provider";
3
+ import { BaseMessageProvider, BotConfig, BufferedMessage, MessageCapabilities, MessageSender, SendOptions } from "@aigne/afs-messaging";
4
+ import { AFSExecResult, AFSListResult, ProviderTreeSchema } from "@aigne/afs";
5
+
6
+ //#region src/index.d.ts
7
+ interface AFSSlackOptions {
8
+ /** Multi-bot config */
9
+ bots?: Array<{
10
+ name: string;
11
+ botToken?: string;
12
+ webhook?: string;
13
+ channels?: string[];
14
+ apiBase?: string;
15
+ }>;
16
+ /** Single-bot backward compat: webhook URL */
17
+ webhook?: string;
18
+ /** Single-bot backward compat: bot token */
19
+ botToken?: string;
20
+ /** Single-bot backward compat: channel IDs */
21
+ channels?: string[];
22
+ apiBase?: string;
23
+ bufferSize?: number;
24
+ }
25
+ declare class AFSSlack extends BaseMessageProvider {
26
+ static manifest(): {
27
+ name: string;
28
+ description: string;
29
+ uriTemplate: string;
30
+ category: string;
31
+ schema: {
32
+ type: string;
33
+ properties: {
34
+ botToken: {
35
+ type: string;
36
+ description: string;
37
+ sensitive: boolean;
38
+ };
39
+ webhook: {
40
+ type: string;
41
+ description: string;
42
+ sensitive: boolean;
43
+ };
44
+ channels: {
45
+ type: string;
46
+ items: {
47
+ type: string;
48
+ };
49
+ description: string;
50
+ };
51
+ };
52
+ };
53
+ tags: string[];
54
+ capabilityTags: string[];
55
+ security: {
56
+ riskLevel: string;
57
+ resourceAccess: string[];
58
+ notes: string[];
59
+ };
60
+ capabilities: {
61
+ network: {
62
+ egress: boolean;
63
+ allowedDomains: string[];
64
+ };
65
+ };
66
+ };
67
+ static treeSchema(): ProviderTreeSchema;
68
+ readonly providerName = "slack";
69
+ readonly eventPrefix = "slack";
70
+ constructor(options: AFSSlackOptions);
71
+ getMessageCapabilities(): MessageCapabilities;
72
+ createBotClient(config: BotConfig): SlackClient;
73
+ sendMessage(client: unknown, convId: string, text: string, opts?: SendOptions): Promise<{
74
+ messageId: string;
75
+ }>;
76
+ sendTypingIndicator(_client: unknown, _convId: string): Promise<void>;
77
+ normalizeMessage(raw: Record<string, unknown>): BufferedMessage;
78
+ normalizeSender(raw: Record<string, unknown>): MessageSender;
79
+ listRootActions(_ctx: RouteContext): Promise<AFSListResult>;
80
+ execProcessEvent(_ctx: RouteContext, args: Record<string, unknown>): Promise<AFSExecResult>;
81
+ /** Process a Slack Events API payload — delegates to emitMessageReceived(). */
82
+ _processEvent(payload: any): void;
83
+ /** Add a channel to a bot. Defaults to first bot. */
84
+ addChannel(channelId: string, botName?: string): void;
85
+ /** Remove a channel from a bot. */
86
+ removeChannel(channelId: string, botName?: string): void;
87
+ /** Add a message to the ring buffer directly. Public for testing/conformance. */
88
+ _addToBuffer(channelId: string, msg: {
89
+ ts: string;
90
+ text: string;
91
+ userId: string;
92
+ date: number;
93
+ }): void;
94
+ }
95
+ //#endregion
96
+ export { AFSSlack, AFSSlackOptions, type SlackClient };
97
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;UAoCiB,eAAA;EAyFM;EAvFrB,IAAA,GAAO,KAAA;IACL,IAAA;IACA,QAAA;IACA,OAAA;IACA,QAAA;IACA,OAAA;EAAA;EAwK8C;EArKhD,OAAA;EAiL+C;EA/K/C,QAAA;EA0LmD;EAxLnD,QAAA;EACA,OAAA;EACA,UAAA;AAAA;AAAA,cAGW,QAAA,SAAiB,mBAAA;EAAA,OACrB,QAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAqCA,UAAA,CAAA,GAAc,kBAAA;EAAA,SA6BZ,YAAA;EAAA,SACA,WAAA;cAEG,OAAA,EAAS,eAAA;EA2BrB,sBAAA,CAAA,GAA0B,mBAAA;EAsB1B,eAAA,CAAgB,MAAA,EAAQ,SAAA,GAAY,WAAA;EAc9B,WAAA,CACJ,MAAA,WACA,MAAA,UACA,IAAA,UACA,IAAA,GAAO,WAAA,GACN,OAAA;IAAU,SAAA;EAAA;EAgBP,mBAAA,CAAoB,OAAA,WAAkB,OAAA,WAAkB,OAAA;EAE9D,gBAAA,CAAiB,GAAA,EAAK,MAAA,oBAA0B,eAAA;EAYhD,eAAA,CAAgB,GAAA,EAAK,MAAA,oBAA0B,aAAA;EAWzC,eAAA,CAAgB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,aAAA;EAiB7C,gBAAA,CACJ,IAAA,EAAM,YAAA,EACN,IAAA,EAAM,MAAA,oBACL,OAAA,CAAQ,aAAA;EA7DE;EAqEb,aAAA,CAAc,OAAA;EArDY;EA0E1B,UAAA,CAAW,SAAA,UAAmB,OAAA;EA1EgC;EAuF9D,aAAA,CAAc,SAAA,UAAmB,OAAA;EArFX;EA+FtB,YAAA,CACE,SAAA,UACA,GAAA;IAAO,EAAA;IAAY,IAAA;IAAc,MAAA;IAAgB,IAAA;EAAA;AAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,289 @@
1
+ import { SlackClient } from "./client.mjs";
2
+ import { __decorate } from "./_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs";
3
+ import { Actions } from "@aigne/afs/provider";
4
+ import { BaseMessageProvider } from "@aigne/afs-messaging";
5
+
6
+ //#region src/index.ts
7
+ var AFSSlack = class extends BaseMessageProvider {
8
+ static manifest() {
9
+ return {
10
+ name: "slack",
11
+ description: "Slack messaging — webhook (outbound) or Bot API (bidirectional).\n- Incoming Webhook for simple notifications\n- Bot token + Events API for full interaction\n- Path: /:bot/conversations/:channelId/messages/:ts",
12
+ uriTemplate: "slack://{botToken}",
13
+ category: "messaging",
14
+ schema: {
15
+ type: "object",
16
+ properties: {
17
+ botToken: {
18
+ type: "string",
19
+ description: "Slack Bot OAuth token",
20
+ sensitive: true
21
+ },
22
+ webhook: {
23
+ type: "string",
24
+ description: "Incoming Webhook URL",
25
+ sensitive: true
26
+ },
27
+ channels: {
28
+ type: "array",
29
+ items: { type: "string" },
30
+ description: "Channel IDs"
31
+ }
32
+ }
33
+ },
34
+ tags: [
35
+ "slack",
36
+ "messaging",
37
+ "chat",
38
+ "workspace"
39
+ ],
40
+ capabilityTags: [
41
+ "read-write",
42
+ "crud",
43
+ "search",
44
+ "auth:token",
45
+ "remote",
46
+ "http",
47
+ "real-time",
48
+ "rate-limited"
49
+ ],
50
+ security: {
51
+ riskLevel: "external",
52
+ resourceAccess: ["internet"],
53
+ notes: ["Connects to Slack API — requires bot token or webhook URL"]
54
+ },
55
+ capabilities: { network: {
56
+ egress: true,
57
+ allowedDomains: ["slack.com"]
58
+ } }
59
+ };
60
+ }
61
+ static treeSchema() {
62
+ return {
63
+ operations: [
64
+ "list",
65
+ "read",
66
+ "exec",
67
+ "stat",
68
+ "explain"
69
+ ],
70
+ tree: {
71
+ "/": {
72
+ kind: "messaging:root",
73
+ operations: ["list", "exec"],
74
+ actions: [
75
+ "add-bot",
76
+ "remove-bot",
77
+ "process-event"
78
+ ]
79
+ },
80
+ "/{bot}": {
81
+ kind: "messaging:bot",
82
+ operations: ["list", "read"]
83
+ },
84
+ "/{bot}/ctl": {
85
+ kind: "messaging:status",
86
+ operations: ["read"]
87
+ },
88
+ "/{bot}/conversations": {
89
+ kind: "messaging:conversations",
90
+ operations: ["list"]
91
+ },
92
+ "/{bot}/conversations/{convId}": {
93
+ kind: "messaging:conversation",
94
+ operations: ["list"]
95
+ },
96
+ "/{bot}/conversations/{convId}/messages": {
97
+ kind: "messaging:messages",
98
+ operations: ["list", "exec"],
99
+ actions: ["send"]
100
+ },
101
+ "/{bot}/conversations/{convId}/messages/{msgId}": {
102
+ kind: "messaging:message",
103
+ operations: ["read"]
104
+ }
105
+ },
106
+ auth: {
107
+ type: "token",
108
+ env: ["SLACK_BOT_TOKEN"]
109
+ },
110
+ bestFor: [
111
+ "team notifications",
112
+ "workflow alerts",
113
+ "chatops"
114
+ ],
115
+ notFor: ["file storage", "database queries"]
116
+ };
117
+ }
118
+ providerName = "slack";
119
+ eventPrefix = "slack";
120
+ constructor(options) {
121
+ let bots;
122
+ if (options.bots) bots = options.bots.map((b) => ({
123
+ ...b,
124
+ conversations: b.channels
125
+ }));
126
+ else {
127
+ if (!options.botToken && !options.webhook) throw new Error("AFSSlack requires either botToken or webhook");
128
+ bots = [{
129
+ name: "default",
130
+ botToken: options.botToken,
131
+ webhook: options.webhook,
132
+ conversations: options.channels ?? [],
133
+ apiBase: options.apiBase
134
+ }];
135
+ }
136
+ super({
137
+ bots,
138
+ bufferSize: options.bufferSize
139
+ });
140
+ }
141
+ getMessageCapabilities() {
142
+ return {
143
+ formats: {
144
+ send: ["text", "markdown"],
145
+ receive: ["text"]
146
+ },
147
+ maxMessageLength: 4e4,
148
+ features: {
149
+ edit: false,
150
+ delete: false,
151
+ reply: true,
152
+ thread: true,
153
+ reaction: true,
154
+ inlineKeyboard: false
155
+ },
156
+ limits: {
157
+ messagesPerSecond: 1,
158
+ messagesPerMinute: 60
159
+ }
160
+ };
161
+ }
162
+ createBotClient(config) {
163
+ const botToken = config.botToken;
164
+ const webhook = config.webhook;
165
+ const apiBase = config.apiBase;
166
+ if (botToken) return SlackClient.bot({
167
+ botToken,
168
+ apiBase
169
+ });
170
+ if (webhook) return SlackClient.webhook(webhook);
171
+ throw new Error(`Slack bot "${config.name}" requires botToken or webhook`);
172
+ }
173
+ async sendMessage(client, convId, text, opts) {
174
+ const sc = client;
175
+ const blocks = opts?.blocks;
176
+ const safeText = SlackClient.escapeSlack(text);
177
+ if (sc.mode === "bot") return { messageId: (await sc.postMessage(convId, safeText, { blocks })).ts };
178
+ await sc.sendWebhook(safeText, { blocks });
179
+ return { messageId: String(Date.now()) };
180
+ }
181
+ async sendTypingIndicator(_client, _convId) {}
182
+ normalizeMessage(raw) {
183
+ const msg = raw;
184
+ return {
185
+ id: String(msg.ts ?? "0"),
186
+ text: String(msg.text ?? ""),
187
+ from: this.normalizeSender({ id: msg.userId ?? msg.user }),
188
+ timestamp: Math.floor(Number.parseFloat(String(msg.ts ?? "0"))),
189
+ conversationId: String(msg.channelId ?? msg.channel ?? ""),
190
+ platform: { ts: msg.ts }
191
+ };
192
+ }
193
+ normalizeSender(raw) {
194
+ return {
195
+ id: String(raw.id ?? "0"),
196
+ name: String(raw.name ?? raw.id ?? ""),
197
+ isBot: raw.isBot
198
+ };
199
+ }
200
+ async listRootActions(_ctx) {
201
+ return { data: [
202
+ this.buildEntry("/.actions/add-bot", { meta: { description: "Add a bot instance at runtime" } }),
203
+ this.buildEntry("/.actions/remove-bot", { meta: { description: "Remove a bot instance" } }),
204
+ this.buildEntry("/.actions/process-event", { meta: { description: "Process an incoming Slack Events API payload" } })
205
+ ] };
206
+ }
207
+ async execProcessEvent(_ctx, args) {
208
+ this._processEvent(args);
209
+ return {
210
+ success: true,
211
+ data: { ok: true }
212
+ };
213
+ }
214
+ /** Process a Slack Events API payload — delegates to emitMessageReceived(). */
215
+ _processEvent(payload) {
216
+ const parsed = SlackClient.parseEvent(payload);
217
+ if (!parsed) return;
218
+ if (parsed.type === "url_verification") return;
219
+ const { text, userId, channelId, ts } = parsed;
220
+ const botName = this._botOrder[0] ?? "default";
221
+ this.emitMessageReceived(botName, {
222
+ id: ts,
223
+ text,
224
+ from: {
225
+ id: userId,
226
+ name: userId
227
+ },
228
+ timestamp: Math.floor(Number.parseFloat(ts)),
229
+ conversationId: channelId,
230
+ platform: {
231
+ ts,
232
+ userId
233
+ }
234
+ });
235
+ }
236
+ /** Add a channel to a bot. Defaults to first bot. */
237
+ addChannel(channelId, botName) {
238
+ const name = botName ?? this._botOrder[0];
239
+ if (!name) return;
240
+ const convs = this._botConversations.get(name);
241
+ if (!convs || convs.has(channelId)) return;
242
+ convs.add(channelId);
243
+ const buffers = this._botBuffers.get(name);
244
+ if (buffers && !buffers.has(channelId)) buffers.set(channelId, []);
245
+ }
246
+ /** Remove a channel from a bot. */
247
+ removeChannel(channelId, botName) {
248
+ const name = botName ?? this._botOrder[0];
249
+ if (!name) return;
250
+ const convs = this._botConversations.get(name);
251
+ if (convs) convs.delete(channelId);
252
+ const buffers = this._botBuffers.get(name);
253
+ if (buffers) buffers.delete(channelId);
254
+ }
255
+ /** Add a message to the ring buffer directly. Public for testing/conformance. */
256
+ _addToBuffer(channelId, msg) {
257
+ const botName = this._botOrder[0] ?? "default";
258
+ const convs = this._botConversations.get(botName);
259
+ if (convs && !convs.has(channelId)) convs.add(channelId);
260
+ let botBuffers = this._botBuffers.get(botName);
261
+ if (!botBuffers) {
262
+ botBuffers = /* @__PURE__ */ new Map();
263
+ this._botBuffers.set(botName, botBuffers);
264
+ }
265
+ let buffer = botBuffers.get(channelId);
266
+ if (!buffer) {
267
+ buffer = [];
268
+ botBuffers.set(channelId, buffer);
269
+ }
270
+ buffer.push({
271
+ id: msg.ts,
272
+ text: msg.text,
273
+ from: {
274
+ id: msg.userId,
275
+ name: msg.userId
276
+ },
277
+ timestamp: msg.date,
278
+ conversationId: channelId,
279
+ platform: { ts: msg.ts }
280
+ });
281
+ while (buffer.length > this._bufferSize) buffer.shift();
282
+ }
283
+ };
284
+ __decorate([Actions("/")], AFSSlack.prototype, "listRootActions", null);
285
+ __decorate([Actions.Exec("/", "process-event")], AFSSlack.prototype, "execProcessEvent", null);
286
+
287
+ //#endregion
288
+ export { AFSSlack };
289
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * AFSSlack — AFS provider for Slack.\n *\n * Extends BaseMessageProvider (Plan 9 model).\n * Path structure (from base):\n * / → List bots\n * /:botName/ctl → Bot status\n * /:botName/conversations/:channelId/messages → List messages\n * /:botName/conversations/:channelId/messages/:ts → Read message\n *\n * Supports two modes:\n * - Webhook mode (outbound only): Send messages via Incoming Webhook\n * - Bot mode (bidirectional): Send via Bot API + receive Events API\n *\n * Additional Slack actions:\n * /.actions/process-event → Process incoming Slack Events API payload\n *\n * Standard events (from base):\n * messaging:message → Inbound text message\n * messaging:command → Inbound /command\n */\n\nimport type { AFSExecResult, AFSListResult, ProviderTreeSchema } from \"@aigne/afs\";\nimport { Actions, type RouteContext } from \"@aigne/afs/provider\";\nimport type {\n BotConfig,\n BufferedMessage,\n MessageCapabilities,\n MessageSender,\n SendOptions,\n} from \"@aigne/afs-messaging\";\nimport { BaseMessageProvider } from \"@aigne/afs-messaging\";\nimport { SlackClient } from \"./client.js\";\n\nexport type { SlackClient } from \"./client.js\";\n\nexport interface AFSSlackOptions {\n /** Multi-bot config */\n bots?: Array<{\n name: string;\n botToken?: string;\n webhook?: string;\n channels?: string[];\n apiBase?: string;\n }>;\n /** Single-bot backward compat: webhook URL */\n webhook?: string;\n /** Single-bot backward compat: bot token */\n botToken?: string;\n /** Single-bot backward compat: channel IDs */\n channels?: string[];\n apiBase?: string;\n bufferSize?: number;\n}\n\nexport class AFSSlack extends BaseMessageProvider {\n static manifest() {\n return {\n name: \"slack\",\n description:\n \"Slack messaging — webhook (outbound) or Bot API (bidirectional).\\n- Incoming Webhook for simple notifications\\n- Bot token + Events API for full interaction\\n- Path: /:bot/conversations/:channelId/messages/:ts\",\n uriTemplate: \"slack://{botToken}\",\n category: \"messaging\",\n schema: {\n type: \"object\",\n properties: {\n botToken: { type: \"string\", description: \"Slack Bot OAuth token\", sensitive: true },\n webhook: { type: \"string\", description: \"Incoming Webhook URL\", sensitive: true },\n channels: { type: \"array\", items: { type: \"string\" }, description: \"Channel IDs\" },\n },\n },\n tags: [\"slack\", \"messaging\", \"chat\", \"workspace\"],\n capabilityTags: [\n \"read-write\",\n \"crud\",\n \"search\",\n \"auth:token\",\n \"remote\",\n \"http\",\n \"real-time\",\n \"rate-limited\",\n ],\n security: {\n riskLevel: \"external\",\n resourceAccess: [\"internet\"],\n notes: [\"Connects to Slack API — requires bot token or webhook URL\"],\n },\n capabilities: {\n network: { egress: true, allowedDomains: [\"slack.com\"] },\n },\n };\n }\n\n static treeSchema(): ProviderTreeSchema {\n return {\n operations: [\"list\", \"read\", \"exec\", \"stat\", \"explain\"],\n tree: {\n \"/\": {\n kind: \"messaging:root\",\n operations: [\"list\", \"exec\"],\n actions: [\"add-bot\", \"remove-bot\", \"process-event\"],\n },\n \"/{bot}\": { kind: \"messaging:bot\", operations: [\"list\", \"read\"] },\n \"/{bot}/ctl\": { kind: \"messaging:status\", operations: [\"read\"] },\n \"/{bot}/conversations\": { kind: \"messaging:conversations\", operations: [\"list\"] },\n \"/{bot}/conversations/{convId}\": { kind: \"messaging:conversation\", operations: [\"list\"] },\n \"/{bot}/conversations/{convId}/messages\": {\n kind: \"messaging:messages\",\n operations: [\"list\", \"exec\"],\n actions: [\"send\"],\n },\n \"/{bot}/conversations/{convId}/messages/{msgId}\": {\n kind: \"messaging:message\",\n operations: [\"read\"],\n },\n },\n auth: { type: \"token\", env: [\"SLACK_BOT_TOKEN\"] },\n bestFor: [\"team notifications\", \"workflow alerts\", \"chatops\"],\n notFor: [\"file storage\", \"database queries\"],\n };\n }\n\n readonly providerName = \"slack\";\n readonly eventPrefix = \"slack\";\n\n constructor(options: AFSSlackOptions) {\n let bots: BotConfig[];\n if (options.bots) {\n bots = options.bots.map((b) => ({\n ...b,\n conversations: b.channels,\n }));\n } else {\n if (!options.botToken && !options.webhook) {\n throw new Error(\"AFSSlack requires either botToken or webhook\");\n }\n bots = [\n {\n name: \"default\",\n botToken: options.botToken,\n webhook: options.webhook,\n conversations: options.channels ?? [],\n apiBase: options.apiBase,\n },\n ];\n }\n\n super({ bots, bufferSize: options.bufferSize });\n }\n\n // ─── Abstract Implementation ─────────────────────────\n\n getMessageCapabilities(): MessageCapabilities {\n return {\n formats: {\n send: [\"text\", \"markdown\"],\n receive: [\"text\"],\n },\n maxMessageLength: 40000,\n features: {\n edit: false,\n delete: false,\n reply: true,\n thread: true,\n reaction: true,\n inlineKeyboard: false,\n },\n limits: {\n messagesPerSecond: 1,\n messagesPerMinute: 60,\n },\n };\n }\n\n createBotClient(config: BotConfig): SlackClient {\n const botToken = config.botToken as string | undefined;\n const webhook = config.webhook as string | undefined;\n const apiBase = config.apiBase as string | undefined;\n\n if (botToken) {\n return SlackClient.bot({ botToken, apiBase });\n }\n if (webhook) {\n return SlackClient.webhook(webhook);\n }\n throw new Error(`Slack bot \"${config.name}\" requires botToken or webhook`);\n }\n\n async sendMessage(\n client: unknown,\n convId: string,\n text: string,\n opts?: SendOptions,\n ): Promise<{ messageId: string }> {\n const sc = client as SlackClient;\n const blocks = opts?.blocks as unknown[] | undefined;\n // Escape Slack special characters to prevent injection (<!channel>, phishing links, etc.)\n const safeText = SlackClient.escapeSlack(text);\n\n if (sc.mode === \"bot\") {\n const result = await sc.postMessage(convId, safeText, { blocks });\n return { messageId: result.ts };\n }\n\n // Webhook mode — can't target specific channel\n await sc.sendWebhook(safeText, { blocks });\n return { messageId: String(Date.now()) };\n }\n\n async sendTypingIndicator(_client: unknown, _convId: string): Promise<void> {}\n\n normalizeMessage(raw: Record<string, unknown>): BufferedMessage {\n const msg = raw as any;\n return {\n id: String(msg.ts ?? \"0\"),\n text: String(msg.text ?? \"\"),\n from: this.normalizeSender({ id: msg.userId ?? msg.user }),\n timestamp: Math.floor(Number.parseFloat(String(msg.ts ?? \"0\"))),\n conversationId: String(msg.channelId ?? msg.channel ?? \"\"),\n platform: { ts: msg.ts },\n };\n }\n\n normalizeSender(raw: Record<string, unknown>): MessageSender {\n return {\n id: String(raw.id ?? \"0\"),\n name: String(raw.name ?? raw.id ?? \"\"),\n isBot: raw.isBot as boolean | undefined,\n };\n }\n\n // ─── Slack-specific Actions ─────────────────────────\n\n @Actions(\"/\")\n async listRootActions(_ctx: RouteContext): Promise<AFSListResult> {\n return {\n data: [\n this.buildEntry(\"/.actions/add-bot\", {\n meta: { description: \"Add a bot instance at runtime\" },\n }),\n this.buildEntry(\"/.actions/remove-bot\", {\n meta: { description: \"Remove a bot instance\" },\n }),\n this.buildEntry(\"/.actions/process-event\", {\n meta: { description: \"Process an incoming Slack Events API payload\" },\n }),\n ],\n };\n }\n\n @Actions.Exec(\"/\", \"process-event\")\n async execProcessEvent(\n _ctx: RouteContext,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n this._processEvent(args);\n return { success: true, data: { ok: true } };\n }\n\n // ─── Event Processing (public for testing) ────────────\n\n /** Process a Slack Events API payload — delegates to emitMessageReceived(). */\n _processEvent(payload: any): void {\n const parsed = SlackClient.parseEvent(payload);\n if (!parsed) return;\n if (parsed.type === \"url_verification\") return;\n\n const { text, userId, channelId, ts } = parsed;\n const botName = this._botOrder[0] ?? \"default\";\n\n this.emitMessageReceived(botName, {\n id: ts,\n text,\n from: { id: userId, name: userId },\n timestamp: Math.floor(Number.parseFloat(ts)),\n conversationId: channelId,\n platform: { ts, userId },\n });\n }\n\n // ─── Convenience Methods (backward compat) ─────────────\n\n /** Add a channel to a bot. Defaults to first bot. */\n addChannel(channelId: string, botName?: string): void {\n const name = botName ?? this._botOrder[0];\n if (!name) return;\n const convs = this._botConversations.get(name);\n if (!convs || convs.has(channelId)) return;\n convs.add(channelId);\n const buffers = this._botBuffers.get(name);\n if (buffers && !buffers.has(channelId)) {\n buffers.set(channelId, []);\n }\n }\n\n /** Remove a channel from a bot. */\n removeChannel(channelId: string, botName?: string): void {\n const name = botName ?? this._botOrder[0];\n if (!name) return;\n const convs = this._botConversations.get(name);\n if (convs) convs.delete(channelId);\n const buffers = this._botBuffers.get(name);\n if (buffers) buffers.delete(channelId);\n }\n\n /** Add a message to the ring buffer directly. Public for testing/conformance. */\n _addToBuffer(\n channelId: string,\n msg: { ts: string; text: string; userId: string; date: number },\n ): void {\n const botName = this._botOrder[0] ?? \"default\";\n\n // Auto-add conversation\n const convs = this._botConversations.get(botName);\n if (convs && !convs.has(channelId)) {\n convs.add(channelId);\n }\n\n // Add to buffer directly (no event emission — for test setup)\n let botBuffers = this._botBuffers.get(botName);\n if (!botBuffers) {\n botBuffers = new Map();\n this._botBuffers.set(botName, botBuffers);\n }\n let buffer = botBuffers.get(channelId);\n if (!buffer) {\n buffer = [];\n botBuffers.set(channelId, buffer);\n }\n buffer.push({\n id: msg.ts,\n text: msg.text,\n from: { id: msg.userId, name: msg.userId },\n timestamp: msg.date,\n conversationId: channelId,\n platform: { ts: msg.ts },\n });\n while (buffer.length > this._bufferSize) {\n buffer.shift();\n }\n }\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@aigne/afs-slack",
3
+ "version": "1.11.0-beta.12",
4
+ "description": "AIGNE AFS provider for Slack (webhook + bot modes)",
5
+ "license": "UNLICENSED",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "author": "Arcblock <blocklet@arcblock.io> https://github.com/arcblock",
10
+ "homepage": "https://github.com/arcblock/afs",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/arcblock/afs"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/arcblock/afs/issues"
17
+ },
18
+ "type": "module",
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.mjs",
21
+ "types": "./dist/index.d.cts",
22
+ "exports": {
23
+ ".": {
24
+ "require": "./dist/index.cjs",
25
+ "import": "./dist/index.mjs"
26
+ },
27
+ "./*": "./*"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "LICENSE",
32
+ "README.md",
33
+ "CHANGELOG.md"
34
+ ],
35
+ "dependencies": {
36
+ "@aigne/afs": "^1.11.0-beta.12",
37
+ "@aigne/afs-messaging": "^1.11.0-beta.12"
38
+ },
39
+ "devDependencies": {
40
+ "@types/bun": "^1.3.6",
41
+ "npm-run-all": "^4.1.5",
42
+ "rimraf": "^6.1.2",
43
+ "tsdown": "0.20.0-beta.3",
44
+ "typescript": "5.9.2",
45
+ "@aigne/scripts": "0.0.0",
46
+ "@aigne/typescript-config": "0.0.0",
47
+ "@aigne/afs-testing": "1.11.0-beta.12"
48
+ },
49
+ "scripts": {
50
+ "build": "tsdown",
51
+ "check-types": "tsc --noEmit",
52
+ "clean": "rimraf dist coverage",
53
+ "test": "bun test",
54
+ "test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text"
55
+ }
56
+ }