@friggframework/core 2.0.0--canary.425.2d58c19.0 → 2.0.0--canary.427.68e753a.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.
package/database/mongo.js CHANGED
@@ -5,14 +5,16 @@
5
5
  const { Encrypt } = require('../encrypt');
6
6
  const { mongoose } = require('./mongoose');
7
7
  const { debug, flushDebugLog } = require('../logs');
8
+ const { findNearestBackendPackageJson } = require('../utils');
9
+ const path = require('path');
10
+ const fs = require('fs');
8
11
 
9
12
  mongoose.plugin(Encrypt);
10
13
  mongoose.set('applyPluginsToDiscriminators', true); // Needed for LHEncrypt
11
14
 
12
- // Buffering means mongoose will queue up operations if it gets
13
- // With serverless, better to fail fast if not connected.
14
- // disconnected from MongoDB and send them when it reconnects.
15
- const mongoConfig = {
15
+ // Load app definition to check for DocumentDB configuration
16
+ let appDefinition = {};
17
+ let mongoConfig = {
16
18
  useNewUrlParser: true,
17
19
  bufferCommands: false, // Disable mongoose buffering
18
20
  autoCreate: false, // Disable because auto creation does not work without buffering
@@ -28,9 +30,133 @@ const connectToDatabase = async () => {
28
30
  return;
29
31
  }
30
32
 
33
+ console.log('🔗 Connecting to database...');
34
+
35
+ // Load appDefinition inside the function
36
+ try {
37
+ console.log(
38
+ '🔍 Loading app definition for DocumentDB configuration...'
39
+ );
40
+
41
+ const backendPath = findNearestBackendPackageJson();
42
+ if (!backendPath) {
43
+ throw new Error('Could not find backend package.json');
44
+ }
45
+
46
+ const backendDir = path.dirname(backendPath);
47
+ const backendFilePath = path.join(backendDir, 'index.js');
48
+ if (!fs.existsSync(backendFilePath)) {
49
+ throw new Error('Could not find index.js');
50
+ }
51
+
52
+ const backend = require(backendFilePath);
53
+ appDefinition = backend.Definition;
54
+
55
+ console.log('📁 AppDefinition content:', JSON.stringify(appDefinition));
56
+
57
+ // Add DocumentDB TLS configuration if enabled
58
+ if (appDefinition.database?.documentDB?.enable === true) {
59
+ console.log('📄 DocumentDB configuration detected, enabling TLS');
60
+ console.log('📁 Current working directory:', process.cwd());
61
+ console.log(
62
+ '📋 App definition database config:',
63
+ JSON.stringify(appDefinition.database, null, 2)
64
+ );
65
+
66
+ mongoConfig.tls = true;
67
+
68
+ // Set TLS CA file path if specified
69
+ if (appDefinition.database.documentDB.tlsCAFile) {
70
+ const tlsCAFile = appDefinition.database.documentDB.tlsCAFile;
71
+
72
+ // Basic safety: reject obviously dangerous paths
73
+ if (tlsCAFile.includes('..') || path.isAbsolute(tlsCAFile)) {
74
+ console.warn(
75
+ '⚠️ Rejecting potentially unsafe tlsCAFile path:',
76
+ tlsCAFile
77
+ );
78
+ } else {
79
+ const tlsCAFilePath = path.resolve(
80
+ process.cwd(),
81
+ tlsCAFile
82
+ );
83
+
84
+ console.log('📄 DocumentDB TLS CA file configured:');
85
+ console.log(' 📎 Original path:', tlsCAFile);
86
+ console.log(' 📎 Resolved path:', tlsCAFilePath);
87
+ console.log(
88
+ ' 📄 File exists:',
89
+ fs.existsSync(tlsCAFilePath)
90
+ );
91
+
92
+ // Only set tlsCAFile if the file actually exists
93
+ if (fs.existsSync(tlsCAFilePath)) {
94
+ mongoConfig.tlsCAFile = tlsCAFilePath;
95
+ console.log('✅ TLS CA file configured successfully');
96
+ } else {
97
+ throw new Error(
98
+ `TLS CA file not found at ${tlsCAFilePath}`
99
+ );
100
+ }
101
+
102
+ // Debug directory listing (only in development)
103
+ if (process.env.NODE_ENV !== 'production') {
104
+ try {
105
+ console.log('📁 Current directory contents:');
106
+ fs.readdirSync(process.cwd()).forEach((item) => {
107
+ const stats = fs.statSync(
108
+ path.join(process.cwd(), item)
109
+ );
110
+ console.log(
111
+ ` ${
112
+ stats.isDirectory() ? '📁' : '📄'
113
+ } ${item}`
114
+ );
115
+ });
116
+
117
+ const securityDir = path.join(
118
+ process.cwd(),
119
+ 'security'
120
+ );
121
+ if (fs.existsSync(securityDir)) {
122
+ console.log('📁 Security directory contents:');
123
+ fs.readdirSync(securityDir).forEach((item) => {
124
+ console.log(` 📄 ${item}`);
125
+ });
126
+ } else {
127
+ console.log(
128
+ '❌ Security directory does not exist at:',
129
+ securityDir
130
+ );
131
+ }
132
+ } catch (error) {
133
+ console.log(
134
+ '❌ Error listing directory contents:',
135
+ error.message
136
+ );
137
+ }
138
+ }
139
+ }
140
+ }
141
+ } else {
142
+ console.log(
143
+ '📄 DocumentDB not enabled, using standard MongoDB configuration'
144
+ );
145
+ }
146
+ } catch (error) {
147
+ console.error('❌ Error loading app definition:', error.message);
148
+ debug(
149
+ 'Could not load app definition for DocumentDB configuration:',
150
+ error.message
151
+ );
152
+ }
153
+
154
+ console.log('🔗 MongoDB URI:', process.env.MONGO_URI ? 'SET' : 'NOT SET');
155
+ console.log('🔧 Final mongoConfig:', JSON.stringify(mongoConfig, null, 2));
156
+
31
157
  debug('=> using new database connection');
32
158
  await mongoose.connect(process.env.MONGO_URI, mongoConfig);
33
- debug('Connection state:', mongoose.STATES[mongoose.connection.readyState]);
159
+ debug('Connection state:', mongoose.STATES[mongoose.connection.readyState]);
34
160
  mongoose.connection.on('error', (error) => flushDebugLog(error));
35
161
  };
36
162
 
@@ -9,18 +9,19 @@ const router = Router();
9
9
 
10
10
  const validateApiKey = (req, res, next) => {
11
11
  const apiKey = req.headers['x-api-key'];
12
-
12
+
13
13
  if (req.path === '/health') {
14
14
  return next();
15
15
  }
16
-
16
+
17
17
  if (!apiKey || apiKey !== process.env.HEALTH_API_KEY) {
18
+ console.error('Unauthorized access attempt to health endpoint');
18
19
  return res.status(401).json({
19
20
  status: 'error',
20
- message: 'Unauthorized'
21
+ message: 'Unauthorized',
21
22
  });
22
23
  }
23
-
24
+
24
25
  next();
25
26
  };
26
27
 
@@ -30,7 +31,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
30
31
  return new Promise((resolve) => {
31
32
  const protocol = url.startsWith('https:') ? https : http;
32
33
  const startTime = Date.now();
33
-
34
+
34
35
  try {
35
36
  const request = protocol.get(url, { timeout }, (res) => {
36
37
  const responseTime = Date.now() - startTime;
@@ -38,7 +39,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
38
39
  status: 'healthy',
39
40
  statusCode: res.statusCode,
40
41
  responseTime,
41
- reachable: res.statusCode < 500
42
+ reachable: res.statusCode < 500,
42
43
  });
43
44
  });
44
45
 
@@ -47,7 +48,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
47
48
  status: 'unhealthy',
48
49
  error: error.message,
49
50
  responseTime: Date.now() - startTime,
50
- reachable: false
51
+ reachable: false,
51
52
  });
