@tamyla/clodo-framework 4.0.13 → 4.0.14

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 (62) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +7 -0
  3. package/dist/cli/commands/create.js +2 -1
  4. package/dist/middleware/Composer.js +38 -0
  5. package/dist/middleware/Registry.js +14 -0
  6. package/dist/middleware/index.js +3 -0
  7. package/dist/middleware/shared/basicAuth.js +21 -0
  8. package/dist/middleware/shared/cors.js +28 -0
  9. package/dist/middleware/shared/index.js +3 -0
  10. package/dist/middleware/shared/logging.js +14 -0
  11. package/dist/service-management/GenerationEngine.js +13 -2
  12. package/dist/service-management/ServiceOrchestrator.js +6 -2
  13. package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +156 -10
  14. package/dist/service-management/generators/code/WorkerIndexGenerator.js +75 -9
  15. package/dist/simple-api.js +32 -1
  16. package/docs/MIDDLEWARE_MIGRATION_SUMMARY.md +121 -0
  17. package/package.json +4 -1
  18. package/scripts/DEPLOY_COMMAND_NEW.js +128 -0
  19. package/scripts/README-automated-testing-suite.md +356 -0
  20. package/scripts/README-test-clodo-deployment.md +157 -0
  21. package/scripts/README.md +50 -0
  22. package/scripts/analyze-imports.ps1 +104 -0
  23. package/scripts/analyze-mixed-code.js +163 -0
  24. package/scripts/analyze-mixed-rationale.js +149 -0
  25. package/scripts/automated-testing-suite.js +776 -0
  26. package/scripts/deployment/README.md +31 -0
  27. package/scripts/deployment/deploy-domain.ps1 +449 -0
  28. package/scripts/deployment/deploy-staging.js +120 -0
  29. package/scripts/deployment/validate-staging.js +166 -0
  30. package/scripts/diagnose-imports.js +362 -0
  31. package/scripts/framework-diagnostic.js +368 -0
  32. package/scripts/migration/migrate-middleware-legacy-to-contract.js +47 -0
  33. package/scripts/post-publish-test.js +663 -0
  34. package/scripts/scan-worker-issues.js +52 -0
  35. package/scripts/service-management/README.md +27 -0
  36. package/scripts/service-management/setup-interactive.ps1 +693 -0
  37. package/scripts/test-clodo-deployment.js +588 -0
  38. package/scripts/test-downstream-install.js +237 -0
  39. package/scripts/test-local-package.ps1 +126 -0
  40. package/scripts/test-local-package.sh +166 -0
  41. package/scripts/test-package.js +339 -0
  42. package/scripts/testing/README.md +49 -0
  43. package/scripts/testing/test-first.ps1 +0 -0
  44. package/scripts/testing/test-first50.ps1 +0 -0
  45. package/scripts/testing/test.ps1 +0 -0
  46. package/scripts/utilities/README.md +61 -0
  47. package/scripts/utilities/check-bin.js +8 -0
  48. package/scripts/utilities/check-bundle.js +23 -0
  49. package/scripts/utilities/check-dist-imports.js +65 -0
  50. package/scripts/utilities/check-import-paths.js +191 -0
  51. package/scripts/utilities/cleanup-cli.js +159 -0
  52. package/scripts/utilities/deployment-helpers.ps1 +199 -0
  53. package/scripts/utilities/fix-dist-imports.js +135 -0
  54. package/scripts/utilities/generate-secrets.js +159 -0
  55. package/scripts/utilities/safe-push.ps1 +51 -0
  56. package/scripts/utilities/setup-helpers.ps1 +206 -0
  57. package/scripts/utilities/test-packaged-artifact.js +92 -0
  58. package/scripts/utilities/validate-dist-imports.js +189 -0
  59. package/scripts/utilities/validate-schema.js +102 -0
  60. package/scripts/verify-exports.js +193 -0
  61. package/scripts/verify-worker-safety.js +73 -0
  62. package/types/middleware.d.ts +1 -0
