slack-logs 3.0.3 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -78,6 +78,29 @@ slack.logBlockMessage("Validation Message!", payload);
78
78
  - if `slackLogConfig(...)` is used, env values are ignored for both fields
79
79
  - `slackLogConfig(...)` does not ask for values interactively
80
80
 
81
+ ### Required Slack webhook setup
82
+
83
+ - credential required: `Incoming Webhook URL`
84
+ - URL format: `https://hooks.slack.com/services/...`
85
+ - where to find it: Slack App Settings -> `Incoming Webhooks` -> `Webhook URLs for Your Workspace`
86
+ - enable `Incoming Webhooks` first in the app settings
87
+ - each webhook URL is tied to one Slack channel
88
+ - if you need different channels, create separate webhook URLs or use `slackbot`
89
+
90
+ ### Create the Slack app / webhook if you don't have one
91
+
92
+ 1. Go to `https://api.slack.com/apps`
93
+ 2. Click `Create New App`
94
+ 3. Select `From scratch`
95
+ 4. Enter the app name and choose the workspace
96
+ 5. Open `Incoming Webhooks`
97
+ 6. Turn on `Activate Incoming Webhooks`
98
+ 7. Click `Add New Webhook to Workspace`
99
+ 8. Select the Slack channel
100
+ 9. Click `Allow`
101
+ 10. Copy the webhook URL from `Webhook URLs for Your Workspace`
102
+ 11. Use it in `slackLogConfig({ webhookUrl: "..." })` or `SLACK_WEBHOOK_URL`
103
+
81
104
  #### Option 2: Use environment variables
82
105
 
83
106
  Use env values only when `slackLogConfig(...)` is not called.