52
53
  });
53
54
 
@@ -57,7 +58,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
57
58
  status: 'timeout',
58
59
  error: 'Request timeout',
59
60
  responseTime: timeout,
60
- reachable: false
61
+ reachable: false,
61
62
  });
62
63
  });
63
64
  } catch (error) {
@@ -65,7 +66,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
65
66
  status: 'error',
66
67
  error: error.message,
67
68
  responseTime: Date.now() - startTime,
68
- reachable: false
69
+ reachable: false,
69
70
  });
70
71
  }
71
72
  });
@@ -76,14 +77,14 @@ const getDatabaseState = () => {
76
77
  0: 'disconnected',
77
78
  1: 'connected',
78
79
  2: 'connecting',
79
- 3: 'disconnecting'
80
+ 3: 'disconnecting',
80
81
  };
81
82
  const readyState = mongoose.connection.readyState;
82
-
83
+
83
84
  return {
84
85
  readyState,
85
86
  stateName: stateMap[readyState],
86
- isConnected: readyState === 1
87
+ isConnected: readyState === 1,
87
88
  };
88
89
  };
89
90
 
@@ -91,7 +92,7 @@ const checkDatabaseHealth = async () => {
91
92
  const { stateName, isConnected } = getDatabaseState();
92
93
  const result = {
93
94
  status: isConnected ? 'healthy' : 'unhealthy',
94
- state: stateName
95
+ state: stateName,
95
96
  };
96
97
 
97
98
  if (isConnected) {
@@ -104,19 +105,20 @@ const checkDatabaseHealth = async () => {
104
105
  };
105
106
 
106
107
  const getEncryptionConfiguration = () => {
107
- const { STAGE, BYPASS_ENCRYPTION_STAGE, KMS_KEY_ARN, AES_KEY_ID } = process.env;
108
-
108
+ const { STAGE, BYPASS_ENCRYPTION_STAGE, KMS_KEY_ARN, AES_KEY_ID } =
109
+ process.env;
110
+
109
111
  const defaultBypassStages = ['dev', 'test', 'local'];
110
112
  const useEnv = BYPASS_ENCRYPTION_STAGE !== undefined;
111
113
  const bypassStages = useEnv
112
114
  ? BYPASS_ENCRYPTION_STAGE.split(',').map((s) => s.trim())
113
115
  : defaultBypassStages;
114
-
116
+
115
117
  const isBypassed = bypassStages.includes(STAGE);
116
118
  const hasAES = AES_KEY_ID && AES_KEY_ID.trim() !== '';
117
119
  const hasKMS = KMS_KEY_ARN && KMS_KEY_ARN.trim() !== '' && !hasAES;
118
120
  const mode = hasAES ? 'aes' : hasKMS ? 'kms' : 'none';
119
-
121
+
120
122
  return {
121
123
  stage: STAGE || null,
122
124
  isBypassed,
@@ -128,41 +130,33 @@ const getEncryptionConfiguration = () => {
128
130
 
129
131
  const createTestEncryptionModel = () => {
130
132
  const { Encrypt } = require('./../../encrypt');
131
-
132
- const testSchema = new mongoose.Schema({
133
- testSecret: { type: String, lhEncrypt: true },
134
- normalField: { type: String },
135
- nestedSecret: {
136
- value: { type: String, lhEncrypt: true }
137
- }
138
- }, { timestamps: false });
139
133
 
140
- testSchema.plugin(Encrypt);
141
-
142
- return mongoose.models.TestEncryption ||
143
- mongoose.model('TestEncryption', testSchema);
144
- };
134
+ const testSchema = new mongoose.Schema(
135
+ {
136
+ testSecret: { type: String, lhEncrypt: true },
137
+ normalField: { type: String },
138
+ nestedSecret: {
139
+ value: { type: String, lhEncrypt: true },
140
+ },
141
+ },
142
+ { timestamps: false }
143
+ );
145
144
 
146
- const createTestDocument = async (TestModel) => {
147
- const testData = {
148
- testSecret: 'This is a secret value that should be encrypted',
149
- normalField: 'This is a normal field that should not be encrypted',
150
- nestedSecret: {
151
- value: 'This is a nested secret that should be encrypted'
152
- }
153
- };
145
+ testSchema.plugin(Encrypt);
154
146
 
155
- const testDoc = new TestModel(testData);
156
- await testDoc.save();
157
-
158
- return { testDoc, testData };
147
+ return (
148
+ mongoose.models.TestEncryption ||
149
+ mongoose.model('TestEncryption', testSchema)
150
+ );
159
151
  };
160
152
 
161
153
  const verifyDecryption = (retrievedDoc, originalData) => {
162
- return retrievedDoc &&
154
+ return (
155
+ retrievedDoc &&
163
156
  retrievedDoc.testSecret === originalData.testSecret &&
164
157
  retrievedDoc.normalField === originalData.normalField &&
165
- retrievedDoc.nestedSecret?.value === originalData.nestedSecret.value;
158
+ retrievedDoc.nestedSecret?.value === originalData.nestedSecret.value
159
+ );
166
160
  };
167
161
 
168
162
  const verifyEncryptionInDatabase = async (testDoc, originalData, TestModel) => {
@@ -171,84 +165,188 @@ const verifyEncryptionInDatabase = async (testDoc, originalData, TestModel) => {
171
165
  .collection(collectionName)
172
166
  .findOne({ _id: testDoc._id });
173
167
 
174
- const secretIsEncrypted = rawDoc &&
175
- typeof rawDoc.testSecret === 'string' &&
176
- rawDoc.testSecret.includes(':') &&
168
+ const secretIsEncrypted =
169
+ rawDoc &&
170
+ typeof rawDoc.testSecret === 'string' &&
171
+ rawDoc.testSecret.includes(':') &&
177
172
  rawDoc.testSecret !== originalData.testSecret;
178
-
179
- const nestedIsEncrypted = rawDoc?.nestedSecret?.value &&
173
+
174
+ const nestedIsEncrypted =
175
+ rawDoc?.nestedSecret?.value &&
180
176
  typeof rawDoc.nestedSecret.value === 'string' &&
181
- rawDoc.nestedSecret.value.includes(':') &&
177
+ rawDoc.nestedSecret.value.includes(':') &&
182
178
  rawDoc.nestedSecret.value !== originalData.nestedSecret.value;
183
-
184
- const normalNotEncrypted = rawDoc &&
185
- rawDoc.normalField === originalData.normalField;
179
+
180
+ const normalNotEncrypted =
181
+ rawDoc && rawDoc.normalField === originalData.normalField;
186
182
 
187
183
  return {
188
184
  secretIsEncrypted,
189
185
  nestedIsEncrypted,
190
- normalNotEncrypted
186
+ normalNotEncrypted,
191
187
  };
192
188
  };
193
189
 
194
190
  const evaluateEncryptionTestResults = (decryptionWorks, encryptionResults) => {
195
- const { secretIsEncrypted, nestedIsEncrypted, normalNotEncrypted } = encryptionResults;
196
-
197
- if (decryptionWorks && secretIsEncrypted && nestedIsEncrypted && normalNotEncrypted) {
191
+ const { secretIsEncrypted, nestedIsEncrypted, normalNotEncrypted } =
192
+ encryptionResults;
193
+
194
+ if (
195
+ decryptionWorks &&
196
+ secretIsEncrypted &&
197
+ nestedIsEncrypted &&
198
+ normalNotEncrypted
199
+ ) {
198
200
  return {
199
201
  status: 'enabled',
200
- testResult: 'Encryption and decryption verified successfully'
202
+ testResult: 'Encryption and decryption verified successfully',
201
203
  };
202
204
  }
203
-
205
+
204
206
  if (decryptionWorks && (!secretIsEncrypted || !nestedIsEncrypted)) {
205
207
  return {
206
208
  status: 'unhealthy',
207
- testResult: 'Fields are not being encrypted in database'
209
+ testResult: 'Fields are not being encrypted in database',
208
210
  };
209
211
  }
210
-
212
+
211
213
  if (decryptionWorks && !normalNotEncrypted) {
212
214
  return {
213
215
  status: 'unhealthy',
214
- testResult: 'Normal fields are being incorrectly encrypted'
216
+ testResult: 'Normal fields are being incorrectly encrypted',
215
217
  };
216
218
  }
217
-
219
+
218
220
  return {
219
221
  status: 'unhealthy',
220
- testResult: 'Decryption failed or data mismatch'
222
+ testResult: 'Decryption failed or data mismatch',
221
223
  };
222
224
  };
223
225
 
226
+ const withTimeout = (promise, ms, errorMessage) => {
227
+ return Promise.race([
228
+ promise,
229
+ new Promise((_, reject) =>
230
+ setTimeout(() => reject(new Error(errorMessage)), ms)
231
+ ),
232
+ ]);
233
+ };
234
+
224
235
  const testEncryption = async () => {
236
+ // eslint-disable-next-line no-console
237
+ console.log('Starting encryption test');
225
238
  const TestModel = createTestEncryptionModel();
226
- const { testDoc, testData } = await createTestDocument(TestModel);
227
-
239
+ // eslint-disable-next-line no-console
240
+ console.log('Test model created');
241
+
242
+ const testData = {
243
+ testSecret: 'This is a secret value that should be encrypted',
244
+ normalField: 'This is a normal field that should not be encrypted',
245
+ nestedSecret: {
246
+ value: 'This is a nested secret that should be encrypted',
247
+ },
248
+ };
249
+
250
+ const testDoc = new TestModel(testData);
251
+
252
+ try {
253
+ // eslint-disable-next-line no-console
254
+ console.log('Attempting to save document with encryption...');
255
+ const startTime = Date.now();
256
+
257
+ await withTimeout(
258
+ testDoc.save(),
259
+ 30000,
260
+ 'Save operation timed out after 30 seconds'
261
+ );
262
+
263
+ const duration = Date.now() - startTime;
264
+ // eslint-disable-next-line no-console
265
+ console.log(`Test document saved successfully in ${duration}ms`);
266
+ } catch (error) {
267
+ // eslint-disable-next-line no-console
268
+ console.error('Save operation failed:', {
269
+ errorName: error.name,
270
+ errorMessage: error.message,
271
+ errorStack: error.stack,
272
+ mongooseConnectionState: testDoc.db.readyState,
273
+ modelName: TestModel.modelName,
274
+ });
275
+
276
+ // Try to get more details about the connection
277
+ if (mongoose.connection && mongoose.connection.db) {
278
+ try {
279
+ const admin = mongoose.connection.db.admin();
280
+ const serverStatus = await admin.serverStatus();
281
+ // eslint-disable-next-line no-console
282
+ console.log('DocumentDB Server Status:', {
283
+ version: serverStatus.version,
284
+ uptime: serverStatus.uptime,
285
+ connections: serverStatus.connections,
286
+ });
287
+ } catch (statusError) {
288
+ // eslint-disable-next-line no-console
289
+ console.error(
290
+ 'Could not get server status:',
291
+ statusError.message
292
+ );
293
+ }
294
+ }
295
+
296
+ throw error;
297
+ }
298
+
228
299
  try {
229
- const retrievedDoc = await TestModel.findById(testDoc._id);
300
+ const retrievedDoc = await withTimeout(
301
+ TestModel.findById(testDoc._id),
302
+ 5000,
303
+ 'Find operation timed out'
304
+ );
305
+ // eslint-disable-next-line no-console
306
+ console.log('Test document retrieved');
230
307
  const decryptionWorks = verifyDecryption(retrievedDoc, testData);
231
- const encryptionResults = await verifyEncryptionInDatabase(testDoc, testData, TestModel);
232
-
233
- const evaluation = evaluateEncryptionTestResults(decryptionWorks, encryptionResults);
234
-
308
+ const encryptionResults = await withTimeout(
309
+ verifyEncryptionInDatabase(testDoc, testData, TestModel),
310
+ 5000,
311
+ 'Database verification timed out'
312
+ );
313
+ // eslint-disable-next-line no-console
314
+ console.log('Encryption verification completed');
315
+
316
+ const evaluation = evaluateEncryptionTestResults(
317
+ decryptionWorks,
318
+ encryptionResults
319
+ );
320
+
235
321
  return {
236
322
  ...evaluation,
237
- encryptionWorks: decryptionWorks
323
+ encryptionWorks: decryptionWorks,
238
324
  };
239
325
  } finally {
240
- await TestModel.deleteOne({ _id: testDoc._id });
326
+ await withTimeout(
327
+ TestModel.deleteOne({ _id: testDoc._id }),
328
+ 5000,
329
+ 'Delete operation timed out'
330
+ );
331
+ // eslint-disable-next-line no-console
332
+ console.log('Test document deleted');
241
333
  }
242
334
  };
243
335
 
244
336
  const checkEncryptionHealth = async () => {
245
337
  const config = getEncryptionConfiguration();
246
-
338
+
247
339
  if (config.isBypassed || config.mode === 'none') {
248
- const testResult = config.isBypassed
249
- ? 'Encryption bypassed for this stage'
340
+ // eslint-disable-next-line no-console
341
+ console.log('Encryption check bypassed:', {
342
+ stage: config.stage,
343
+ mode: config.mode,
344
+ });
345
+
346
+ const testResult = config.isBypassed
347
+ ? 'Encryption bypassed for this stage'
250
348
  : 'No encryption keys configured';
251
-
349
+
252
350
  return {
253
351
  status: 'disabled',
254
352
  mode: config.mode,
@@ -258,14 +356,14 @@ const checkEncryptionHealth = async () => {
258
356
  encryptionWorks: false,
259
357
  debug: {
260
358
  hasKMS: config.hasKMS,
261
- hasAES: config.hasAES
262
- }
359
+ hasAES: config.hasAES,
360
+ },
263
361
  };
264
362
  }
265
363
 
266
364
  try {
267
365
  const testResults = await testEncryption();
268
-
366
+
269
367
  return {
270
368
  ...testResults,
271
369
  mode: config.mode,
@@ -273,8 +371,8 @@ const checkEncryptionHealth = async () => {
273
371
  stage: config.stage,
274
372
  debug: {
275
373
  hasKMS: config.hasKMS,
276
- hasAES: config.hasAES
277
- }
374
+ hasAES: config.hasAES,
375
+ },
278
376
  };
279
377
  } catch (error) {
280
378
  return {
@@ -286,8 +384,8 @@ const checkEncryptionHealth = async () => {
286
384
  encryptionWorks: false,
287
385
  debug: {
288
386
  hasKMS: config.hasKMS,
289
- hasAES: config.hasAES
290
- }
387
+ hasAES: config.hasAES,
388
+ },
291
389
  };
292
390
  }
293
391
  };
@@ -295,25 +393,28 @@ const checkEncryptionHealth = async () => {
295
393
  const checkExternalAPIs = async () => {
296
394
  const apis = [
297
395
  { name: 'github', url: 'https://api.github.com/status' },
298
- { name: 'npm', url: 'https://registry.npmjs.org' }
396
+ { name: 'npm', url: 'https://registry.npmjs.org' },
299
397
  ];
300
398
 
301
399
  const results = await Promise.all(
302
- apis.map(api =>
303
- checkExternalAPI(api.url).then(result => ({ name: api.name, ...result }))
400
+ apis.map((api) =>
401
+ checkExternalAPI(api.url).then((result) => ({
402
+ name: api.name,
403
+ ...result,
404
+ }))
304
405
  )
305
406
  );
306
-
407
+
307
408
  const apiStatuses = {};
308
409
  let allReachable = true;
309
-
410
+
310
411
  results.forEach(({ name, ...checkResult }) => {
311
412
  apiStatuses[name] = checkResult;
312
413
  if (!checkResult.reachable) {
313
414
  allReachable = false;
314
415
  }
315
416
  });
316
-
417
+
317
418
  return { apiStatuses, allReachable };
318
419
  };
319
420
 
@@ -321,7 +422,7 @@ const checkIntegrations = () => {
321
422
  const moduleTypes = Array.isArray(moduleFactory.moduleTypes)
322
423
  ? moduleFactory.moduleTypes
323
424
  : [];
324
-
425
+
325
426
  const integrationTypes = Array.isArray(integrationFactory.integrationTypes)
326
427
  ? integrationFactory.integrationTypes
327
428
  : [];
@@ -345,7 +446,7 @@ const buildHealthCheckResponse = (startTime) => {
345
446
  status: 'healthy',
346
447
  timestamp: new Date().toISOString(),
347
448
  checks: {},
348
- calculateResponseTime: () => Date.now() - startTime
449
+ calculateResponseTime: () => Date.now() - startTime,
349
450
  };
350
451
  };
351
452
 
@@ -353,13 +454,15 @@ router.get('/health', async (_req, res) => {
353
454
  const status = {
354
455
  status: 'ok',
355
456
  timestamp: new Date().toISOString(),
356
- service: 'frigg-core-api'
457
+ service: 'frigg-core-api',
357
458
  };
358
459
 
359
460
  res.status(200).json(status);
360
461
  });
361
462
 
362
463
  router.get('/health/detailed', async (_req, res) => {
464
+ // eslint-disable-next-line no-console
465
+ console.log('Starting detailed health check');
363
466
  const startTime = Date.now();
364
467
  const response = buildHealthCheckResponse(startTime);
365
468
 
@@ -369,12 +472,16 @@ router.get('/health/detailed', async (_req, res) => {
369
472
  if (!dbState.isConnected) {
370
473
  response.status = 'unhealthy';
371
474
  }
475
+ // eslint-disable-next-line no-console
476
+ console.log('Database check completed:', response.checks.database);
372
477
  } catch (error) {
373
478
  response.checks.database = {
374
479
  status: 'unhealthy',
375
- error: error.message
480
+ error: error.message,
376
481
  };
377
482
  response.status = 'unhealthy';
483
+ // eslint-disable-next-line no-console
484
+ console.log('Database check error:', error.message);
378
485
  }
379
486
 
380
487
  try {
@@ -382,12 +489,16 @@ router.get('/health/detailed', async (_req, res) => {
382
489
  if (response.checks.encryption.status === 'unhealthy') {
383
490
  response.status = 'unhealthy';
384
491
  }
492
+ // eslint-disable-next-line no-console
493
+ console.log('Encryption check completed:', response.checks.encryption);
385
494
  } catch (error) {
386
495
  response.checks.encryption = {
387
496
  status: 'unhealthy',
388
- error: error.message
497
+ error: error.message,
389
498
  };
390
499
  response.status = 'unhealthy';
500
+ // eslint-disable-next-line no-console
501
+ console.log('Encryption check error:', error.message);
391
502
  }
392
503
 
393
504
  const { apiStatuses, allReachable } = await checkExternalAPIs();
@@ -395,15 +506,24 @@ router.get('/health/detailed', async (_req, res) => {
395
506
  if (!allReachable) {
396
507
  response.status = 'unhealthy';
397
508
  }
509
+ // eslint-disable-next-line no-console
510
+ console.log('External APIs check completed:', response.checks.externalApis);
398
511
 
399
512
  try {
400
513
  response.checks.integrations = checkIntegrations();
514
+ // eslint-disable-next-line no-console
515
+ console.log(
516
+ 'Integrations check completed:',
517
+ response.checks.integrations
518
+ );
401
519
  } catch (error) {
402
520
  response.checks.integrations = {
403
521
  status: 'unhealthy',
404
- error: error.message
522
+ error: error.message,
405
523
  };
406
524
  response.status = 'unhealthy';
525
+ // eslint-disable-next-line no-console
526
+ console.log('Integrations check error:', error.message);
407
527
  }
408
528
 
409
529
  response.responseTime = response.calculateResponseTime();
@@ -411,19 +531,27 @@ router.get('/health/detailed', async (_req, res) => {
411
531
 
412
532
  const statusCode = response.status === 'healthy' ? 200 : 503;
413
533
  res.status(statusCode).json(response);
534
+
535
+ // eslint-disable-next-line no-console
536
+ console.log(
537
+ 'Final health status:',
538
+ response.status,
539
+ 'Response time:',
540
+ response.responseTime
541
+ );
414
542
  });
415
543
 
416
544
  router.get('/health/live', (_req, res) => {
417
545
  res.status(200).json({
418
546
  status: 'alive',
419
- timestamp: new Date().toISOString()
547
+ timestamp: new Date().toISOString(),
420
548
  });
421
549
  });
422
550
 
423
551
  router.get('/health/ready', async (_req, res) => {
424
552
  const dbState = getDatabaseState();
425
553
  const isDbReady = dbState.isConnected;
426
-
554
+
427
555
  let areModulesReady = false;
428
556
  try {
429
557
  const moduleTypes = Array.isArray(moduleFactory.moduleTypes)
@@ -441,11 +569,11 @@ router.get('/health/ready', async (_req, res) => {
441
569
  timestamp: new Date().toISOString(),
442
570
  checks: {
443
571
  database: isDbReady,
444
- modules: areModulesReady
445
- }
572
+ modules: areModulesReady,
573
+ },
446
574
  });
447
575
  });
448
576
 
449
577
  const handler = createAppHandler('HTTP Event: Health', router);
450
578
 
451
- module.exports = { handler, router };
579
+ module.exports = { handler, router };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/core",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.425.2d58c19.0",
4
+ "version": "2.0.0--canary.427.68e753a.0",
5
5
  "dependencies": {
6
6
  "@hapi/boom": "^10.0.1",
7
7
  "aws-sdk": "^2.1200.0",
@@ -22,9 +22,9 @@
22
22
  "uuid": "^9.0.1"
23
23
  },
24
24
  "devDependencies": {
25
- "@friggframework/eslint-config": "2.0.0--canary.425.2d58c19.0",
26
- "@friggframework/prettier-config": "2.0.0--canary.425.2d58c19.0",
27
- "@friggframework/test": "2.0.0--canary.425.2d58c19.0",
25
+ "@friggframework/eslint-config": "2.0.0--canary.427.68e753a.0",
26
+ "@friggframework/prettier-config": "2.0.0--canary.427.68e753a.0",
27
+ "@friggframework/test": "2.0.0--canary.427.68e753a.0",
28
28
  "@types/lodash": "4.17.15",
29
29
  "@typescript-eslint/eslint-plugin": "^8.0.0",
30
30
  "chai": "^4.3.6",
@@ -56,5 +56,5 @@
56
56
  "publishConfig": {
57
57
  "access": "public"
58
58
  },
59
- "gitHead": "2d58c196b068fafce914e0fc631d72a30b745f31"
59
+ "gitHead": "68e753a98bf315deb2004e4f5c6ab58495e04d2b"
60
60
  }