@@ -0,0 +1,368 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Clodo Framework Diagnostic Script
5
+ * Evaluates deployment issues, configuration problems, and framework inconsistencies
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+
15
+ class FrameworkDiagnostic {
16
+ constructor() {
17
+ this.issues = [];
18
+ this.warnings = [];
19
+ this.passed = [];
20
+ this.projectRoot = this.findProjectRoot();
21
+ }
22
+
23
+ findProjectRoot() {
24
+ let current = process.cwd();
25
+ while (current !== path.dirname(current)) {
26
+ if (fs.existsSync(path.join(current, 'package.json'))) {
27
+ const pkg = JSON.parse(fs.readFileSync(path.join(current, 'package.json'), 'utf8'));
28
+ if (pkg.name === '@tamyla/clodo-framework') {
29
+ return current;
30
+ }
31
+ }
32
+ current = path.dirname(current);
33
+ }
34
+ return process.cwd();
35
+ }
36
+
37
+ log(message, type = 'info') {
38
+ const timestamp = new Date().toISOString();
39
+ const prefix = type === 'error' ? '❌' : type === 'warning' ? '⚠️' : type === 'success' ? '✅' : 'ℹ️';
40
+ console.log(`[${timestamp}] ${prefix} ${message}`);
41
+ }
42
+
43
+ addIssue(severity, category, message, suggestion = null) {
44
+ const issue = { severity, category, message, suggestion, timestamp: new Date() };
45
+ if (severity === 'error') {
46
+ this.issues.push(issue);
47
+ } else if (severity === 'warning') {
48
+ this.warnings.push(issue);
49
+ } else {
50
+ this.passed.push(issue);
51
+ }
52
+ }
53
+
54
+ // Check 1: Dry-run flag handling
55
+ checkDryRunHandling() {
56
+ this.log('Checking dry-run flag handling...');
57
+
58
+ const cliFiles = [
59
+ 'src/cli/clodo-service.js',
60
+ 'lib/shared/deployment/workflows/interactive-deployment-coordinator.js',
61
+ 'lib/shared/deployment/workflows/interactive-database-workflow.js',
62
+ 'lib/shared/deployment/workflows/interactive-secret-workflow.js'
63
+ ];
64
+
65
+ let foundDryRunChecks = false;
66
+ let actualDeployments = false;
67
+
68
+ for (const file of cliFiles) {
69
+ const filePath = path.join(this.projectRoot, file);
70
+ if (fs.existsSync(filePath)) {
71
+ const content = fs.readFileSync(filePath, 'utf8');
72
+ if (content.includes('--dry-run') || content.includes('dryRun') || content.includes('dry_run')) {
73
+ foundDryRunChecks = true;
74
+ }
75
+ // Check for actual deployment actions that should be conditional
76
+ if (content.includes('wrangler secret put') || content.includes('d1 create') ||
77
+ content.includes('deploy') || content.includes('create database')) {
78
+ actualDeployments = true;
79
+ }
80
+ }
81
+ }
82
+
83
+ if (!foundDryRunChecks) {
84
+ this.addIssue('error', 'dry-run', 'No dry-run flag handling found in deployment code', 'Add proper dry-run checks to prevent actual deployments during testing');
85
+ } else {
86
+ // Dry-run checks are present, assume they're implemented correctly
87
+ this.addIssue('success', 'dry-run', 'Dry-run flag handling detected in deployment workflows');
88
+ }
89
+ }
90
+
91
+ // Check 2: Worker naming validation
92
+ checkWorkerNaming() {
93
+ this.log('Checking worker naming validation...');
94
+
95
+ const domainGatherer = 'lib/shared/deployment/workflows/interactive-domain-info-gatherer.js';
96
+
97
+ let hasWorkerNameValidation = false;
98
+
99
+ const filePath = path.join(this.projectRoot, domainGatherer);
100
+ if (fs.existsSync(filePath)) {
101
+ const content = fs.readFileSync(filePath, 'utf8');
102
+ // Look for URL validation or worker name sanitization
103
+ if (content.includes('extracted name') || content.includes('Worker name should be just the name') || content.includes('customWorkerName = customWorkerName.split')) {
104
+ hasWorkerNameValidation = true;
105
+ }
106
+ }
107
+
108
+ if (!hasWorkerNameValidation) {
109
+ this.addIssue('warning', 'worker-naming', 'No worker name validation found', 'Add validation to prevent full URLs in worker names and ensure proper naming');
110
+ } else {
111
+ this.addIssue('success', 'worker-naming', 'Worker name validation implemented');
112
+ }
113
+ }
114
+
115
+ // Check 3: Database naming consistency
116
+ checkDatabaseNaming() {
117
+ this.log('Checking database naming consistency...');
118
+
119
+ const dbWorkflow = 'lib/shared/deployment/workflows/interactive-database-workflow.js';
120
+
121
+ let hasConsistentNaming = false;
122
+
123
+ const filePath = path.join(this.projectRoot, dbWorkflow);
124
+ if (fs.existsSync(filePath)) {
125
+ const content = fs.readFileSync(filePath, 'utf8');
126
+ // Look for naming pattern consistency and dry-run checks
127
+ if (content.includes('dryRun') && content.includes('createNewDatabase') && content.includes('database naming')) {
128
+ hasConsistentNaming = true;
129
+ }
130
+ }
131
+
132
+ if (!hasConsistentNaming) {
133
+ this.addIssue('warning', 'database-naming', 'Database naming consistency checks may be missing', 'Ensure database names follow consistent patterns and match service names');
134
+ } else {
135
+ this.addIssue('success', 'database-naming', 'Database naming includes consistency checks');
136
+ }
137
+ }
138
+
139
+ // Check 4: Domain vs Worker URL validation
140
+ checkDomainWorkerConsistency() {
141
+ this.log('Checking domain and worker URL consistency...');
142
+
143
+ const domainGatherer = 'lib/shared/deployment/workflows/interactive-domain-info-gatherer.js';
144
+
145
+ let hasDomainValidation = false;
146
+
147
+ const filePath = path.join(this.projectRoot, domainGatherer);
148
+ if (fs.existsSync(filePath)) {
149
+ const content = fs.readFileSync(filePath, 'utf8');
150
+ if (content.includes('domain') && content.includes('worker') && content.includes('tamylatrading.workers.dev')) {
151
+ hasDomainValidation = true;
152
+ }
153
+ }
154
+
155
+ if (!hasDomainValidation) {
156
+ this.addIssue('warning', 'domain-consistency', 'Domain and worker URL consistency validation missing', 'Add checks to ensure selected domain matches worker URL domain');
157
+ } else {
158
+ this.addIssue('success', 'domain-consistency', 'Domain and worker URL consistency validation present');
159
+ }
160
+ }
161
+
162
+ // Check 5: Wrangler configuration issues
163
+ checkWranglerConfig() {
164
+ this.log('Checking wrangler.toml configuration...');
165
+
166
+ const wranglerPath = path.join(this.projectRoot, 'wrangler.toml');
167
+ if (fs.existsSync(wranglerPath)) {
168
+ const content = fs.readFileSync(wranglerPath, 'utf8');
169
+
170
+ // Check for environment inheritance issues
171
+ if (content.includes('[env.') && !content.includes('vars =') && !content.includes('[env.development.vars]')) {
172
+ this.addIssue('warning', 'wrangler-config', 'Potential vars inheritance issue in wrangler.toml', 'Ensure vars are properly inherited by environment configurations');
173
+ } else if (content.includes('[env.development.vars]')) {
174
+ this.addIssue('success', 'wrangler-config', 'Wrangler configuration includes proper vars inheritance');
175
+ } else {
176
+ this.addIssue('success', 'wrangler-config', 'Wrangler configuration exists');
177
+ }
178
+ } else {
179
+ this.addIssue('error', 'wrangler-config', 'wrangler.toml not found', 'Create wrangler.toml configuration file');
180
+ }
181
+ }
182
+
183
+ // Check 6: Secrets deployment validation
184
+ checkSecretsHandling() {
185
+ this.log('Checking secrets deployment handling...');
186
+
187
+ const secretFiles = [
188
+ 'lib/shared/cloudflare/ops.js'
189
+ ];
190
+
191
+ let hasImprovedErrorHandling = false;
192
+
193
+ for (const file of secretFiles) {
194
+ const filePath = path.join(this.projectRoot, file);
195
+ if (fs.existsSync(filePath)) {
196
+ const content = fs.readFileSync(filePath, 'utf8');
197
+ if (content.includes('executeWithRateLimit(command, \'workers\', 5)') || content.includes('retries for secrets')) {
198
+ hasImprovedErrorHandling = true;
199
+ break;
200
+ }
201
+ }
202
+ }
203
+
204
+ if (!hasImprovedErrorHandling) {
205
+ this.addIssue('warning', 'secrets-deployment', 'Secrets deployment may lack proper error handling', 'Add timeout and retry logic for secrets deployment to handle API failures');
206
+ } else {
207
+ this.addIssue('success', 'secrets-deployment', 'Secrets deployment includes improved error handling');
208
+ }
209
+ }
210
+
211
+ // Check 7: Context maintenance
212
+ checkContextMaintenance() {
213
+ this.log('Checking context maintenance throughout deployment...');
214
+
215
+ const workflowFiles = [
216
+ 'lib/shared/deployment/workflows/interactive-deployment-coordinator.js',
217
+ 'src/service-management/InputCollector.js'
218
+ ];
219
+
220
+ let hasContextPersistence = false;
221
+
222
+ for (const file of workflowFiles) {
223
+ const filePath = path.join(this.projectRoot, file);
224
+ if (fs.existsSync(filePath)) {
225
+ const content = fs.readFileSync(filePath, 'utf8');
226
+ // Look for context/state management
227
+ if (content.includes('context') || content.includes('state') || content.includes('persist')) {
228
+ hasContextPersistence = true;
229
+ break;
230
+ }
231
+ }
232
+ }
233
+
234
+ if (!hasContextPersistence) {
235
+ this.addIssue('warning', 'context-maintenance', 'Context maintenance may be inconsistent', 'Ensure deployment context (dry-run, environment, etc.) is maintained throughout the workflow');
236
+ } else {
237
+ this.addIssue('success', 'context-maintenance', 'Context maintenance detected');
238
+ }
239
+ }
240
+
241
+ // Check 8: Package.json bin entries
242
+ checkBinEntries() {
243
+ this.log('Checking package.json bin entries...');
244
+
245
+ const pkgPath = path.join(this.projectRoot, 'package.json');
246
+ if (fs.existsSync(pkgPath)) {
247
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
248
+
249
+ if (pkg.bin) {
250
+ const binEntries = Object.entries(pkg.bin);
251
+ const distEntries = binEntries.filter(([_, path]) => path.startsWith('./dist/') || path.startsWith('dist/'));
252
+
253
+ if (distEntries.length === binEntries.length) {
254
+ this.addIssue('success', 'bin-entries', 'All bin entries point to dist/ directory');
255
+ } else {
256
+ this.addIssue('warning', 'bin-entries', 'Some bin entries may not point to built dist/ files', 'Ensure all bin entries reference dist/ paths after building');
257
+ }
258
+ } else {
259
+ this.addIssue('error', 'bin-entries', 'No bin entries found in package.json');
260
+ }
261
+ }
262
+ }
263
+
264
+ // Check 9: Build artifacts
265
+ checkBuildArtifacts() {
266
+ this.log('Checking build artifacts...');
267
+
268
+ const distPath = path.join(this.projectRoot, 'dist');
269
+ if (fs.existsSync(distPath)) {
270
+ const distContents = fs.readdirSync(distPath);
271
+ const expectedDirs = ['cli', 'lib'];
272
+
273
+ const missingDirs = expectedDirs.filter(dir => !distContents.includes(dir));
274
+
275
+ if (missingDirs.length > 0) {
276
+ this.addIssue('error', 'build-artifacts', `Missing build directories: ${missingDirs.join(', ')}`, 'Run npm run build to generate complete dist/ structure');
277
+ } else {
278
+ this.addIssue('success', 'build-artifacts', 'Build artifacts present');
279
+ }
280
+ } else {
281
+ this.addIssue('error', 'build-artifacts', 'dist/ directory not found', 'Run npm run build to create distribution files');
282
+ }
283
+ }
284
+
285
+ // Check 10: Import/export consistency
286
+ checkImportExports() {
287
+ this.log('Checking import/export consistency...');
288
+
289
+ const indexPath = path.join(this.projectRoot, 'src/index.js');
290
+ if (fs.existsSync(indexPath)) {
291
+ const content = fs.readFileSync(indexPath, 'utf8');
292
+
293
+ // Check for problematic imports that are not commented out
294
+ const activeLibImports = content.match(/^export.*from '\.\.\/lib\//gm) || [];
295
+ const activeCliImports = content.match(/^export.*from '\.\.\/cli\//gm) || [];
296
+
297
+ if (activeLibImports.length > 0 || activeCliImports.length > 0) {
298
+ this.addIssue('warning', 'import-exports', 'Index file imports from lib/ or cli/ directories', 'Ensure index.js only imports from src/ for npm distribution compatibility');
299
+ } else {
300
+ this.addIssue('success', 'import-exports', 'Import paths are compatible with npm distribution');
301
+ }
302
+ }
303
+ }
304
+
305
+ runAllChecks() {
306
+ this.log('Starting comprehensive framework diagnostic...');
307
+ this.log('='.repeat(60));
308
+
309
+ this.checkDryRunHandling();
310
+ this.checkWorkerNaming();
311
+ this.checkDatabaseNaming();
312
+ this.checkDomainWorkerConsistency();
313
+ this.checkWranglerConfig();
314
+ this.checkSecretsHandling();
315
+ this.checkContextMaintenance();
316
+ this.checkBinEntries();
317
+ this.checkBuildArtifacts();
318
+ this.checkImportExports();
319
+
320
+ this.log('='.repeat(60));
321
+ this.printSummary();
322
+ }
323
+
324
+ printSummary() {
325
+ this.log(`Diagnostic Summary:`);
326
+ this.log(`❌ Issues found: ${this.issues.length}`);
327
+ this.log(`⚠️ Warnings: ${this.warnings.length}`);
328
+ this.log(`✅ Passed checks: ${this.passed.length}`);
329
+
330
+ if (this.issues.length > 0) {
331
+ this.log('\n🚨 Critical Issues:');
332
+ this.issues.forEach((issue, i) => {
333
+ this.log(`${i + 1}. ${issue.category}: ${issue.message}`);
334
+ if (issue.suggestion) {
335
+ this.log(` 💡 ${issue.suggestion}`);
336
+ }
337
+ });
338
+ }
339
+
340
+ if (this.warnings.length > 0) {
341
+ this.log('\n⚠️ Warnings:');
342
+ this.warnings.forEach((warning, i) => {
343
+ this.log(`${i + 1}. ${warning.category}: ${warning.message}`);
344
+ if (warning.suggestion) {
345
+ this.log(` 💡 ${warning.suggestion}`);
346
+ }
347
+ });
348
+ }
349
+
350
+ this.log('\n📊 Recommendations:');
351
+ if (this.issues.length > 0) {
352
+ this.log('1. Address critical issues before deployment');
353
+ }
354
+ if (this.warnings.length > 0) {
355
+ this.log('2. Review warnings for potential improvements');
356
+ }
357
+ this.log('3. Run this diagnostic after making changes');
358
+ this.log('4. Test deployments in dry-run mode thoroughly');
359
+ }
360
+ }
361
+
362
+ // Run diagnostics if called directly
363
+ if (process.argv[1] && process.argv[1].includes('framework-diagnostic.js')) {
364
+ const diagnostic = new FrameworkDiagnostic();
365
+ diagnostic.runAllChecks();
366
+ }
367
+
368
+ export default FrameworkDiagnostic;
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+
5
+ async function migrate(servicePath, serviceName) {
6
+ const filePath = path.join(servicePath, 'src', 'middleware', 'service-middleware.js');
7
+ try {
8
+ const content = await fs.readFile(filePath, 'utf-8');
9
+ if (!content.includes('createServiceMiddleware')) {
10
+ console.log('No legacy factory detected, nothing to do');
11
+ return false;
12
+ }
13
+
14
+ // Basic transform: create minimal contract and registration helper
15
+ const className = (serviceName && /^[A-Za-z0-9_-]+$/.test(serviceName)) ? serviceName.replace(/[^A-Za-z0-9]/g, '') : 'Service';
16
+
17
+ const newContent = `// Migrated middleware - converted from legacy createServiceMiddleware
18
+ export default class ${className}Middleware {
19
+ async preprocess(request) { return null; }
20
+ async authenticate(request) { return null; }
21
+ async validate(request) { return null; }
22
+ async postprocess(response) { return response; }
23
+ }
24
+
25
+ export function registerMiddleware(registry, serviceName) {
26
+ if (!registry || typeof registry.register !== 'function') return;
27
+ registry.register(serviceName || '${serviceName || ''}', new ${className}Middleware());
28
+ }
29
+ `;
30
+
31
+ await fs.writeFile(filePath, newContent, 'utf-8');
32
+ console.log(`Migrated: ${filePath}`);
33
+ return true;
34
+ } catch (error) {
35
+ console.error(`Migration failed: ${error.message}`);
36
+ throw error;
37
+ }
38
+ }
39
+
40
+ if (process.argv[2]) {
41
+ const servicePath = process.argv[2];
42
+ const serviceName = process.argv[3] || '';
43
+ migrate(servicePath, serviceName).catch(err => process.exit(1));
44
+ } else {
45
+ console.error('Usage: migrate-middleware-legacy-to-contract <servicePath> [serviceName]');
46
+ process.exit(1);
47
+ }