@tamyla/clodo-framework 3.1.10 → 3.1.12
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 +3 -3
- 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/validation/ValidationRegistry.js +1 -1
- package/dist/deployment/wrangler-deployer.js +1 -1
- package/dist/orchestration/cross-domain-coordinator.js +5 -5
- package/dist/security/index.js +1 -1
- package/dist/service-management/ConfirmationEngine.js +1 -1
- package/dist/service-management/ErrorTracker.js +1 -1
- package/dist/service-management/InputCollector.js +1 -1
- package/dist/service-management/ServiceCreator.js +1 -1
- package/dist/service-management/ServiceInitializer.js +1 -1
- package/dist/utils/config/unified-config-manager.js +1 -1
- package/dist/utils/deployment/config-cache.js +1 -1
- package/dist/utils/deployment/secret-generator.js +1 -1
- package/dist/utils/framework-config.js +1 -1
- package/dist/worker/integration.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,374 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database Connection Manager
|
|
3
|
-
* Implements connection pooling, timeout handling, and retry logic for D1 operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { executeSql } from '../cloudflare/ops.js';
|
|
7
|
-
import { ErrorRecoveryManager } from '../utils/index.js';
|
|
8
|
-
|
|
9
|
-
export class DatabaseConnectionManager {
|
|
10
|
-
constructor(options = {}) {
|
|
11
|
-
this.options = options;
|
|
12
|
-
this.config = null;
|
|
13
|
-
this.connectionPool = new Map();
|
|
14
|
-
this.activeConnections = 0;
|
|
15
|
-
this.errorRecovery = null; // Will be initialized after framework config is loaded
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Initialize with framework configuration
|
|
20
|
-
*/
|
|
21
|
-
async initialize() {
|
|
22
|
-
// Import framework config for consistent database connection settings
|
|
23
|
-
const { frameworkConfig } = await import('../../../dist/utils/framework-config.js');
|
|
24
|
-
const timing = frameworkConfig.getTiming();
|
|
25
|
-
const database = frameworkConfig.getDatabaseConfig();
|
|
26
|
-
|
|
27
|
-
this.config = {
|
|
28
|
-
maxRetries: this.options.maxRetries || timing.retryAttempts,
|
|
29
|
-
retryDelay: this.options.retryDelay || timing.retryDelay,
|
|
30
|
-
connectionTimeout: this.options.connectionTimeout || database.connectionTimeout,
|
|
31
|
-
queryTimeout: this.options.queryTimeout || database.queryTimeout,
|
|
32
|
-
enableConnectionPooling: this.options.enableConnectionPooling !== false,
|
|
33
|
-
maxPoolSize: this.options.maxPoolSize || database.maxPoolSize,
|
|
34
|
-
connectionIdleTimeout: this.options.connectionIdleTimeout || database.connectionIdleTimeout,
|
|
35
|
-
...this.options
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// Initialize error recovery with loaded config
|
|
39
|
-
const { ErrorRecoveryManager } = await import('../utils/index.js');
|
|
40
|
-
this.errorRecovery = new ErrorRecoveryManager({
|
|
41
|
-
maxRetries: this.config.maxRetries,
|
|
42
|
-
retryDelay: this.config.retryDelay,
|
|
43
|
-
gracefulDegradation: true
|
|
44
|
-
});
|
|
45
|
-
await this.errorRecovery.initialize();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Execute a database query with connection management
|
|
50
|
-
*/
|
|
51
|
-
async executeQuery(databaseName, sql, options = {}) {
|
|
52
|
-
if (!this.config) {
|
|
53
|
-
throw new Error('ConnectionManager must be initialized before use. Call initialize() first.');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const config = {
|
|
57
|
-
env: 'production',
|
|
58
|
-
timeout: this.config.queryTimeout,
|
|
59
|
-
usePool: this.config.enableConnectionPooling,
|
|
60
|
-
...options
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
return await this.errorRecovery.executeWithRecovery(async () => {
|
|
64
|
-
return await this.executeQueryInternal(databaseName, sql, config);
|
|
65
|
-
}, { operationId: `db_query_${databaseName}` });
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Execute query with timeout and connection handling
|
|
70
|
-
*/
|
|
71
|
-
async executeQueryInternal(databaseName, sql, config) {
|
|
72
|
-
const startTime = Date.now();
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
// Get or create connection
|
|
76
|
-
const connection = await this.getConnection(databaseName, config);
|
|
77
|
-
|
|
78
|
-
// Execute query with timeout
|
|
79
|
-
const result = await this.executeWithTimeout(
|
|
80
|
-
() => executeSql(databaseName, sql, config.env),
|
|
81
|
-
config.timeout
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
const duration = Date.now() - startTime;
|
|
85
|
-
|
|
86
|
-
// Release connection back to pool
|
|
87
|
-
if (config.usePool) {
|
|
88
|
-
this.releaseConnection(databaseName, connection);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
success: true,
|
|
93
|
-
result,
|
|
94
|
-
duration,
|
|
95
|
-
connectionId: connection.id
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
} catch (error) {
|
|
99
|
-
const duration = Date.now() - startTime;
|
|
100
|
-
|
|
101
|
-
// Handle connection errors
|
|
102
|
-
if (this.isConnectionError(error)) {
|
|
103
|
-
await this.handleConnectionError(databaseName, error);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
throw new Error(`Database query failed: ${error.message} (duration: ${duration}ms)`);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Execute multiple queries in a transaction
|
|
112
|
-
*/
|
|
113
|
-
async executeTransaction(databaseName, queries, options = {}) {
|
|
114
|
-
const config = {
|
|
115
|
-
env: 'production',
|
|
116
|
-
timeout: this.config.queryTimeout * queries.length, // Longer timeout for transactions
|
|
117
|
-
...options
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
return await this.errorRecovery.executeWithRecovery(async () => {
|
|
121
|
-
return await this.executeTransactionInternal(databaseName, queries, config);
|
|
122
|
-
}, { operationId: `db_transaction_${databaseName}` });
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Execute transaction with proper error handling
|
|
127
|
-
*/
|
|
128
|
-
async executeTransactionInternal(databaseName, queries, config) {
|
|
129
|
-
const startTime = Date.now();
|
|
130
|
-
const results = [];
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const connection = await this.getConnection(databaseName, config);
|
|
134
|
-
|
|
135
|
-
for (let i = 0; i < queries.length; i++) {
|
|
136
|
-
const query = queries[i];
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
const result = await this.executeWithTimeout(
|
|
140
|
-
() => executeSql(databaseName, query, config.env),
|
|
141
|
-
config.timeout / queries.length // Divide timeout among queries
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
results.push({
|
|
145
|
-
index: i,
|
|
146
|
-
success: true,
|
|
147
|
-
result,
|
|
148
|
-
query
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
} catch (queryError) {
|
|
152
|
-
// Transaction failed, all previous queries should be rolled back
|
|
153
|
-
// Note: D1 doesn't support explicit transactions, so we need to handle this at application level
|
|
154
|
-
results.push({
|
|
155
|
-
index: i,
|
|
156
|
-
success: false,
|
|
157
|
-
error: queryError.message,
|
|
158
|
-
query
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
throw new Error(`Transaction failed at query ${i}: ${queryError.message}`);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const duration = Date.now() - startTime;
|
|
166
|
-
|
|
167
|
-
if (config.usePool) {
|
|
168
|
-
this.releaseConnection(databaseName, connection);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
success: true,
|
|
173
|
-
results,
|
|
174
|
-
duration,
|
|
175
|
-
transactionId: `txn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
} catch (error) {
|
|
179
|
-
const duration = Date.now() - startTime;
|
|
180
|
-
throw new Error(`Database transaction failed: ${error.message} (duration: ${duration}ms)`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Get a connection from the pool or create a new one
|
|
186
|
-
*/
|
|
187
|
-
async getConnection(databaseName, config) {
|
|
188
|
-
if (!config.usePool) {
|
|
189
|
-
return this.createConnection(databaseName);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const poolKey = databaseName;
|
|
193
|
-
let pool = this.connectionPool.get(poolKey);
|
|
194
|
-
|
|
195
|
-
if (!pool) {
|
|
196
|
-
pool = [];
|
|
197
|
-
this.connectionPool.set(poolKey, pool);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Find an available connection
|
|
201
|
-
let connection = pool.find(conn => !conn.inUse && !this.isConnectionExpired(conn));
|
|
202
|
-
|
|
203
|
-
if (!connection && pool.length < this.config.maxPoolSize) {
|
|
204
|
-
connection = this.createConnection(databaseName);
|
|
205
|
-
pool.push(connection);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (!connection) {
|
|
209
|
-
// Wait for an available connection
|
|
210
|
-
connection = await this.waitForAvailableConnection(pool, config.timeout);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (!connection) {
|
|
214
|
-
throw new Error('No available database connections');
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
connection.inUse = true;
|
|
218
|
-
connection.lastUsed = Date.now();
|
|
219
|
-
this.activeConnections++;
|
|
220
|
-
|
|
221
|
-
return connection;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Release a connection back to the pool
|
|
226
|
-
*/
|
|
227
|
-
releaseConnection(databaseName, connection) {
|
|
228
|
-
connection.inUse = false;
|
|
229
|
-
connection.lastUsed = Date.now();
|
|
230
|
-
this.activeConnections--;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Create a new database connection
|
|
235
|
-
*/
|
|
236
|
-
createConnection(databaseName) {
|
|
237
|
-
return {
|
|
238
|
-
id: `conn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
239
|
-
databaseName,
|
|
240
|
-
created: Date.now(),
|
|
241
|
-
lastUsed: Date.now(),
|
|
242
|
-
inUse: false
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Wait for an available connection
|
|
248
|
-
*/
|
|
249
|
-
async waitForAvailableConnection(pool, timeout) {
|
|
250
|
-
const startTime = Date.now();
|
|
251
|
-
|
|
252
|
-
while (Date.now() - startTime < timeout) {
|
|
253
|
-
const connection = pool.find(conn => !conn.inUse && !this.isConnectionExpired(conn));
|
|
254
|
-
if (connection) {
|
|
255
|
-
return connection;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Wait a bit before checking again
|
|
259
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return null;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Check if a connection is expired
|
|
267
|
-
*/
|
|
268
|
-
isConnectionExpired(connection) {
|
|
269
|
-
const now = Date.now();
|
|
270
|
-
return (now - connection.lastUsed) > this.config.connectionIdleTimeout;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Handle connection errors
|
|
275
|
-
*/
|
|
276
|
-
async handleConnectionError(databaseName, error) {
|
|
277
|
-
// Clean up any bad connections from the pool
|
|
278
|
-
const poolKey = databaseName;
|
|
279
|
-
const pool = this.connectionPool.get(poolKey);
|
|
280
|
-
|
|
281
|
-
if (pool) {
|
|
282
|
-
const validConnections = pool.filter(conn => !this.isConnectionExpired(conn));
|
|
283
|
-
this.connectionPool.set(poolKey, validConnections);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Could implement connection health checks here
|
|
287
|
-
console.warn(`Database connection error for ${databaseName}:`, error.message);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Check if error is connection-related
|
|
292
|
-
*/
|
|
293
|
-
isConnectionError(error) {
|
|
294
|
-
const connectionErrorPatterns = [
|
|
295
|
-
'connection',
|
|
296
|
-
'timeout',
|
|
297
|
-
'network',
|
|
298
|
-
'ECONNREFUSED',
|
|
299
|
-
'ENOTFOUND',
|
|
300
|
-
'ETIMEDOUT'
|
|
301
|
-
];
|
|
302
|
-
|
|
303
|
-
const errorMessage = error.message.toLowerCase();
|
|
304
|
-
return connectionErrorPatterns.some(pattern => errorMessage.includes(pattern));
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Execute a function with timeout
|
|
309
|
-
*/
|
|
310
|
-
async executeWithTimeout(fn, timeout) {
|
|
311
|
-
return new Promise((resolve, reject) => {
|
|
312
|
-
const timeoutId = setTimeout(() => {
|
|
313
|
-
reject(new Error(`Operation timed out after ${timeout}ms`));
|
|
314
|
-
}, timeout);
|
|
315
|
-
|
|
316
|
-
fn().then((result) => {
|
|
317
|
-
clearTimeout(timeoutId);
|
|
318
|
-
resolve(result);
|
|
319
|
-
}).catch((error) => {
|
|
320
|
-
clearTimeout(timeoutId);
|
|
321
|
-
reject(error);
|
|
322
|
-
});
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Get connection pool statistics
|
|
328
|
-
*/
|
|
329
|
-
getPoolStats(databaseName) {
|
|
330
|
-
const pool = this.connectionPool.get(databaseName) || [];
|
|
331
|
-
|
|
332
|
-
return {
|
|
333
|
-
databaseName,
|
|
334
|
-
totalConnections: pool.length,
|
|
335
|
-
activeConnections: pool.filter(conn => conn.inUse).length,
|
|
336
|
-
idleConnections: pool.filter(conn => !conn.inUse).length,
|
|
337
|
-
expiredConnections: pool.filter(conn => this.isConnectionExpired(conn)).length,
|
|
338
|
-
globalActiveConnections: this.activeConnections
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Get all pool statistics
|
|
344
|
-
*/
|
|
345
|
-
getAllPoolStats() {
|
|
346
|
-
const stats = {};
|
|
347
|
-
for (const [databaseName, pool] of this.connectionPool) {
|
|
348
|
-
stats[databaseName] = this.getPoolStats(databaseName);
|
|
349
|
-
}
|
|
350
|
-
return stats;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Clean up expired connections
|
|
355
|
-
*/
|
|
356
|
-
cleanupExpiredConnections() {
|
|
357
|
-
for (const [databaseName, pool] of this.connectionPool) {
|
|
358
|
-
const validConnections = pool.filter(conn => !this.isConnectionExpired(conn));
|
|
359
|
-
this.connectionPool.set(databaseName, validConnections);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Close all connections
|
|
365
|
-
*/
|
|
366
|
-
async closeAllConnections() {
|
|
367
|
-
for (const [databaseName, pool] of this.connectionPool) {
|
|
368
|
-
// In a real implementation, you'd close actual connections
|
|
369
|
-
pool.length = 0;
|
|
370
|
-
}
|
|
371
|
-
this.connectionPool.clear();
|
|
372
|
-
this.activeConnections = 0;
|
|
373
|
-
}
|
|
374
|
-
}
|