dicoshot-nest 0.2.2 → 0.3.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.
Files changed (33) hide show
  1. package/README.ko.md +415 -0
  2. package/README.md +387 -69
  3. package/dist/app.controller.js.map +1 -1
  4. package/dist/app.module.js.map +1 -1
  5. package/dist/decorators/dicoshot-notify.decorator.d.ts +8 -0
  6. package/dist/decorators/dicoshot-notify.decorator.js +8 -0
  7. package/dist/decorators/dicoshot-notify.decorator.js.map +1 -0
  8. package/dist/dicoshot.constants.d.ts +1 -0
  9. package/dist/dicoshot.constants.js +2 -1
  10. package/dist/dicoshot.constants.js.map +1 -1
  11. package/dist/dicoshot.listener.js.map +1 -1
  12. package/dist/dicoshot.module.js +3 -0
  13. package/dist/dicoshot.module.js.map +1 -1
  14. package/dist/dicoshot.service.d.ts +6 -3
  15. package/dist/dicoshot.service.js +17 -8
  16. package/dist/dicoshot.service.js.map +1 -1
  17. package/dist/filters/dicoshot-exception.filter.js +16 -8
  18. package/dist/filters/dicoshot-exception.filter.js.map +1 -1
  19. package/dist/index.d.ts +7 -4
  20. package/dist/index.js +9 -5
  21. package/dist/index.js.map +1 -1
  22. package/dist/interceptors/dicoshot-notify.interceptor.d.ts +10 -0
  23. package/dist/interceptors/dicoshot-notify.interceptor.js +45 -0
  24. package/dist/interceptors/dicoshot-notify.interceptor.js.map +1 -0
  25. package/dist/interceptors/dicoshot.interceptor.d.ts +1 -1
  26. package/dist/interceptors/dicoshot.interceptor.js +37 -24
  27. package/dist/interceptors/dicoshot.interceptor.js.map +1 -1
  28. package/dist/main.js.map +1 -1
  29. package/dist/utils/stack.util.d.ts +3 -0
  30. package/dist/utils/stack.util.js +20 -0
  31. package/dist/utils/stack.util.js.map +1 -0
  32. package/package.json +9 -19
  33. package/dist/tsconfig.build.tsbuildinfo +0 -1
