strapi-plugin-magic-mail 2.1.0 → 2.2.2

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.1.0",
2
+ "version": "2.2.2",
3
3
  "keywords": [
4
4
  "strapi",
5
5
  "strapi-plugin",
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { createLogger } = require('./utils/logger');
4
+
3
5
  /**
4
6
  * Bootstrap: Initialize MagicMail plugin
5
7
  * Sets up email account counter resets and health checks
@@ -7,7 +9,9 @@
7
9
  */
8
10
 
9
11
  module.exports = async ({ strapi }) => {
10
- strapi.log.info('[BOOTSTRAP] [magic-mail] Starting...');
12
+ const log = createLogger(strapi);
13
+
14
+ log.info('[BOOTSTRAP] Starting...');
11
15
 
12
16
  try {
13
17
  // Initialize License Guard
@@ -18,17 +22,17 @@ module.exports = async ({ strapi }) => {
18
22
  const licenseStatus = await licenseGuardService.initialize();
19
23
 
20
24
  if (!licenseStatus.valid && licenseStatus.demo) {
21
- strapi.log.error('╔════════════════════════════════════════════════════════════════╗');
22
- strapi.log.error('║ [ERROR] MAGICMAIL - NO VALID LICENSE ║');
23
- strapi.log.error('║ ║');
24
- strapi.log.error('║ This plugin requires a valid license to operate. ║');
25
- strapi.log.error('║ Please activate your license via Admin UI: ║');
26
- strapi.log.error('║ Go to MagicMail → License tab ║');
27
- strapi.log.error('║ ║');
28
- strapi.log.error('║ Click "Generate Free License" to get started! ║');
29
- strapi.log.error('╚════════════════════════════════════════════════════════════════╝');
25
+ log.error('╔════════════════════════════════════════════════════════════════╗');
26
+ log.error('║ [ERROR] MAGICMAIL - NO VALID LICENSE ║');
27
+ log.error('║ ║');
28
+ log.error('║ This plugin requires a valid license to operate. ║');
29
+ log.error('║ Please activate your license via Admin UI: ║');
30
+ log.error('║ Go to MagicMail → License tab ║');
31
+ log.error('║ ║');
32
+ log.error('║ Click "Generate Free License" to get started! ║');
33
+ log.error('╚════════════════════════════════════════════════════════════════╝');
30
34
  } else if (licenseStatus.gracePeriod) {
31
- strapi.log.warn('[WARNING] Running on grace period (license server unreachable)');
35
+ log.warn('[WARNING] Running on grace period (license server unreachable)');
32
36
  }
33
37
  // No additional log here, as initialize() already outputs the license box
34
38
  }, 2000);
@@ -49,8 +53,8 @@ module.exports = async ({ strapi }) => {
49
53
 
50
54
  // Override the send method
51
55
  originalEmailService.send = async (emailData) => {
52
- strapi.log.info('[magic-mail] [EMAIL] Intercepted from native Strapi service');
53
- strapi.log.debug('[magic-mail] Email data:', {
56
+ log.info('[EMAIL] Intercepted from native Strapi service');
57
+ log.debug('Email data:', {
54
58
  to: emailData.to,
55
59
  subject: emailData.subject,
56
60
  templateId: emailData.templateId,
@@ -67,22 +71,22 @@ module.exports = async ({ strapi }) => {
67
71
  // Route through MagicMail
68
72
  const result = await emailRouter.send(emailData);
69
73
 
70
- strapi.log.info('[magic-mail] [SUCCESS] Email routed successfully through MagicMail');
74
+ log.info('[SUCCESS] Email routed successfully through MagicMail');
71
75
  return result;
72
76
  } catch (magicMailError) {
73
- strapi.log.warn('[magic-mail] [WARNING] MagicMail routing failed, falling back to original service');
74
- strapi.log.error('[magic-mail] Error:', magicMailError.message);
77
+ log.warn('[WARNING] MagicMail routing failed, falling back to original service');
78
+ log.error('Error:', magicMailError.message);
75
79
 
76
80
  // Fallback to original Strapi email service
77
81
  return await originalSend(emailData);
78
82
  }
79
83
  };
80
84
 
81
- strapi.log.info('[magic-mail] [SUCCESS] Native email service overridden!');
82
- strapi.log.info('[magic-mail] [INFO] All strapi.plugins.email.services.email.send() calls will route through MagicMail');
85
+ log.info('[SUCCESS] Native email service overridden!');
86
+ log.info('[INFO] All strapi.plugins.email.services.email.send() calls will route through MagicMail');
83
87
  } else {
84
- strapi.log.warn('[magic-mail] [WARNING] Native email service not found - MagicMail will work standalone');
85
- strapi.log.warn('[magic-mail] [INFO] Make sure @strapi/plugin-email is installed');
88
+ log.warn('[WARNING] Native email service not found - MagicMail will work standalone');
89
+ log.warn('[INFO] Make sure @strapi/plugin-email is installed');
86
90
  }
87
91
 
88
92
  // ============================================================
@@ -93,14 +97,14 @@ module.exports = async ({ strapi }) => {
93
97
  const hourlyResetInterval = setInterval(async () => {
94
98
  try {
95
99
  if (!strapi || !strapi.plugin) {
96
- console.warn('[magic-mail] Strapi not available for hourly reset');
100
+ console.warn('Strapi not available for hourly reset');
97
101
  return;
98
102
  }
99
103
  const accountMgr = strapi.plugin('magic-mail').service('account-manager');
100
104
  await accountMgr.resetCounters('hourly');
101
- strapi.log.info('[magic-mail] [RESET] Hourly counters reset');
105
+ log.info('[RESET] Hourly counters reset');
102
106
  } catch (err) {
103
- console.error('[magic-mail] Hourly reset error:', err.message);
107
+ console.error('Hourly reset error:', err.message);
104
108
  }
105
109
  }, 60 * 60 * 1000); // Every hour
106
110
 
@@ -116,38 +120,38 @@ module.exports = async ({ strapi }) => {
116
120
  setTimeout(async () => {
117
121
  try {
118
122
  if (!strapi || !strapi.plugin) {
119
- console.warn('[magic-mail] Strapi not available for daily reset');
123
+ console.warn('Strapi not available for daily reset');
120
124
  return;
121
125
  }
122
126
  const accountMgr = strapi.plugin('magic-mail').service('account-manager');
123
127
  await accountMgr.resetCounters('daily');
124
- strapi.log.info('[magic-mail] [RESET] Daily counters reset');
128
+ log.info('[RESET] Daily counters reset');
125
129
 
126
130
  // Then set daily interval
127
131
  const dailyResetInterval = setInterval(async () => {
128
132
  try {
129
133
  if (!strapi || !strapi.plugin) {
130
- console.warn('[magic-mail] Strapi not available for daily reset');
134
+ console.warn('Strapi not available for daily reset');
131
135
  return;
132
136
  }
133
137
  const accountMgr = strapi.plugin('magic-mail').service('account-manager');
134
138
  await accountMgr.resetCounters('daily');
135
- strapi.log.info('[magic-mail] [RESET] Daily counters reset');
139
+ log.info('[RESET] Daily counters reset');
136
140
  } catch (err) {
137
- console.error('[magic-mail] Daily reset error:', err.message);
141
+ console.error('Daily reset error:', err.message);
138
142
  }
139
143
  }, 24 * 60 * 60 * 1000); // Every 24 hours
140
144
 
141
145
  // Store interval for cleanup
142
146
  global.magicMailIntervals.daily = dailyResetInterval;
143
147
  } catch (err) {
144
- console.error('[magic-mail] Initial daily reset error:', err.message);
148
+ console.error('Initial daily reset error:', err.message);
145
149
  }
146
150
  }, msUntilMidnight);
147
151
 
148
- strapi.log.info('[magic-mail] [SUCCESS] Counter reset schedules initialized');
149
- strapi.log.info('[magic-mail] [SUCCESS] Bootstrap complete');
152
+ log.info('[SUCCESS] Counter reset schedules initialized');
153
+ log.info('[SUCCESS] Bootstrap complete');
150
154
  } catch (err) {
151
- strapi.log.error('[magic-mail] [ERROR] Bootstrap error:', err);
155
+ log.error('[ERROR] Bootstrap error:', err);
152
156
  }
153
157
  };
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  module.exports = {
4
- default: {},
4
+ default: {
5
+ // Enable debug logging (set to true to see all plugin logs)
6
+ debug: false,
7
+ },
5
8
  validator() {},
6
9
  };
@@ -1,23 +1,27 @@
1
1
  'use strict';
2
2
 
3
+ const { createLogger } = require('./utils/logger');
4
+
3
5
  module.exports = ({ strapi }) => {
6
+ const log = createLogger(strapi);
7
+
4
8
  // Cleanup intervals
5
9
  if (global.magicMailIntervals) {
6
10
  if (global.magicMailIntervals.hourly) {
7
11
  clearInterval(global.magicMailIntervals.hourly);
8
- strapi.log.info('[magic-mail] Cleared hourly reset interval');
12
+ log.info('Cleared hourly reset interval');
9
13
  }
10
14
  if (global.magicMailIntervals.daily) {
11
15
  clearInterval(global.magicMailIntervals.daily);
12
- strapi.log.info('[magic-mail] Cleared daily reset interval');
16
+ log.info('Cleared daily reset interval');
13
17
  }
14
18
  }
15
19
 
16
20
  // Cleanup license guard ping interval
17
21
  if (strapi.licenseGuardMagicMail && strapi.licenseGuardMagicMail.pingInterval) {
18
22
  clearInterval(strapi.licenseGuardMagicMail.pingInterval);
19
- strapi.log.info('[magic-mail] Cleared license ping interval');
23
+ log.info('Cleared license ping interval');
20
24
  }
21
25
 
22
- strapi.log.info('[magic-mail] 👋 Plugin destroyed gracefully');
26
+ log.info('👋 Plugin destroyed gracefully');
23
27
  };
@@ -6,11 +6,15 @@
6
6
  const crypto = require('crypto');
7
7
  const os = require('os');
8
8
  const pluginPkg = require('../../../package.json');
9
+ const { createLogger } = require('../utils/logger');
9
10
 
10
11
  // FIXED LICENSE SERVER URL
11
12
  const LICENSE_SERVER_URL = 'https://magicapi.fitlex.me';
12
13
 
13
- module.exports = ({ strapi }) => ({
14
+ module.exports = ({ strapi }) => {
15
+ const log = createLogger(strapi);
16
+
17
+ return {
14
18
  /**
15
19
  * Get license server URL
16
20
  */
@@ -101,14 +105,14 @@ module.exports = ({ strapi }) => ({
101
105
  const data = await response.json();
102
106
 
103
107
  if (data.success) {
104
- strapi.log.info('[magic-mail] [SUCCESS] License created:', data.data.licenseKey);
108
+ log.info('[SUCCESS] License created:', data.data.licenseKey);
105
109
  return data.data;
106
110
  } else {
107
- strapi.log.error('[magic-mail] [ERROR] License creation failed:', data);
111
+ log.error('[ERROR] License creation failed:', data);
108
112
  return null;
109
113
  }
110
114
  } catch (error) {
111
- strapi.log.error('[magic-mail] [ERROR] Error creating license:', error);
115
+ log.error('[ERROR] Error creating license:', error);
112
116
  return null;
113
117
  }
114
118
  },
@@ -140,10 +144,10 @@ module.exports = ({ strapi }) => ({
140
144
  }
141
145
  } catch (error) {
142
146
  if (allowGracePeriod) {
143
- strapi.log.warn('[magic-mail] [WARNING] License verification timeout - grace period active');
147
+ log.warn('[WARNING] License verification timeout - grace period active');
144
148
  return { valid: true, data: null, gracePeriod: true };
145
149
  }
146
- strapi.log.error('[magic-mail] [ERROR] License verification error:', error.message);
150
+ log.error('[ERROR] License verification error:', error.message);
147
151
  return { valid: false, data: null };
148
152
  }
149
153
  },
@@ -166,7 +170,7 @@ module.exports = ({ strapi }) => ({
166
170
 
167
171
  return null;
168
172
  } catch (error) {
169
- strapi.log.error('[magic-mail] Error fetching license by key:', error);
173
+ log.error('Error fetching license by key:', error);
170
174
  return null;
171
175
  }
172
176
  },
@@ -206,7 +210,7 @@ module.exports = ({ strapi }) => ({
206
210
  name: 'magic-mail'
207
211
  });
208
212
  await pluginStore.set({ key: 'licenseKey', value: licenseKey });
209
- strapi.log.info(`[magic-mail] [SUCCESS] License key stored: ${licenseKey.substring(0, 8)}...`);
213
+ log.info(`[SUCCESS] License key stored: ${licenseKey.substring(0, 8)}...`);
210
214
  },
211
215
 
212
216
  startPinging(licenseKey, intervalMinutes = 15) {
@@ -217,7 +221,7 @@ module.exports = ({ strapi }) => ({
217
221
  try {
218
222
  await this.pingLicense(licenseKey);
219
223
  } catch (error) {
220
- console.error('[magic-mail] Ping error:', error);
224
+ console.error('Ping error:', error);
221
225
  }
222
226
  }, intervalMinutes * 60 * 1000);
223
227
 
@@ -242,7 +246,7 @@ module.exports = ({ strapi }) => ({
242
246
  const license = await this.getLicenseByKey(licenseKey);
243
247
  return license;
244
248
  } catch (error) {
245
- strapi.log.error(`[magic-mail] [ERROR] Error loading license:`, error);
249
+ log.error(`[ERROR] Error loading license:`, error);
246
250
  return null;
247
251
  }
248
252
  },
@@ -298,7 +302,7 @@ module.exports = ({ strapi }) => ({
298
302
  */
299
303
  async initialize() {
300
304
  try {
301
- strapi.log.info('[INIT] Initializing License Guard...');
305
+ log.info('[INIT] Initializing License Guard...');
302
306
 
303
307
  // Check if license key exists in plugin store
304
308
  const pluginStore = strapi.store({
@@ -319,26 +323,26 @@ module.exports = ({ strapi }) => ({
319
323
  withinGracePeriod = hoursSinceValidation < gracePeriodHours;
320
324
  }
321
325
 
322
- strapi.log.info('──────────────────────────────────────────────────────────');
323
- strapi.log.info(`📦 Plugin Store Check:`);
326
+ log.info('──────────────────────────────────────────────────────────');
327
+ log.info(`📦 Plugin Store Check:`);
324
328
  if (licenseKey) {
325
- strapi.log.info(` [SUCCESS] License Key found: ${licenseKey}`);
326
- strapi.log.info(` [LICENSE] Key (short): ${licenseKey.substring(0, 10)}...`);
329
+ log.info(` [SUCCESS] License Key found: ${licenseKey}`);
330
+ log.info(` [LICENSE] Key (short): ${licenseKey.substring(0, 10)}...`);
327
331
  if (lastValidated) {
328
332
  const lastValidatedDate = new Date(lastValidated);
329
333
  const hoursAgo = Math.floor((now.getTime() - lastValidatedDate.getTime()) / (1000 * 60 * 60));
330
- strapi.log.info(` [TIME] Last validated: ${hoursAgo}h ago (Grace: ${withinGracePeriod ? 'ACTIVE' : 'EXPIRED'})`);
334
+ log.info(` [TIME] Last validated: ${hoursAgo}h ago (Grace: ${withinGracePeriod ? 'ACTIVE' : 'EXPIRED'})`);
331
335
  } else {
332
- strapi.log.info(` [TIME] Last validated: Never (Grace: ACTIVE for first ${gracePeriodHours}h)`);
336
+ log.info(` [TIME] Last validated: Never (Grace: ACTIVE for first ${gracePeriodHours}h)`);
333
337
  }
334
338
  } else {
335
- strapi.log.info(` [ERROR] No license key stored`);
339
+ log.info(` [ERROR] No license key stored`);
336
340
  }
337
- strapi.log.info('──────────────────────────────────────────────────────────');
341
+ log.info('──────────────────────────────────────────────────────────');
338
342
 
339
343
  if (!licenseKey) {
340
- strapi.log.info('[DEMO] No license found - Running in demo mode');
341
- strapi.log.info('[INFO] Create a license in the admin panel to activate full features');
344
+ log.info('[DEMO] No license found - Running in demo mode');
345
+ log.info('[INFO] Create a license in the admin panel to activate full features');
342
346
  return {
343
347
  valid: false,
344
348
  demo: true,
@@ -346,7 +350,7 @@ module.exports = ({ strapi }) => ({
346
350
  };
347
351
  }
348
352
 
349
- strapi.log.info('[VERIFY] Verifying stored license key...');
353
+ log.info('[VERIFY] Verifying stored license key...');
350
354
 
351
355
  // Verify license (allow grace period if we have a last validation)
352
356
  const verification = await this.verifyLicense(licenseKey, withinGracePeriod);
@@ -355,7 +359,7 @@ module.exports = ({ strapi }) => ({
355
359
  // Get license details for display
356
360
  const license = await this.getLicenseByKey(licenseKey);
357
361
 
358
- strapi.log.info(`[SUCCESS] License verified online: ACTIVE (Key: ${licenseKey.substring(0, 10)}...)`);
362
+ log.info(`[SUCCESS] License verified online: ACTIVE (Key: ${licenseKey.substring(0, 10)}...)`);
359
363
 
360
364
  // Update last validated timestamp
361
365
  await pluginStore.set({
@@ -363,11 +367,11 @@ module.exports = ({ strapi }) => ({
363
367
  value: now.toISOString()
364
368
  });
365
369
 
366
- strapi.log.info('[SUCCESS] License is valid and active');
370
+ log.info('[SUCCESS] License is valid and active');
367
371
 
368
372
  // Start automatic pinging
369
373
  const pingInterval = this.startPinging(licenseKey, 15);
370
- strapi.log.info('[PING] Started pinging license every 15 minutes');
374
+ log.info('[PING] Started pinging license every 15 minutes');
371
375
 
372
376
  // Store interval globally so we can clean it up
373
377
  strapi.licenseGuardMagicMail = {
@@ -377,15 +381,15 @@ module.exports = ({ strapi }) => ({
377
381
  };
378
382
 
379
383
  // Display license info box
380
- strapi.log.info('╔════════════════════════════════════════════════════════════════╗');
381
- strapi.log.info('║ [SUCCESS] MAGIC MAIL PLUGIN LICENSE ACTIVE ║');
382
- strapi.log.info('║ ║');
383
- strapi.log.info(`║ License: ${licenseKey.padEnd(38, ' ')}║`);
384
- strapi.log.info(`║ User: ${(license?.firstName + ' ' + license?.lastName).padEnd(41, ' ')}║`);
385
- strapi.log.info(`║ Email: ${(license?.email || 'N/A').padEnd(40, ' ')}║`);
386
- strapi.log.info('║ ║');
387
- strapi.log.info('║ [AUTO] Pinging every 15 minutes ║');
388
- strapi.log.info('╚════════════════════════════════════════════════════════════════╝');
384
+ log.info('╔════════════════════════════════════════════════════════════════╗');
385
+ log.info('║ [SUCCESS] MAGIC MAIL PLUGIN LICENSE ACTIVE ║');
386
+ log.info('║ ║');
387
+ log.info(`║ License: ${licenseKey.padEnd(38, ' ')}║`);
388
+ log.info(`║ User: ${(license?.firstName + ' ' + license?.lastName).padEnd(41, ' ')}║`);
389
+ log.info(`║ Email: ${(license?.email || 'N/A').padEnd(40, ' ')}║`);
390
+ log.info('║ ║');
391
+ log.info('║ [AUTO] Pinging every 15 minutes ║');
392
+ log.info('╚════════════════════════════════════════════════════════════════╝');
389
393
 
390
394
  return {
391
395
  valid: true,
@@ -394,9 +398,9 @@ module.exports = ({ strapi }) => ({
394
398
  gracePeriod: verification.gracePeriod || false,
395
399
  };
396
400
  } else {
397
- strapi.log.error(`[ERROR] License validation failed (Key: ${licenseKey.substring(0, 10)}...)`);
398
- strapi.log.info('──────────────────────────────────────────────────────────');
399
- strapi.log.info('[WARNING] Running in demo mode with limited features');
401
+ log.error(`[ERROR] License validation failed (Key: ${licenseKey.substring(0, 10)}...)`);
402
+ log.info('──────────────────────────────────────────────────────────');
403
+ log.info('[WARNING] Running in demo mode with limited features');
400
404
  return {
401
405
  valid: false,
402
406
  demo: true,
@@ -405,7 +409,7 @@ module.exports = ({ strapi }) => ({
405
409
  };
406
410
  }
407
411
  } catch (error) {
408
- strapi.log.error('[ERROR] Error initializing License Guard:', error);
412
+ log.error('[ERROR] Error initializing License Guard:', error);
409
413
  return {
410
414
  valid: false,
411
415
  demo: true,
@@ -414,5 +418,6 @@ module.exports = ({ strapi }) => ({
414
418
  };
415
419
  }
416
420
  },
417
- });
421
+ };
422
+ };
418
423
 
@@ -0,0 +1,84 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Debug Logger Utility for magic-mail
5
+ * Only logs messages when debug: true in plugin config
6
+ * ALL logs (including errors/warnings) are hidden unless debug mode is enabled
7
+ */
8
+
9
+ const PLUGIN_NAME = 'magic-mail';
10
+ const PREFIX = '[magic-mail]';
11
+
12
+ /**
13
+ * Format message with prefix - returns a formatted string
14
+ */
15
+ function formatMessage(prefix, args) {
16
+ if (args.length === 0) return prefix;
17
+ const parts = args.map(arg =>
18
+ typeof arg === 'string' ? arg : JSON.stringify(arg)
19
+ );
20
+ return `${prefix} ${parts.join(' ')}`;
21
+ }
22
+
23
+ /**
24
+ * Creates a logger instance that respects debug config
25
+ * @param {object} strapi - Strapi instance
26
+ * @returns {object} Logger with info, debug, warn, error methods
27
+ */
28
+ function createLogger(strapi) {
29
+ const getDebugMode = () => {
30
+ try {
31
+ const config = strapi.config.get(`plugin::${PLUGIN_NAME}`) || {};
32
+ return config.debug === true;
33
+ } catch {
34
+ return false;
35
+ }
36
+ };
37
+
38
+ return {
39
+ /**
40
+ * Log info - only when debug: true
41
+ */
42
+ info: (...args) => {
43
+ if (getDebugMode()) {
44
+ strapi.log.info(formatMessage(PREFIX, args));
45
+ }
46
+ },
47
+
48
+ /**
49
+ * Log debug - only when debug: true
50
+ */
51
+ debug: (...args) => {
52
+ if (getDebugMode()) {
53
+ strapi.log.debug(formatMessage(PREFIX, args));
54
+ }
55
+ },
56
+
57
+ /**
58
+ * Log warning - only when debug: true
59
+ */
60
+ warn: (...args) => {
61
+ if (getDebugMode()) {
62
+ strapi.log.warn(formatMessage(PREFIX, args));
63
+ }
64
+ },
65
+
66
+ /**
67
+ * Log error - only when debug: true
68
+ */
69
+ error: (...args) => {
70
+ if (getDebugMode()) {
71
+ strapi.log.error(formatMessage(PREFIX, args));
72
+ }
73
+ },
74
+
75
+ /**
76
+ * Force log - always logged (for critical errors only)
77
+ */
78
+ forceError: (...args) => {
79
+ strapi.log.error(formatMessage(PREFIX, args));
80
+ },
81
+ };
82
+ }
83
+
84
+ module.exports = { createLogger };