1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.slackDefaultMessagePrefixHook = exports.SlackService = void 0;
|
4 | const time_lib_1 = require("@naturalcycles/time-lib");
|
5 | const got_1 = require("got");
|
6 | const __1 = require("..");
|
7 | const GAE = !!process.env['GAE_INSTANCE'];
|
8 | const DEFAULTS = () => ({
|
9 | username: 'bot',
|
10 | channel: '#log',
|
11 | icon_emoji: ':spider_web:',
|
12 | items: 'no text',
|
13 | });
|
14 | const INSPECT_OPT = {
|
15 | colors: false,
|
16 | includeErrorData: true,
|
17 | includeErrorStack: true,
|
18 | };
|
19 | const log = (0, __1.Debug)('nc:nodejs-lib:slack');
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | class SlackService {
|
33 | constructor(cfg) {
|
34 | this.cfg = {
|
35 | messagePrefixHook: slackDefaultMessagePrefixHook,
|
36 | ...cfg,
|
37 | };
|
38 | }
|
39 | |
40 |
|
41 |
|
42 | async log(...items) {
|
43 | await this.send({
|
44 |
|
45 | items: items.length === 1 ? items[0] : items,
|
46 | });
|
47 | }
|
48 | async send(msg, ctx) {
|
49 | const { webhookUrl, messagePrefixHook } = this.cfg;
|
50 |
|
51 | if (typeof msg === 'string') {
|
52 | msg = {
|
53 | items: msg,
|
54 | };
|
55 | }
|
56 | if (ctx !== undefined) {
|
57 | Object.assign(msg, { ctx });
|
58 | }
|
59 | if (!msg.noLog) {
|
60 | log[msg.level || __1.DebugLogLevel.info](...[msg.items, msg.kv, msg.attachments, msg.mentions].filter(Boolean));
|
61 | }
|
62 | if (!webhookUrl)
|
63 | return;
|
64 |
|
65 | if (msg.kv) {
|
66 | msg.attachments = [...(msg.attachments || []), { fields: this.kvToFields(msg.kv) }];
|
67 | delete msg.kv;
|
68 | }
|
69 | let text;
|
70 | const inspectOpt = {
|
71 | ...INSPECT_OPT,
|
72 | ...msg.inspectOptions,
|
73 | };
|
74 |
|
75 | if (Array.isArray(msg.items)) {
|
76 | text = msg.items.map(t => (0, __1.inspectAny)(t, inspectOpt)).join('\n');
|
77 | }
|
78 | else {
|
79 | text = (0, __1.inspectAny)(msg.items, inspectOpt);
|
80 | }
|
81 |
|
82 | if (typeof msg.items !== 'string') {
|
83 | text = '```' + text + '```';
|
84 | }
|
85 | if (msg.mentions?.length) {
|
86 | text += '\n' + msg.mentions.map(s => `<@${s}>`).join(' ');
|
87 | }
|
88 | const prefix = await messagePrefixHook(msg);
|
89 | if (prefix === null)
|
90 | return;
|
91 | const json = {
|
92 | ...DEFAULTS(),
|
93 | ...this.cfg.defaults,
|
94 | ...msg,
|
95 |
|
96 | text: [prefix.join(': '), text].filter(Boolean).join('\n'),
|
97 | };
|
98 |
|
99 | delete json['items'];
|
100 | delete json['ctx'];
|
101 | delete json['noLog'];
|
102 | json.channel = (this.cfg.channelByLevel || {})[msg.level] || json.channel;
|
103 | await got_1.default
|
104 | .post(webhookUrl, {
|
105 | json,
|
106 | responseType: 'text',
|
107 | })
|
108 | .catch(err => {
|
109 |
|
110 | if (msg.throwOnError)
|
111 | throw err;
|
112 | });
|
113 | }
|
114 | kvToFields(kv) {
|
115 | return Object.entries(kv).map(([k, v]) => ({
|
116 | title: k,
|
117 | value: String(v),
|
118 | short: String(v).length < 80,
|
119 | }));
|
120 | }
|
121 | }
|
122 | exports.SlackService = SlackService;
|
123 | function slackDefaultMessagePrefixHook(msg) {
|
124 | const tokens = [(0, time_lib_1.dayjs)().toPretty()];
|
125 | const { ctx } = msg;
|
126 |
|
127 | if (GAE && ctx && typeof ctx === 'object' && typeof ctx.header === 'function') {
|
128 | tokens.push(ctx.header('x-appengine-country'), ctx.header('x-appengine-city'));
|
129 | }
|
130 | return tokens.filter(Boolean);
|
131 | }
|
132 | exports.slackDefaultMessagePrefixHook = slackDefaultMessagePrefixHook;
|