@maroonedsoftware/slack 1.8.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/LICENSE +21 -0
- package/README.md +280 -0
- package/dist/client/slack.client.d.ts +61 -0
- package/dist/client/slack.client.d.ts.map +1 -0
- package/dist/client/slack.logger.adapter.d.ts +21 -0
- package/dist/client/slack.logger.adapter.d.ts.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +363 -0
- package/dist/index.js.map +1 -0
- package/dist/slack.command.handler.d.ts +50 -0
- package/dist/slack.command.handler.d.ts.map +1 -0
- package/dist/slack.config.d.ts +31 -0
- package/dist/slack.config.d.ts.map +1 -0
- package/dist/slack.dispatcher.d.ts +124 -0
- package/dist/slack.dispatcher.d.ts.map +1 -0
- package/dist/slack.error.d.ts +18 -0
- package/dist/slack.error.d.ts.map +1 -0
- package/dist/slack.event.handler.d.ts +51 -0
- package/dist/slack.event.handler.d.ts.map +1 -0
- package/dist/slack.interaction.handler.d.ts +68 -0
- package/dist/slack.interaction.handler.d.ts.map +1 -0
- package/dist/slack.signature.d.ts +65 -0
- package/dist/slack.signature.d.ts.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Marooned Software
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# @maroonedsoftware/slack
|
|
2
|
+
|
|
3
|
+
Transport-agnostic Slack integration for ServerKit. The package gives you:
|
|
4
|
+
|
|
5
|
+
- a DI-friendly wrapper around `@slack/web-api` for sending messages and posting to incoming-webhook URLs, and
|
|
6
|
+
- a single `SlackDispatcher` service that routes parsed Slack payloads (Events API, slash commands, interactive components) to typed handlers.
|
|
7
|
+
|
|
8
|
+
The package owns no HTTP routes or signature middleware — wire `SlackDispatcher` from your own Koa, Express, Fastify, or Lambda handler.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pnpm add @maroonedsoftware/slack
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Exports
|
|
17
|
+
|
|
18
|
+
| Symbol | Purpose |
|
|
19
|
+
|---------------------------------|---------------------------------------------------------------------------------------------------------------|
|
|
20
|
+
| `SlackConfig` | Abstract `@Injectable()` token; carries `botToken`, `signingSecret`, optional `incomingWebhookUrl`, optional `signatureMaxAgeSeconds`. Consumer registers a concrete value. |
|
|
21
|
+
| `SlackClient` | Wraps `@slack/web-api`'s `WebClient`; routes its diagnostics through ServerKit's `Logger`. Methods: `postMessage`, `updateMessage`, `deleteMessage`, `openView`, `postWebhook`. Underlying SDK reachable at `.web`. |
|
|
22
|
+
| `SlackDispatcher` | Three-method service: `dispatchEvent`, `dispatchCommand`, `dispatchInteraction`. |
|
|
23
|
+
| `SlackEventHandlerMap` | `Map<eventType, SlackEventHandler>` — register one handler per Slack event type (`app_mention`, `message`, …). |
|
|
24
|
+
| `SlackCommandHandlerMap` | `Map<commandKeyword, SlackCommandHandler>` — register one handler per slash command (`/deploy`, …). |
|
|
25
|
+
| `SlackInteractionHandlerMap` | `Map<routingKey, SlackInteractionHandler>` — keys are `${type}:${identifier}`; see [interaction routing](#interaction-routing). |
|
|
26
|
+
| `SlackError` | `ServerkitError` subclass for non-HTTP domain failures (signature mismatch, webhook POST failed, …). |
|
|
27
|
+
| `verifySlackSignature(input)` | Pure helper that validates Slack's v0 HMAC scheme + replay window. No request/context coupling. |
|
|
28
|
+
| `interactionRouteKey(payload)` | Helper that produces the `SlackInteractionHandlerMap` key for a given payload. |
|
|
29
|
+
|
|
30
|
+
## Configuration
|
|
31
|
+
|
|
32
|
+
The package does not read `AppConfig` itself — services take `SlackConfig` directly via DI. Resolve it at bootstrap and register it:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { AppConfigBuilder, AppConfigSourceJson } from '@maroonedsoftware/appconfig';
|
|
36
|
+
import { SlackConfig } from '@maroonedsoftware/slack';
|
|
37
|
+
|
|
38
|
+
const appConfig = await new AppConfigBuilder()
|
|
39
|
+
.addSource(new AppConfigSourceJson('./config.json'))
|
|
40
|
+
.build();
|
|
41
|
+
|
|
42
|
+
const slackConfig = appConfig.getAs<SlackConfig>('slack');
|
|
43
|
+
container.register(SlackConfig, { useValue: slackConfig });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```jsonc
|
|
47
|
+
// config.json
|
|
48
|
+
{
|
|
49
|
+
"slack": {
|
|
50
|
+
"botToken": "xoxb-...",
|
|
51
|
+
"signingSecret": "...",
|
|
52
|
+
"incomingWebhookUrl": "https://hooks.slack.com/services/...", // optional
|
|
53
|
+
"signatureMaxAgeSeconds": 300 // optional
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
| Field | Required | Used by |
|
|
59
|
+
|---------------------------|----------|-------------------------------------------------------------------------|
|
|
60
|
+
| `botToken` | yes | `SlackClient` constructor — passed to `WebClient`. |
|
|
61
|
+
| `signingSecret` | yes | Your signature verifier (Slack signs requests with this secret). |
|
|
62
|
+
| `incomingWebhookUrl` | no | `SlackClient.postWebhook` default URL when no per-call URL is supplied. |
|
|
63
|
+
| `signatureMaxAgeSeconds` | no | Replay-protection window for your signature verifier (default `300`). |
|
|
64
|
+
|
|
65
|
+
## Sending messages
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { SlackClient } from '@maroonedsoftware/slack';
|
|
69
|
+
|
|
70
|
+
const slack = container.get(SlackClient);
|
|
71
|
+
|
|
72
|
+
// Bot-token Web API call
|
|
73
|
+
await slack.postMessage({ channel: '#ops', text: 'deploy complete :ship:' });
|
|
74
|
+
|
|
75
|
+
// Incoming webhook URL or a per-payload response_url follow-up
|
|
76
|
+
await slack.postWebhook({ text: 'still working on it…' }, payload.response_url);
|
|
77
|
+
|
|
78
|
+
// Anything not exposed as a typed passthrough — reach for the underlying client
|
|
79
|
+
await slack.web.users.info({ user: 'U123' });
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`postWebhook` throws `SlackError` if neither `config.incomingWebhookUrl` nor an explicit URL is provided, or if the HTTP response is non-2xx.
|
|
83
|
+
|
|
84
|
+
## Receiving Slack requests
|
|
85
|
+
|
|
86
|
+
You own the route. The pattern is the same for all three Slack endpoint types:
|
|
87
|
+
|
|
88
|
+
1. Read the raw body (signature verification needs unparsed bytes).
|
|
89
|
+
2. Verify the Slack signature with `verifySlackSignature` (see [signature verification](#signature-verification)).
|
|
90
|
+
3. Parse the body for the endpoint type.
|
|
91
|
+
4. Call the matching `dispatcher.dispatch*` method.
|
|
92
|
+
5. If the dispatcher returns a value, send it as the response body; otherwise ack `200 ''`.
|
|
93
|
+
|
|
94
|
+
Examples below use Koa, but any HTTP framework works.
|
|
95
|
+
|
|
96
|
+
### Events API
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import {
|
|
100
|
+
SlackConfig,
|
|
101
|
+
SlackDispatcher,
|
|
102
|
+
SlackEventHandlerMap,
|
|
103
|
+
verifySlackSignature,
|
|
104
|
+
type SlackEventHandler,
|
|
105
|
+
} from '@maroonedsoftware/slack';
|
|
106
|
+
import rawBody from 'raw-body';
|
|
107
|
+
|
|
108
|
+
class AppMentionHandler implements SlackEventHandler {
|
|
109
|
+
async handle(event: { type: 'app_mention'; channel: string; text: string }) {
|
|
110
|
+
// Ack quickly — Slack retries any non-2xx within ~3s.
|
|
111
|
+
// Offload slow work via @maroonedsoftware/jobbroker.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Bootstrap
|
|
116
|
+
const events = new SlackEventHandlerMap();
|
|
117
|
+
events.set('app_mention', container.get(AppMentionHandler));
|
|
118
|
+
container.register(SlackEventHandlerMap, { useValue: events });
|
|
119
|
+
|
|
120
|
+
// Route
|
|
121
|
+
router.post('/slack/events', async (ctx) => {
|
|
122
|
+
const raw = await rawBody(ctx.req, { encoding: 'utf8' });
|
|
123
|
+
verifySlackSignature({
|
|
124
|
+
signingSecret: ctx.container.get(SlackConfig).signingSecret,
|
|
125
|
+
rawBody: raw,
|
|
126
|
+
timestamp: ctx.get('x-slack-request-timestamp'),
|
|
127
|
+
signature: ctx.get('x-slack-signature'),
|
|
128
|
+
});
|
|
129
|
+
const result = await ctx.container.get(SlackDispatcher).dispatchEvent(JSON.parse(raw));
|
|
130
|
+
if (result) ctx.body = result; // url_verification challenge
|
|
131
|
+
else { ctx.status = 200; ctx.body = ''; }
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`dispatchEvent` returns `{ challenge }` for the `url_verification` handshake and `undefined` for everything else (event handlers run for their side effects). Unregistered event types are logged at debug and acked — Slack retries any non-2xx, so dropping unknown events on the floor is intentional.
|
|
136
|
+
|
|
137
|
+
### Slash commands
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import {
|
|
141
|
+
SlackCommandHandlerMap,
|
|
142
|
+
SlackConfig,
|
|
143
|
+
SlackDispatcher,
|
|
144
|
+
verifySlackSignature,
|
|
145
|
+
type SlackCommandHandler,
|
|
146
|
+
type SlackCommandPayload,
|
|
147
|
+
} from '@maroonedsoftware/slack';
|
|
148
|
+
import rawBody from 'raw-body';
|
|
149
|
+
|
|
150
|
+
class DeployCommand implements SlackCommandHandler {
|
|
151
|
+
async handle(payload: SlackCommandPayload) {
|
|
152
|
+
return { response_type: 'in_channel' as const, text: `Deploying ${payload.text}…` };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const commands = new SlackCommandHandlerMap();
|
|
157
|
+
commands.set('/deploy', container.get(DeployCommand));
|
|
158
|
+
container.register(SlackCommandHandlerMap, { useValue: commands });
|
|
159
|
+
|
|
160
|
+
router.post('/slack/commands', async (ctx) => {
|
|
161
|
+
const raw = await rawBody(ctx.req, { encoding: 'utf8' });
|
|
162
|
+
verifySlackSignature({
|
|
163
|
+
signingSecret: ctx.container.get(SlackConfig).signingSecret,
|
|
164
|
+
rawBody: raw,
|
|
165
|
+
timestamp: ctx.get('x-slack-request-timestamp'),
|
|
166
|
+
signature: ctx.get('x-slack-signature'),
|
|
167
|
+
});
|
|
168
|
+
const form = new URLSearchParams(raw);
|
|
169
|
+
const payload = {
|
|
170
|
+
token: form.get('token') ?? '',
|
|
171
|
+
team_id: form.get('team_id') ?? '',
|
|
172
|
+
team_domain: form.get('team_domain') ?? '',
|
|
173
|
+
channel_id: form.get('channel_id') ?? '',
|
|
174
|
+
channel_name: form.get('channel_name') ?? '',
|
|
175
|
+
user_id: form.get('user_id') ?? '',
|
|
176
|
+
user_name: form.get('user_name') ?? '',
|
|
177
|
+
command: form.get('command') ?? '',
|
|
178
|
+
text: form.get('text') ?? '',
|
|
179
|
+
response_url: form.get('response_url') ?? '',
|
|
180
|
+
trigger_id: form.get('trigger_id') ?? '',
|
|
181
|
+
} satisfies SlackCommandPayload;
|
|
182
|
+
const result = await ctx.container.get(SlackDispatcher).dispatchCommand(payload);
|
|
183
|
+
if (result) ctx.body = result;
|
|
184
|
+
else { ctx.status = 200; ctx.body = ''; }
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
If your handler returns a `SlackCommandResponse`, Slack renders it inline. Return `void` to ack with an empty 200 and follow up later via `slackClient.postWebhook(payload, payload.response_url)` (Slack accepts up to 30 minutes / 5 follow-ups per command).
|
|
189
|
+
|
|
190
|
+
### Interactive components
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import {
|
|
194
|
+
SlackConfig,
|
|
195
|
+
SlackDispatcher,
|
|
196
|
+
SlackInteractionHandlerMap,
|
|
197
|
+
verifySlackSignature,
|
|
198
|
+
type SlackInteractionHandler,
|
|
199
|
+
} from '@maroonedsoftware/slack';
|
|
200
|
+
import rawBody from 'raw-body';
|
|
201
|
+
|
|
202
|
+
const interactions = new SlackInteractionHandlerMap();
|
|
203
|
+
interactions.set('block_actions:approve', container.get(ApproveButton));
|
|
204
|
+
interactions.set('view_submission:create_ticket_modal', container.get(CreateTicketModal));
|
|
205
|
+
container.register(SlackInteractionHandlerMap, { useValue: interactions });
|
|
206
|
+
|
|
207
|
+
router.post('/slack/interactions', async (ctx) => {
|
|
208
|
+
const raw = await rawBody(ctx.req, { encoding: 'utf8' });
|
|
209
|
+
verifySlackSignature({
|
|
210
|
+
signingSecret: ctx.container.get(SlackConfig).signingSecret,
|
|
211
|
+
rawBody: raw,
|
|
212
|
+
timestamp: ctx.get('x-slack-request-timestamp'),
|
|
213
|
+
signature: ctx.get('x-slack-signature'),
|
|
214
|
+
});
|
|
215
|
+
const payload = JSON.parse(new URLSearchParams(raw).get('payload') ?? '{}');
|
|
216
|
+
const result = await ctx.container.get(SlackDispatcher).dispatchInteraction(payload);
|
|
217
|
+
if (result) ctx.body = result;
|
|
218
|
+
else { ctx.status = 200; ctx.body = ''; }
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Slack POSTs interactive payloads as `application/x-www-form-urlencoded` with a single `payload` field whose value is JSON — that's why the snippet above unwraps `payload` after URL-decoding the form.
|
|
223
|
+
|
|
224
|
+
#### Interaction routing
|
|
225
|
+
|
|
226
|
+
`SlackInteractionHandlerMap` is keyed by `${type}:${identifier}`:
|
|
227
|
+
|
|
228
|
+
| Payload type | Key |
|
|
229
|
+
|-------------------|----------------------------------------|
|
|
230
|
+
| `block_actions` | `block_actions:<actions[0].action_id>` |
|
|
231
|
+
| `view_submission` | `view_submission:<view.callback_id>` |
|
|
232
|
+
| `view_closed` | `view_closed:<view.callback_id>` |
|
|
233
|
+
| `shortcut` | `shortcut:<callback_id>` |
|
|
234
|
+
| `message_action` | `message_action:<callback_id>` |
|
|
235
|
+
|
|
236
|
+
`interactionRouteKey(payload)` is exported in case you want to compute the key yourself (e.g. to register handlers dynamically). View-submission handlers may return a `SlackInteractionResponse` with `response_action: 'errors' | 'update' | 'push' | 'clear'` to drive Slack's modal flow.
|
|
237
|
+
|
|
238
|
+
## Signature verification
|
|
239
|
+
|
|
240
|
+
`verifySlackSignature` is a pure function — no request, context, or framework awareness. The caller pulls headers and the raw body from whatever transport it's using and passes them in:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { verifySlackSignature, SlackError } from '@maroonedsoftware/slack';
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
verifySlackSignature({
|
|
247
|
+
signingSecret: slackConfig.signingSecret,
|
|
248
|
+
rawBody, // exactly what Slack sent
|
|
249
|
+
timestamp: req.headers['x-slack-request-timestamp'] as string,
|
|
250
|
+
signature: req.headers['x-slack-signature'] as string,
|
|
251
|
+
maxAgeSeconds: slackConfig.signatureMaxAgeSeconds, // optional, default 300
|
|
252
|
+
});
|
|
253
|
+
} catch (err) {
|
|
254
|
+
if (err instanceof SlackError) {
|
|
255
|
+
// err.internalDetails.reason is one of:
|
|
256
|
+
// 'missing_timestamp' | 'invalid_timestamp' | 'stale_timestamp'
|
|
257
|
+
// 'missing_signature' | 'invalid_signature'
|
|
258
|
+
throw httpError(401).withCause(err);
|
|
259
|
+
}
|
|
260
|
+
throw err;
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
What the helper enforces:
|
|
265
|
+
|
|
266
|
+
1. `X-Slack-Request-Timestamp` is present and an integer.
|
|
267
|
+
2. `|now - timestamp| <= maxAgeSeconds` (default 300) — replay protection.
|
|
268
|
+
3. `X-Slack-Signature` matches `v0=` + `HMAC-SHA256(signingSecret, "v0:{timestamp}:{rawBody}")` as hex, compared with `crypto.timingSafeEqual`.
|
|
269
|
+
|
|
270
|
+
On any failure the helper throws `SlackError` with `internalDetails.reason` set to a `SlackSignatureFailureReason` code. Map to HTTP 401 at the route boundary.
|
|
271
|
+
|
|
272
|
+
For deterministic tests, pass `now` (Unix seconds) to override the clock.
|
|
273
|
+
|
|
274
|
+
## Limitations
|
|
275
|
+
|
|
276
|
+
- v1 supports a single workspace via the bot token in `SlackConfig`. Multi-workspace OAuth install is out of scope.
|
|
277
|
+
|
|
278
|
+
## License
|
|
279
|
+
|
|
280
|
+
MIT
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { WebClient } from '@slack/web-api';
|
|
2
|
+
import type { ChatPostMessageArguments, ChatPostMessageResponse, ChatUpdateArguments, ChatUpdateResponse, ChatDeleteArguments, ChatDeleteResponse, ViewsOpenArguments, ViewsOpenResponse } from '@slack/web-api';
|
|
3
|
+
import { Logger } from '@maroonedsoftware/logger';
|
|
4
|
+
import { SlackConfig } from '../slack.config.js';
|
|
5
|
+
/**
|
|
6
|
+
* Payload for an incoming-webhook POST. Mirrors the subset of fields Slack's
|
|
7
|
+
* incoming webhooks accept (text, blocks, attachments, response shaping).
|
|
8
|
+
* The body is JSON-stringified verbatim, so any extra fields are preserved.
|
|
9
|
+
*/
|
|
10
|
+
export type IncomingWebhookPayload = {
|
|
11
|
+
text?: string;
|
|
12
|
+
blocks?: unknown[];
|
|
13
|
+
attachments?: unknown[];
|
|
14
|
+
thread_ts?: string;
|
|
15
|
+
response_type?: 'in_channel' | 'ephemeral';
|
|
16
|
+
replace_original?: boolean;
|
|
17
|
+
delete_original?: boolean;
|
|
18
|
+
unfurl_links?: boolean;
|
|
19
|
+
unfurl_media?: boolean;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Thin DI-friendly wrapper around `@slack/web-api`'s `WebClient`. Constructed
|
|
24
|
+
* once per request scope (or as a singleton, depending on how the consumer
|
|
25
|
+
* registers it) and exposes typed passthroughs for the most common Web API
|
|
26
|
+
* methods plus a `postWebhook` helper for incoming-webhook URLs and the
|
|
27
|
+
* `response_url` returned by slash commands and interactive payloads.
|
|
28
|
+
*
|
|
29
|
+
* Reach for {@link SlackClient.web} directly for anything else the underlying
|
|
30
|
+
* client supports.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* await container.get(SlackClient).postMessage({ channel: '#ops', text: 'hello' });
|
|
35
|
+
* await container.get(SlackClient).postWebhook({ text: 'follow-up' }, payload.response_url);
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare class SlackClient {
|
|
39
|
+
private readonly config;
|
|
40
|
+
private readonly logger;
|
|
41
|
+
/** Underlying `@slack/web-api` client. */
|
|
42
|
+
readonly web: WebClient;
|
|
43
|
+
constructor(config: SlackConfig, logger: Logger);
|
|
44
|
+
/** Posts a message via `chat.postMessage`. */
|
|
45
|
+
postMessage(args: ChatPostMessageArguments): Promise<ChatPostMessageResponse>;
|
|
46
|
+
/** Updates a message via `chat.update`. */
|
|
47
|
+
updateMessage(args: ChatUpdateArguments): Promise<ChatUpdateResponse>;
|
|
48
|
+
/** Deletes a message via `chat.delete`. */
|
|
49
|
+
deleteMessage(args: ChatDeleteArguments): Promise<ChatDeleteResponse>;
|
|
50
|
+
/** Opens a modal view via `views.open`. */
|
|
51
|
+
openView(args: ViewsOpenArguments): Promise<ViewsOpenResponse>;
|
|
52
|
+
/**
|
|
53
|
+
* POSTs a payload to a Slack incoming-webhook-style URL — either the
|
|
54
|
+
* configured `incomingWebhookUrl` or an explicit URL (e.g. the
|
|
55
|
+
* `response_url` from a slash command or interactive payload).
|
|
56
|
+
*
|
|
57
|
+
* @throws {@link SlackError} if no URL is available or the response is non-2xx.
|
|
58
|
+
*/
|
|
59
|
+
postWebhook(payload: IncomingWebhookPayload, url?: string): Promise<void>;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=slack.client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.client.d.ts","sourceRoot":"","sources":["../../src/client/slack.client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjN,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIjD;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;IAC3C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,qBACa,WAAW;IAKpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,0CAA0C;IAC1C,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;gBAGL,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,MAAM;IAKjC,8CAA8C;IAC9C,WAAW,CAAC,IAAI,EAAE,wBAAwB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAI7E,2CAA2C;IAC3C,aAAa,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIrE,2CAA2C;IAC3C,aAAa,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIrE,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI9D;;;;;;OAMG;IACG,WAAW,CAAC,OAAO,EAAE,sBAAsB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAgBhF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Logger as SlackLogger } from '@slack/web-api';
|
|
2
|
+
import { Logger } from '@maroonedsoftware/logger';
|
|
3
|
+
/**
|
|
4
|
+
* Adapts a ServerKit {@link Logger} to the `@slack/web-api` {@link SlackLogger}
|
|
5
|
+
* interface so the WebClient can route its diagnostics through the host
|
|
6
|
+
* application's logger.
|
|
7
|
+
*
|
|
8
|
+
* The Slack SDK's logger calls `logger.info(...args)` with a variable number
|
|
9
|
+
* of arguments and no separate "primary message"; the adapter forwards them
|
|
10
|
+
* to ServerKit's `(message, ...optionalParams)` shape, with an empty-string
|
|
11
|
+
* primary when no args are passed.
|
|
12
|
+
*
|
|
13
|
+
* `setLevel`, `setName`, and `getLevel` are stored locally — ServerKit
|
|
14
|
+
* loggers do not expose these knobs but the SDK expects them on its logger.
|
|
15
|
+
*
|
|
16
|
+
* @param logger - The ServerKit logger to forward calls to.
|
|
17
|
+
* @param name - Initial value for the SDK logger's name. Defaults to `'slack-web-api'`.
|
|
18
|
+
* @returns A `@slack/web-api`-compatible logger object.
|
|
19
|
+
*/
|
|
20
|
+
export declare const adaptLogger: (logger: Logger, name?: string) => SlackLogger;
|
|
21
|
+
//# sourceMappingURL=slack.logger.adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.logger.adapter.d.ts","sourceRoot":"","sources":["../../src/client/slack.logger.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAY,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAElD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,aAAsB,KAAG,WAmBpE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './slack.config.js';
|
|
2
|
+
export * from './slack.error.js';
|
|
3
|
+
export * from './slack.signature.js';
|
|
4
|
+
export * from './slack.event.handler.js';
|
|
5
|
+
export * from './slack.command.handler.js';
|
|
6
|
+
export * from './slack.interaction.handler.js';
|
|
7
|
+
export * from './slack.dispatcher.js';
|
|
8
|
+
export * from './client/slack.client.js';
|
|
9
|
+
export * from './client/slack.logger.adapter.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC"}
|