@memberjunction/messaging-adapters 0.0.1 → 5.18.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 +231 -43
- package/dist/base/BaseMessagingAdapter.d.ts +428 -0
- package/dist/base/BaseMessagingAdapter.d.ts.map +1 -0
- package/dist/base/BaseMessagingAdapter.js +934 -0
- package/dist/base/BaseMessagingAdapter.js.map +1 -0
- package/dist/base/message-formatter.d.ts +70 -0
- package/dist/base/message-formatter.d.ts.map +1 -0
- package/dist/base/message-formatter.js +201 -0
- package/dist/base/message-formatter.js.map +1 -0
- package/dist/base/types.d.ts +211 -0
- package/dist/base/types.d.ts.map +1 -0
- package/dist/base/types.js +6 -0
- package/dist/base/types.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/slack/SlackAdapter.d.ts +141 -0
- package/dist/slack/SlackAdapter.d.ts.map +1 -0
- package/dist/slack/SlackAdapter.js +291 -0
- package/dist/slack/SlackAdapter.js.map +1 -0
- package/dist/slack/SlackMessagingExtension.d.ts +148 -0
- package/dist/slack/SlackMessagingExtension.d.ts.map +1 -0
- package/dist/slack/SlackMessagingExtension.js +433 -0
- package/dist/slack/SlackMessagingExtension.js.map +1 -0
- package/dist/slack/slack-block-builder.d.ts +133 -0
- package/dist/slack/slack-block-builder.d.ts.map +1 -0
- package/dist/slack/slack-block-builder.js +748 -0
- package/dist/slack/slack-block-builder.js.map +1 -0
- package/dist/slack/slack-formatter.d.ts +37 -0
- package/dist/slack/slack-formatter.d.ts.map +1 -0
- package/dist/slack/slack-formatter.js +116 -0
- package/dist/slack/slack-formatter.js.map +1 -0
- package/dist/slack/slack-interactivity.d.ts +38 -0
- package/dist/slack/slack-interactivity.d.ts.map +1 -0
- package/dist/slack/slack-interactivity.js +414 -0
- package/dist/slack/slack-interactivity.js.map +1 -0
- package/dist/slack/slack-routes.d.ts +35 -0
- package/dist/slack/slack-routes.d.ts.map +1 -0
- package/dist/slack/slack-routes.js +98 -0
- package/dist/slack/slack-routes.js.map +1 -0
- package/dist/teams/TeamsAdapter.d.ts +155 -0
- package/dist/teams/TeamsAdapter.d.ts.map +1 -0
- package/dist/teams/TeamsAdapter.js +383 -0
- package/dist/teams/TeamsAdapter.js.map +1 -0
- package/dist/teams/TeamsMessagingExtension.d.ts +75 -0
- package/dist/teams/TeamsMessagingExtension.d.ts.map +1 -0
- package/dist/teams/TeamsMessagingExtension.js +176 -0
- package/dist/teams/TeamsMessagingExtension.js.map +1 -0
- package/dist/teams/teams-card-builder.d.ts +94 -0
- package/dist/teams/teams-card-builder.d.ts.map +1 -0
- package/dist/teams/teams-card-builder.js +648 -0
- package/dist/teams/teams-card-builder.js.map +1 -0
- package/dist/teams/teams-formatter.d.ts +39 -0
- package/dist/teams/teams-formatter.d.ts.map +1 -0
- package/dist/teams/teams-formatter.js +107 -0
- package/dist/teams/teams-formatter.js.map +1 -0
- package/package.json +40 -7
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @memberjunction/messaging-adapters
|
|
3
|
+
* @description Slack Server Extension — registers webhook routes and delegates to SlackAdapter.
|
|
4
|
+
*
|
|
5
|
+
* This is the entry point for Slack integration. It extends `BaseServerExtension`
|
|
6
|
+
* to plug into MJServer's extension framework, registering a POST webhook endpoint
|
|
7
|
+
* that receives Slack Events API payloads.
|
|
8
|
+
*
|
|
9
|
+
* ## Slack App Setup
|
|
10
|
+
*
|
|
11
|
+
* 1. Create a Slack App at https://api.slack.com/apps
|
|
12
|
+
* 2. Enable Event Subscriptions and point the Request URL to `{your-server}/webhook/slack`
|
|
13
|
+
* 3. Subscribe to bot events: `message.im`, `message.channels`, `message.groups`, `app_mention`
|
|
14
|
+
* - `message.im` — direct messages to the bot
|
|
15
|
+
* - `message.channels` / `message.groups` — thread replies in public/private channels
|
|
16
|
+
* - `app_mention` — @mentions of the bot in channels
|
|
17
|
+
* 4. Add OAuth scopes: `chat:write`, `channels:history`, `groups:history`,
|
|
18
|
+
* `im:history`, `users:read`, `users:read.email`, `app_mentions:read`
|
|
19
|
+
* 5. Install the app to your workspace
|
|
20
|
+
* 6. Copy the Bot User OAuth Token and Signing Secret to your `mj.config.cjs`
|
|
21
|
+
*
|
|
22
|
+
* ## Configuration
|
|
23
|
+
*
|
|
24
|
+
* ```javascript
|
|
25
|
+
* // mj.config.cjs
|
|
26
|
+
* serverExtensions: [{
|
|
27
|
+
* Enabled: true,
|
|
28
|
+
* DriverClass: 'SlackMessagingExtension',
|
|
29
|
+
* RootPath: '/webhook/slack',
|
|
30
|
+
* Settings: {
|
|
31
|
+
* DefaultAgentName: 'Sage',
|
|
32
|
+
* ContextUserEmail: 'bot@company.com',
|
|
33
|
+
* BotToken: process.env.SLACK_BOT_TOKEN,
|
|
34
|
+
* SigningSecret: process.env.SLACK_SIGNING_SECRET,
|
|
35
|
+
* ConnectionMode: 'http', // or 'socket' for Socket Mode
|
|
36
|
+
* MaxThreadMessages: 50,
|
|
37
|
+
* StreamingUpdateIntervalMs: 1500,
|
|
38
|
+
* }
|
|
39
|
+
* }]
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
import { Application } from 'express';
|
|
43
|
+
import { BaseServerExtension, ServerExtensionConfig, ExtensionInitResult, ExtensionHealthResult } from '@memberjunction/server-extensions-core';
|
|
44
|
+
/**
|
|
45
|
+
* Server Extension that registers Slack webhook routes and delegates
|
|
46
|
+
* message handling to the `SlackAdapter`.
|
|
47
|
+
*
|
|
48
|
+
* Supports two connection modes:
|
|
49
|
+
* - **HTTP** (default): Registers a POST endpoint for Slack Events API webhooks
|
|
50
|
+
* - **Socket Mode**: Uses Slack's WebSocket-based Socket Mode (no public URL needed,
|
|
51
|
+
* ideal for local development)
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* // Auto-discovered by MJServer when package is imported and config is present
|
|
56
|
+
* // No manual instantiation needed — just add to mj.config.cjs
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare class SlackMessagingExtension extends BaseServerExtension {
|
|
60
|
+
/** The Slack adapter handling message processing. */
|
|
61
|
+
private adapter;
|
|
62
|
+
/** Slack WebClient for interactivity handlers (modals, etc.). */
|
|
63
|
+
private interactClient;
|
|
64
|
+
/** The signing secret for webhook verification. */
|
|
65
|
+
private signingSecret;
|
|
66
|
+
/** Slash command → agent name mapping from config. */
|
|
67
|
+
private slashCommands;
|
|
68
|
+
/** Socket Mode client (only used when ConnectionMode is 'socket'). */
|
|
69
|
+
private socketModeClient;
|
|
70
|
+
/** The active connection mode for health reporting. */
|
|
71
|
+
private connectionMode;
|
|
72
|
+
/**
|
|
73
|
+
* Initialize the Slack extension.
|
|
74
|
+
*
|
|
75
|
+
* Creates and initializes the `SlackAdapter`, then sets up either:
|
|
76
|
+
* - **HTTP mode** (default): POST webhook endpoint for Slack Events API
|
|
77
|
+
* - **Socket Mode**: WebSocket connection using an App-Level Token (no public URL needed)
|
|
78
|
+
*/
|
|
79
|
+
Initialize(app: Application, config: ServerExtensionConfig): Promise<ExtensionInitResult>;
|
|
80
|
+
/**
|
|
81
|
+
* Shut down the Slack extension. Releases the adapter and disconnects Socket Mode.
|
|
82
|
+
*/
|
|
83
|
+
Shutdown(): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Health check for the Slack extension.
|
|
86
|
+
* Reports whether the adapter is initialized and ready.
|
|
87
|
+
*/
|
|
88
|
+
HealthCheck(): Promise<ExtensionHealthResult>;
|
|
89
|
+
/**
|
|
90
|
+
* Set up HTTP webhook mode: register POST endpoints for Slack Events API
|
|
91
|
+
* and Slack Interactivity payloads.
|
|
92
|
+
*/
|
|
93
|
+
private initializeHttpMode;
|
|
94
|
+
/**
|
|
95
|
+
* Handle an incoming Slack webhook request (HTTP mode).
|
|
96
|
+
*
|
|
97
|
+
* 1. Verify the request signature (if signing secret is configured)
|
|
98
|
+
* 2. Handle URL verification challenges (Slack sends these during setup)
|
|
99
|
+
* 3. Acknowledge immediately (Slack requires response within 3 seconds)
|
|
100
|
+
* 4. Process the message asynchronously via the adapter
|
|
101
|
+
*/
|
|
102
|
+
private handleWebhook;
|
|
103
|
+
/**
|
|
104
|
+
* Set up Socket Mode: connect via WebSocket using an App-Level Token.
|
|
105
|
+
*
|
|
106
|
+
* Socket Mode is ideal for local development — no public URL or ngrok needed.
|
|
107
|
+
* Requires an App-Level Token (`xapp-...`) with `connections:write` scope.
|
|
108
|
+
*/
|
|
109
|
+
private initializeSocketMode;
|
|
110
|
+
/**
|
|
111
|
+
* Handle Slack interactivity payloads (button clicks, modal submissions).
|
|
112
|
+
* Slack sends these as `application/x-www-form-urlencoded` with a `payload` JSON field.
|
|
113
|
+
*/
|
|
114
|
+
private handleInteraction;
|
|
115
|
+
/**
|
|
116
|
+
* Handle a Slack slash command (e.g., `/research what is quantum computing?`).
|
|
117
|
+
*
|
|
118
|
+
* Slack sends slash commands as `application/x-www-form-urlencoded` with fields:
|
|
119
|
+
* `command`, `text`, `user_id`, `user_name`, `channel_id`, `channel_name`, `trigger_id`.
|
|
120
|
+
*
|
|
121
|
+
* Must respond within 3 seconds. We acknowledge immediately with a brief message,
|
|
122
|
+
* then route to the agent pipeline asynchronously (which posts results to the channel).
|
|
123
|
+
*/
|
|
124
|
+
private handleSlashCommand;
|
|
125
|
+
/**
|
|
126
|
+
* Resolve a slash command string (e.g., `/research`) to an agent name.
|
|
127
|
+
* Tries exact match first, then strips the leading `/` and matches case-insensitively.
|
|
128
|
+
*/
|
|
129
|
+
private resolveSlashCommandAgent;
|
|
130
|
+
/**
|
|
131
|
+
* Build the slash command → agent name map.
|
|
132
|
+
* Auto-generates a command for every loaded agent using its first word
|
|
133
|
+
* (e.g., "Research Agent" → `/research`). Explicit config overrides take precedence.
|
|
134
|
+
*/
|
|
135
|
+
private buildSlashCommandMap;
|
|
136
|
+
/** Format the list of configured slash commands for display. */
|
|
137
|
+
private listSlashCommands;
|
|
138
|
+
/**
|
|
139
|
+
* Post a visible thread-root message for the slash command, then construct
|
|
140
|
+
* an IncomingMessage with that thread's `ts` so all responses appear as replies.
|
|
141
|
+
*/
|
|
142
|
+
private processSlashCommandAsync;
|
|
143
|
+
/**
|
|
144
|
+
* Process a Slack event from either HTTP webhook or Socket Mode.
|
|
145
|
+
*/
|
|
146
|
+
private processSlackEvent;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=SlackMessagingExtension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlackMessagingExtension.d.ts","sourceRoot":"","sources":["../../src/slack/SlackMessagingExtension.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAgB,EAAE,WAAW,EAA6B,MAAM,SAAS,CAAC;AAK1E,OAAO,EACH,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,EACxB,MAAM,wCAAwC,CAAC;AAMhD;;;;;;;;;;;;;;GAcG;AACH,qBACa,uBAAwB,SAAQ,mBAAmB;IAC5D,qDAAqD;IACrD,OAAO,CAAC,OAAO,CAA6B;IAE5C,iEAAiE;IACjE,OAAO,CAAC,cAAc,CAA0B;IAEhD,mDAAmD;IACnD,OAAO,CAAC,aAAa,CAAc;IAEnC,sDAAsD;IACtD,OAAO,CAAC,aAAa,CAA8B;IAEnD,sEAAsE;IACtE,OAAO,CAAC,gBAAgB,CAAiC;IAEzD,uDAAuD;IACvD,OAAO,CAAC,cAAc,CAA6B;IAEnD;;;;;;OAMG;IACG,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAkC/F;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAS/B;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAenD;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA0C1B;;;;;;;OAOG;YACW,aAAa;IAsB3B;;;;;OAKG;YACW,oBAAoB;IAkClC;;;OAGG;YACW,iBAAiB;IAwB/B;;;;;;;;OAQG;YACW,kBAAkB;IA2BhC;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAiBhC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAe5B,gEAAgE;IAChE,OAAO,CAAC,iBAAiB;IAMzB;;;OAGG;YACW,wBAAwB;IAwDtC;;OAEG;YACW,iBAAiB;CAiClC"}
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @memberjunction/messaging-adapters
|
|
3
|
+
* @description Slack Server Extension — registers webhook routes and delegates to SlackAdapter.
|
|
4
|
+
*
|
|
5
|
+
* This is the entry point for Slack integration. It extends `BaseServerExtension`
|
|
6
|
+
* to plug into MJServer's extension framework, registering a POST webhook endpoint
|
|
7
|
+
* that receives Slack Events API payloads.
|
|
8
|
+
*
|
|
9
|
+
* ## Slack App Setup
|
|
10
|
+
*
|
|
11
|
+
* 1. Create a Slack App at https://api.slack.com/apps
|
|
12
|
+
* 2. Enable Event Subscriptions and point the Request URL to `{your-server}/webhook/slack`
|
|
13
|
+
* 3. Subscribe to bot events: `message.im`, `message.channels`, `message.groups`, `app_mention`
|
|
14
|
+
* - `message.im` — direct messages to the bot
|
|
15
|
+
* - `message.channels` / `message.groups` — thread replies in public/private channels
|
|
16
|
+
* - `app_mention` — @mentions of the bot in channels
|
|
17
|
+
* 4. Add OAuth scopes: `chat:write`, `channels:history`, `groups:history`,
|
|
18
|
+
* `im:history`, `users:read`, `users:read.email`, `app_mentions:read`
|
|
19
|
+
* 5. Install the app to your workspace
|
|
20
|
+
* 6. Copy the Bot User OAuth Token and Signing Secret to your `mj.config.cjs`
|
|
21
|
+
*
|
|
22
|
+
* ## Configuration
|
|
23
|
+
*
|
|
24
|
+
* ```javascript
|
|
25
|
+
* // mj.config.cjs
|
|
26
|
+
* serverExtensions: [{
|
|
27
|
+
* Enabled: true,
|
|
28
|
+
* DriverClass: 'SlackMessagingExtension',
|
|
29
|
+
* RootPath: '/webhook/slack',
|
|
30
|
+
* Settings: {
|
|
31
|
+
* DefaultAgentName: 'Sage',
|
|
32
|
+
* ContextUserEmail: 'bot@company.com',
|
|
33
|
+
* BotToken: process.env.SLACK_BOT_TOKEN,
|
|
34
|
+
* SigningSecret: process.env.SLACK_SIGNING_SECRET,
|
|
35
|
+
* ConnectionMode: 'http', // or 'socket' for Socket Mode
|
|
36
|
+
* MaxThreadMessages: 50,
|
|
37
|
+
* StreamingUpdateIntervalMs: 1500,
|
|
38
|
+
* }
|
|
39
|
+
* }]
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
43
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
44
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
45
|
+
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;
|
|
46
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
47
|
+
};
|
|
48
|
+
import express, { Router } from 'express';
|
|
49
|
+
import { WebClient } from '@slack/web-api';
|
|
50
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
51
|
+
import { LogError, LogStatus } from '@memberjunction/core';
|
|
52
|
+
import { SocketModeClient } from '@slack/socket-mode';
|
|
53
|
+
import { BaseServerExtension } from '@memberjunction/server-extensions-core';
|
|
54
|
+
import { SlackAdapter } from './SlackAdapter.js';
|
|
55
|
+
import { verifySlackSignature } from './slack-routes.js';
|
|
56
|
+
import { handleSlackInteraction } from './slack-interactivity.js';
|
|
57
|
+
/**
|
|
58
|
+
* Server Extension that registers Slack webhook routes and delegates
|
|
59
|
+
* message handling to the `SlackAdapter`.
|
|
60
|
+
*
|
|
61
|
+
* Supports two connection modes:
|
|
62
|
+
* - **HTTP** (default): Registers a POST endpoint for Slack Events API webhooks
|
|
63
|
+
* - **Socket Mode**: Uses Slack's WebSocket-based Socket Mode (no public URL needed,
|
|
64
|
+
* ideal for local development)
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* // Auto-discovered by MJServer when package is imported and config is present
|
|
69
|
+
* // No manual instantiation needed — just add to mj.config.cjs
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
let SlackMessagingExtension = class SlackMessagingExtension extends BaseServerExtension {
|
|
73
|
+
constructor() {
|
|
74
|
+
super(...arguments);
|
|
75
|
+
/** The Slack adapter handling message processing. */
|
|
76
|
+
this.adapter = null;
|
|
77
|
+
/** Slack WebClient for interactivity handlers (modals, etc.). */
|
|
78
|
+
this.interactClient = null;
|
|
79
|
+
/** The signing secret for webhook verification. */
|
|
80
|
+
this.signingSecret = '';
|
|
81
|
+
/** Slash command → agent name mapping from config. */
|
|
82
|
+
this.slashCommands = {};
|
|
83
|
+
/** Socket Mode client (only used when ConnectionMode is 'socket'). */
|
|
84
|
+
this.socketModeClient = null;
|
|
85
|
+
/** The active connection mode for health reporting. */
|
|
86
|
+
this.connectionMode = 'http';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Initialize the Slack extension.
|
|
90
|
+
*
|
|
91
|
+
* Creates and initializes the `SlackAdapter`, then sets up either:
|
|
92
|
+
* - **HTTP mode** (default): POST webhook endpoint for Slack Events API
|
|
93
|
+
* - **Socket Mode**: WebSocket connection using an App-Level Token (no public URL needed)
|
|
94
|
+
*/
|
|
95
|
+
async Initialize(app, config) {
|
|
96
|
+
try {
|
|
97
|
+
// The Zod config pipeline may strip unknown keys from Settings, so we
|
|
98
|
+
// fall back to env vars for settings that may be missing.
|
|
99
|
+
const settings = config.Settings;
|
|
100
|
+
if (!settings.ExplorerBaseURL && process.env.MJ_EXPLORER_BASE_URL) {
|
|
101
|
+
settings.ExplorerBaseURL = process.env.MJ_EXPLORER_BASE_URL;
|
|
102
|
+
}
|
|
103
|
+
LogStatus(`[Slack] Extension settings keys: ${Object.keys(settings).join(', ')}, ExplorerBaseURL=${settings.ExplorerBaseURL ?? 'NOT SET'}`);
|
|
104
|
+
this.signingSecret = settings.SigningSecret ?? '';
|
|
105
|
+
this.connectionMode = settings.ConnectionMode ?? 'http';
|
|
106
|
+
// Create and initialize the Slack adapter + interactivity client
|
|
107
|
+
this.adapter = new SlackAdapter(settings);
|
|
108
|
+
this.interactClient = new WebClient(settings.BotToken);
|
|
109
|
+
await this.adapter.Initialize();
|
|
110
|
+
// Build slash command map: auto-generate from loaded agents + merge config overrides
|
|
111
|
+
this.slashCommands = this.buildSlashCommandMap(settings.SlashCommands);
|
|
112
|
+
if (this.connectionMode === 'socket') {
|
|
113
|
+
return await this.initializeSocketMode(settings);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
return this.initializeHttpMode(app, config, settings);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
121
|
+
return {
|
|
122
|
+
Success: false,
|
|
123
|
+
Message: `Failed to initialize Slack extension: ${message}`
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Shut down the Slack extension. Releases the adapter and disconnects Socket Mode.
|
|
129
|
+
*/
|
|
130
|
+
async Shutdown() {
|
|
131
|
+
LogStatus('Shutting down Slack messaging extension');
|
|
132
|
+
if (this.socketModeClient) {
|
|
133
|
+
await this.socketModeClient.disconnect();
|
|
134
|
+
this.socketModeClient = null;
|
|
135
|
+
}
|
|
136
|
+
this.adapter = null;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Health check for the Slack extension.
|
|
140
|
+
* Reports whether the adapter is initialized and ready.
|
|
141
|
+
*/
|
|
142
|
+
async HealthCheck() {
|
|
143
|
+
return {
|
|
144
|
+
Healthy: this.adapter !== null,
|
|
145
|
+
Name: 'SlackMessagingExtension',
|
|
146
|
+
Details: {
|
|
147
|
+
adapterInitialized: this.adapter !== null,
|
|
148
|
+
connectionMode: this.connectionMode,
|
|
149
|
+
signatureVerificationEnabled: this.signingSecret.length > 0,
|
|
150
|
+
socketModeConnected: this.socketModeClient !== null
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// ─── HTTP Mode ───────────────────────────────────────────────────────
|
|
155
|
+
/**
|
|
156
|
+
* Set up HTTP webhook mode: register POST endpoints for Slack Events API
|
|
157
|
+
* and Slack Interactivity payloads.
|
|
158
|
+
*/
|
|
159
|
+
initializeHttpMode(app, config, settings) {
|
|
160
|
+
const router = Router();
|
|
161
|
+
router.use(express.json({
|
|
162
|
+
limit: '1mb',
|
|
163
|
+
verify: (req, _res, buf) => {
|
|
164
|
+
req.rawBody = buf.toString('utf-8');
|
|
165
|
+
}
|
|
166
|
+
}));
|
|
167
|
+
router.post('/', this.handleWebhook.bind(this));
|
|
168
|
+
// Interactivity endpoint for button clicks, modal submissions, etc.
|
|
169
|
+
// Slack sends these as application/x-www-form-urlencoded with a `payload` JSON field
|
|
170
|
+
const interactRouter = Router();
|
|
171
|
+
interactRouter.use(express.urlencoded({ extended: true }));
|
|
172
|
+
interactRouter.post('/', this.handleInteraction.bind(this));
|
|
173
|
+
app.use(config.RootPath + '/interact', interactRouter);
|
|
174
|
+
// Slash command endpoint — Slack sends these as application/x-www-form-urlencoded
|
|
175
|
+
const slashRouter = Router();
|
|
176
|
+
slashRouter.use(express.urlencoded({ extended: true }));
|
|
177
|
+
slashRouter.post('/', this.handleSlashCommand.bind(this));
|
|
178
|
+
app.use(config.RootPath + '/slash', slashRouter);
|
|
179
|
+
app.use(config.RootPath, router);
|
|
180
|
+
const registeredRoutes = [
|
|
181
|
+
`POST ${config.RootPath}`,
|
|
182
|
+
`POST ${config.RootPath}/interact`,
|
|
183
|
+
`POST ${config.RootPath}/slash`,
|
|
184
|
+
];
|
|
185
|
+
return {
|
|
186
|
+
Success: true,
|
|
187
|
+
Message: `Slack extension loaded (HTTP mode) for agent ${settings.DefaultAgentName}`,
|
|
188
|
+
RegisteredRoutes: registeredRoutes
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Handle an incoming Slack webhook request (HTTP mode).
|
|
193
|
+
*
|
|
194
|
+
* 1. Verify the request signature (if signing secret is configured)
|
|
195
|
+
* 2. Handle URL verification challenges (Slack sends these during setup)
|
|
196
|
+
* 3. Acknowledge immediately (Slack requires response within 3 seconds)
|
|
197
|
+
* 4. Process the message asynchronously via the adapter
|
|
198
|
+
*/
|
|
199
|
+
async handleWebhook(req, res) {
|
|
200
|
+
// 1. Verify signature
|
|
201
|
+
if (this.signingSecret && !verifySlackSignature(req, this.signingSecret)) {
|
|
202
|
+
res.status(401).send('Invalid signature');
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// 2. Handle URL verification challenge (sent during app setup)
|
|
206
|
+
if (req.body?.type === 'url_verification') {
|
|
207
|
+
res.json({ challenge: req.body.challenge });
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// 3. Acknowledge immediately (Slack requires < 3s response)
|
|
211
|
+
res.status(200).send();
|
|
212
|
+
// 4. Process asynchronously
|
|
213
|
+
await this.processSlackEvent(req.body?.event);
|
|
214
|
+
}
|
|
215
|
+
// ─── Socket Mode ─────────────────────────────────────────────────────
|
|
216
|
+
/**
|
|
217
|
+
* Set up Socket Mode: connect via WebSocket using an App-Level Token.
|
|
218
|
+
*
|
|
219
|
+
* Socket Mode is ideal for local development — no public URL or ngrok needed.
|
|
220
|
+
* Requires an App-Level Token (`xapp-...`) with `connections:write` scope.
|
|
221
|
+
*/
|
|
222
|
+
async initializeSocketMode(settings) {
|
|
223
|
+
const appToken = settings.AppToken;
|
|
224
|
+
if (!appToken) {
|
|
225
|
+
return {
|
|
226
|
+
Success: false,
|
|
227
|
+
Message: 'Socket Mode requires an AppToken (xapp-...) in Settings'
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
this.socketModeClient = new SocketModeClient({ appToken });
|
|
231
|
+
// Listen for message and app_mention events
|
|
232
|
+
this.socketModeClient.on('message', async ({ event, ack }) => {
|
|
233
|
+
await ack();
|
|
234
|
+
await this.processSlackEvent(event);
|
|
235
|
+
});
|
|
236
|
+
this.socketModeClient.on('app_mention', async ({ event, ack }) => {
|
|
237
|
+
await ack();
|
|
238
|
+
await this.processSlackEvent(event);
|
|
239
|
+
});
|
|
240
|
+
await this.socketModeClient.start();
|
|
241
|
+
LogStatus('Slack Socket Mode connected');
|
|
242
|
+
return {
|
|
243
|
+
Success: true,
|
|
244
|
+
Message: `Slack extension loaded (Socket Mode) for agent ${settings.DefaultAgentName}`,
|
|
245
|
+
RegisteredRoutes: ['WebSocket (Socket Mode)']
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
// ─── Interactivity ─────────────────────────────────────────────────────
|
|
249
|
+
/**
|
|
250
|
+
* Handle Slack interactivity payloads (button clicks, modal submissions).
|
|
251
|
+
* Slack sends these as `application/x-www-form-urlencoded` with a `payload` JSON field.
|
|
252
|
+
*/
|
|
253
|
+
async handleInteraction(req, res) {
|
|
254
|
+
// Acknowledge immediately
|
|
255
|
+
res.status(200).send();
|
|
256
|
+
const payloadStr = req.body?.payload;
|
|
257
|
+
if (!payloadStr) {
|
|
258
|
+
LogStatus('Slack interact: no payload in request');
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (!this.interactClient || !this.adapter) {
|
|
262
|
+
LogStatus('Slack interact: extension not fully initialized');
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
await handleSlackInteraction(payloadStr, this.interactClient, this.adapter);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
LogError('Error handling Slack interaction:', undefined, error);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// ─── Slash Commands ─────────────────────────────────────────────────
|
|
273
|
+
/**
|
|
274
|
+
* Handle a Slack slash command (e.g., `/research what is quantum computing?`).
|
|
275
|
+
*
|
|
276
|
+
* Slack sends slash commands as `application/x-www-form-urlencoded` with fields:
|
|
277
|
+
* `command`, `text`, `user_id`, `user_name`, `channel_id`, `channel_name`, `trigger_id`.
|
|
278
|
+
*
|
|
279
|
+
* Must respond within 3 seconds. We acknowledge immediately with a brief message,
|
|
280
|
+
* then route to the agent pipeline asynchronously (which posts results to the channel).
|
|
281
|
+
*/
|
|
282
|
+
async handleSlashCommand(req, res) {
|
|
283
|
+
const { command, text, user_id, user_name, channel_id } = req.body;
|
|
284
|
+
LogStatus(`Slack slash command: command=${command}, text="${text}", user=${user_id}, channel=${channel_id}`);
|
|
285
|
+
// Look up the agent for this command
|
|
286
|
+
const agentName = this.resolveSlashCommandAgent(command);
|
|
287
|
+
if (!agentName) {
|
|
288
|
+
res.json({
|
|
289
|
+
response_type: 'ephemeral',
|
|
290
|
+
text: `Unknown command \`${command}\`. Configured commands: ${this.listSlashCommands()}`
|
|
291
|
+
});
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
// Acknowledge within 3 seconds — visible only to the user
|
|
295
|
+
res.json({
|
|
296
|
+
response_type: 'ephemeral',
|
|
297
|
+
text: `_Routing to *${agentName}*..._`
|
|
298
|
+
});
|
|
299
|
+
// Process asynchronously — post a thread-root message first, then route to the agent
|
|
300
|
+
this.processSlashCommandAsync(agentName, text ?? '', user_id, user_name, channel_id).catch(error => {
|
|
301
|
+
LogError(`Error processing slash command for agent '${agentName}':`, undefined, error);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Resolve a slash command string (e.g., `/research`) to an agent name.
|
|
306
|
+
* Tries exact match first, then strips the leading `/` and matches case-insensitively.
|
|
307
|
+
*/
|
|
308
|
+
resolveSlashCommandAgent(command) {
|
|
309
|
+
// Exact match (e.g., `/research` → 'Research Agent')
|
|
310
|
+
if (this.slashCommands[command]) {
|
|
311
|
+
return this.slashCommands[command];
|
|
312
|
+
}
|
|
313
|
+
// Case-insensitive match
|
|
314
|
+
const lowerCmd = command.toLowerCase();
|
|
315
|
+
for (const [key, value] of Object.entries(this.slashCommands)) {
|
|
316
|
+
if (key.toLowerCase() === lowerCmd) {
|
|
317
|
+
return value;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Build the slash command → agent name map.
|
|
324
|
+
* Auto-generates a command for every loaded agent using its first word
|
|
325
|
+
* (e.g., "Research Agent" → `/research`). Explicit config overrides take precedence.
|
|
326
|
+
*/
|
|
327
|
+
buildSlashCommandMap(configuredCommands) {
|
|
328
|
+
const autoCommands = {};
|
|
329
|
+
for (const name of (this.adapter?.AvailableAgentNames ?? [])) {
|
|
330
|
+
const firstWord = name.split(/\s+/)[0].toLowerCase();
|
|
331
|
+
const cmd = `/${firstWord}`;
|
|
332
|
+
if (!autoCommands[cmd]) {
|
|
333
|
+
autoCommands[cmd] = name;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const merged = { ...autoCommands, ...(configuredCommands ?? {}) };
|
|
337
|
+
LogStatus(`Slack slash commands: ${Object.keys(merged).length} available (${Object.keys(configuredCommands ?? {}).length} from config, ${Object.keys(autoCommands).length} auto-generated)`);
|
|
338
|
+
return merged;
|
|
339
|
+
}
|
|
340
|
+
/** Format the list of configured slash commands for display. */
|
|
341
|
+
listSlashCommands() {
|
|
342
|
+
const entries = Object.entries(this.slashCommands);
|
|
343
|
+
if (entries.length === 0)
|
|
344
|
+
return '_none configured_';
|
|
345
|
+
return entries.map(([cmd, agent]) => `\`${cmd}\` → ${agent}`).join(', ');
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Post a visible thread-root message for the slash command, then construct
|
|
349
|
+
* an IncomingMessage with that thread's `ts` so all responses appear as replies.
|
|
350
|
+
*/
|
|
351
|
+
async processSlashCommandAsync(agentName, text, userId, userName, channelId) {
|
|
352
|
+
const now = new Date();
|
|
353
|
+
// Post a visible message to serve as the thread root
|
|
354
|
+
let threadRootTs;
|
|
355
|
+
if (this.interactClient) {
|
|
356
|
+
try {
|
|
357
|
+
const displayText = text || `(invoked via slash command)`;
|
|
358
|
+
const result = await this.interactClient.chat.postMessage({
|
|
359
|
+
channel: channelId,
|
|
360
|
+
text: `*/${agentName.split(/\s+/)[0].toLowerCase()}* ${displayText}`,
|
|
361
|
+
blocks: [
|
|
362
|
+
{
|
|
363
|
+
type: 'section',
|
|
364
|
+
text: {
|
|
365
|
+
type: 'mrkdwn',
|
|
366
|
+
text: `<@${userId}> used \`/${agentName.split(/\s+/)[0].toLowerCase()}\`\n>${displayText}`
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
]
|
|
370
|
+
});
|
|
371
|
+
threadRootTs = result.ts ?? undefined;
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
LogError('Failed to post slash command thread root:', undefined, error);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const messageTs = threadRootTs ?? (now.getTime() / 1000).toFixed(6);
|
|
378
|
+
const incomingMessage = {
|
|
379
|
+
MessageID: messageTs,
|
|
380
|
+
Text: text || `(invoked via slash command)`,
|
|
381
|
+
SenderID: userId,
|
|
382
|
+
SenderName: userName ?? '',
|
|
383
|
+
ChannelID: channelId,
|
|
384
|
+
ThreadID: threadRootTs ?? null, // Thread under the root message if we posted one
|
|
385
|
+
IsDirectMessage: false,
|
|
386
|
+
IsBotMention: true, // Treat slash commands like @mentions so shouldRespond passes
|
|
387
|
+
MentionedAgentNames: [agentName],
|
|
388
|
+
Timestamp: now,
|
|
389
|
+
RawEvent: { type: 'slash_command', command: agentName, text }
|
|
390
|
+
};
|
|
391
|
+
this.adapter?.HandleMessage(incomingMessage).catch(error => {
|
|
392
|
+
LogError(`Error handling slash command for agent '${agentName}':`, undefined, error);
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
// ─── Shared event processing ─────────────────────────────────────────
|
|
396
|
+
/**
|
|
397
|
+
* Process a Slack event from either HTTP webhook or Socket Mode.
|
|
398
|
+
*/
|
|
399
|
+
async processSlackEvent(event) {
|
|
400
|
+
if (!event) {
|
|
401
|
+
LogStatus('Slack webhook: no event in payload');
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const eventType = event.type;
|
|
405
|
+
LogStatus(`Slack event received: type=${eventType}, channel=${event.channel}, user=${event.user}`);
|
|
406
|
+
// Only handle message and app_mention events
|
|
407
|
+
if (eventType !== 'message' && eventType !== 'app_mention') {
|
|
408
|
+
LogStatus(`Slack: ignoring event type '${eventType}'`);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
// Skip bot messages (prevent loops) and message edits/deletes
|
|
412
|
+
if (event.bot_id || event.subtype) {
|
|
413
|
+
LogStatus(`Slack: skipping bot/subtype message (bot_id=${event.bot_id}, subtype=${event.subtype})`);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (!this.adapter) {
|
|
417
|
+
LogStatus('Slack: adapter not initialized, ignoring event');
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
try {
|
|
421
|
+
const incomingMessage = this.adapter.MapSlackEvent(event);
|
|
422
|
+
await this.adapter.HandleMessage(incomingMessage);
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
LogError('Error handling Slack event:', undefined, error);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
SlackMessagingExtension = __decorate([
|
|
430
|
+
RegisterClass(BaseServerExtension, 'SlackMessagingExtension')
|
|
431
|
+
], SlackMessagingExtension);
|
|
432
|
+
export { SlackMessagingExtension };
|
|
433
|
+
//# sourceMappingURL=SlackMessagingExtension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlackMessagingExtension.js","sourceRoot":"","sources":["../../src/slack/SlackMessagingExtension.ts"],"names":[],"mappings":"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"}
|