@tamyla/clodo-framework 3.1.9 ā 3.1.11
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/CHANGELOG.md +14 -0
- package/dist/bin/clodo-service-old.js +2 -2
- package/dist/bin/commands/create.js +1 -1
- package/dist/bin/commands/diagnose.js +1 -1
- package/dist/bin/commands/update.js +1 -1
- package/dist/bin/commands/validate.js +1 -1
- package/dist/bin/database/enterprise-db-manager.js +4 -4
- package/dist/bin/deployment/enterprise-deploy.js +3 -3
- package/dist/bin/deployment/master-deploy.js +3 -3
- package/dist/bin/deployment/modular-enterprise-deploy.js +3 -3
- package/dist/bin/deployment/modules/DeploymentOrchestrator.js +1 -1
- package/dist/bin/deployment/modules/EnvironmentManager.js +2 -2
- package/dist/bin/portfolio/portfolio-manager.js +3 -3
- package/dist/bin/security/security-cli.js +1 -1
- package/dist/bin/service-management/create-service.js +1 -1
- package/dist/bin/service-management/init-service.js +1 -1
- package/dist/bin/shared/cloudflare/domain-manager.js +1 -1
- package/dist/bin/shared/config/index.js +1 -1
- package/dist/bin/shared/deployment/index.js +2 -2
- package/dist/bin/shared/validation/ValidationRegistry.js +1 -1
- package/package.json +1 -6
- package/bin/README.md +0 -71
- package/bin/clodo-service.js +0 -72
- package/bin/database/README.md +0 -33
- package/bin/database/deployment-db-manager.js +0 -527
- package/bin/database/enterprise-db-manager.js +0 -738
- package/bin/database/wrangler-d1-manager.js +0 -775
- package/bin/security/security-cli.js +0 -117
- package/bin/service-management/README.md +0 -74
- package/bin/service-management/create-service.js +0 -129
- package/bin/service-management/init-service.js +0 -103
- package/bin/service-management/init-service.js.backup +0 -889
- package/bin/shared/cloudflare/domain-discovery.js +0 -637
- package/bin/shared/cloudflare/domain-manager.js +0 -952
- package/bin/shared/cloudflare/index.js +0 -8
- package/bin/shared/cloudflare/ops.js +0 -401
- package/bin/shared/config/ConfigurationManager.js +0 -539
- package/bin/shared/config/cache.js +0 -1230
- package/bin/shared/config/command-config-manager.js +0 -184
- package/bin/shared/config/index.js +0 -21
- package/bin/shared/config/manager.js +0 -315
- package/bin/shared/database/connection-manager.js +0 -374
- package/bin/shared/database/index.js +0 -7
- package/bin/shared/database/orchestrator.js +0 -727
- package/bin/shared/deployment/auditor.js +0 -970
- package/bin/shared/deployment/index.js +0 -10
- package/bin/shared/deployment/rollback-manager.js +0 -570
- package/bin/shared/deployment/validator.js +0 -779
- package/bin/shared/index.js +0 -32
- package/bin/shared/logging/Logger.js +0 -214
- package/bin/shared/monitoring/health-checker.js +0 -484
- package/bin/shared/monitoring/index.js +0 -8
- package/bin/shared/monitoring/memory-manager.js +0 -387
- package/bin/shared/monitoring/production-monitor.js +0 -403
- package/bin/shared/production-tester/api-tester.js +0 -82
- package/bin/shared/production-tester/auth-tester.js +0 -132
- package/bin/shared/production-tester/core.js +0 -197
- package/bin/shared/production-tester/database-tester.js +0 -109
- package/bin/shared/production-tester/index.js +0 -77
- package/bin/shared/production-tester/load-tester.js +0 -131
- package/bin/shared/production-tester/performance-tester.js +0 -103
- package/bin/shared/security/api-token-manager.js +0 -312
- package/bin/shared/security/index.js +0 -8
- package/bin/shared/security/secret-generator.js +0 -942
- package/bin/shared/security/secure-token-manager.js +0 -398
- package/bin/shared/utils/ErrorHandler.js +0 -675
- package/bin/shared/utils/error-recovery.js +0 -245
- package/bin/shared/utils/file-manager.js +0 -162
- package/bin/shared/utils/formatters.js +0 -247
- package/bin/shared/utils/graceful-shutdown-manager.js +0 -390
- package/bin/shared/utils/index.js +0 -19
- package/bin/shared/utils/interactive-prompts.js +0 -146
- package/bin/shared/utils/interactive-utils.js +0 -530
- package/bin/shared/utils/rate-limiter.js +0 -246
- package/bin/shared/validation/ValidationRegistry.js +0 -143
|
@@ -1,484 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Health Checker Module
|
|
3
|
-
* Endpoint health checking and validation utilities
|
|
4
|
-
*
|
|
5
|
-
* Consolidates health checking across 20+ scripts
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { exec, execSync } from 'child_process';
|
|
9
|
-
import { promisify } from 'util';
|
|
10
|
-
import https from 'https';
|
|
11
|
-
import http from 'http';
|
|
12
|
-
|
|
13
|
-
const execAsync = promisify(exec);
|
|
14
|
-
|
|
15
|
-
// Load framework configuration
|
|
16
|
-
const { frameworkConfig } = await import('../../../dist/utils/framework-config.js');
|
|
17
|
-
const timing = frameworkConfig.getTiming();
|
|
18
|
-
|
|
19
|
-
function makeHttpRequest(url, method = 'GET', timeout = 5000) {
|
|
20
|
-
return new Promise((resolve, reject) => {
|
|
21
|
-
const protocol = url.startsWith('https:') ? https : http;
|
|
22
|
-
const req = protocol.request(url, { method, timeout }, (res) => {
|
|
23
|
-
let data = '';
|
|
24
|
-
res.on('data', (chunk) => data += chunk);
|
|
25
|
-
res.on('end', () => {
|
|
26
|
-
resolve({ data, statusCode: res.statusCode });
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
req.on('error', (err) => {
|
|
31
|
-
reject(err);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
req.on('timeout', () => {
|
|
35
|
-
req.destroy();
|
|
36
|
-
reject(new Error('Request timed out'));
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
req.end();
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export async function checkHealth(url, timeout = timing.healthCheckTimeout) {
|
|
44
|
-
return new Promise((resolve, reject) => {
|
|
45
|
-
const protocol = url.startsWith('https:') ? https : http;
|
|
46
|
-
const healthUrl = `${url}/health`;
|
|
47
|
-
|
|
48
|
-
const req = protocol.get(healthUrl, { timeout }, (res) => {
|
|
49
|
-
let data = '';
|
|
50
|
-
res.on('data', (chunk) => data += chunk);
|
|
51
|
-
res.on('end', () => {
|
|
52
|
-
try {
|
|
53
|
-
const response = JSON.parse(data);
|
|
54
|
-
if (response.status === 'healthy' || response.status === 'ok') {
|
|
55
|
-
resolve({
|
|
56
|
-
status: 'ok',
|
|
57
|
-
framework: response.framework,
|
|
58
|
-
message: 'Service is healthy',
|
|
59
|
-
url: healthUrl,
|
|
60
|
-
timestamp: new Date().toISOString()
|
|
61
|
-
});
|
|
62
|
-
} else {
|
|
63
|
-
resolve({
|
|
64
|
-
status: 'error',
|
|
65
|
-
message: `Service reported unhealthy: ${response.status}`,
|
|
66
|
-
url: healthUrl,
|
|
67
|
-
timestamp: new Date().toISOString()
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
} catch (e) {
|
|
71
|
-
resolve({
|
|
72
|
-
status: 'error',
|
|
73
|
-
message: 'Invalid JSON response from health endpoint',
|
|
74
|
-
url: healthUrl,
|
|
75
|
-
timestamp: new Date().toISOString()
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
req.on('error', (err) => {
|
|
82
|
-
reject({
|
|
83
|
-
status: 'error',
|
|
84
|
-
message: `Health check failed: ${err.message}`,
|
|
85
|
-
url: healthUrl,
|
|
86
|
-
timestamp: new Date().toISOString()
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
req.on('timeout', () => {
|
|
91
|
-
req.destroy();
|
|
92
|
-
reject({
|
|
93
|
-
status: 'error',
|
|
94
|
-
message: 'Health check timed out',
|
|
95
|
-
url: healthUrl,
|
|
96
|
-
timestamp: new Date().toISOString()
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export async function waitForDeployment(url, maxWaitTime = timing.deploymentTimeout, interval = timing.deploymentInterval) {
|
|
103
|
-
const startTime = Date.now();
|
|
104
|
-
let attempts = 0;
|
|
105
|
-
|
|
106
|
-
console.log(`ā³ Waiting for deployment at ${url}...`);
|
|
107
|
-
|
|
108
|
-
while (Date.now() - startTime < maxWaitTime) {
|
|
109
|
-
try {
|
|
110
|
-
attempts++;
|
|
111
|
-
console.log(` š Attempt ${attempts}: Checking health...`);
|
|
112
|
-
|
|
113
|
-
const health = await checkHealth(url);
|
|
114
|
-
if (health.status === 'ok') {
|
|
115
|
-
console.log(` ā
Deployment active! Framework: ${health.framework?.name || 'Unknown'}`);
|
|
116
|
-
return health;
|
|
117
|
-
}
|
|
118
|
-
} catch (error) {
|
|
119
|
-
console.log(` ā³ Not ready yet: ${error.message}`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
await new Promise(resolve => setTimeout(resolve, interval));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
throw new Error(`Deployment verification timed out after ${maxWaitTime}ms (${attempts} attempts)`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export async function validateEndpoints(baseUrl, endpoints = [], timeout = timing.endpointValidationTimeout) {
|
|
129
|
-
console.log(`š Validating ${endpoints.length} endpoints...`);
|
|
130
|
-
|
|
131
|
-
const results = [];
|
|
132
|
-
|
|
133
|
-
for (const endpoint of endpoints) {
|
|
134
|
-
try {
|
|
135
|
-
const url = endpoint.startsWith('http') ? endpoint : `${baseUrl}${endpoint}`;
|
|
136
|
-
console.log(` Testing: ${endpoint}`);
|
|
137
|
-
|
|
138
|
-
const result = await makeHttpRequest(url, 'GET', timeout);
|
|
139
|
-
|
|
140
|
-
results.push({
|
|
141
|
-
endpoint,
|
|
142
|
-
url,
|
|
143
|
-
status: 'ok',
|
|
144
|
-
response: result.data.substring(0, 200) + (result.data.length > 200 ? '...' : '')
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
console.log(` ā
OK`);
|
|
148
|
-
} catch (error) {
|
|
149
|
-
results.push({
|
|
150
|
-
endpoint,
|
|
151
|
-
url: endpoint.startsWith('http') ? endpoint : `${baseUrl}${endpoint}`,
|
|
152
|
-
status: 'failed',
|
|
153
|
-
error: error.message
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
console.log(` ā Failed: ${error.message}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const successful = results.filter(r => r.status === 'ok').length;
|
|
161
|
-
const failed = results.filter(r => r.status === 'failed').length;
|
|
162
|
-
|
|
163
|
-
console.log(`š Results: ${successful} passed, ${failed} failed`);
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
summary: { successful, failed, total: results.length },
|
|
167
|
-
results,
|
|
168
|
-
allPassed: failed === 0
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export async function quickHealthCheck(url) {
|
|
173
|
-
try {
|
|
174
|
-
const health = await checkHealth(url, 5000);
|
|
175
|
-
return {
|
|
176
|
-
isHealthy: true,
|
|
177
|
-
details: health
|
|
178
|
-
};
|
|
179
|
-
} catch (error) {
|
|
180
|
-
return {
|
|
181
|
-
isHealthy: false,
|
|
182
|
-
error: error.message
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export async function comprehensiveHealthCheck(url) {
|
|
188
|
-
console.log(`š„ Running comprehensive health check for ${url}...`);
|
|
189
|
-
|
|
190
|
-
const checks = {
|
|
191
|
-
basic: { endpoint: '/health', description: 'Basic health check' },
|
|
192
|
-
auth: { endpoint: '/auth/magic-link', description: 'Authentication endpoint', method: 'POST' },
|
|
193
|
-
users: { endpoint: '/users/profile', description: 'User profile endpoint', requiresAuth: true },
|
|
194
|
-
framework: { endpoint: '/framework/models', description: 'Framework models' }
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
const results = {};
|
|
198
|
-
|
|
199
|
-
for (const [name, config] of Object.entries(checks)) {
|
|
200
|
-
try {
|
|
201
|
-
console.log(` Testing ${config.description}...`);
|
|
202
|
-
|
|
203
|
-
if (config.requiresAuth) {
|
|
204
|
-
console.log(` āļø Skipped (requires authentication)`);
|
|
205
|
-
results[name] = { status: 'skipped', reason: 'requires authentication' };
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const endpoint = `${url}${config.endpoint}`;
|
|
210
|
-
const method = config.method || 'GET';
|
|
211
|
-
|
|
212
|
-
const response = await makeHttpRequest(endpoint, method, 5000);
|
|
213
|
-
results[name] = {
|
|
214
|
-
status: 'ok',
|
|
215
|
-
endpoint: config.endpoint,
|
|
216
|
-
response: response.data.substring(0, 100) + (response.data.length > 100 ? '...' : '')
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
console.log(` ā
${config.description} - OK`);
|
|
220
|
-
} catch (error) {
|
|
221
|
-
results[name] = {
|
|
222
|
-
status: 'failed',
|
|
223
|
-
endpoint: config.endpoint,
|
|
224
|
-
error: error.message
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
console.log(` ā ${config.description} - ${error.message}`);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const passed = Object.values(results).filter(r => r.status === 'ok').length;
|
|
232
|
-
const total = Object.keys(results).length;
|
|
233
|
-
|
|
234
|
-
console.log(`š Health check complete: ${passed}/${total} checks passed`);
|
|
235
|
-
|
|
236
|
-
return {
|
|
237
|
-
summary: { passed, total, success: passed === total },
|
|
238
|
-
results,
|
|
239
|
-
timestamp: new Date().toISOString()
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export function formatHealthReport(healthData) {
|
|
244
|
-
const lines = [
|
|
245
|
-
'š„ HEALTH REPORT',
|
|
246
|
-
'===============',
|
|
247
|
-
'',
|
|
248
|
-
`š Timestamp: ${healthData.timestamp || new Date().toISOString()}`,
|
|
249
|
-
`š URL: ${healthData.url || 'Unknown'}`,
|
|
250
|
-
`š Status: ${healthData.status || 'Unknown'}`
|
|
251
|
-
];
|
|
252
|
-
|
|
253
|
-
if (healthData.framework) {
|
|
254
|
-
lines.push('');
|
|
255
|
-
lines.push('šļø Framework Details:');
|
|
256
|
-
lines.push(` š¦ Name: ${healthData.framework.name || 'Unknown'}`);
|
|
257
|
-
lines.push(` š Models: ${healthData.framework.models?.length || 0}`);
|
|
258
|
-
lines.push(` š£ļø Routes: ${healthData.framework.routes?.length || 0}`);
|
|
259
|
-
lines.push(` š§ Modules: ${healthData.framework.modules?.length || 0}`);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return lines.join('\n');
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Check D1 database connectivity and configuration
|
|
267
|
-
* @param {string} databaseName - D1 database name
|
|
268
|
-
* @param {Object} options - Check options
|
|
269
|
-
* @returns {Promise<Object>} D1 health check result
|
|
270
|
-
*/
|
|
271
|
-
export async function checkD1Health(databaseName, options = {}) {
|
|
272
|
-
const {
|
|
273
|
-
timeout = 10000,
|
|
274
|
-
testQuery = 'SELECT 1 as test',
|
|
275
|
-
validateSchema = false
|
|
276
|
-
} = options;
|
|
277
|
-
|
|
278
|
-
const startTime = Date.now();
|
|
279
|
-
const result = {
|
|
280
|
-
database: databaseName,
|
|
281
|
-
status: 'unknown',
|
|
282
|
-
connectivity: false,
|
|
283
|
-
responseTime: 0,
|
|
284
|
-
details: {},
|
|
285
|
-
timestamp: new Date().toISOString()
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
try {
|
|
289
|
-
// Test basic connectivity with a simple query
|
|
290
|
-
console.log(` šļø Testing D1 database: ${databaseName}`);
|
|
291
|
-
|
|
292
|
-
const queryCommand = `wrangler d1 execute ${databaseName} --command "${testQuery}"`;
|
|
293
|
-
const queryResult = await execAsync(queryCommand, { timeout });
|
|
294
|
-
|
|
295
|
-
result.responseTime = Date.now() - startTime;
|
|
296
|
-
result.connectivity = true;
|
|
297
|
-
result.details.queryResult = queryResult.stdout;
|
|
298
|
-
|
|
299
|
-
// Test database info
|
|
300
|
-
try {
|
|
301
|
-
const infoCommand = `wrangler d1 info ${databaseName}`;
|
|
302
|
-
const infoResult = await execAsync(infoCommand, { timeout: 5000 });
|
|
303
|
-
result.details.databaseInfo = infoResult.stdout;
|
|
304
|
-
} catch (infoError) {
|
|
305
|
-
result.details.infoError = infoError.message;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Validate schema if requested
|
|
309
|
-
if (validateSchema) {
|
|
310
|
-
try {
|
|
311
|
-
const schemaCommand = `wrangler d1 execute ${databaseName} --command "SELECT name FROM sqlite_master WHERE type='table'"`;
|
|
312
|
-
const schemaResult = await execAsync(schemaCommand, { timeout: 5000 });
|
|
313
|
-
result.details.tables = schemaResult.stdout;
|
|
314
|
-
} catch (schemaError) {
|
|
315
|
-
result.details.schemaError = schemaError.message;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
result.status = 'healthy';
|
|
320
|
-
console.log(` ā
D1 database '${databaseName}' is healthy (${result.responseTime}ms)`);
|
|
321
|
-
|
|
322
|
-
} catch (error) {
|
|
323
|
-
result.status = 'unhealthy';
|
|
324
|
-
result.responseTime = Date.now() - startTime;
|
|
325
|
-
result.error = error.message;
|
|
326
|
-
|
|
327
|
-
// Analyze the error for more specific feedback
|
|
328
|
-
if (error.message.includes('not found')) {
|
|
329
|
-
result.details.issue = 'Database not found';
|
|
330
|
-
result.details.suggestion = 'Check database name or create the database';
|
|
331
|
-
} else if (error.message.includes('authentication')) {
|
|
332
|
-
result.details.issue = 'Authentication failed';
|
|
333
|
-
result.details.suggestion = 'Check wrangler authentication and permissions';
|
|
334
|
-
} else {
|
|
335
|
-
result.details.issue = 'Connection failed';
|
|
336
|
-
result.details.suggestion = 'Check database status and network connectivity';
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
console.log(` ā D1 database '${databaseName}' is unhealthy: ${error.message}`);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return result;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Check multiple D1 databases health
|
|
347
|
-
* @param {Array<string>} databases - Array of database names
|
|
348
|
-
* @param {Object} options - Check options
|
|
349
|
-
* @returns {Promise<Object>} Combined health check results
|
|
350
|
-
*/
|
|
351
|
-
export async function checkMultipleD1Health(databases, options = {}) {
|
|
352
|
-
console.log(`šļø Checking health of ${databases.length} D1 databases...`);
|
|
353
|
-
|
|
354
|
-
const results = {
|
|
355
|
-
overall: 'unknown',
|
|
356
|
-
healthy: 0,
|
|
357
|
-
unhealthy: 0,
|
|
358
|
-
databases: [],
|
|
359
|
-
timestamp: new Date().toISOString()
|
|
360
|
-
};
|
|
361
|
-
|
|
362
|
-
for (const databaseName of databases) {
|
|
363
|
-
const dbResult = await checkD1Health(databaseName, options);
|
|
364
|
-
results.databases.push(dbResult);
|
|
365
|
-
|
|
366
|
-
if (dbResult.status === 'healthy') {
|
|
367
|
-
results.healthy++;
|
|
368
|
-
} else {
|
|
369
|
-
results.unhealthy++;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// Determine overall status
|
|
374
|
-
if (results.unhealthy === 0) {
|
|
375
|
-
results.overall = 'healthy';
|
|
376
|
-
} else if (results.healthy === 0) {
|
|
377
|
-
results.overall = 'unhealthy';
|
|
378
|
-
} else {
|
|
379
|
-
results.overall = 'partial';
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
console.log(` š D1 Health Summary: ${results.healthy} healthy, ${results.unhealthy} unhealthy`);
|
|
383
|
-
return results;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Comprehensive health check including D1 databases
|
|
388
|
-
* @param {string} serviceUrl - Service URL to check
|
|
389
|
-
* @param {Array<string>} databases - D1 databases to check
|
|
390
|
-
* @param {Object} options - Check options
|
|
391
|
-
* @returns {Promise<Object>} Comprehensive health result
|
|
392
|
-
*/
|
|
393
|
-
export async function enhancedComprehensiveHealthCheck(serviceUrl, databases = [], options = {}) {
|
|
394
|
-
console.log(`š„ Comprehensive Health Check`);
|
|
395
|
-
console.log(` Service: ${serviceUrl}`);
|
|
396
|
-
console.log(` D1 Databases: ${databases.length}`);
|
|
397
|
-
|
|
398
|
-
const startTime = Date.now();
|
|
399
|
-
const result = {
|
|
400
|
-
overall: 'unknown',
|
|
401
|
-
service: null,
|
|
402
|
-
databases: null,
|
|
403
|
-
duration: 0,
|
|
404
|
-
timestamp: new Date().toISOString()
|
|
405
|
-
};
|
|
406
|
-
|
|
407
|
-
try {
|
|
408
|
-
// Check service health
|
|
409
|
-
console.log('\nš” Checking service health...');
|
|
410
|
-
result.service = await checkHealth(serviceUrl, options.serviceTimeout);
|
|
411
|
-
|
|
412
|
-
// Check D1 databases if provided
|
|
413
|
-
if (databases.length > 0) {
|
|
414
|
-
console.log('\nšļø Checking D1 databases...');
|
|
415
|
-
result.databases = await checkMultipleD1Health(databases, options);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// Determine overall status
|
|
419
|
-
const serviceHealthy = result.service.status === 'ok';
|
|
420
|
-
const databasesHealthy = !result.databases || result.databases.overall === 'healthy';
|
|
421
|
-
|
|
422
|
-
if (serviceHealthy && databasesHealthy) {
|
|
423
|
-
result.overall = 'healthy';
|
|
424
|
-
} else if (!serviceHealthy && (!result.databases || result.databases.overall === 'unhealthy')) {
|
|
425
|
-
result.overall = 'unhealthy';
|
|
426
|
-
} else {
|
|
427
|
-
result.overall = 'partial';
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
result.duration = Date.now() - startTime;
|
|
431
|
-
|
|
432
|
-
console.log(`\nš Overall Health: ${result.overall.toUpperCase()} (${result.duration}ms)`);
|
|
433
|
-
return result;
|
|
434
|
-
|
|
435
|
-
} catch (error) {
|
|
436
|
-
result.overall = 'error';
|
|
437
|
-
result.error = error.message;
|
|
438
|
-
result.duration = Date.now() - startTime;
|
|
439
|
-
|
|
440
|
-
console.log(`\nā Health check failed: ${error.message}`);
|
|
441
|
-
throw error;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
/**
|
|
446
|
-
* Format D1 health check results for display
|
|
447
|
-
* @param {Object} d1Results - D1 health check results
|
|
448
|
-
* @returns {string} Formatted output
|
|
449
|
-
*/
|
|
450
|
-
export function formatD1HealthResults(d1Results) {
|
|
451
|
-
const lines = [
|
|
452
|
-
'šļø D1 Database Health Report',
|
|
453
|
-
'=============================='
|
|
454
|
-
];
|
|
455
|
-
|
|
456
|
-
if (d1Results.databases) {
|
|
457
|
-
lines.push(`š Overall Status: ${d1Results.overall.toUpperCase()}`);
|
|
458
|
-
lines.push(`ā
Healthy: ${d1Results.healthy}`);
|
|
459
|
-
lines.push(`ā Unhealthy: ${d1Results.unhealthy}`);
|
|
460
|
-
lines.push('');
|
|
461
|
-
|
|
462
|
-
d1Results.databases.forEach(db => {
|
|
463
|
-
const status = db.status === 'healthy' ? 'ā
' : 'ā';
|
|
464
|
-
lines.push(`${status} ${db.database} (${db.responseTime}ms)`);
|
|
465
|
-
|
|
466
|
-
if (db.status === 'unhealthy' && db.details.suggestion) {
|
|
467
|
-
lines.push(` š” ${db.details.suggestion}`);
|
|
468
|
-
}
|
|
469
|
-
});
|
|
470
|
-
} else {
|
|
471
|
-
lines.push(`š Database: ${d1Results.database}`);
|
|
472
|
-
lines.push(`š Status: ${d1Results.status.toUpperCase()}`);
|
|
473
|
-
lines.push(`ā±ļø Response Time: ${d1Results.responseTime}ms`);
|
|
474
|
-
|
|
475
|
-
if (d1Results.status === 'unhealthy') {
|
|
476
|
-
lines.push(`ā Error: ${d1Results.error}`);
|
|
477
|
-
if (d1Results.details.suggestion) {
|
|
478
|
-
lines.push(`š” Suggestion: ${d1Results.details.suggestion}`);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
return lines.join('\n');
|
|
484
|
-
}
|