@fluojs/slack 1.1.3 → 2.0.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.ko.md +134 -8
- package/README.md +134 -8
- package/dist/errors.d.ts +13 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +13 -2
- package/dist/module.d.ts +5 -5
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +7 -14
- package/dist/service.d.ts +16 -2
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +108 -21
- package/dist/types.d.ts +22 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/webhook.d.ts.map +1 -1
- package/dist/webhook.js +1 -2
- package/package.json +7 -7
package/README.ko.md
CHANGED
|
@@ -10,9 +10,12 @@ fluo를 위한 webhook-first, transport-agnostic Slack 전달 코어 패키지
|
|
|
10
10
|
- [사용 시점](#사용-시점)
|
|
11
11
|
- [빠른 시작](#빠른-시작)
|
|
12
12
|
- [일반적인 패턴](#일반적인-패턴)
|
|
13
|
+
- [모듈 visibility와 migration boundary](#모듈-visibility와-migration-boundary)
|
|
13
14
|
- [`createSlackProviders`를 이용한 수동 provider 조합](#createslackproviders를-이용한-수동-provider-조합)
|
|
14
15
|
- [`SlackService`를 이용한 standalone 전달](#slackservice를-이용한-standalone-전달)
|
|
16
|
+
- [`verifyOnModuleInit`을 이용한 bootstrap 검증](#verifyonmoduleinit을-이용한-bootstrap-검증)
|
|
15
17
|
- [`@fluojs/notifications`와의 통합](#fluojs-notifications와의-통합)
|
|
18
|
+
- [Template rendering과 merge precedence](#template-rendering과-merge-precedence)
|
|
16
19
|
- [명시적 fetch 주입을 사용하는 webhook-first 전달](#명시적-fetch-주입을-사용하는-webhook-first-전달)
|
|
17
20
|
- [의도적인 제한 사항](#의도적인-제한-사항)
|
|
18
21
|
- [공개 API 개요](#공개-api-개요)
|
|
@@ -25,7 +28,7 @@ fluo를 위한 webhook-first, transport-agnostic Slack 전달 코어 패키지
|
|
|
25
28
|
npm install @fluojs/slack @fluojs/notifications
|
|
26
29
|
```
|
|
27
30
|
|
|
28
|
-
이 패키지는
|
|
31
|
+
이 패키지는 패키지 자체의 지원 계약에 따라 Node.js `>=24.0.0 <27`을 요구합니다. Node 20 및 Node 22 host를 Node.js `>=24.0.0 <27`로 올리세요. Node 24 미만과 Node 27 이상은 지원하지 않으므로 process를 지원되는 line으로 옮겨야 합니다. 런타임 전달 계약 자체는 명시적인 fetch-compatible 경계를 통해 계속 transport-agnostic하게 유지됩니다.
|
|
29
32
|
|
|
30
33
|
## 사용 시점
|
|
31
34
|
|
|
@@ -76,9 +79,17 @@ export class DeployNotifier {
|
|
|
76
79
|
|
|
77
80
|
## 일반적인 패턴
|
|
78
81
|
|
|
82
|
+
### 모듈 visibility와 migration boundary
|
|
83
|
+
|
|
84
|
+
`SlackModule.forRoot(...)`와 `SlackModule.forRootAsync(...)`는 기본적으로 global module을 반환합니다. 이 module은 `SlackService`, `SlackChannel`, `SLACK`, `SLACK_CHANNEL`을 export하며, migrated code에서 해당 provider를 반환된 module을 명시적으로 import한 module에만 보이게 해야 할 때만 `global: false`를 전달합니다. 옵션 이름은 NestJS `isGlobal`이 아니라 `global?: boolean`입니다.
|
|
85
|
+
|
|
86
|
+
Async registration은 injected factory 형태인 `SlackModule.forRootAsync({ inject, useFactory, global? })`만 지원합니다. `inject`와 `useFactory`만 소비하며 NestJS `imports`, `useClass`, `useExisting`은 소비하지 않습니다. 필요한 의존성은 application module graph에 먼저 등록하고 token을 `inject`에 나열한 뒤, `useFactory`에서 최종 Slack option을 반환하세요.
|
|
87
|
+
|
|
88
|
+
패키지 수준 registration surface는 의도적으로 singleton 중심입니다. `SLACK`과 `SLACK_CHANNEL`은 하나의 설정된 Slack service와 notifications channel을 위한 compatibility token이며, `createSlackProviders(...)`는 수동 module composition에서도 같은 singleton wiring을 재사용합니다. 여러 Slack client가 필요한 애플리케이션은 package-level multi-client registry를 기대하지 말고, 서로 다른 `SlackTransport` 인스턴스를 감싸는 자체 module/provider를 조합하거나 app-owned facade를 노출해야 합니다.
|
|
89
|
+
|
|
79
90
|
### `createSlackProviders`를 이용한 수동 provider 조합
|
|
80
91
|
|
|
81
|
-
`createSlackProviders(...)`는 애플리케이션이 `SlackModule.forRoot(...)` 밖에서 동일한 provider 정규화 구성을 재사용해야 할 때 지원되는 manual-composition helper입니다.
|
|
92
|
+
`createSlackProviders(...)`는 애플리케이션이 `SlackModule.forRoot(...)` 밖에서 동일한 singleton provider 정규화 구성을 재사용해야 할 때 지원되는 manual-composition helper입니다.
|
|
82
93
|
|
|
83
94
|
```typescript
|
|
84
95
|
import { Module } from '@fluojs/core';
|
|
@@ -126,13 +137,81 @@ SlackModule.forRootAsync({
|
|
|
126
137
|
Behavioral contract 메모:
|
|
127
138
|
|
|
128
139
|
- `SlackService.send(...)`는 전달 전에 `defaultChannel`을 해석합니다.
|
|
129
|
-
- `SlackService.sendMany(...)`는 메시지를 순차적으로 보내며, fail-fast 대신 batch result가 필요한 호출자를 위해 `continueOnError`를 지원합니다.
|
|
130
|
-
- `SlackService.send(...)`, `SlackService.sendMany(...)`, `SlackService.sendNotification(...)`은 provider handoff 전에 이미 abort된 signal을
|
|
140
|
+
- `SlackService.sendMany(...)`는 메시지를 순차적으로 보내며, fail-fast 대신 batch result가 필요한 호출자를 위해 `continueOnError`를 지원합니다. 다만 일반 provider 실패만 수집하며 caller 취소는 항상 batch를 reject합니다.
|
|
141
|
+
- `SlackService.send(...)`, `SlackService.sendMany(...)`, `SlackService.sendNotification(...)`은 provider handoff 전에 이미 abort된 signal을 존중합니다. Abort된 signal 또는 transport의 `AbortError`는 `continueOnError`보다 우선하며, 같은 signal은 notification channel을 거쳐 transport 호출까지 전달됩니다.
|
|
131
142
|
- 서비스는 모듈 bootstrap 시 transport를 초기화하고, factory가 소유한 리소스만 애플리케이션 shutdown 시 닫습니다.
|
|
132
|
-
-
|
|
143
|
+
- 직접 전달과 notifications 기반 전달은 lifecycle이 `ready`일 때만 허용됩니다. `onModuleInit()`이 끝나기 전, 초기화 실패 뒤, 또는 shutdown 중 호출하면 transport를 lazy 생성하거나 재사용하지 않고 `SlackLifecycleError`로 실패합니다.
|
|
144
|
+
- shutdown은 새 전달을 거부하고, 진행 중인 factory 소유 transport 생성과 `verify()` 호출을 포함하는 공유 bootstrap initialization promise가 settle되기를 기다린 뒤 활성 전달을 drain하고, 소유한 transport를 닫고 완료됩니다.
|
|
145
|
+
- factory 소유 transport cleanup은 bootstrap 실패 cleanup과 application shutdown 사이에서 직렬화되므로, 두 경로가 경합해도 같은 owned transport는 최대 한 번만 닫힙니다.
|
|
133
146
|
- `SlackService.createPlatformStatusSnapshot()`은 호출자가 내부 옵션에 접근하지 않아도 lifecycle, readiness, transport 소유권을 보고합니다.
|
|
134
147
|
- 이 패키지는 절대로 `process.env`를 직접 읽지 않습니다. 모든 설정은 명시적인 옵션 또는 DI를 통해 들어와야 합니다.
|
|
135
148
|
|
|
149
|
+
### `verifyOnModuleInit`을 이용한 bootstrap 검증
|
|
150
|
+
|
|
151
|
+
선택한 transport가 bootstrap 중 자신의 readiness를 검증할 수 있다면 `SlackModuleOptions.verifyOnModuleInit?: boolean`을 `true`로 설정합니다. `SlackService.onModuleInit()`은 항상 설정된 transport를 먼저 해석하며, `verifyOnModuleInit`이 켜져 있고 해석된 transport가 optional `verify()` 메서드를 노출할 때에만 `transport.verify()`를 기다린 뒤 Slack provider를 ready로 표시합니다. `verify`를 구현하지 않는 transport도 유효하며, 이 경우 검증 단계만 건너뜁니다.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { Module } from '@fluojs/core';
|
|
155
|
+
import {
|
|
156
|
+
SlackModule,
|
|
157
|
+
type SlackTemplateRenderer,
|
|
158
|
+
type SlackTransport,
|
|
159
|
+
} from '@fluojs/slack';
|
|
160
|
+
|
|
161
|
+
const renderer: SlackTemplateRenderer = {
|
|
162
|
+
render({ template, payload, subject }) {
|
|
163
|
+
if (template === 'deploy.finished') {
|
|
164
|
+
return {
|
|
165
|
+
blocks: [
|
|
166
|
+
{
|
|
167
|
+
text: { text: `*${String(payload.version)}* is live`, type: 'mrkdwn' },
|
|
168
|
+
type: 'section',
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
text: subject,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return { text: subject };
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const slackApiTransport: SlackTransport = {
|
|
180
|
+
async verify() {
|
|
181
|
+
await slackApi.authTest();
|
|
182
|
+
},
|
|
183
|
+
async send(message, { signal }) {
|
|
184
|
+
const receipt = await slackApi.postMessage(message, { signal });
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
channel: receipt.channel,
|
|
188
|
+
messageTs: receipt.ts,
|
|
189
|
+
ok: receipt.ok,
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
@Module({
|
|
195
|
+
imports: [
|
|
196
|
+
SlackModule.forRoot({
|
|
197
|
+
defaultChannel: '#ops',
|
|
198
|
+
renderer,
|
|
199
|
+
transport: slackApiTransport,
|
|
200
|
+
verifyOnModuleInit: true,
|
|
201
|
+
}),
|
|
202
|
+
],
|
|
203
|
+
})
|
|
204
|
+
export class AppModule {}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Behavioral contract 메모:
|
|
208
|
+
|
|
209
|
+
- `verifyOnModuleInit`은 선택 사항이며 기본값은 `false`입니다.
|
|
210
|
+
- 검증은 capability 기반입니다. `verify()`를 노출하는 transport만 호출하므로 webhook-only 또는 애플리케이션이 소유한 transport가 no-op verifier를 추가할 필요는 없습니다.
|
|
211
|
+
- Bootstrap initialization과 verification은 shutdown과 하나의 promise를 공유하므로, factory 소유 transport는 진행 중인 `verify()`가 settle될 때까지 열린 상태를 유지하고 이후 최대 한 번만 닫힙니다.
|
|
212
|
+
- `transport.verify()`가 reject되면 bootstrap은 초기화 실패를 감싼 `SlackLifecycleError`로 실패하고, service lifecycle은 `failed`로 이동하며, readiness/status snapshot은 provider를 not ready로 보고하고, 이미 해석된 factory 소유 transport는 오류를 다시 던지기 전에 닫습니다. 그 cleanup이 진행 중일 때 shutdown이 시작되면 두 호출자는 같은 close 작업을 기다립니다.
|
|
213
|
+
- `SlackService.createPlatformStatusSnapshot()`은 bootstrap 검증 요청 여부를 health/readiness tooling이 확인할 수 있도록 `verifiedOnModuleInit`을 포함합니다.
|
|
214
|
+
|
|
136
215
|
### `@fluojs/notifications`와의 통합
|
|
137
216
|
|
|
138
217
|
`SLACK_CHANNEL`을 `NotificationsModule.forRootAsync(...)`에 주입하여, Slack 전용 payload 필드와 recipient-to-channel 해석 규칙이 모두 `@fluojs/slack` 안에만 남도록 구성합니다.
|
|
@@ -179,6 +258,51 @@ Behavioral contract 메모:
|
|
|
179
258
|
- notification metadata는 전달 전에 payload metadata, dispatch metadata, subject/template marker를 합쳐 구성됩니다.
|
|
180
259
|
- 여러 Slack 대상지로 fan-out이 필요하다면 하나의 multi-recipient dispatch 대신 `sendMany(...)`를 사용해야 합니다.
|
|
181
260
|
|
|
261
|
+
### Template rendering과 merge precedence
|
|
262
|
+
|
|
263
|
+
Notification template을 공유 `@fluojs/notifications` envelope에서 Slack 전용 text, blocks, attachments로 변환해야 한다면 `SlackTemplateRenderer`를 제공합니다. `SlackService.sendNotification(...)`은 `notification.template`과 `SlackModuleOptions.renderer`가 모두 있을 때에만 `renderer.render(input)`을 호출합니다. Render input에는 `template`, `payload`, optional `subject`, optional `locale`, optional dispatch `metadata`가 들어갑니다.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import type { SlackTemplateRenderer } from '@fluojs/slack';
|
|
267
|
+
|
|
268
|
+
const renderer: SlackTemplateRenderer = {
|
|
269
|
+
async render(input) {
|
|
270
|
+
return {
|
|
271
|
+
blocks: [
|
|
272
|
+
{
|
|
273
|
+
text: {
|
|
274
|
+
text: `*${String(input.payload.releaseId)}* deployed for ${input.locale ?? 'default'}`,
|
|
275
|
+
type: 'mrkdwn',
|
|
276
|
+
},
|
|
277
|
+
type: 'section',
|
|
278
|
+
},
|
|
279
|
+
],
|
|
280
|
+
text: input.subject,
|
|
281
|
+
};
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
await notifications.dispatch({
|
|
286
|
+
channel: 'slack',
|
|
287
|
+
locale: 'en',
|
|
288
|
+
metadata: { source: 'ci' },
|
|
289
|
+
payload: {
|
|
290
|
+
metadata: { releaseId: 'rel-42' },
|
|
291
|
+
text: 'Deploy rel-42 finished.',
|
|
292
|
+
},
|
|
293
|
+
recipients: ['#ops'],
|
|
294
|
+
subject: 'Deploy finished',
|
|
295
|
+
template: 'deploy.finished',
|
|
296
|
+
});
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Merge precedence는 결정적입니다.
|
|
300
|
+
|
|
301
|
+
- `payload.attachments`, `payload.blocks`가 정의되어 있으면 rendered `attachments`, `blocks`보다 우선합니다. 비공백 `payload.text`는 rendered `text`보다 우선합니다.
|
|
302
|
+
- Text는 비공백 `payload.text`에서 비공백 rendered `text`, 그리고 비공백 `notification.subject` 순서로 fallback합니다. 빈 문자열 또는 공백 전용 text 값은 미지정으로 취급합니다.
|
|
303
|
+
- Metadata는 payload metadata, dispatch metadata, subject marker, template marker 순서로 merge됩니다. 중복 키는 뒤쪽 값이 이기므로, 최종 메시지는 존재하는 dispatch `subject`와 `template` marker를 기록합니다.
|
|
304
|
+
- `template`이 없거나 renderer가 등록되지 않았다면 template rendering은 실행되지 않습니다. 이 경우 notification은 payload와 subject만으로 Slack 메시지로 변환됩니다.
|
|
305
|
+
|
|
182
306
|
### 명시적 fetch 주입을 사용하는 webhook-first 전달
|
|
183
307
|
|
|
184
308
|
런타임에 독립적인 1st-party transport가 필요하다면 fetch-compatible HTTP 경계만 의존하는 `createSlackWebhookTransport(...)`를 사용합니다.
|
|
@@ -200,7 +324,7 @@ await slack.send({
|
|
|
200
324
|
Behavioral contract 메모:
|
|
201
325
|
|
|
202
326
|
- `fetch`를 명시적으로 전달하는 방식이 portable path이며 모든 지원 런타임에서 권장됩니다. 하위 호환성을 위해 `fetch`를 생략하면 ambient runtime API인 `globalThis.fetch`가 있을 때 이를 폴백으로 사용합니다. `globalThis.fetch`가 없는 런타임에서는 `SlackConfigurationError`로 빠르게 실패합니다.
|
|
203
|
-
- 내장 webhook transport는 `408`, `429`, `5xx` 같은 일시적
|
|
327
|
+
- 내장 webhook transport는 `408`, `429`, `5xx` 같은 일시적 실패 응답의 본문을 소비한 뒤 bounded exponential backoff로 재시도하고, 재시도가 모두 소진된 뒤에만 호출자에게 에러를 노출합니다.
|
|
204
328
|
- Abort signal은 주입된 `fetch` 경계로 전달되며, retry backoff를 취소할 때 `AbortError`를 `SlackTransportError`로 감싸지 않습니다.
|
|
205
329
|
- 호출자에게 보이는 `SlackTransportError` 메시지는 기본적으로 raw upstream response body를 포함하지 않습니다.
|
|
206
330
|
|
|
@@ -211,6 +335,7 @@ Slack 패키지는 의도적으로 다음을 **포함하지 않습니다**:
|
|
|
211
335
|
- 자격 증명이나 webhook URL을 `process.env`에서 직접 읽는 동작
|
|
212
336
|
- 공유 루트 패키지 경계에 Node 전용 Slack SDK를 내장하는 것
|
|
213
337
|
- webhook helper와 export된 transport 계약 이상으로 하나의 provider 전략을 강제하는 것
|
|
338
|
+
- singleton module/helper surface를 넘어서는 package-level multi-client registry를 제공하는 것
|
|
214
339
|
- 하나의 dispatch 호출 안에서 multi-channel fan-out을 자동 변환하는 것
|
|
215
340
|
|
|
216
341
|
이 제한 사항은 런타임 선택, provider capability, rollout 전략이 애플리케이션 경계에서 명시적으로 결정되도록 하기 위한 package contract의 일부입니다.
|
|
@@ -268,8 +393,8 @@ Slack 패키지는 의도적으로 다음을 **포함하지 않습니다**:
|
|
|
268
393
|
- `SlackLifecycleState`
|
|
269
394
|
- `SlackStatusAdapterInput`
|
|
270
395
|
- `SlackConfigurationError`
|
|
271
|
-
- `SlackLifecycleError`: lifecycle로 차단된
|
|
272
|
-
- `SlackMessageValidationError`
|
|
396
|
+
- `SlackLifecycleError`: readiness 전, 초기화 실패 뒤, 또는 shutdown 중 lifecycle로 차단된 전달과 transport factory, verification, 소유 리소스 cleanup 실패에서 발생합니다. bootstrap 또는 애플리케이션 teardown과 전송이 경합할 수 있다면 이 에러를 catch하세요.
|
|
397
|
+
- `SlackMessageValidationError`: 직접 메시지에 Slack에서 보이는 `text`, `blocks`, `attachments`가 없거나, 하나의 notification dispatch가 여러 Slack recipient로 해석되어 `sendMany(...)`로 분리해야 할 때 발생합니다.
|
|
273
398
|
- `SlackTransportError`
|
|
274
399
|
|
|
275
400
|
## 관련 패키지
|
|
@@ -281,5 +406,6 @@ Slack 패키지는 의도적으로 다음을 **포함하지 않습니다**:
|
|
|
281
406
|
## 예제 소스
|
|
282
407
|
|
|
283
408
|
- `packages/slack/src/module.test.ts`: 모듈 등록, `createSlackProviders(...)` helper coverage, async wiring, webhook transport, notifications integration 예제.
|
|
409
|
+
- `packages/slack/src/lifecycle-regression.test.ts`: Bootstrap verification과 shutdown 순서의 regression coverage.
|
|
284
410
|
- `packages/slack/src/public-surface.test.ts`: 공개 export와 TypeScript 계약 검증 예제.
|
|
285
411
|
- `packages/slack/src/status.test.ts`: health/readiness 계약 예제.
|
package/README.md
CHANGED
|
@@ -10,9 +10,12 @@ Webhook-first, transport-agnostic Slack delivery core for fluo. It provides a Ne
|
|
|
10
10
|
- [When to Use](#when-to-use)
|
|
11
11
|
- [Quick Start](#quick-start)
|
|
12
12
|
- [Common Patterns](#common-patterns)
|
|
13
|
+
- [Module visibility and migration boundaries](#module-visibility-and-migration-boundaries)
|
|
13
14
|
- [Manual provider composition with `createSlackProviders`](#manual-provider-composition-with-createslackproviders)
|
|
14
15
|
- [Standalone delivery with `SlackService`](#standalone-delivery-with-slackservice)
|
|
16
|
+
- [Bootstrap verification with `verifyOnModuleInit`](#bootstrap-verification-with-verifyonmoduleinit)
|
|
15
17
|
- [Integration with `@fluojs/notifications`](#integration-with-fluojs-notifications)
|
|
18
|
+
- [Template rendering and merge precedence](#template-rendering-and-merge-precedence)
|
|
16
19
|
- [Webhook-first delivery with explicit fetch injection](#webhook-first-delivery-with-explicit-fetch-injection)
|
|
17
20
|
- [Intentional limitations](#intentional-limitations)
|
|
18
21
|
- [Public API Overview](#public-api-overview)
|
|
@@ -25,7 +28,7 @@ Webhook-first, transport-agnostic Slack delivery core for fluo. It provides a Ne
|
|
|
25
28
|
npm install @fluojs/slack @fluojs/notifications
|
|
26
29
|
```
|
|
27
30
|
|
|
28
|
-
This package
|
|
31
|
+
This package requires Node.js `>=24.0.0 <27` as its package-owned support contract. Upgrade Node 20 and Node 22 hosts to Node.js `>=24.0.0 <27`; Node versions below 24 and Node 27+ are unsupported, so move the process to a supported line. Its delivery contract remains transport-agnostic at runtime through explicit fetch-compatible boundaries.
|
|
29
32
|
|
|
30
33
|
## When to Use
|
|
31
34
|
|
|
@@ -76,9 +79,17 @@ export class DeployNotifier {
|
|
|
76
79
|
|
|
77
80
|
## Common Patterns
|
|
78
81
|
|
|
82
|
+
### Module visibility and migration boundaries
|
|
83
|
+
|
|
84
|
+
`SlackModule.forRoot(...)` and `SlackModule.forRootAsync(...)` return a global module by default. The module exports `SlackService`, `SlackChannel`, `SLACK`, and `SLACK_CHANNEL`; pass `global: false` only when migrated code needs those providers to remain visible only to modules that explicitly import the returned module. The option is `global?: boolean`, not NestJS `isGlobal`.
|
|
85
|
+
|
|
86
|
+
Async registration supports the injected factory shape only: `SlackModule.forRootAsync({ inject, useFactory, global? })`. It consumes `inject` and `useFactory`, not NestJS `imports`, `useClass`, or `useExisting`. Register dependencies in the application module graph first, list their tokens in `inject`, then return the final Slack options from `useFactory`.
|
|
87
|
+
|
|
88
|
+
The package-level registration surface is intentionally singleton-oriented. `SLACK` and `SLACK_CHANNEL` are compatibility tokens for the one configured Slack service and notifications channel, and `createSlackProviders(...)` mirrors that same singleton wiring for manual module composition. Applications that need multiple Slack clients should compose their own modules/providers around distinct `SlackTransport` instances or expose app-owned facades instead of expecting a package-level multi-client registry.
|
|
89
|
+
|
|
79
90
|
### Manual provider composition with `createSlackProviders`
|
|
80
91
|
|
|
81
|
-
`createSlackProviders(...)` is the supported manual-composition helper when applications need the same provider normalization outside `SlackModule.forRoot(...)`.
|
|
92
|
+
`createSlackProviders(...)` is the supported manual-composition helper when applications need the same singleton provider normalization outside `SlackModule.forRoot(...)`.
|
|
82
93
|
|
|
83
94
|
```typescript
|
|
84
95
|
import { Module } from '@fluojs/core';
|
|
@@ -126,13 +137,81 @@ SlackModule.forRootAsync({
|
|
|
126
137
|
Behavioral contract notes:
|
|
127
138
|
|
|
128
139
|
- `SlackService.send(...)` resolves `defaultChannel` before delivery.
|
|
129
|
-
- `SlackService.sendMany(...)` sends messages sequentially and supports `continueOnError` when callers need a batch result instead of fail-fast behavior.
|
|
130
|
-
- `SlackService.send(...)`, `SlackService.sendMany(...)`, and `SlackService.sendNotification(...)` honor already-aborted signals before provider handoff
|
|
140
|
+
- `SlackService.sendMany(...)` sends messages sequentially and supports `continueOnError` when callers need a batch result instead of fail-fast behavior; it collects ordinary provider failures only, while caller cancellation always rejects the batch.
|
|
141
|
+
- `SlackService.send(...)`, `SlackService.sendMany(...)`, and `SlackService.sendNotification(...)` honor already-aborted signals before provider handoff. An aborted signal or a transport `AbortError` takes precedence over `continueOnError`, and the same signal is propagated through notification channels to transport calls.
|
|
131
142
|
- The service initializes the configured transport during module bootstrap and closes factory-owned resources during application shutdown.
|
|
132
|
-
-
|
|
143
|
+
- Direct and notification-backed delivery require the lifecycle to be `ready`; calls before `onModuleInit()` finishes, after initialization failure, or during shutdown fail with `SlackLifecycleError` instead of lazily creating or reusing transports.
|
|
144
|
+
- Shutdown rejects new deliveries, waits for the shared bootstrap initialization promise—including any in-flight factory-owned transport creation and `verify()` call—to settle, drains active deliveries, and then closes the owned transport before completion.
|
|
145
|
+
- Factory-owned transport cleanup is serialized across bootstrap-failure cleanup and application shutdown, so the same owned transport is closed at most once even when those paths race.
|
|
133
146
|
- `SlackService.createPlatformStatusSnapshot()` reports lifecycle, readiness, and transport ownership without requiring callers to reach into internal options.
|
|
134
147
|
- The package never reads `process.env` directly. All configuration must enter through explicit options or DI.
|
|
135
148
|
|
|
149
|
+
### Bootstrap verification with `verifyOnModuleInit`
|
|
150
|
+
|
|
151
|
+
Set `SlackModuleOptions.verifyOnModuleInit?: boolean` to `true` when the selected transport can verify its own readiness during application bootstrap. `SlackService.onModuleInit()` always resolves the configured transport first; if `verifyOnModuleInit` is enabled **and** the resolved transport exposes an optional `verify()` method, the service awaits `transport.verify()` before marking the Slack provider ready. Transports that do not implement `verify` are still valid and simply skip the verification step.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { Module } from '@fluojs/core';
|
|
155
|
+
import {
|
|
156
|
+
SlackModule,
|
|
157
|
+
type SlackTemplateRenderer,
|
|
158
|
+
type SlackTransport,
|
|
159
|
+
} from '@fluojs/slack';
|
|
160
|
+
|
|
161
|
+
const renderer: SlackTemplateRenderer = {
|
|
162
|
+
render({ template, payload, subject }) {
|
|
163
|
+
if (template === 'deploy.finished') {
|
|
164
|
+
return {
|
|
165
|
+
blocks: [
|
|
166
|
+
{
|
|
167
|
+
text: { text: `*${String(payload.version)}* is live`, type: 'mrkdwn' },
|
|
168
|
+
type: 'section',
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
text: subject,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return { text: subject };
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const slackApiTransport: SlackTransport = {
|
|
180
|
+
async verify() {
|
|
181
|
+
await slackApi.authTest();
|
|
182
|
+
},
|
|
183
|
+
async send(message, { signal }) {
|
|
184
|
+
const receipt = await slackApi.postMessage(message, { signal });
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
channel: receipt.channel,
|
|
188
|
+
messageTs: receipt.ts,
|
|
189
|
+
ok: receipt.ok,
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
@Module({
|
|
195
|
+
imports: [
|
|
196
|
+
SlackModule.forRoot({
|
|
197
|
+
defaultChannel: '#ops',
|
|
198
|
+
renderer,
|
|
199
|
+
transport: slackApiTransport,
|
|
200
|
+
verifyOnModuleInit: true,
|
|
201
|
+
}),
|
|
202
|
+
],
|
|
203
|
+
})
|
|
204
|
+
export class AppModule {}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Behavioral contract notes:
|
|
208
|
+
|
|
209
|
+
- `verifyOnModuleInit` is optional and defaults to `false`.
|
|
210
|
+
- Verification is capability-based: only transports that expose `verify()` are called, so webhook-only or app-owned transports do not have to add a no-op verifier.
|
|
211
|
+
- Bootstrap initialization and verification share one promise with shutdown, so a factory-owned transport remains open until an in-flight `verify()` call settles and is then closed at most once.
|
|
212
|
+
- If `transport.verify()` rejects, bootstrap fails with `SlackLifecycleError` wrapping the initialization failure, the service lifecycle moves to `failed`, readiness/status snapshots report the provider as not ready, and factory-owned transports that were already resolved are closed before the error is rethrown. If shutdown starts while that cleanup is still in progress, both callers await the same close work.
|
|
213
|
+
- `SlackService.createPlatformStatusSnapshot()` includes `verifiedOnModuleInit` so health/readiness tooling can tell whether bootstrap verification was requested.
|
|
214
|
+
|
|
136
215
|
### Integration with `@fluojs/notifications`
|
|
137
216
|
|
|
138
217
|
Inject `SLACK_CHANNEL` into `NotificationsModule.forRootAsync(...)` so the Slack package remains the only place that understands Slack-specific payload fields and recipient-to-channel translation.
|
|
@@ -179,6 +258,51 @@ Behavioral contract notes:
|
|
|
179
258
|
- Notification metadata is merged from payload metadata, dispatch metadata, and subject/template markers before delivery.
|
|
180
259
|
- If a notification needs fan-out across multiple Slack destinations, call `sendMany(...)` instead of one multi-recipient dispatch.
|
|
181
260
|
|
|
261
|
+
### Template rendering and merge precedence
|
|
262
|
+
|
|
263
|
+
Provide a `SlackTemplateRenderer` when notification templates should turn shared `@fluojs/notifications` envelopes into Slack-specific text, blocks, or attachments. `SlackService.sendNotification(...)` calls `renderer.render(input)` only when both `notification.template` and `SlackModuleOptions.renderer` are present. The render input includes `template`, `payload`, optional `subject`, optional `locale`, and optional dispatch `metadata`.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import type { SlackTemplateRenderer } from '@fluojs/slack';
|
|
267
|
+
|
|
268
|
+
const renderer: SlackTemplateRenderer = {
|
|
269
|
+
async render(input) {
|
|
270
|
+
return {
|
|
271
|
+
blocks: [
|
|
272
|
+
{
|
|
273
|
+
text: {
|
|
274
|
+
text: `*${String(input.payload.releaseId)}* deployed for ${input.locale ?? 'default'}`,
|
|
275
|
+
type: 'mrkdwn',
|
|
276
|
+
},
|
|
277
|
+
type: 'section',
|
|
278
|
+
},
|
|
279
|
+
],
|
|
280
|
+
text: input.subject,
|
|
281
|
+
};
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
await notifications.dispatch({
|
|
286
|
+
channel: 'slack',
|
|
287
|
+
locale: 'en',
|
|
288
|
+
metadata: { source: 'ci' },
|
|
289
|
+
payload: {
|
|
290
|
+
metadata: { releaseId: 'rel-42' },
|
|
291
|
+
text: 'Deploy rel-42 finished.',
|
|
292
|
+
},
|
|
293
|
+
recipients: ['#ops'],
|
|
294
|
+
subject: 'Deploy finished',
|
|
295
|
+
template: 'deploy.finished',
|
|
296
|
+
});
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Merge precedence is deterministic:
|
|
300
|
+
|
|
301
|
+
- `payload.attachments` and `payload.blocks` win over rendered `attachments` and `blocks` when those payload fields are defined. Non-blank `payload.text` wins over rendered `text`.
|
|
302
|
+
- Text falls back from non-blank `payload.text` to non-blank rendered `text`, then to non-blank `notification.subject`. Empty or whitespace-only text values are treated as unspecified.
|
|
303
|
+
- Metadata is merged as payload metadata, dispatch metadata, subject marker, then template marker. Later entries win on duplicate keys, so the final message records the dispatch `subject` and `template` markers when present.
|
|
304
|
+
- If no `template` is set or no renderer is registered, no template rendering occurs; the notification is adapted from its payload and subject only.
|
|
305
|
+
|
|
182
306
|
### Webhook-first delivery with explicit fetch injection
|
|
183
307
|
|
|
184
308
|
Use `createSlackWebhookTransport(...)` when you want a portable first-party transport that only depends on a fetch-compatible HTTP boundary.
|
|
@@ -200,7 +324,7 @@ For richer API integrations such as `chat.postMessage`, implement the exported `
|
|
|
200
324
|
Behavioral contract notes:
|
|
201
325
|
|
|
202
326
|
- Passing `fetch` explicitly is the portable path and is recommended for all supported runtimes. For backward compatibility, omitting `fetch` falls back to `globalThis.fetch` when that ambient runtime API exists; runtimes without `globalThis.fetch` fail fast with `SlackConfigurationError`.
|
|
203
|
-
- The built-in webhook transport
|
|
327
|
+
- The built-in webhook transport consumes transient `408`, `429`, and `5xx` response bodies before retrying with bounded exponential backoff, then surfaces an error only after retries are exhausted.
|
|
204
328
|
- Abort signals are passed to the injected `fetch` boundary and cancel retry backoff without wrapping `AbortError` values as `SlackTransportError`.
|
|
205
329
|
- Caller-visible `SlackTransportError` messages omit raw upstream response bodies by default.
|
|
206
330
|
|
|
@@ -211,6 +335,7 @@ The Slack package intentionally does **not**:
|
|
|
211
335
|
- read credentials or webhook URLs from `process.env`
|
|
212
336
|
- ship a Node-only Slack SDK inside the shared root package boundary
|
|
213
337
|
- force one provider strategy beyond the webhook-first helper and exported transport contract
|
|
338
|
+
- provide a package-level multi-client registry beyond the singleton module/helper surface
|
|
214
339
|
- translate one notification into multi-channel fan-out inside a single dispatch call
|
|
215
340
|
|
|
216
341
|
These limitations are part of the package contract so runtime choice, provider capability, and rollout strategy stay explicit at the application boundary.
|
|
@@ -268,8 +393,8 @@ These limitations are part of the package contract so runtime choice, provider c
|
|
|
268
393
|
- `SlackLifecycleState`
|
|
269
394
|
- `SlackStatusAdapterInput`
|
|
270
395
|
- `SlackConfigurationError`
|
|
271
|
-
- `SlackLifecycleError`: thrown by lifecycle-gated delivery,
|
|
272
|
-
- `SlackMessageValidationError`
|
|
396
|
+
- `SlackLifecycleError`: thrown by lifecycle-gated delivery before readiness, after initialization failure, or during shutdown, plus transport factory, verification, and owned-resource cleanup failures. Catch this error when sends can race with bootstrap or application teardown.
|
|
397
|
+
- `SlackMessageValidationError`: thrown when a direct message has no Slack-visible `text`, `blocks`, or `attachments`, or when one notification dispatch resolves multiple Slack recipients and should be split with `sendMany(...)`.
|
|
273
398
|
- `SlackTransportError`
|
|
274
399
|
|
|
275
400
|
## Related Packages
|
|
@@ -281,5 +406,6 @@ These limitations are part of the package contract so runtime choice, provider c
|
|
|
281
406
|
## Example Sources
|
|
282
407
|
|
|
283
408
|
- `packages/slack/src/module.test.ts`: Module registration, `createSlackProviders(...)` helper coverage, async wiring, webhook transport, and notifications integration examples.
|
|
409
|
+
- `packages/slack/src/lifecycle-regression.test.ts`: Bootstrap verification and shutdown ordering regression coverage.
|
|
284
410
|
- `packages/slack/src/public-surface.test.ts`: Public export and TypeScript contract verification.
|
|
285
411
|
- `packages/slack/src/status.test.ts`: Health/readiness contract examples.
|
package/dist/errors.d.ts
CHANGED
|
@@ -5,13 +5,24 @@ export declare class SlackConfigurationError extends Error {
|
|
|
5
5
|
constructor(message: string);
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Thrown when
|
|
8
|
+
* Thrown when caller-supplied Slack message data violates the public delivery contract.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Direct messages surface this error when normalized content has no Slack-visible `text`, `blocks`, or `attachments`.
|
|
12
|
+
* Notification-backed delivery also surfaces it when one dispatch resolves to more than one Slack destination and callers
|
|
13
|
+
* should use `sendMany(...)` for fan-out instead.
|
|
9
14
|
*/
|
|
10
15
|
export declare class SlackMessageValidationError extends Error {
|
|
11
16
|
constructor(message: string);
|
|
12
17
|
}
|
|
13
18
|
/**
|
|
14
|
-
* Thrown when Slack delivery
|
|
19
|
+
* Thrown when Slack delivery, transport initialization, verification, or owned-resource cleanup is blocked by lifecycle state.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Direct and notification-backed delivery require a ready service. Calls made before module initialization finishes,
|
|
23
|
+
* after initialization fails, or after shutdown starts surface this error instead of lazily creating or reusing a transport.
|
|
24
|
+
* Bootstrap also wraps transport factory or `verify()` failures in this type, and application shutdown wraps failures from
|
|
25
|
+
* factory-owned transport cleanup so callers can distinguish lifecycle failures from provider delivery failures.
|
|
15
26
|
*/
|
|
16
27
|
export declare class SlackLifecycleError extends Error {
|
|
17
28
|
constructor(message: string, options?: ErrorOptions);
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;GAOG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;gBACxC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAIpD;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B"}
|
package/dist/errors.js
CHANGED
|
@@ -9,7 +9,12 @@ export class SlackConfigurationError extends Error {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Thrown when
|
|
12
|
+
* Thrown when caller-supplied Slack message data violates the public delivery contract.
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* Direct messages surface this error when normalized content has no Slack-visible `text`, `blocks`, or `attachments`.
|
|
16
|
+
* Notification-backed delivery also surfaces it when one dispatch resolves to more than one Slack destination and callers
|
|
17
|
+
* should use `sendMany(...)` for fan-out instead.
|
|
13
18
|
*/
|
|
14
19
|
export class SlackMessageValidationError extends Error {
|
|
15
20
|
constructor(message) {
|
|
@@ -19,7 +24,13 @@ export class SlackMessageValidationError extends Error {
|
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
|
-
* Thrown when Slack delivery
|
|
27
|
+
* Thrown when Slack delivery, transport initialization, verification, or owned-resource cleanup is blocked by lifecycle state.
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
* Direct and notification-backed delivery require a ready service. Calls made before module initialization finishes,
|
|
31
|
+
* after initialization fails, or after shutdown starts surface this error instead of lazily creating or reusing a transport.
|
|
32
|
+
* Bootstrap also wraps transport factory or `verify()` failures in this type, and application shutdown wraps failures from
|
|
33
|
+
* factory-owned transport cleanup so callers can distinguish lifecycle failures from provider delivery failures.
|
|
23
34
|
*/
|
|
24
35
|
export class SlackLifecycleError extends Error {
|
|
25
36
|
constructor(message, options) {
|
package/dist/module.d.ts
CHANGED
|
@@ -2,10 +2,10 @@ import type { Provider } from '@fluojs/di';
|
|
|
2
2
|
import { type ModuleType } from '@fluojs/runtime';
|
|
3
3
|
import type { SlackAsyncModuleOptions, SlackModuleOptions } from './types.js';
|
|
4
4
|
/**
|
|
5
|
-
* Creates Slack providers for manual module composition.
|
|
5
|
+
* Creates the singleton Slack providers for manual module composition.
|
|
6
6
|
*
|
|
7
|
-
* @param options Static Slack module options including explicit transport wiring.
|
|
8
|
-
* @returns Provider definitions equivalent to {@link SlackModule.forRoot} wiring
|
|
7
|
+
* @param options Static singleton Slack module options including explicit transport wiring.
|
|
8
|
+
* @returns Provider definitions equivalent to {@link SlackModule.forRoot} wiring for `SlackService`, `SlackChannel`, `SLACK`, and `SLACK_CHANNEL`.
|
|
9
9
|
*/
|
|
10
10
|
export declare function createSlackProviders(options: SlackModuleOptions): Provider[];
|
|
11
11
|
/** Runtime module entrypoint for Slack delivery and notifications integration. */
|
|
@@ -14,7 +14,7 @@ export declare class SlackModule {
|
|
|
14
14
|
* Registers Slack providers using static options.
|
|
15
15
|
*
|
|
16
16
|
* @param options Static Slack module options including transport wiring and optional template rendering behavior.
|
|
17
|
-
* @returns A
|
|
17
|
+
* @returns A module definition that exports {@link SlackService}, {@link SlackChannel}, and compatibility tokens.
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```ts
|
|
@@ -31,7 +31,7 @@ export declare class SlackModule {
|
|
|
31
31
|
* Registers Slack providers from an async DI factory.
|
|
32
32
|
*
|
|
33
33
|
* @param options Async module options that resolve Slack transport and renderer configuration through DI.
|
|
34
|
-
* @returns A
|
|
34
|
+
* @returns A module definition that resolves async options through each active application container.
|
|
35
35
|
*
|
|
36
36
|
* @example
|
|
37
37
|
* ```ts
|
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMhE,OAAO,KAAK,EAGV,uBAAuB,EACvB,kBAAkB,EAGnB,MAAM,YAAY,CAAC;AA0DpB;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,QAAQ,EAAE,CAK5E;
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMhE,OAAO,KAAK,EAGV,uBAAuB,EACvB,kBAAkB,EAGnB,MAAM,YAAY,CAAC;AA0DpB;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,QAAQ,EAAE,CAK5E;AA8BD,kFAAkF;AAClF,qBAAa,WAAW;IACtB;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,UAAU;IAIvD;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,UAAU;CAGlE"}
|
package/dist/module.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineModule } from '@fluojs/runtime';
|
|
2
|
-
import { SlackConfigurationError } from './errors.js';
|
|
3
2
|
import { SlackChannel } from './channel.js';
|
|
3
|
+
import { SlackConfigurationError } from './errors.js';
|
|
4
4
|
import { SlackService } from './service.js';
|
|
5
5
|
import { SLACK, SLACK_CHANNEL, SLACK_OPTIONS } from './tokens.js';
|
|
6
6
|
function normalizeOptionalString(value) {
|
|
@@ -47,10 +47,10 @@ function createSlackRuntimeProviders(optionsProvider) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* Creates Slack providers for manual module composition.
|
|
50
|
+
* Creates the singleton Slack providers for manual module composition.
|
|
51
51
|
*
|
|
52
|
-
* @param options Static Slack module options including explicit transport wiring.
|
|
53
|
-
* @returns Provider definitions equivalent to {@link SlackModule.forRoot} wiring
|
|
52
|
+
* @param options Static singleton Slack module options including explicit transport wiring.
|
|
53
|
+
* @returns Provider definitions equivalent to {@link SlackModule.forRoot} wiring for `SlackService`, `SlackChannel`, `SLACK`, and `SLACK_CHANNEL`.
|
|
54
54
|
*/
|
|
55
55
|
export function createSlackProviders(options) {
|
|
56
56
|
return createSlackRuntimeProviders({
|
|
@@ -69,13 +69,6 @@ function buildSlackModule(options) {
|
|
|
69
69
|
function buildSlackModuleAsync(options) {
|
|
70
70
|
class SlackAsyncModuleDefinition {}
|
|
71
71
|
const factory = options.useFactory;
|
|
72
|
-
let cachedResult;
|
|
73
|
-
const memoizedFactory = (...deps) => {
|
|
74
|
-
if (!cachedResult) {
|
|
75
|
-
cachedResult = Promise.resolve(factory(...deps)).then(resolved => normalizeSlackModuleOptions(resolved));
|
|
76
|
-
}
|
|
77
|
-
return cachedResult;
|
|
78
|
-
};
|
|
79
72
|
return defineModule(SlackAsyncModuleDefinition, {
|
|
80
73
|
exports: [SlackService, SlackChannel, SLACK, SLACK_CHANNEL],
|
|
81
74
|
global: options.global ?? true,
|
|
@@ -83,7 +76,7 @@ function buildSlackModuleAsync(options) {
|
|
|
83
76
|
inject: options.inject,
|
|
84
77
|
provide: SLACK_OPTIONS,
|
|
85
78
|
scope: 'singleton',
|
|
86
|
-
useFactory: (...deps) =>
|
|
79
|
+
useFactory: (...deps) => Promise.resolve(factory(...deps)).then(resolved => normalizeSlackModuleOptions(resolved))
|
|
87
80
|
})
|
|
88
81
|
});
|
|
89
82
|
}
|
|
@@ -94,7 +87,7 @@ export class SlackModule {
|
|
|
94
87
|
* Registers Slack providers using static options.
|
|
95
88
|
*
|
|
96
89
|
* @param options Static Slack module options including transport wiring and optional template rendering behavior.
|
|
97
|
-
* @returns A
|
|
90
|
+
* @returns A module definition that exports {@link SlackService}, {@link SlackChannel}, and compatibility tokens.
|
|
98
91
|
*
|
|
99
92
|
* @example
|
|
100
93
|
* ```ts
|
|
@@ -114,7 +107,7 @@ export class SlackModule {
|
|
|
114
107
|
* Registers Slack providers from an async DI factory.
|
|
115
108
|
*
|
|
116
109
|
* @param options Async module options that resolve Slack transport and renderer configuration through DI.
|
|
117
|
-
* @returns A
|
|
110
|
+
* @returns A module definition that resolves async options through each active application container.
|
|
118
111
|
*
|
|
119
112
|
* @example
|
|
120
113
|
* ```ts
|
package/dist/service.d.ts
CHANGED
|
@@ -10,14 +10,21 @@ import type { NormalizedSlackModuleOptions, Slack, SlackMessage, SlackNotificati
|
|
|
10
10
|
*/
|
|
11
11
|
export declare class SlackService implements Slack, OnModuleInit, OnApplicationShutdown {
|
|
12
12
|
private readonly options;
|
|
13
|
+
private readonly inFlightDeliveries;
|
|
14
|
+
private initializationPromise;
|
|
13
15
|
private lifecycleState;
|
|
16
|
+
private ownedTransportCleanupPromise;
|
|
14
17
|
private resolvedTransport;
|
|
15
18
|
private shutdownPromise;
|
|
16
19
|
private transportPromise;
|
|
17
20
|
constructor(options: NormalizedSlackModuleOptions);
|
|
18
21
|
onApplicationShutdown(): Promise<void>;
|
|
19
22
|
private closeOwnedTransport;
|
|
23
|
+
private closeOwnedTransportResources;
|
|
24
|
+
private closeOwnedTransportResourcesOnce;
|
|
25
|
+
private resolveTransportForCleanup;
|
|
20
26
|
onModuleInit(): Promise<void>;
|
|
27
|
+
private initializeTransport;
|
|
21
28
|
/**
|
|
22
29
|
* Creates a platform status snapshot for the active Slack transport wiring.
|
|
23
30
|
*
|
|
@@ -30,7 +37,8 @@ export declare class SlackService implements Slack, OnModuleInit, OnApplicationS
|
|
|
30
37
|
* @param message Caller-supplied Slack message with text and/or block content.
|
|
31
38
|
* @param options Optional abort signal propagated to the transport.
|
|
32
39
|
* @returns A normalized delivery receipt describing the transport response.
|
|
33
|
-
* @throws {SlackMessageValidationError} When the resolved message
|
|
40
|
+
* @throws {SlackMessageValidationError} When the resolved message has no Slack-visible `text`, `blocks`, or `attachments`.
|
|
41
|
+
* @throws {SlackLifecycleError} When delivery is requested before readiness, after initialization failure, or during shutdown.
|
|
34
42
|
*
|
|
35
43
|
* @example
|
|
36
44
|
* ```ts
|
|
@@ -47,6 +55,7 @@ export declare class SlackService implements Slack, OnModuleInit, OnApplicationS
|
|
|
47
55
|
* @param messages Ordered message list to deliver through the configured transport.
|
|
48
56
|
* @param options Optional tolerant batch controls such as `continueOnError`.
|
|
49
57
|
* @returns A batch summary containing successes and any captured failures.
|
|
58
|
+
* @throws {SlackLifecycleError} When delivery is requested before readiness, after initialization failure, or during shutdown.
|
|
50
59
|
*
|
|
51
60
|
* @example
|
|
52
61
|
* ```ts
|
|
@@ -61,7 +70,8 @@ export declare class SlackService implements Slack, OnModuleInit, OnApplicationS
|
|
|
61
70
|
* @param notification Shared notification envelope interpreted by the Slack package.
|
|
62
71
|
* @param options Optional abort signal propagated to rendering and transport work.
|
|
63
72
|
* @returns A normalized delivery receipt for the resulting Slack message.
|
|
64
|
-
* @throws {SlackMessageValidationError} When the notification
|
|
73
|
+
* @throws {SlackMessageValidationError} When the notification resolves multiple Slack recipients or no Slack-visible content.
|
|
74
|
+
* @throws {SlackLifecycleError} When delivery is requested before readiness, after initialization failure, or during shutdown.
|
|
65
75
|
*
|
|
66
76
|
* @example
|
|
67
77
|
* ```ts
|
|
@@ -74,6 +84,10 @@ export declare class SlackService implements Slack, OnModuleInit, OnApplicationS
|
|
|
74
84
|
*/
|
|
75
85
|
sendNotification(notification: SlackNotificationDispatchRequest, options?: SlackSendOptions): Promise<SlackSendResult>;
|
|
76
86
|
private ensureTransport;
|
|
87
|
+
private clearResolvedTransport;
|
|
88
|
+
private handleTransportInitializationFailure;
|
|
89
|
+
private drainInFlightDeliveries;
|
|
90
|
+
private trackInFlightDelivery;
|
|
77
91
|
private assertCanCreateOrUseTransport;
|
|
78
92
|
private assertCanDeliver;
|
|
79
93
|
private normalizeMessage;
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK3E,OAAO,KAAK,EAEV,4BAA4B,EAC5B,KAAK,EACL,YAAY,EACZ,gCAAgC,EAChC,oBAAoB,EAEpB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EAGhB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK3E,OAAO,KAAK,EAEV,4BAA4B,EAC5B,KAAK,EACL,YAAY,EACZ,gCAAgC,EAChC,oBAAoB,EAEpB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EAGhB,MAAM,YAAY,CAAC;AAsDpB;;;;;;;GAOG;AACH,qBACa,YAAa,YAAW,KAAK,EAAE,YAAY,EAAE,qBAAqB;IASjE,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA+B;IAClE,OAAO,CAAC,qBAAqB,CAA4B;IACzD,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,4BAA4B,CAA4B;IAChE,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,gBAAgB,CAAsC;gBAEjC,OAAO,EAAE,4BAA4B;IAE5D,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;YAgB9B,mBAAmB;IAoBjC,OAAO,CAAC,4BAA4B;YAQtB,gCAAgC;YAYhC,0BAA0B;IAexC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAoBf,mBAAmB;IAsBjC;;;;OAIG;IACH,4BAA4B;IAW5B;;;;;;;;;;;;;;;;OAgBG;IACG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IAyB3F;;;;;;;;;;;;;OAaG;IACG,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAgCpH;;;;;;;;;;;;;;;;;OAiBG;IACG,gBAAgB,CACpB,YAAY,EAAE,gCAAgC,EAC9C,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC;YAkCb,eAAe;IAiB7B,OAAO,CAAC,sBAAsB;YAKhB,oCAAoC;YAsBpC,uBAAuB;YAMvB,qBAAqB;IAWnC,OAAO,CAAC,6BAA6B;IAMrC,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,0BAA0B;YAkBpB,kBAAkB;CAkBjC"}
|
package/dist/service.js
CHANGED
|
@@ -18,11 +18,17 @@ function assertNotAborted(signal) {
|
|
|
18
18
|
throw createAbortError();
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
function isAbortError(error) {
|
|
22
|
+
return error.name === 'AbortError';
|
|
23
|
+
}
|
|
21
24
|
function createLifecycleError(message, cause) {
|
|
22
25
|
return new SlackLifecycleError(message, {
|
|
23
26
|
cause
|
|
24
27
|
});
|
|
25
28
|
}
|
|
29
|
+
function createCleanupFailureCause(originalError, cleanupError) {
|
|
30
|
+
return new AggregateError([originalError, cleanupError], 'Slack transport verification failed and the owned transport failed to close.');
|
|
31
|
+
}
|
|
26
32
|
function createDeliveryLifecycleError(state) {
|
|
27
33
|
return new SlackLifecycleError(`Slack delivery cannot start while the service lifecycle is ${state}.`);
|
|
28
34
|
}
|
|
@@ -52,7 +58,10 @@ class SlackService {
|
|
|
52
58
|
static {
|
|
53
59
|
[_SlackService, _initClass] = _applyDecs(this, [Inject(SLACK_OPTIONS)], []).c;
|
|
54
60
|
}
|
|
61
|
+
inFlightDeliveries = new Set();
|
|
62
|
+
initializationPromise;
|
|
55
63
|
lifecycleState = 'created';
|
|
64
|
+
ownedTransportCleanupPromise;
|
|
56
65
|
resolvedTransport;
|
|
57
66
|
shutdownPromise;
|
|
58
67
|
transportPromise;
|
|
@@ -72,21 +81,60 @@ class SlackService {
|
|
|
72
81
|
}
|
|
73
82
|
async closeOwnedTransport() {
|
|
74
83
|
try {
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
77
|
-
await
|
|
84
|
+
const initializationPromise = this.initializationPromise;
|
|
85
|
+
if (initializationPromise) {
|
|
86
|
+
await initializationPromise.then(() => undefined, () => undefined);
|
|
78
87
|
}
|
|
88
|
+
await this.drainInFlightDeliveries();
|
|
89
|
+
await this.closeOwnedTransportResources();
|
|
79
90
|
this.lifecycleState = 'stopped';
|
|
80
91
|
} catch (error) {
|
|
81
92
|
this.lifecycleState = 'failed';
|
|
82
93
|
throw createLifecycleError('Slack transport failed to close cleanly.', error);
|
|
83
94
|
}
|
|
84
95
|
}
|
|
85
|
-
|
|
96
|
+
closeOwnedTransportResources() {
|
|
97
|
+
if (!this.ownedTransportCleanupPromise) {
|
|
98
|
+
this.ownedTransportCleanupPromise = this.closeOwnedTransportResourcesOnce();
|
|
99
|
+
}
|
|
100
|
+
return this.ownedTransportCleanupPromise;
|
|
101
|
+
}
|
|
102
|
+
async closeOwnedTransportResourcesOnce() {
|
|
103
|
+
try {
|
|
104
|
+
const transport = await this.resolveTransportForCleanup();
|
|
105
|
+
if (transport && this.options.transport.ownsResources && transport.close) {
|
|
106
|
+
await transport.close();
|
|
107
|
+
}
|
|
108
|
+
} finally {
|
|
109
|
+
this.clearResolvedTransport();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async resolveTransportForCleanup() {
|
|
113
|
+
if (this.resolvedTransport) {
|
|
114
|
+
return this.resolvedTransport;
|
|
115
|
+
}
|
|
116
|
+
if (!this.transportPromise) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
return this.transportPromise.then(transport => transport, () => undefined);
|
|
120
|
+
}
|
|
121
|
+
onModuleInit() {
|
|
86
122
|
if (this.lifecycleState === 'stopping' || this.lifecycleState === 'stopped') {
|
|
87
|
-
return;
|
|
123
|
+
return Promise.resolve();
|
|
88
124
|
}
|
|
89
|
-
this.
|
|
125
|
+
if (!this.initializationPromise) {
|
|
126
|
+
let resolveInitialization = () => undefined;
|
|
127
|
+
let rejectInitialization = _reason => undefined;
|
|
128
|
+
this.lifecycleState = 'starting';
|
|
129
|
+
this.initializationPromise = new Promise((resolve, reject) => {
|
|
130
|
+
resolveInitialization = resolve;
|
|
131
|
+
rejectInitialization = reject;
|
|
132
|
+
});
|
|
133
|
+
void this.initializeTransport().then(resolveInitialization, rejectInitialization);
|
|
134
|
+
}
|
|
135
|
+
return this.initializationPromise;
|
|
136
|
+
}
|
|
137
|
+
async initializeTransport() {
|
|
90
138
|
try {
|
|
91
139
|
const transport = await this.ensureTransport();
|
|
92
140
|
if (this.lifecycleState !== 'starting') {
|
|
@@ -100,11 +148,7 @@ class SlackService {
|
|
|
100
148
|
}
|
|
101
149
|
this.lifecycleState = 'ready';
|
|
102
150
|
} catch (error) {
|
|
103
|
-
|
|
104
|
-
throw error;
|
|
105
|
-
}
|
|
106
|
-
this.lifecycleState = 'failed';
|
|
107
|
-
throw createLifecycleError('Slack transport failed to initialize.', error);
|
|
151
|
+
await this.handleTransportInitializationFailure(error);
|
|
108
152
|
}
|
|
109
153
|
}
|
|
110
154
|
|
|
@@ -130,7 +174,8 @@ class SlackService {
|
|
|
130
174
|
* @param message Caller-supplied Slack message with text and/or block content.
|
|
131
175
|
* @param options Optional abort signal propagated to the transport.
|
|
132
176
|
* @returns A normalized delivery receipt describing the transport response.
|
|
133
|
-
* @throws {SlackMessageValidationError} When the resolved message
|
|
177
|
+
* @throws {SlackMessageValidationError} When the resolved message has no Slack-visible `text`, `blocks`, or `attachments`.
|
|
178
|
+
* @throws {SlackLifecycleError} When delivery is requested before readiness, after initialization failure, or during shutdown.
|
|
134
179
|
*
|
|
135
180
|
* @example
|
|
136
181
|
* ```ts
|
|
@@ -148,7 +193,10 @@ class SlackService {
|
|
|
148
193
|
assertMessageContent(normalized);
|
|
149
194
|
assertNotAborted(options.signal);
|
|
150
195
|
this.assertCanDeliver();
|
|
151
|
-
const result = await
|
|
196
|
+
const result = await this.trackInFlightDelivery(() => {
|
|
197
|
+
assertNotAborted(options.signal);
|
|
198
|
+
return transport.send(normalized, options);
|
|
199
|
+
});
|
|
152
200
|
return {
|
|
153
201
|
channel: result.channel ?? normalized.channel,
|
|
154
202
|
messageTs: result.messageTs,
|
|
@@ -166,6 +214,7 @@ class SlackService {
|
|
|
166
214
|
* @param messages Ordered message list to deliver through the configured transport.
|
|
167
215
|
* @param options Optional tolerant batch controls such as `continueOnError`.
|
|
168
216
|
* @returns A batch summary containing successes and any captured failures.
|
|
217
|
+
* @throws {SlackLifecycleError} When delivery is requested before readiness, after initialization failure, or during shutdown.
|
|
169
218
|
*
|
|
170
219
|
* @example
|
|
171
220
|
* ```ts
|
|
@@ -175,6 +224,7 @@ class SlackService {
|
|
|
175
224
|
*/
|
|
176
225
|
async sendMany(messages, options = {}) {
|
|
177
226
|
assertNotAborted(options.signal);
|
|
227
|
+
this.assertCanDeliver();
|
|
178
228
|
const results = [];
|
|
179
229
|
const failures = [];
|
|
180
230
|
for (const message of messages) {
|
|
@@ -185,7 +235,7 @@ class SlackService {
|
|
|
185
235
|
error: error instanceof Error ? error : new Error('Slack delivery failed.'),
|
|
186
236
|
message
|
|
187
237
|
};
|
|
188
|
-
if (!(options.continueOnError ?? false)) {
|
|
238
|
+
if (options.signal?.aborted || isAbortError(failure.error) || !(options.continueOnError ?? false)) {
|
|
189
239
|
throw failure.error;
|
|
190
240
|
}
|
|
191
241
|
failures.push(failure);
|
|
@@ -205,7 +255,8 @@ class SlackService {
|
|
|
205
255
|
* @param notification Shared notification envelope interpreted by the Slack package.
|
|
206
256
|
* @param options Optional abort signal propagated to rendering and transport work.
|
|
207
257
|
* @returns A normalized delivery receipt for the resulting Slack message.
|
|
208
|
-
* @throws {SlackMessageValidationError} When the notification
|
|
258
|
+
* @throws {SlackMessageValidationError} When the notification resolves multiple Slack recipients or no Slack-visible content.
|
|
259
|
+
* @throws {SlackLifecycleError} When delivery is requested before readiness, after initialization failure, or during shutdown.
|
|
209
260
|
*
|
|
210
261
|
* @example
|
|
211
262
|
* ```ts
|
|
@@ -240,7 +291,7 @@ class SlackService {
|
|
|
240
291
|
},
|
|
241
292
|
mrkdwn: payload.mrkdwn,
|
|
242
293
|
replyBroadcast: payload.replyBroadcast,
|
|
243
|
-
text: payload.text ?? rendered?.text ?? notification.subject,
|
|
294
|
+
text: normalizeOptionalString(payload.text) ?? normalizeOptionalString(rendered?.text) ?? normalizeOptionalString(notification.subject),
|
|
244
295
|
threadTs: payload.threadTs,
|
|
245
296
|
unfurlLinks: payload.unfurlLinks,
|
|
246
297
|
unfurlMedia: payload.unfurlMedia,
|
|
@@ -260,13 +311,49 @@ class SlackService {
|
|
|
260
311
|
}
|
|
261
312
|
return this.transportPromise;
|
|
262
313
|
}
|
|
314
|
+
clearResolvedTransport() {
|
|
315
|
+
this.resolvedTransport = undefined;
|
|
316
|
+
this.transportPromise = undefined;
|
|
317
|
+
}
|
|
318
|
+
async handleTransportInitializationFailure(error) {
|
|
319
|
+
const interruptedByShutdown = isShutdownLifecycleState(this.lifecycleState);
|
|
320
|
+
if (!interruptedByShutdown) {
|
|
321
|
+
this.lifecycleState = 'failed';
|
|
322
|
+
}
|
|
323
|
+
let cause = error;
|
|
324
|
+
try {
|
|
325
|
+
await this.closeOwnedTransportResources();
|
|
326
|
+
} catch (cleanupError) {
|
|
327
|
+
cause = createCleanupFailureCause(error, cleanupError);
|
|
328
|
+
}
|
|
329
|
+
if (!interruptedByShutdown && !isShutdownLifecycleState(this.lifecycleState)) {
|
|
330
|
+
this.lifecycleState = 'failed';
|
|
331
|
+
}
|
|
332
|
+
throw createLifecycleError('Slack transport failed to initialize.', cause);
|
|
333
|
+
}
|
|
334
|
+
async drainInFlightDeliveries() {
|
|
335
|
+
while (this.inFlightDeliveries.size > 0) {
|
|
336
|
+
await Promise.allSettled(Array.from(this.inFlightDeliveries));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
async trackInFlightDelivery(start) {
|
|
340
|
+
const delivery = Promise.resolve().then(start);
|
|
341
|
+
this.inFlightDeliveries.add(delivery);
|
|
342
|
+
try {
|
|
343
|
+
return await delivery;
|
|
344
|
+
} finally {
|
|
345
|
+
this.inFlightDeliveries.delete(delivery);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
263
348
|
assertCanCreateOrUseTransport() {
|
|
264
349
|
if (this.lifecycleState === 'stopping' || this.lifecycleState === 'stopped' || this.lifecycleState === 'failed') {
|
|
265
350
|
throw createDeliveryLifecycleError(this.lifecycleState);
|
|
266
351
|
}
|
|
267
352
|
}
|
|
268
353
|
assertCanDeliver() {
|
|
269
|
-
this.
|
|
354
|
+
if (this.lifecycleState !== 'ready') {
|
|
355
|
+
throw createDeliveryLifecycleError(this.lifecycleState);
|
|
356
|
+
}
|
|
270
357
|
}
|
|
271
358
|
normalizeMessage(message) {
|
|
272
359
|
return {
|
|
@@ -286,14 +373,14 @@ class SlackService {
|
|
|
286
373
|
};
|
|
287
374
|
}
|
|
288
375
|
resolveNotificationChannel(notification) {
|
|
289
|
-
const payloadChannel = normalizeOptionalString(notification.payload.channel);
|
|
290
|
-
if (payloadChannel) {
|
|
291
|
-
return payloadChannel;
|
|
292
|
-
}
|
|
293
376
|
const recipients = notification.recipients?.map(entry => entry.trim()).filter(entry => entry.length > 0) ?? [];
|
|
294
377
|
if (recipients.length > 1) {
|
|
295
378
|
throw new SlackMessageValidationError('Slack notifications accept exactly one target channel per dispatch. Use `sendMany(...)` for fan-out delivery.');
|
|
296
379
|
}
|
|
380
|
+
const payloadChannel = normalizeOptionalString(notification.payload.channel);
|
|
381
|
+
if (payloadChannel) {
|
|
382
|
+
return payloadChannel;
|
|
383
|
+
}
|
|
297
384
|
return recipients[0] ?? this.options.defaultChannel;
|
|
298
385
|
}
|
|
299
386
|
async renderNotification(notification, signal) {
|
package/dist/types.d.ts
CHANGED
|
@@ -107,14 +107,12 @@ export interface SlackFetchResponse {
|
|
|
107
107
|
text(): MaybePromise<string>;
|
|
108
108
|
}
|
|
109
109
|
/** Minimal fetch-compatible function signature used by the built-in webhook transport helper. */
|
|
110
|
-
export
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}): MaybePromise<SlackFetchResponse>;
|
|
117
|
-
}
|
|
110
|
+
export type SlackFetchLike = (input: string, init?: {
|
|
111
|
+
body?: string;
|
|
112
|
+
headers?: Readonly<Record<string, string>>;
|
|
113
|
+
method?: string;
|
|
114
|
+
signal?: AbortSignal;
|
|
115
|
+
}) => MaybePromise<SlackFetchResponse>;
|
|
118
116
|
/** Options accepted by {@link createSlackWebhookTransport}. */
|
|
119
117
|
export interface SlackWebhookTransportOptions {
|
|
120
118
|
fetch?: SlackFetchLike;
|
|
@@ -193,13 +191,23 @@ export interface SlackSendManyOptions extends SlackSendOptions {
|
|
|
193
191
|
/** Module options accepted by {@link SlackModule.forRoot} and `forRootAsync`. */
|
|
194
192
|
export interface SlackModuleOptions {
|
|
195
193
|
defaultChannel?: string;
|
|
196
|
-
/**
|
|
194
|
+
/**
|
|
195
|
+
* Controls whether Slack providers are visible through the whole module graph.
|
|
196
|
+
*
|
|
197
|
+
* @remarks
|
|
198
|
+
* Defaults to `true` for Nest-like root registration. Set `false` when migrated code needs `SlackService`,
|
|
199
|
+
* `SlackChannel`, `SLACK`, and `SLACK_CHANNEL` to stay visible only to modules that explicitly import the returned
|
|
200
|
+
* module definition.
|
|
201
|
+
*/
|
|
197
202
|
global?: boolean;
|
|
198
203
|
notifications?: {
|
|
199
204
|
channel?: string;
|
|
200
205
|
};
|
|
201
206
|
renderer?: SlackTemplateRenderer;
|
|
202
207
|
transport: SlackTransport | SlackTransportFactory;
|
|
208
|
+
/**
|
|
209
|
+
* Verifies the configured transport during `onModuleInit()` before the service becomes ready for delivery.
|
|
210
|
+
*/
|
|
203
211
|
verifyOnModuleInit?: boolean;
|
|
204
212
|
}
|
|
205
213
|
/** Async registration options for Slack modules that derive config through DI. */
|
|
@@ -226,6 +234,8 @@ export interface Slack {
|
|
|
226
234
|
* @param message Caller-supplied Slack message with text and/or block content.
|
|
227
235
|
* @param options Optional abort signal propagated to the transport.
|
|
228
236
|
* @returns A normalized delivery receipt describing the transport response.
|
|
237
|
+
* @throws {SlackMessageValidationError} When the resolved message has no Slack-visible `text`, `blocks`, or `attachments`.
|
|
238
|
+
* @throws {SlackLifecycleError} When delivery is requested before readiness, after initialization failure, or during shutdown.
|
|
229
239
|
*/
|
|
230
240
|
send(message: SlackMessage, options?: SlackSendOptions): Promise<SlackSendResult>;
|
|
231
241
|
/**
|
|
@@ -234,6 +244,7 @@ export interface Slack {
|
|
|
234
244
|
* @param messages Ordered message list to deliver through the configured transport.
|
|
235
245
|
* @param options Optional tolerant batch controls such as `continueOnError`.
|
|
236
246
|
* @returns A batch summary containing successes and any captured failures.
|
|
247
|
+
* @throws {SlackLifecycleError} When delivery is requested before readiness, after initialization failure, or during shutdown.
|
|
237
248
|
*/
|
|
238
249
|
sendMany(messages: readonly SlackMessage[], options?: SlackSendManyOptions): Promise<SlackSendBatchResult>;
|
|
239
250
|
/**
|
|
@@ -242,6 +253,8 @@ export interface Slack {
|
|
|
242
253
|
* @param notification Shared notification envelope interpreted by the Slack package.
|
|
243
254
|
* @param options Optional abort signal propagated to rendering and transport work.
|
|
244
255
|
* @returns A normalized delivery receipt for the resulting Slack message.
|
|
256
|
+
* @throws {SlackMessageValidationError} When the notification resolves multiple Slack recipients or no Slack-visible content.
|
|
257
|
+
* @throws {SlackLifecycleError} When delivery is requested before readiness, after initialization failure, or during shutdown.
|
|
245
258
|
*/
|
|
246
259
|
sendNotification(notification: SlackNotificationDispatchRequest, options?: SlackSendOptions): Promise<SlackSendResult>;
|
|
247
260
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/webhook.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAIV,cAAc,EAEd,4BAA4B,EAC7B,MAAM,YAAY,CAAC;AA4FpB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,4BAA4B,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAIV,cAAc,EAEd,4BAA4B,EAC7B,MAAM,YAAY,CAAC;AA4FpB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,4BAA4B,GAAG,cAAc,CA4DjG"}
|
package/dist/webhook.js
CHANGED
|
@@ -134,15 +134,14 @@ export function createSlackWebhookTransport(options) {
|
|
|
134
134
|
method: 'POST',
|
|
135
135
|
signal: context.signal
|
|
136
136
|
});
|
|
137
|
+
const body = await readResponseBody(response);
|
|
137
138
|
if (!response.ok) {
|
|
138
139
|
if (attempt < DEFAULT_RETRY_ATTEMPTS && isTransientStatus(response.status)) {
|
|
139
140
|
await waitForRetry(DEFAULT_RETRY_DELAY_MS * 2 ** (attempt - 1), context.signal);
|
|
140
141
|
continue;
|
|
141
142
|
}
|
|
142
|
-
await readResponseBody(response);
|
|
143
143
|
throw new SlackTransportError(createStatusFailureMessage(response, attempt));
|
|
144
144
|
}
|
|
145
|
-
const body = await readResponseBody(response);
|
|
146
145
|
return {
|
|
147
146
|
channel: message.channel,
|
|
148
147
|
ok: true,
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"portable",
|
|
10
10
|
"fetch"
|
|
11
11
|
],
|
|
12
|
-
"version": "
|
|
12
|
+
"version": "2.0.0",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"directory": "packages/slack"
|
|
19
19
|
},
|
|
20
20
|
"engines": {
|
|
21
|
-
"node": ">=
|
|
21
|
+
"node": ">=24.0.0 <27"
|
|
22
22
|
},
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"dist"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@fluojs/core": "^
|
|
40
|
-
"@fluojs/di": "^
|
|
41
|
-
"@fluojs/notifications": "^
|
|
42
|
-
"@fluojs/runtime": "^
|
|
39
|
+
"@fluojs/core": "^2.0.0",
|
|
40
|
+
"@fluojs/di": "^3.0.0",
|
|
41
|
+
"@fluojs/notifications": "^2.0.0",
|
|
42
|
+
"@fluojs/runtime": "^3.0.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"vitest": "^
|
|
45
|
+
"vitest": "^4.1.11"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|