@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 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"}
@@ -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"}