@@ -267,3 +290,168 @@ slack.rawBody(payload);
267
290
  ```
268
291
 
269
292
  If payload is invalid or sending fails, it logs a console error.
293
+
294
+ ---
295
+
296
+ ## Slack Bot
297
+
298
+ Use `slackbot` when you want the same logging helpers with bot-token based multi-channel support.
299
+
300
+ ### Configuration
301
+
302
+ ```
303
+ import { slackbot, slackBotConfig } from "slack-logs";
304
+ or
305
+ const { slackbot, slackBotConfig } = require("slack-logs");
306
+
307
+ slackBotConfig({
308
+ botToken: "xoxb-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXX",
309
+ defaultChannelId: "C0123456789",
310
+ enableAlerts: true,
311
+ });
312
+ ```
313
+
314
+ `slackBotConfig(...)` rules:
315
+
316
+ - `botToken` and `enableAlerts` are required
317
+ - `defaultChannelId` is optional if you pass `channelId` in method calls
318
+ - if `defaultChannelId` is not set in config, package falls back to `SLACK_BOT_DEFAULT_CHANNEL_ID`
319
+
320
+ ### Required Slack app setup
321
+
322
+ - token required: `Bot User OAuth Access Token`
323
+ - token format: `xoxb-...`
324
+ - where to find it: Slack App Settings -> `OAuth & Permissions` -> `Bot User OAuth Access Token`
325
+ - important: the token appears only after you click `Install to Workspace`
326
+ - add scopes under `OAuth & Permissions` -> `Bot Token Scopes`
327
+ - required scope: `chat:write`
328
+ - optional scope: `chat:write.public` if you want to post in public channels without inviting the app first
329
+ - do not use `User Token Scopes`
330
+ - do not use app-level tokens (`xapp-...`) for this package
331
+ - if the app is not in a channel, invite it first unless you added `chat:write.public`
332
+
333
+ ### Environment variables
334
+
335
+ Use env values only when `slackBotConfig(...)` is not called.
336
+
337
+ `.env` 🚨
338
+
339
+ ```
340
+ ...
341
+ SLACK_BOT_TOKEN="xoxb-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXX"
342
+ SLACK_BOT_DEFAULT_CHANNEL_ID="C0123456789"
343
+
344
+ # Optional field.
345
+ # If not defined, logs are sent by default.
346
+ # true / True / TRUE sends logs.
347
+ # false / False / FALSE skips logs.
348
+ ENABLE_SLACK_BOT_LOGS=true
349
+ ...
350
+ ```
351
+
352
+ ### Create the Slack app if you don't have one
353
+
354
+ 1. Go to `https://api.slack.com/apps`
355
+ 2. Click `Create New App`
356
+ 3. Select `From scratch`
357
+ 4. Enter the app name and choose the workspace
358
+ 5. Open `OAuth & Permissions`
359
+ 6. Under `Bot Token Scopes`, add `chat:write`
360
+ 7. Optional: add `chat:write.public`
361
+ 8. Click `Install to Workspace`
362
+ 9. Copy the `Bot User OAuth Access Token` (`xoxb-...`)
363
+ 10. Use it in `slackBotConfig({ botToken: "xoxb-..." })` or `SLACK_BOT_TOKEN`
364
+
365
+ ### Methods
366
+
367
+ ```
368
+ slackbot.log(label, data, channelId?);
369
+ slackbot.logBlockMessage(label, payload, errorType?, channelId?);
370
+ slackbot.rawBody(payload, channelId?);
371
+ ```
372
+
373
+ ### `slackbot.log(...)`
374
+
375
+ `slackbot.log(...)` uses the same payload format as `slack.log(...)`, so the output style is the same.
376
+
377
+ ```
378
+ import { slackbot } from "slack-logs";
379
+
380
+ slackbot.log("Data Log with bold", "Here is *BOLD* message", "C0123456789");
381
+ slackbot.log("Highlight Log", "`Message`", "C0123456789");
382
+ slackbot.log("Emoji :rocket: Log", "Yeah :female-technologist::skin-tone-2:");
383
+ slackbot.log("Object Log", {id:"123", value:"Lorem Impulse"});
384
+ ```
385
+
386
+ ![Sample Image](https://i.imgur.com/ucAnAiJ.png)
387
+
388
+ ### `slackbot.logBlockMessage(...)`
389
+
390
+ `slackbot.logBlockMessage(...)` uses the same payload format as `slack.logBlockMessage(...)`, so the same output examples apply.
391
+
392
+ ```
393
+ import { LogLevel, slackbot } from "slack-logs";
394
+
395
+ const payload = [
396
+ { title: "Title 1", value: "1234" },
397
+ { title: "Title 2", value: 123 },
398
+ { title: "Title 3", value: { id: 12 } },
399
+ { title: "Title 4", value: [{ id: 12 }] },
400
+ ];
401
+
402
+ slackbot.logBlockMessage("Custom Logs!", payload, LogLevel.DEFAULT, "C0123456789");
403
+ slackbot.logBlockMessage("Some Information Logs!", payload, LogLevel.INFO);
404
+ slackbot.logBlockMessage("Critical Alert!", payload, LogLevel.ERROR);
405
+ ```
406
+
407
+ ![Sample Image](https://i.imgur.com/Ohlktzr.png)
408
+
409
+ ### `slackbot.rawBody(...)`
410
+
411
+ Use `slackbot.rawBody(...)` when you want to send a custom Slack payload with an optional `channelId`.
412
+
413
+ ```
414
+ import { slackbot } from "slack-logs";
415
+
416
+ const payload = {
417
+ blocks: [
418
+ {
419
+ type: "section",
420
+ text: {
421
+ type: "mrkdwn",
422
+ text: "Hello from custom payload",
423
+ },
424
+ },
425
+ {
426
+ type: "divider",
427
+ },
428
+ {
429
+ type: "actions",
430
+ elements: [
431
+ {
432
+ type: "button",
433
+ text: {
434
+ type: "plain_text",
435
+ text: "Open",
436
+ emoji: true,
437
+ },
438
+ value: "click_me_123",
439
+ url: "https://google.com",
440
+ },
441
+ ],
442
+ },
443
+ ],
444
+ };
445
+
446
+ slackbot.rawBody(payload, "C0123456789");
447
+ ```
448
+
449
+ `slackbot.rawBody(...)` expects a plain object payload like:
450
+
451
+ ```
452
+ {
453
+ "blocks": [...]
454
+ }
455
+ ```
456
+
457
+ If payload is invalid or sending fails, it logs a console error.
package/dist/index.d.ts CHANGED
@@ -1,30 +1,13 @@
1
+ import type { BlocksInterface, LogLevel } from "./shared";
1
2
  interface Slack {
2
3
  log(label: string, data: any): Promise<null | undefined>;
3
- logBlockMessage(label: string, objectData: BlocksInterface[], error_type?: LogLevel): Promise<null | undefined>;
4
+ logBlockMessage(label: string, objectData: BlocksInterface[], errorType?: LogLevel): Promise<null | undefined>;
4
5
  rawBody(payload: Record<string, any>): Promise<null | undefined>;
5
6
  }
6
- export interface SlackLogConfigOptions {
7
- webhookUrl: string;
8
- enableAlerts: boolean;
9
- }
10
- interface BlocksInterface {
11
- title: string;
12
- value: any;
13
- }
14
- export declare enum LogLevel {
15
- DEFAULT = "DEFAULT",
16
- SUCCESS = "SUCCESS",
17
- INFO = "INFO",
18
- WARN = "WARN",
19
- ERROR = "ERROR"
20
- }
21
- export declare enum LogColor {
22
- DEFAULT = "#B4B4B8",
23
- SUCCESS = "#65B741",
24
- INFO = "#40A2D8",
25
- WARN = "#E3651D",
26
- ERROR = "#FF0000"
27
- }
28
- export declare function slackLogConfig(config: SlackLogConfigOptions): void;
7
+ export type { SlackBotConfigOptions } from "./slack-bot";
8
+ export { slackBotConfig, slackbot } from "./slack-bot";
9
+ export type { BlocksInterface } from "./shared";
10
+ export { LogColor, LogLevel } from "./shared";
11
+ export type { SlackLogConfigOptions } from "./webhook";
12
+ export { slackLogConfig } from "./webhook";
29
13
  export declare const slack: Slack;
30
- export {};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}Object.defineProperty(exports,"__esModule",{value:!0});var o,t,r=e(require("axios"));exports.LogLevel=void 0,(o=exports.LogLevel||(exports.LogLevel={})).DEFAULT="DEFAULT",o.SUCCESS="SUCCESS",o.INFO="INFO",o.WARN="WARN",o.ERROR="ERROR",exports.LogColor=void 0,(t=exports.LogColor||(exports.LogColor={})).DEFAULT="#B4B4B8",t.SUCCESS="#65B741",t.INFO="#40A2D8",t.WARN="#E3651D",t.ERROR="#FF0000";const n={};const s={async log(e,o){const t=JSON.stringify(o);if(!l())return console.error("🚨 Invalid Slack webhook URL. Kindly check slackLogConfig(...) or 'SLACK_WEBHOOK_URL' in your .env file! 🚨"),null;let r={text:`*${e}:* ${t}`};await c(r)},async logBlockMessage(e,o,t=exports.LogLevel.DEFAULT){if(!l())return console.error("🚨 Invalid Slack webhook URL. Kindly check slackLogConfig(...) or 'SLACK_WEBHOOK_URL' in your .env file! 🚨"),null;const r=exports.LogColor[t],n=[],s=[],a=[];n.push({type:"divider"}),n.push({type:"header",text:{type:"plain_text",text:e,emoji:!0}}),n.push({type:"divider"}),o?.length&&o.forEach((e=>{let o=JSON.stringify(e.value);a.push({type:"section",text:{type:"mrkdwn",text:`*${e.title}:* ${o}`}})})),s.push({color:r,blocks:a});let i={text:e,blocks:n,attachments:s};await c(i)},rawBody:async e=>l()?function(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}(e)?void await c(e):(console.error('🚨 Invalid Slack payload for rawBody(...). Expected an object like { "blocks": [...] } 🚨'),null):(console.error("🚨 Invalid Slack webhook URL. Kindly check slackLogConfig(...) or 'SLACK_WEBHOOK_URL' in your .env file! 🚨"),null)};function l(){const e=a();if(!e)return!1;return!!/^https:\/\/hooks\.slack\.com\/services\/[A-Za-z0-9]+\/[A-Za-z0-9]+\/[A-Za-z0-9]+$/.test(e)||(console.error(`🚨 Slack webhook URL does not look in correct format. Current value is "${e}", expected format is "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX". 🚨`),!1)}function a(){return n.webhookUrl??process.env.SLACK_WEBHOOK_URL}async function c(e){if(!function(){if("boolean"==typeof n.enableAlerts)return n.enableAlerts;const e=(process?.env?.ENABLE_SLACK_LOGS??"").toString().trim();return!e||"true"===e.toLowerCase()||(e.toLowerCase(),!1)}())return null;const o=a();return await r.default.post(o,JSON.stringify(e),{headers:{"Content-Type":"application/json"}}).catch((e=>{const o=e?.response?.data?.error||e?.response?.statusText||e?.message||"Unknown error";console.error(`🚨 Error sending log message to Slack: ${o}`)}))}exports.slack=s,exports.slackLogConfig=function(e){n.webhookUrl=e.webhookUrl,n.enableAlerts=e.enableAlerts};
1
+ "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}Object.defineProperty(exports,"__esModule",{value:!0});var o,t,n=e(require("axios"));exports.LogLevel=void 0,(o=exports.LogLevel||(exports.LogLevel={})).DEFAULT="DEFAULT",o.SUCCESS="SUCCESS",o.INFO="INFO",o.WARN="WARN",o.ERROR="ERROR",exports.LogColor=void 0,(t=exports.LogColor||(exports.LogColor={})).DEFAULT="#B4B4B8",t.SUCCESS="#65B741",t.INFO="#40A2D8",t.WARN="#E3651D",t.ERROR="#FF0000";const r={};function s(){const e=l();if(!e)return!1;return!!/^https:\/\/hooks\.slack\.com\/services\/[A-Za-z0-9]+\/[A-Za-z0-9]+\/[A-Za-z0-9]+$/.test(e)||(console.error(`🚨 Slack webhook URL does not look in correct format. Current value is "${e}", expected format is "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX". 🚨`),!1)}function l(){return r.webhookUrl??process.env.SLACK_WEBHOOK_URL}async function a(e){if(!function(){if("boolean"==typeof r.enableAlerts)return r.enableAlerts;const e=(process?.env?.ENABLE_SLACK_LOGS??"").toString().trim();return!e||"true"===e.toLowerCase()||(e.toLowerCase(),!1)}())return null;const o=l();await n.default.post(o,JSON.stringify(e),{headers:{"Content-Type":"application/json"}}).catch((e=>{const o=e?.response?.data?.error||e?.response?.statusText||e?.message||"Unknown error";console.error(`🚨 Error sending log message to Slack: ${o}`)}))}const c={};const i={log:async(e,o,t)=>(await p(function(e,o){return{text:`*${e}:* ${JSON.stringify(o)}`}}(e,o),t),null),logBlockMessage:async(e,o,t=exports.LogLevel.DEFAULT,n)=>(await p(function(e,o,t=exports.LogLevel.DEFAULT){const n=[];return o?.length&&o.forEach((e=>{n.push({type:"section",text:{type:"mrkdwn",text:`*${e.title}:* ${JSON.stringify(e.value)}`}})})),{text:e,blocks:[{type:"divider"},{type:"header",text:{type:"plain_text",text:e,emoji:!0}},{type:"divider"}],attachments:[{color:exports.LogColor[t],blocks:n}]}}(e,o,t),n),null),rawBody:async(e,o)=>function(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}(e)?(await p(e,o),null):(console.error('🚨 Invalid Slack payload for slackbot.rawBody(...). Expected an object like { "blocks": [...] } 🚨'),null)};function u(e,o){const t=("string"==typeof e.channel?e.channel:void 0)??o??c.defaultChannelId??process.env.SLACK_BOT_DEFAULT_CHANNEL_ID;return function(e){return!!e&&/^[CGD][A-Z0-9]+$/.test(e)}(t)?t:(console.error("🚨 Invalid Slack channel ID. Kindly pass a valid channelId or set 'defaultChannelId' in slackBotConfig(...) / 'SLACK_BOT_DEFAULT_CHANNEL_ID' in your .env file! 🚨"),null)}async function p(e,o){if(!function(){if("boolean"==typeof c.enableAlerts)return c.enableAlerts;const e=(process?.env?.ENABLE_SLACK_BOT_LOGS??process?.env?.ENABLE_SLACK_LOGS??"").toString().trim();return!e||"true"===e.toLowerCase()||(e.toLowerCase(),!1)}())return null;const t=c.botToken??process.env.SLACK_BOT_TOKEN;if(!function(e){return!!e&&/^xoxb-[A-Za-z0-9-]+$/.test(e)}(t))return console.error("🚨 Invalid Slack bot token. Kindly check slackBotConfig(...) or 'SLACK_BOT_TOKEN' in your .env file! 🚨"),null;const r=u(e,o);return r?await n.default.post("https://slack.com/api/chat.postMessage",{...e,channel:r},{headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json; charset=utf-8"}}).then((e=>{e?.data?.ok||console.error(`🚨 Error sending bot message to Slack: ${e?.data?.error||"Unknown error"}`)})).catch((e=>{const o=e?.response?.data?.error||e?.response?.statusText||e?.message||"Unknown error";console.error(`🚨 Error sending bot message to Slack: ${o}`)})):null}const d={...{async log(e,o){const t=JSON.stringify(o);if(!s())return console.error("🚨 Invalid Slack webhook URL. Kindly check slackLogConfig(...) or 'SLACK_WEBHOOK_URL' in your .env file! 🚨"),null;const n={text:`*${e}:* ${t}`};await a(n)},async logBlockMessage(e,o,t=exports.LogLevel.DEFAULT){if(!s())return console.error("🚨 Invalid Slack webhook URL. Kindly check slackLogConfig(...) or 'SLACK_WEBHOOK_URL' in your .env file! 🚨"),null;const n=exports.LogColor[t],r=[],l=[],c=[];r.push({type:"divider"}),r.push({type:"header",text:{type:"plain_text",text:e,emoji:!0}}),r.push({type:"divider"}),o?.length&&o.forEach((e=>{const o=JSON.stringify(e.value);c.push({type:"section",text:{type:"mrkdwn",text:`*${e.title}:* ${o}`}})})),l.push({color:n,blocks:c});const i={text:e,blocks:r,attachments:l};await a(i)},rawBody:async e=>s()?function(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}(e)?void await a(e):(console.error('🚨 Invalid Slack payload for rawBody(...). Expected an object like { "blocks": [...] } 🚨'),null):(console.error("🚨 Invalid Slack webhook URL. Kindly check slackLogConfig(...) or 'SLACK_WEBHOOK_URL' in your .env file! 🚨"),null)}};exports.slack=d,exports.slackBotConfig=function(e){c.botToken=e.botToken,c.defaultChannelId=e.defaultChannelId,c.enableAlerts=e.enableAlerts},exports.slackLogConfig=function(e){r.webhookUrl=e.webhookUrl,r.enableAlerts=e.enableAlerts},exports.slackbot=i;
@@ -0,0 +1,40 @@
1
+ export interface BlocksInterface {
2
+ title: string;
3
+ value: any;
4
+ }
5
+ export declare enum LogLevel {
6
+ DEFAULT = "DEFAULT",
7
+ SUCCESS = "SUCCESS",
8
+ INFO = "INFO",
9
+ WARN = "WARN",
10
+ ERROR = "ERROR"
11
+ }
12
+ export declare enum LogColor {
13
+ DEFAULT = "#B4B4B8",
14
+ SUCCESS = "#65B741",
15
+ INFO = "#40A2D8",
16
+ WARN = "#E3651D",
17
+ ERROR = "#FF0000"
18
+ }
19
+ export declare function buildLogPayload(label: string, data: any): {
20
+ text: string;
21
+ };
22
+ export declare function buildLogBlockPayload(label: string, objectData: BlocksInterface[], errorType?: LogLevel): {
23
+ text: string;
24
+ blocks: ({
25
+ type: string;
26
+ text?: undefined;
27
+ } | {
28
+ type: string;
29
+ text: {
30
+ type: string;
31
+ text: string;
32
+ emoji: boolean;
33
+ };
34
+ })[];
35
+ attachments: {
36
+ color: LogColor;
37
+ blocks: object[];
38
+ }[];
39
+ };
40
+ export declare function isValidRawPayload(payload: Record<string, any>): boolean;
@@ -0,0 +1,15 @@
1
+ import type { BlocksInterface } from "./shared";
2
+ import { LogLevel } from "./shared";
3
+ export interface SlackBotConfigOptions {
4
+ botToken: string;
5
+ defaultChannelId?: string;
6
+ enableAlerts: boolean;
7
+ }
8
+ interface SlackBot {
9
+ log(label: string, data: any, channelId?: string): Promise<null | undefined>;
10
+ logBlockMessage(label: string, objectData: BlocksInterface[], errorType?: LogLevel, channelId?: string): Promise<null | undefined>;
11
+ rawBody(payload: Record<string, any>, channelId?: string): Promise<null | undefined>;
12
+ }
13
+ export declare function slackBotConfig(config: SlackBotConfigOptions): void;
14
+ export declare const slackbot: SlackBot;
15
+ export {};
@@ -0,0 +1,12 @@
1
+ import { LogLevel } from "./shared";
2
+ import type { BlocksInterface } from "./shared";
3
+ export interface SlackLogConfigOptions {
4
+ webhookUrl: string;
5
+ enableAlerts: boolean;
6
+ }
7
+ export declare function slackLogConfig(config: SlackLogConfigOptions): void;
8
+ export declare const slackWebhook: {
9
+ log(label: string, data: any): Promise<null | undefined>;
10
+ logBlockMessage(label: string, objectData: BlocksInterface[], errorType?: LogLevel): Promise<null | undefined>;
11
+ rawBody(payload: Record<string, any>): Promise<null | undefined>;
12
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slack-logs",
3
- "version": "3.0.3",
3
+ "version": "3.0.5",
4
4
  "description": "slack-logs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",