@goniglep57/node 1.0.0 → 1.0.1

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 (3) hide show
  1. package/index.js +1 -0
  2. package/package.json +1 -1
  3. package/slack.js +184 -0
package/index.js CHANGED
@@ -4,4 +4,5 @@ exports.dropbox = require('./dropbox.js')
4
4
  exports.ncrypt = require('./ncrypt.js')
5
5
  exports.secret = require('./secret.js')
6
6
  exports.server = require('./server.js')
7
+ exports.slack = require('./slack.js')
7
8
  exports.util = require('./util.js')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goniglep57/node",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "A package full of utility functions",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/slack.js ADDED
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Slack notification module for error alerting across all services
3
+ *
4
+ * Usage:
5
+ * const { slack } = require('@goniglep57/node')
6
+ *
7
+ * // Configure once at startup
8
+ * slack.configure({
9
+ * webhookUrl: process.env.SLACK_ERROR_WEBHOOK,
10
+ * serviceName: 'tonomo-front-end',
11
+ * environment: process.env.NODE_ENV || 'development'
12
+ * })
13
+ *
14
+ * // Send error notifications
15
+ * await slack.error('Database connection failed', { userId: 123 })
16
+ * await slack.warn('Rate limit approaching', { current: 90, max: 100 })
17
+ * await slack.info('Deployment complete')
18
+ */
19
+
20
+ let config = null
21
+
22
+ /**
23
+ * Configure the Slack module
24
+ * @param {Object} options
25
+ * @param {string} options.webhookUrl - Slack incoming webhook URL
26
+ * @param {string} options.serviceName - Name of the service (e.g., 'tonomo-front-end')
27
+ * @param {string} [options.environment='production'] - Environment name
28
+ */
29
+ const configure = (options) => {
30
+ const { webhookUrl, serviceName, environment = 'production' } = options
31
+
32
+ if (!webhookUrl) {
33
+ console.warn('[slack] No webhook URL provided, notifications will be disabled')
34
+ config = null
35
+ return { configured: false }
36
+ }
37
+
38
+ if (!serviceName) {
39
+ throw new Error('slack.configure requires serviceName')
40
+ }
41
+
42
+ config = {
43
+ webhookUrl,
44
+ serviceName,
45
+ environment
46
+ }
47
+
48
+ return { configured: true }
49
+ }
50
+
51
+ /**
52
+ * Check if Slack is configured
53
+ */
54
+ const isConfigured = () => config !== null
55
+
56
+ /**
57
+ * Send a notification to Slack
58
+ * @param {string} level - 'error', 'warn', or 'info'
59
+ * @param {string} message - The message
60
+ * @param {Object} [context={}] - Additional context
61
+ */
62
+ const send = async (level, message, context = {}) => {
63
+ if (!config) {
64
+ return { sent: false, reason: 'not configured' }
65
+ }
66
+
67
+ const emoji = {
68
+ error: '🚨',
69
+ warn: 'âš ī¸',
70
+ info: 'â„šī¸'
71
+ }[level] || 'đŸ“ĸ'
72
+
73
+ const color = {
74
+ error: '#dc3545',
75
+ warn: '#ffc107',
76
+ info: '#17a2b8'
77
+ }[level] || '#6c757d'
78
+
79
+ try {
80
+ const contextLines = Object.entries(context)
81
+ .filter(([_, v]) => v !== undefined && v !== null)
82
+ .map(([key, value]) => {
83
+ const displayValue = typeof value === 'object'
84
+ ? JSON.stringify(value).substring(0, 200)
85
+ : String(value).substring(0, 200)
86
+ return `â€ĸ *${key}:* ${displayValue}`
87
+ })
88
+ .join('\n')
89
+
90
+ const payload = {
91
+ attachments: [
92
+ {
93
+ color,
94
+ blocks: [
95
+ {
96
+ type: 'header',
97
+ text: {
98
+ type: 'plain_text',
99
+ text: `${emoji} ${config.serviceName} - ${level.toUpperCase()}`,
100
+ emoji: true
101
+ }
102
+ },
103
+ {
104
+ type: 'section',
105
+ text: {
106
+ type: 'mrkdwn',
107
+ text: `*Message:*\n${message}`
108
+ }
109
+ }
110
+ ]
111
+ }
112
+ ]
113
+ }
114
+
115
+ if (contextLines) {
116
+ payload.attachments[0].blocks.push({
117
+ type: 'section',
118
+ text: {
119
+ type: 'mrkdwn',
120
+ text: `*Context:*\n${contextLines}`
121
+ }
122
+ })
123
+ }
124
+
125
+ payload.attachments[0].blocks.push({
126
+ type: 'context',
127
+ elements: [
128
+ {
129
+ type: 'mrkdwn',
130
+ text: `🌍 ${config.environment} | ⏰ ${new Date().toISOString()}`
131
+ }
132
+ ]
133
+ })
134
+
135
+ const response = await fetch(config.webhookUrl, {
136
+ method: 'POST',
137
+ headers: { 'Content-Type': 'application/json' },
138
+ body: JSON.stringify(payload)
139
+ })
140
+
141
+ if (!response.ok) {
142
+ console.error('[slack] Failed to send notification:', response.status)
143
+ return { sent: false, reason: `HTTP ${response.status}` }
144
+ }
145
+
146
+ return { sent: true }
147
+ } catch (err) {
148
+ // Don't let Slack errors break the main flow
149
+ console.error('[slack] Error sending notification:', err.message)
150
+ return { sent: false, reason: err.message }
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Send an error notification
156
+ */
157
+ const error = (message, context = {}) => send('error', message, context)
158
+
159
+ /**
160
+ * Send a warning notification
161
+ */
162
+ const warn = (message, context = {}) => send('warn', message, context)
163
+
164
+ /**
165
+ * Send an info notification
166
+ */
167
+ const info = (message, context = {}) => send('info', message, context)
168
+
169
+ /**
170
+ * Reset configuration (useful for testing)
171
+ */
172
+ const reset = () => {
173
+ config = null
174
+ }
175
+
176
+ module.exports = {
177
+ configure,
178
+ isConfigured,
179
+ send,
180
+ error,
181
+ warn,
182
+ info,
183
+ reset
184
+ }