package/README.md CHANGED
@@ -1,98 +1,416 @@
1
- <p align="center">
2
- <a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
3
- </p>
4
-
5
- [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
6
- [circleci-url]: https://circleci.com/gh/nestjs/nest
7
-
8
- <p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
9
- <p align="center">
10
- <a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
11
- <a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
12
- <a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
13
- <a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
14
- <a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
15
- <a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
16
- <a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
17
- <a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
18
- <a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
19
- <a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
20
- </p>
21
- <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
22
- [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
23
-
24
- ## Description
25
-
26
- [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
27
-
28
- ## Project setup
1
+ # dicoshot-nest
2
+
3
+ English | [한국어](README.ko.md)
4
+
5
+ An SDK that automatically notifies a Discord channel about NestJS application startup/shutdown, unhandled exceptions, and slow responses. Works by simply registering the module.
6
+
7
+ ## Features
8
+
9
+ - **Automatic notifications**: Startup/shutdown notifications via `OnApplicationBootstrap`/`OnApplicationShutdown` hooks, no extra code required
10
+ - **Automatic exception notifications**: A global `ExceptionFilter` immediately sends unhandled exceptions to Discord (can include stack trace and request body), with the exact throw site (`file:line:col`) surfaced in a dedicated `Location` field
11
+ - **Slow response notifications**: A `NestInterceptor` notifies when response time exceeds a threshold
12
+ - **Custom messages**: Inject `DicoshotService` to send arbitrary Discord messages at any time, or annotate a handler with `@DicoshotNotify()` to send one automatically on success
13
+ - **Failure isolation**: Webhook delivery failures never block app startup/shutdown/request handling (only a WARN log is emitted)
14
+ - **MSA-friendly**: hostname and applicationName are automatically included in messages, making it easy to tell instances apart
15
+ - **Automatic environment detection**: `NODE_ENV` and `npm_package_version` are included automatically
16
+ - **Duplicate notification prevention**: The same error won't be notified twice even when filter and interceptor are both enabled
17
+ - **Localized notifications**: Titles and field labels (Service, Environment, Status, Location, ...) can be sent in English, Korean, Japanese, or Chinese via `locale` — or any other language by passing your own translations
18
+
19
+ ## Module structure
20
+
21
+ | Module | Description |
22
+ | --------------- | ----------------------------------------------------------------------------------- |
23
+ | `dicoshot-core` | Pure TypeScript with no NestJS dependency. Message model, webhook client |
24
+ | `dicoshot-nest` | NestJS DynamicModule, lifecycle hooks, ExceptionFilter, Interceptor |
25
+
26
+ ## Installation
29
27
 
30
28
  ```bash
31
- $ npm install
29
+ npm install dicoshot-nest
32
30
  ```
33
31
 
34
- ## Compile and run the project
32
+ ## Quick start
35
33
 
36
- ```bash
37
- # development
38
- $ npm run start
34
+ ```typescript
35
+ // app.module.ts
36
+ import { Module } from '@nestjs/common';
37
+ import { DicoshotModule } from 'dicoshot-nest';
38
+
39
+ @Module({
40
+ imports: [
41
+ DicoshotModule.register({
42
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
43
+ applicationName: 'my-service',
44
+ }),
45
+ ],
46
+ })
47
+ export class AppModule {}
48
+ ```
49
+
50
+ When you run the app, the following embeds arrive in the Discord channel.
39
51
 
40
- # watch mode
41
- $ npm run start:dev
52
+ - **On startup**: green embed, title "🟢 Application Started", includes service name/environment/version/hostname/timestamp
53
+ - **On shutdown**: red embed, title "🔴 Application Stopped"
42
54
 
43
- # production mode
44
- $ npm run start:prod
55
+ ## ConfigService integration
56
+
57
+ ```typescript
58
+ DicoshotModule.registerAsync({
59
+ imports: [ConfigModule],
60
+ useFactory: (config: ConfigService) => ({
61
+ webhookUrl: config.get('DISCORD_WEBHOOK_URL'),
62
+ applicationName: config.get('APP_NAME'),
63
+ }),
64
+ inject: [ConfigService],
65
+ // filter/interceptor must be specified separately at the registerAsync() call site.
66
+ // (They determine whether APP_FILTER/APP_INTERCEPTOR are registered on the
67
+ // DynamicModule, so they're fixed at registration time regardless of the
68
+ // async factory's result.)
69
+ filter: true,
70
+ interceptor: { slowThreshold: 2000 },
71
+ });
45
72
  ```
46
73
 
47
- ## Run tests
74
+ ## Sending custom messages directly
48
75
 
49
- ```bash
50
- # unit tests
51
- $ npm run test
76
+ Inject `DicoshotService` to send Discord messages from anywhere in your code.
77
+
78
+ ### sendCustom() convenience method
52
79
 
53
- # e2e tests
54
- $ npm run test:e2e
80
+ ```typescript
81
+ @Injectable()
82
+ export class DeployService {
83
+ constructor(private readonly dicoshot: DicoshotService) {}
55
84
 
56
- # test coverage
57
- $ npm run test:cov
85
+ async onDeployComplete(version: string) {
86
+ await this.dicoshot.sendCustom({
87
+ title: 'Deploy complete',
88
+ description: `v${version} deployed successfully`,
89
+ color: 'success', // 'success' | 'danger' | 'warning' | 'info'
90
+ fields: [{ name: 'Version', value: `v${version}`, inline: true }],
91
+ mention: '<@&123456789012345678>', // appended after the description
92
+ });
93
+ }
94
+ }
58
95
  ```
59
96
 
60
- ## Deployment
97
+ Color presets:
61
98
 
62
- When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
99
+ | Value | Color |
100
+ | ----------- | ------ |
101
+ | `'success'` | Green |
102
+ | `'danger'` | Red |
103
+ | `'warning'` | Yellow |
104
+ | `'info'` | Blue |
63
105
 
64
- If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
106
+ You can also specify a hex value directly: `color: 0xFF0000`
65
107
 
66
- ```bash
67
- $ npm install -g @nestjs/mau
68
- $ mau deploy
108
+ ### send() — raw method
109
+
110
+ Build the Discord embed structure yourself and send it.
111
+
112
+ ```typescript
113
+ await this.dicoshot.send({
114
+ embeds: [
115
+ {
116
+ title: 'Notification',
117
+ description: '...',
118
+ color: 0x57f287,
119
+ fields: [{ name: 'Version', value: 'v1.2.3', inline: true }],
120
+ },
121
+ ],
122
+ });
123
+ ```
124
+
125
+ > Neither method throws. Both resolve to a `boolean` indicating whether the message was delivered; failures are logged as a WARN, consistent with the rest of the SDK's failure-isolation behavior.
126
+
127
+ ### `@DicoshotNotify()` — decorator
128
+
129
+ Annotate a controller (or any Nest-pipeline) handler to send a custom message automatically once it resolves successfully. No `@UseInterceptors()` setup needed — the interceptor is registered globally and is a no-op on handlers without the decorator. Nothing is sent if the handler throws (use `filter`/`interceptor` for error notifications).
130
+
131
+ ```typescript
132
+ @Controller('orders')
133
+ export class OrderController {
134
+ @Post()
135
+ @DicoshotNotify({ title: 'New order created', color: 'success' })
136
+ create(@Body() dto: CreateOrderDto) {
137
+ return this.orderService.create(dto);
138
+ }
139
+
140
+ @Post(':id/deploy')
141
+ @DicoshotNotify({
142
+ title: (args) => `Deploy complete: ${args[0]}`, // args = handler arguments, in order
143
+ description: (_args, result) => `Result: ${JSON.stringify(result)}`,
144
+ color: 'success',
145
+ })
146
+ deploy(@Param('id') id: string) {
147
+ return this.orderService.deploy(id);
148
+ }
149
+ }
69
150
  ```
70
151
 
71
- With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
152
+ `title`/`description` accept either a static string or a `(args, result) => string` function, where `args` is the handler's argument array and `result` is its return value.
153
+
154
+ ## Automatic exception notifications (`filter`)
155
+
156
+ Enabling the `filter` option registers `DicoshotExceptionFilter` as a global `APP_FILTER`. By default, it notifies Discord for unhandled exceptions and any error with an HTTP status of `500` or above (4xx `HttpException`s like `NotFoundException` are not notified unless `minStatus` is lowered). Non-HTTP contexts (WebSocket, RPC, etc.) are ignored and not notified.
157
+
158
+ When a stack trace is available, the notification includes a `Location` field with the exact `file:line:col` where the error was thrown — extracted from the top stack frame — so you don't have to scan the full `Stack Trace` block to find it.
159
+
160
+ ```typescript
161
+ DicoshotModule.register({
162
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
163
+ applicationName: 'order-service',
164
+ filter: true, // or a FilterOptions object
165
+ });
166
+ ```
167
+
168
+ This is what arrives in Discord:
169
+
170
+ > 🚨 **[production] order-service — TypeError**
171
+ > `Cannot read properties of undefined (reading 'id')`
172
+ >
173
+ > **Service** `order-service` **Environment** `production` **Status** `500`
174
+ > **Method** `POST` **Path** `/orders`
175
+ >
176
+ > **Location**
177
+ > `/app/src/order/order.service.ts:42:18`
178
+ >
179
+ > **Request Body**
180
+ > ```json
181
+ > {"productId":"abc123","quantity":2}
182
+ > ```
183
+ >
184
+ > **Stack Trace**
185
+ > ```
186
+ > TypeError: Cannot read properties of undefined (reading 'id')
187
+ > at OrderService.create (/app/src/order/order.service.ts:42:18)
188
+ > at OrderController.create (/app/src/order/order.controller.ts:15:30)
189
+ > ```
190
+
191
+ `Location` is always the very first line of `Stack Trace` — it's pulled out into its own field so you can see where the error actually happened without scrolling through the rest of the trace.
192
+
193
+ ### FilterOptions
72
194
 
73
- ## Resources
195
+ | Key | Default | Description |
196
+ | ---------------- | ------- | ------------------------------------------------------------------------------------ |
197
+ | `minStatus` | `500` | Only notify for status codes at or above this value (unhandled exceptions are always treated as `500`) |
198
+ | `ignore` | - | Array of HTTP status codes to skip notifying (e.g. `[404]`) |
199
+ | `environment` | - | Only notify in this environment (`string` or `string[]`, based on `NODE_ENV`) |
200
+ | `mention` | - | Mention string to add to the embed body (e.g. `'<@&ROLE_ID>'`) |
201
+ | `throttle` | - | Suppress repeated notifications for the same error (class+method+path) for N seconds |
202
+ | `includeStack` | `true` | Whether to include the stack trace |
203
+ | `includeRequest` | `true` | Whether to include the request body |
74
204
 
75
- Check out a few resources that may come in handy when working with NestJS:
205
+ ```typescript
206
+ DicoshotModule.register({
207
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
208
+ filter: {
209
+ ignore: [404, 401],
210
+ environment: 'production',
211
+ mention: '<@&123456789012345678>',
212
+ throttle: 60, // notify the same error at most once every 60 seconds
213
+ },
214
+ });
215
+ ```
216
+
217
+ Error notifications are sent to `webhooks.error` if configured, otherwise to the default `webhookUrl`.
218
+
219
+ ## Slow response / error notifications (`interceptor`)
220
+
221
+ Enabling the `interceptor` option registers `DicoshotInterceptor` as a global `APP_INTERCEPTOR`, notifying Discord when response time exceeds the threshold. When `filter` is not enabled, the interceptor also handles error notifications (when `filter` is enabled, the interceptor skips error notifications to avoid duplicates) — including the same `Location` and `Stack Trace` fields described above.
222
+
223
+ ```typescript
224
+ DicoshotModule.register({
225
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
226
+ interceptor: true, // or an InterceptorOptions object
227
+ });
228
+ ```
229
+
230
+ ### InterceptorOptions
231
+
232
+ | Key | Default | Description |
233
+ | --------------- | ------- | ---------------------------------------------------------------------- |
234
+ | `slowThreshold` | `3000` | Threshold (ms) for considering a response slow |
235
+ | `excludePaths` | - | Array of path prefixes excluded from notifications (e.g. `['/health']`) |
236
+ | `onlyErrors` | `false` | If `true`, disables slow response notifications and only sends error notifications |
237
+ | `minStatus` | `500` | Only notify error responses at or above this status (unhandled exceptions are always treated as `500`) |
238
+
239
+ ```typescript
240
+ DicoshotModule.register({
241
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
242
+ interceptor: {
243
+ slowThreshold: 1500,
244
+ excludePaths: ['/health', '/metrics'],
245
+ },
246
+ });
247
+ ```
76
248
 
77
- - Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
78
- - For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
79
- - To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
80
- - Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
81
- - Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
82
- - Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
83
- - To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
84
- - Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
249
+ Slow response notifications are sent to `webhooks.slow` if configured, otherwise to the default `webhookUrl`.
85
250
 
86
- ## Support
251
+ ## Webhook retry (`retry`)
252
+
253
+ If a webhook delivery fails (network error, Discord 5xx, rate limit, etc.), it's retried with exponential backoff. If Discord returns `429` with a `Retry-After` header, that value takes priority; otherwise the wait is `backoffMs * 2^attempt`.
254
+
255
+ ```typescript
256
+ DicoshotModule.register({
257
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
258
+ retry: true, // or a RetryOptions object. Disabled by default (no retries)
259
+ });
260
+ ```
261
+
262
+ ### RetryOptions
263
+
264
+ | Key | Default | Description |
265
+ | ----------- | ------- | -------------------------------------------------------------------- |
266
+ | `attempts` | `2` | Number of retries after the initial attempt fails |
267
+ | `backoffMs` | `500` | Wait time (ms) before the first retry. Doubles on each subsequent attempt |
268
+
269
+ ```typescript
270
+ DicoshotModule.register({
271
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
272
+ retry: { attempts: 3, backoffMs: 300 },
273
+ });
274
+ ```
275
+
276
+ If all retries fail, the final error is propagated to the caller. `DicoshotListener`/`DicoshotExceptionFilter`/`DicoshotInterceptor` catch this error and only emit a WARN log, so it doesn't affect app behavior.
277
+
278
+ ## Configuration
279
+
280
+ | Key | Default | Description |
281
+ | ------------------ | ------------ | ----------------------------------------------------------------------------------------- |
282
+ | `webhookUrl` | - | Discord webhook URL. Auto-disabled if not set |
283
+ | `enabled` | `true` | Global enable toggle (applies to startup/shutdown notifications) |
284
+ | `notifyOnStartup` | `true` | Whether to send a startup notification |
285
+ | `notifyOnShutdown` | `true` | Whether to send a shutdown notification |
286
+ | `applicationName` | - | Service name shown in the embed |
287
+ | `locale` | `'en'` | Language for notification titles/field labels: `'en'` \| `'ko'` \| `'ja'` \| `'zh'`, or a custom [`DicoshotMessages`](#example-custom-locale) object |
288
+ | `timeoutMs` | `5000` | HTTP timeout (ms) |
289
+ | `webhooks.error` | - | Dedicated webhook URL for exception notifications (falls back to `webhookUrl`) |
290
+ | `webhooks.slow` | - | Dedicated webhook URL for slow response notifications (falls back to `webhookUrl`) |
291
+ | `filter` | `false` | Enable automatic exception notifications (`boolean` or [`FilterOptions`](#filteroptions)) |
292
+ | `interceptor` | `false` | Enable slow response/error notifications (`boolean` or [`InterceptorOptions`](#interceptoroptions)) |
293
+ | `retry` | `false` | Enable retries on webhook delivery failure (`boolean` or [`RetryOptions`](#retryoptions)) |
294
+
295
+ ### Example: notify only on startup
296
+
297
+ ```typescript
298
+ DicoshotModule.register({
299
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
300
+ notifyOnShutdown: false,
301
+ applicationName: 'order-service',
302
+ });
303
+ ```
304
+
305
+ ### Example: notifications in another language
306
+
307
+ ```typescript
308
+ DicoshotModule.register({
309
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
310
+ applicationName: '주문-서비스',
311
+ locale: 'ko', // 'en' | 'ko' | 'ja' | 'zh'
312
+ });
313
+ ```
314
+
315
+ Titles and field labels (Service, Environment, Status, Location, ...) are translated. Values that come from your runtime — the exception class name (`TypeError`, `NotFoundException`, ...), the error message, the stack trace, the request path — are sent as-is and aren't translated.
316
+
317
+ ### Example: custom locale
318
+
319
+ Not all of your team's users speak one of the built-in languages? Pass a full `DicoshotMessages` object instead of a locale code and every title/field label is taken from it.
320
+
321
+ ```typescript
322
+ import { DicoshotMessages } from 'dicoshot-nest';
323
+
324
+ const fr: DicoshotMessages = {
325
+ startupTitle: '🟢 Application démarrée',
326
+ shutdownTitle: '🔴 Application arrêtée',
327
+ slowResponseLabel: 'Réponse lente',
328
+ field: {
329
+ service: 'Service',
330
+ environment: 'Environnement',
331
+ version: 'Version',
332
+ hostname: 'Hôte',
333
+ time: 'Heure',
334
+ status: 'Statut',
335
+ method: 'Méthode',
336
+ path: 'Chemin',
337
+ duration: 'Durée',
338
+ location: 'Emplacement',
339
+ stackTrace: 'Pile d\'appels',
340
+ requestBody: 'Corps de la requête',
341
+ },
342
+ };
343
+
344
+ DicoshotModule.register({
345
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
346
+ locale: fr,
347
+ });
348
+ ```
349
+
350
+ ### Example: separate channels for errors and slow responses
351
+
352
+ ```typescript
353
+ DicoshotModule.register({
354
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL, // for startup/shutdown notifications
355
+ webhooks: {
356
+ error: process.env.DISCORD_ERROR_WEBHOOK_URL, // for exception notifications
357
+ slow: process.env.DISCORD_SLOW_WEBHOOK_URL, // for slow response notifications
358
+ },
359
+ filter: { environment: 'production' },
360
+ interceptor: { slowThreshold: 2000 },
361
+ });
362
+ ```
363
+
364
+ ### Example: inject the webhook URL via an environment variable
365
+
366
+ ```typescript
367
+ DicoshotModule.register({
368
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL,
369
+ });
370
+ ```
371
+
372
+ `webhookUrl` is optional — if it's unset or empty, the SDK is automatically disabled, so no errors occur in local development.
373
+
374
+ ## How it works
375
+
376
+ 1. `DicoshotModule.register()`/`registerAsync()` registers the options in the NestJS DI container.
377
+ 2. `DicoshotNotifyInterceptor` is always registered globally as `APP_INTERCEPTOR`; it's a no-op except on handlers annotated with `@DicoshotNotify()`. If the `filter`/`interceptor` options are enabled, `DicoshotExceptionFilter`/`DicoshotInterceptor` are also registered globally as `APP_FILTER`/`APP_INTERCEPTOR`.
378
+ 3. `DicoshotListener` subscribes to NestJS lifecycle hooks and sends startup/shutdown messages at `onApplicationBootstrap()`/`onApplicationShutdown()`.
379
+ 4. When an exception occurs during request handling, `DicoshotExceptionFilter` (or `DicoshotInterceptor` if `filter` is disabled) sends an error message.
380
+ 5. When response time exceeds `slowThreshold`, `DicoshotInterceptor` sends a slow response message.
381
+ 6. When a handler annotated with `@DicoshotNotify()` resolves successfully, `DicoshotNotifyInterceptor` sends the configured custom message.
382
+ 7. Every webhook call swallows its own exceptions and only emits a WARN log on failure, so app behavior is never affected.
383
+
384
+ ## MSA environments
385
+
386
+ - Each service uses `dicoshot-nest` independently.
387
+ - `applicationName` and `hostname` are automatically included in messages, making it easy to identify which service and which instance sent them.
388
+ - In environments with frequent pod restarts (e.g. K8s), you can disable only startup notifications with `notifyOnStartup: false`, or disable everything with `enabled: false`.
389
+ - Configure `filter.throttle` per service to keep a repeated error from flooding the Discord channel.
390
+
391
+ ## Requirements
392
+
393
+ - Node.js 18+
394
+ - NestJS 10+
395
+
396
+ ## Build
397
+
398
+ ```bash
399
+ # Build everything
400
+ npm run build --workspaces
401
+
402
+ # Build individually
403
+ cd dicoshot-core && npm run build
404
+ cd dicoshot-nest && npm run build
405
+ ```
87
406
 
88
- Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
407
+ ## Out of scope (current version)
89
408
 
90
- ## Stay in touch
409
+ The following features are not yet included.
91
410
 
92
- - Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
93
- - Website - [https://nestjs.com](https://nestjs.com/)
94
- - Twitter - [@nestframework](https://twitter.com/nestframework)
411
+ - Asynchronous queueing (persisting messages that fail permanently beyond retries)
412
+ - Simultaneous delivery to multiple webhooks or other platforms like Slack
95
413
 
96
414
  ## License
97
415
 
98
- Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
416
+ [MIT License](LICENSE) © 2026 DicoShot
@@ -1 +1 @@
1
- {"version":3,"file":"app.controller.js","sourceRoot":"","sources":["../src/app.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAiD;AACjD,+CAA2C;AAGpC,IAAM,aAAa,GAAnB,MAAM,aAAa;IACK;IAA7B,YAA6B,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAGvD,QAAQ;QACN,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;CACF,CAAA;AAPY,sCAAa;AAIxB;IADC,IAAA,YAAG,GAAE;;;;6CAGL;wBANU,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAE8B,wBAAU;GADxC,aAAa,CAOzB"}
1
+ {"version":3,"file":"app.controller.js","sourceRoot":"","sources":["../src/app.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAiD;AAEjD,+CAA2C;AAGpC,IAAM,aAAa,GAAnB,MAAM,aAAa;IACK;IAA7B,YAA6B,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAGvD,QAAQ;QACN,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;CACF,CAAA;AAPY,sCAAa;AAIxB;IADC,IAAA,YAAG,GAAE;;;;6CAGL;wBANU,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAE8B,wBAAU;GADxC,aAAa,CAOzB"}
@@ -1 +1 @@
1
- {"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,qDAAiD;AACjD,+CAA2C;AAOpC,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IALrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,CAAC,8BAAa,CAAC;QAC5B,SAAS,EAAE,CAAC,wBAAU,CAAC;KACxB,CAAC;GACW,SAAS,CAAG"}
1
+ {"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AAExC,qDAAiD;AACjD,+CAA2C;AAOpC,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IALrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,CAAC,8BAAa,CAAC;QAC5B,SAAS,EAAE,CAAC,wBAAU,CAAC;KACxB,CAAC;GACW,SAAS,CAAG"}
@@ -0,0 +1,8 @@
1
+ import type { ColorPreset } from '../dicoshot.service';
2
+ export type DicoshotNotifyResolver<T> = T | ((args: unknown[], result: unknown) => T);
3
+ export interface DicoshotNotifyOptions {
4
+ title: DicoshotNotifyResolver<string>;
5
+ description?: DicoshotNotifyResolver<string>;
6
+ color?: ColorPreset | number;
7
+ }
8
+ export declare const DicoshotNotify: (options: DicoshotNotifyOptions) => MethodDecorator;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DicoshotNotify = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const dicoshot_constants_1 = require("../dicoshot.constants");
6
+ const DicoshotNotify = (options) => (0, common_1.SetMetadata)(dicoshot_constants_1.DICOSHOT_NOTIFY_METADATA, options);
7
+ exports.DicoshotNotify = DicoshotNotify;
8
+ //# sourceMappingURL=dicoshot-notify.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dicoshot-notify.decorator.js","sourceRoot":"","sources":["../../src/decorators/dicoshot-notify.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAG7C,8DAAiE;AAc1D,MAAM,cAAc,GAAG,CAAC,OAA8B,EAAmB,EAAE,CAChF,IAAA,oBAAW,EAAC,6CAAwB,EAAE,OAAO,CAAC,CAAC;AADpC,QAAA,cAAc,kBACsB"}
@@ -1,2 +1,3 @@
1
1
  export declare const DICOSHOT_OPTIONS = "DICOSHOT_OPTIONS";
2
2
  export declare const DICOSHOT_CLIENT = "DICOSHOT_CLIENT";
3
+ export declare const DICOSHOT_NOTIFY_METADATA = "DICOSHOT_NOTIFY_METADATA";
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DICOSHOT_CLIENT = exports.DICOSHOT_OPTIONS = void 0;
3
+ exports.DICOSHOT_NOTIFY_METADATA = exports.DICOSHOT_CLIENT = exports.DICOSHOT_OPTIONS = void 0;
4
4
  exports.DICOSHOT_OPTIONS = 'DICOSHOT_OPTIONS';
5
5
  exports.DICOSHOT_CLIENT = 'DICOSHOT_CLIENT';
6
+ exports.DICOSHOT_NOTIFY_METADATA = 'DICOSHOT_NOTIFY_METADATA';
6
7
  //# sourceMappingURL=dicoshot.constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dicoshot.constants.js","sourceRoot":"","sources":["../src/dicoshot.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AACtC,QAAA,eAAe,GAAG,iBAAiB,CAAC"}
1
+ {"version":3,"file":"dicoshot.constants.js","sourceRoot":"","sources":["../src/dicoshot.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AACtC,QAAA,eAAe,GAAG,iBAAiB,CAAC;AACpC,QAAA,wBAAwB,GAAG,0BAA0B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"dicoshot.listener.js","sourceRoot":"","sources":["../src/dicoshot.listener.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAMwB;AAExB,iDAAmE;AACnE,6DAAyE;AAGlE,IAAM,gBAAgB,wBAAtB,MAAM,gBAAgB;IAOkB;IACD;IAL3B,MAAM,GAAG,IAAI,eAAM,CAAC,kBAAgB,CAAC,IAAI,CAAC,CAAC;IAC3C,OAAO,CAAiB;IAEzC,YAC6C,OAAwB,EACzB,MAA0B;QADzB,YAAO,GAAP,OAAO,CAAiB;QACzB,WAAM,GAAN,MAAM,CAAoB;QAEpE,IAAI,CAAC,OAAO,GAAG,IAAI,8BAAc,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,sBAAsB;QAC1B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,KAAK;YAAE,OAAO;QACvE,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,KAAK,KAAK;YAAE,OAAO;QACnD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,wCAAyC,GAAa,CAAC,OAAO,EAAE,CACjE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,qBAAqB;QACzB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,KAAK;YAAE,OAAO;QACvE,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,KAAK,KAAK;YAAE,OAAO;QACpD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,yCAA0C,GAAa,CAAC,OAAO,EAAE,CAClE,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAA;AApCY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;IAQR,WAAA,IAAA,eAAM,EAAC,qCAAgB,CAAC,CAAA;IACxB,WAAA,IAAA,eAAM,EAAC,oCAAe,CAAC,CAAA;6CAA0B,kCAAkB;GAR3D,gBAAgB,CAoC5B"}
1
+ {"version":3,"file":"dicoshot.listener.js","sourceRoot":"","sources":["../src/dicoshot.listener.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAMwB;AAGxB,iDAAmE;AAEnE,6DAAyE;AAGlE,IAAM,gBAAgB,wBAAtB,MAAM,gBAAgB;IAKkB;IACD;IAL3B,MAAM,GAAG,IAAI,eAAM,CAAC,kBAAgB,CAAC,IAAI,CAAC,CAAC;IAC3C,OAAO,CAAiB;IAEzC,YAC6C,OAAwB,EACzB,MAA0B;QADzB,YAAO,GAAP,OAAO,CAAiB;QACzB,WAAM,GAAN,MAAM,CAAoB;QAEpE,IAAI,CAAC,OAAO,GAAG,IAAI,8BAAc,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,sBAAsB;QAC1B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,KAAK;YAAE,OAAO;QACvE,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,KAAK,KAAK;YAAE,OAAO;QACnD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAyC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,qBAAqB;QACzB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,KAAK;YAAE,OAAO;QACvE,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,KAAK,KAAK;YAAE,OAAO;QACpD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yCAA0C,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;CACF,CAAA;AA9BY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;IAMR,WAAA,IAAA,eAAM,EAAC,qCAAgB,CAAC,CAAA;IACxB,WAAA,IAAA,eAAM,EAAC,oCAAe,CAAC,CAAA;6CAA0B,kCAAkB;GAN3D,gBAAgB,CA8B5B"}
@@ -15,6 +15,7 @@ const dicoshot_constants_1 = require("./dicoshot.constants");
15
15
  const dicoshot_listener_1 = require("./dicoshot.listener");
16
16
  const dicoshot_service_1 = require("./dicoshot.service");
17
17
  const dicoshot_exception_filter_1 = require("./filters/dicoshot-exception.filter");
18
+ const dicoshot_notify_interceptor_1 = require("./interceptors/dicoshot-notify.interceptor");
18
19
  const dicoshot_interceptor_1 = require("./interceptors/dicoshot.interceptor");
19
20
  const clientProvider = {
20
21
  provide: dicoshot_constants_1.DICOSHOT_CLIENT,
@@ -27,6 +28,7 @@ function buildProviders(options) {
27
28
  clientProvider,
28
29
  dicoshot_listener_1.DicoshotListener,
29
30
  dicoshot_service_1.DicoshotService,
31
+ { provide: core_1.APP_INTERCEPTOR, useClass: dicoshot_notify_interceptor_1.DicoshotNotifyInterceptor },
30
32
  ];
31
33
  if (options.filter) {
32
34
  providers.push({ provide: core_1.APP_FILTER, useClass: dicoshot_exception_filter_1.DicoshotExceptionFilter });
@@ -62,6 +64,7 @@ let DicoshotModule = DicoshotModule_1 = class DicoshotModule {
62
64
  clientProvider,
63
65
  dicoshot_listener_1.DicoshotListener,
64
66
  dicoshot_service_1.DicoshotService,
67
+ { provide: core_1.APP_INTERCEPTOR, useClass: dicoshot_notify_interceptor_1.DicoshotNotifyInterceptor },
65
68
  ];
66
69
  if (filter) {
67
70
  providers.push({ provide: core_1.APP_FILTER, useClass: dicoshot_exception_filter_1.DicoshotExceptionFilter });
@@ -1 +1 @@
1
- {"version":3,"file":"dicoshot.module.js","sourceRoot":"","sources":["../src/dicoshot.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAKwB;AACxB,uCAA2D;AAC3D,iDAAuG;AACvG,6DAAyE;AACzE,2DAAuD;AACvD,yDAAqD;AACrD,mFAA8E;AAC9E,8EAA0E;AAmB1E,MAAM,cAAc,GAAa;IAC/B,OAAO,EAAE,oCAAe;IACxB,UAAU,EAAE,CAAC,OAAwB,EAAE,EAAE,CAAC,IAAI,kCAAkB,CAAC,OAAO,CAAC;IACzE,MAAM,EAAE,CAAC,qCAAgB,CAAC;CAC3B,CAAC;AAEF,SAAS,cAAc,CAAC,OAAwB;IAC9C,MAAM,SAAS,GAAe;QAC5B,EAAE,OAAO,EAAE,qCAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE;QAChD,cAAc;QACd,oCAAgB;QAChB,kCAAe;KAChB,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,iBAAU,EAAE,QAAQ,EAAE,mDAAuB,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,sBAAe,EAAE,QAAQ,EAAE,0CAAmB,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAGM,IAAM,cAAc,sBAApB,MAAM,cAAc;IACzB,MAAM,CAAC,QAAQ,CAAC,OAAwB;QACtC,OAAO;YACL,MAAM,EAAE,gBAAc;YACtB,SAAS,EAAE,cAAc,CAAC,OAAO,CAAC;YAClC,OAAO,EAAE,CAAC,kCAAe,CAAC;SAC3B,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,EACnB,UAAU,EACV,MAAM,EACN,OAAO,EACP,MAAM,EACN,WAAW,GACU;QACrB,MAAM,eAAe,GAAa;YAChC,OAAO,EAAE,qCAAgB;YACzB,UAAU,EAAE,KAAK,EAAE,GAAG,IAAe,EAAE,EAAE;gBACvC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;gBAEvC,OAAO;oBACL,GAAG,IAAI;oBACP,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;oBACvC,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;iBAClD,CAAC;YACJ,CAAC;YACD,MAAM,EAAG,MAAa,IAAI,EAAE;SAC7B,CAAC;QAEF,MAAM,SAAS,GAAe;YAC5B,eAAe;YACf,cAAc;YACd,oCAAgB;YAChB,kCAAe;SAChB,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,iBAAU,EAAE,QAAQ,EAAE,mDAAuB,EAAE,CAAC,CAAC;QAC7E,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,sBAAe,EAAE,QAAQ,EAAE,0CAAmB,EAAE,CAAC,CAAC;QAC9E,CAAC;QAED,OAAO;YACL,MAAM,EAAE,gBAAc;YACtB,OAAO,EAAE,OAAO,IAAI,EAAE;YACtB,SAAS;YACT,OAAO,EAAE,CAAC,kCAAe,CAAC;SAC3B,CAAC;IACJ,CAAC;CACF,CAAA;AApDY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,cAAc,CAoD1B"}
1
+ {"version":3,"file":"dicoshot.module.js","sourceRoot":"","sources":["../src/dicoshot.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAiF;AACjF,uCAA2D;AAE3D,iDAKuB;AAEvB,6DAAyE;AACzE,2DAAuD;AACvD,yDAAqD;AACrD,mFAA8E;AAC9E,4FAAuF;AACvF,8EAA0E;AAiB1E,MAAM,cAAc,GAAa;IAC/B,OAAO,EAAE,oCAAe;IACxB,UAAU,EAAE,CAAC,OAAwB,EAAE,EAAE,CAAC,IAAI,kCAAkB,CAAC,OAAO,CAAC;IACzE,MAAM,EAAE,CAAC,qCAAgB,CAAC;CAC3B,CAAC;AAEF,SAAS,cAAc,CAAC,OAAwB;IAC9C,MAAM,SAAS,GAAe;QAC5B,EAAE,OAAO,EAAE,qCAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE;QAChD,cAAc;QACd,oCAAgB;QAChB,kCAAe;QAEf,EAAE,OAAO,EAAE,sBAAe,EAAE,QAAQ,EAAE,uDAAyB,EAAE;KAClE,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,iBAAU,EAAE,QAAQ,EAAE,mDAAuB,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,sBAAe,EAAE,QAAQ,EAAE,0CAAmB,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAGM,IAAM,cAAc,sBAApB,MAAM,cAAc;IACzB,MAAM,CAAC,QAAQ,CAAC,OAAwB;QACtC,OAAO;YACL,MAAM,EAAE,gBAAc;YACtB,SAAS,EAAE,cAAc,CAAC,OAAO,CAAC;YAClC,OAAO,EAAE,CAAC,kCAAe,CAAC;SAC3B,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,EACnB,UAAU,EACV,MAAM,EACN,OAAO,EACP,MAAM,EACN,WAAW,GACU;QACrB,MAAM,eAAe,GAAa;YAChC,OAAO,EAAE,qCAAgB;YACzB,UAAU,EAAE,KAAK,EAAE,GAAG,IAAe,EAAE,EAAE;gBACvC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;gBAEvC,OAAO;oBACL,GAAG,IAAI;oBACP,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;oBACvC,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;iBAClD,CAAC;YACJ,CAAC;YACD,MAAM,EAAG,MAAa,IAAI,EAAE;SAC7B,CAAC;QAEF,MAAM,SAAS,GAAe;YAC5B,eAAe;YACf,cAAc;YACd,oCAAgB;YAChB,kCAAe;YAEf,EAAE,OAAO,EAAE,sBAAe,EAAE,QAAQ,EAAE,uDAAyB,EAAE;SAClE,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,iBAAU,EAAE,QAAQ,EAAE,mDAAuB,EAAE,CAAC,CAAC;QAC7E,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,sBAAe,EAAE,QAAQ,EAAE,0CAAmB,EAAE,CAAC,CAAC;QAC9E,CAAC;QAED,OAAO;YACL,MAAM,EAAE,gBAAc;YACtB,OAAO,EAAE,OAAO,IAAI,EAAE;YACtB,SAAS;YACT,OAAO,EAAE,CAAC,kCAAe,CAAC;SAC3B,CAAC;IACJ,CAAC;CACF,CAAA;AAtDY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,cAAc,CAsD1B"}
@@ -1,14 +1,17 @@
1
- import type { DiscordMessage } from 'dicoshot-core';
1
+ import type { DiscordField, DiscordMessage } from 'dicoshot-core';
2
2
  import { DicoshotClientImpl } from 'dicoshot-core';
3
3
  export type ColorPreset = 'success' | 'danger' | 'warning' | 'info';
4
4
  export interface CustomMessageOptions {
5
5
  title: string;
6
6
  description?: string;
7
7
  color?: ColorPreset | number;
8
+ fields?: DiscordField[];
9
+ mention?: string;
8
10
  }
9
11
  export declare class DicoshotService {
10
12
  private readonly client;
13
+ private readonly logger;
11
14
  constructor(client: DicoshotClientImpl);
12
- send(message: DiscordMessage): Promise<void>;
13
- sendCustom({ title, description, color }: CustomMessageOptions): Promise<void>;
15
+ send(message: DiscordMessage): Promise<boolean>;
16
+ sendCustom({ title, description, color, fields, mention, }: CustomMessageOptions): Promise<boolean>;
14
17
  }