@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.
- package/CHANGELOG.md +11 -0
- package/README.md +7 -0
- package/dist/cli/commands/create.js +2 -1
- package/dist/middleware/Composer.js +38 -0
- package/dist/middleware/Registry.js +14 -0
- package/dist/middleware/index.js +3 -0
- package/dist/middleware/shared/basicAuth.js +21 -0
- package/dist/middleware/shared/cors.js +28 -0
- package/dist/middleware/shared/index.js +3 -0
- package/dist/middleware/shared/logging.js +14 -0
- package/dist/service-management/GenerationEngine.js +13 -2
- package/dist/service-management/ServiceOrchestrator.js +6 -2
- package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +156 -10
- package/dist/service-management/generators/code/WorkerIndexGenerator.js +75 -9
- package/dist/simple-api.js +32 -1
- package/docs/MIDDLEWARE_MIGRATION_SUMMARY.md +121 -0
- package/package.json +4 -1
- package/scripts/DEPLOY_COMMAND_NEW.js +128 -0
- package/scripts/README-automated-testing-suite.md +356 -0
- package/scripts/README-test-clodo-deployment.md +157 -0
- package/scripts/README.md +50 -0
- package/scripts/analyze-imports.ps1 +104 -0
- package/scripts/analyze-mixed-code.js +163 -0
- package/scripts/analyze-mixed-rationale.js +149 -0
- package/scripts/automated-testing-suite.js +776 -0
- package/scripts/deployment/README.md +31 -0
- package/scripts/deployment/deploy-domain.ps1 +449 -0
- package/scripts/deployment/deploy-staging.js +120 -0
- package/scripts/deployment/validate-staging.js +166 -0
- package/scripts/diagnose-imports.js +362 -0
- package/scripts/framework-diagnostic.js +368 -0
- package/scripts/migration/migrate-middleware-legacy-to-contract.js +47 -0
- package/scripts/post-publish-test.js +663 -0
- package/scripts/scan-worker-issues.js +52 -0
- package/scripts/service-management/README.md +27 -0
- package/scripts/service-management/setup-interactive.ps1 +693 -0
- package/scripts/test-clodo-deployment.js +588 -0
- package/scripts/test-downstream-install.js +237 -0
- package/scripts/test-local-package.ps1 +126 -0
- package/scripts/test-local-package.sh +166 -0
- package/scripts/test-package.js +339 -0
- package/scripts/testing/README.md +49 -0
- package/scripts/testing/test-first.ps1 +0 -0
- package/scripts/testing/test-first50.ps1 +0 -0
- package/scripts/testing/test.ps1 +0 -0
- package/scripts/utilities/README.md +61 -0
- package/scripts/utilities/check-bin.js +8 -0
- package/scripts/utilities/check-bundle.js +23 -0
- package/scripts/utilities/check-dist-imports.js +65 -0
- package/scripts/utilities/check-import-paths.js +191 -0
- package/scripts/utilities/cleanup-cli.js +159 -0
- package/scripts/utilities/deployment-helpers.ps1 +199 -0
- package/scripts/utilities/fix-dist-imports.js +135 -0
- package/scripts/utilities/generate-secrets.js +159 -0
- package/scripts/utilities/safe-push.ps1 +51 -0
- package/scripts/utilities/setup-helpers.ps1 +206 -0
- package/scripts/utilities/test-packaged-artifact.js +92 -0
- package/scripts/utilities/validate-dist-imports.js +189 -0
- package/scripts/utilities/validate-schema.js +102 -0
- package/scripts/verify-exports.js +193 -0
- package/scripts/verify-worker-safety.js +73 -0
- package/types/middleware.d.ts +1 -0
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Post-Publish Release Testing
|
|
4
|
+
*
|
|
5
|
+
* Comprehensive test that:
|
|
6
|
+
* 1. Creates a fresh test project in temp directory
|
|
7
|
+
* 2. Installs the published npm package
|
|
8
|
+
* 3. Tests all major exports and functionality
|
|
9
|
+
* 4. Validates CLI commands work
|
|
10
|
+
* 5. Tests worker integration
|
|
11
|
+
* 6. Verifies no import path errors
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { mkdtemp, rm, writeFile, mkdir } from 'fs/promises';
|
|
15
|
+
import { tmpdir } from 'os';
|
|
16
|
+
import { join } from 'path';
|
|
17
|
+
import { execSync } from 'child_process';
|
|
18
|
+
|
|
19
|
+
const PACKAGE_NAME = '@tamyla/clodo-framework';
|
|
20
|
+
const TEST_TIMEOUT = 120000; // 2 minutes
|
|
21
|
+
|
|
22
|
+
class PostPublishTester {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.testDir = null;
|
|
25
|
+
this.results = {
|
|
26
|
+
passed: [],
|
|
27
|
+
failed: [],
|
|
28
|
+
skipped: []
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
log(message, type = 'info') {
|
|
33
|
+
const icons = { info: 'ℹ️', success: '✅', error: '❌', warning: '⚠️', test: '🧪' };
|
|
34
|
+
console.log(`${icons[type] || icons.info} ${message}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async setupTestEnvironment() {
|
|
38
|
+
this.log('Setting up test environment...', 'test');
|
|
39
|
+
|
|
40
|
+
// Create temporary directory
|
|
41
|
+
this.testDir = await mkdtemp(join(tmpdir(), 'clodo-release-test-'));
|
|
42
|
+
this.log(`Test directory: ${this.testDir}`);
|
|
43
|
+
|
|
44
|
+
// Create package.json
|
|
45
|
+
const packageJson = {
|
|
46
|
+
name: 'clodo-release-test',
|
|
47
|
+
version: '1.0.0',
|
|
48
|
+
type: 'module',
|
|
49
|
+
private: true
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
await writeFile(
|
|
53
|
+
join(this.testDir, 'package.json'),
|
|
54
|
+
JSON.stringify(packageJson, null, 2)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
this.log('Test environment ready', 'success');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async installPublishedPackage() {
|
|
61
|
+
this.log(`Installing ${PACKAGE_NAME} from npm...`, 'test');
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
execSync(`npm install ${PACKAGE_NAME}`, {
|
|
65
|
+
cwd: this.testDir,
|
|
66
|
+
stdio: 'pipe',
|
|
67
|
+
timeout: TEST_TIMEOUT
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Verify installation
|
|
71
|
+
const version = execSync(`npm list ${PACKAGE_NAME} --depth=0`, {
|
|
72
|
+
cwd: this.testDir,
|
|
73
|
+
encoding: 'utf8'
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.log(`Installed: ${version.trim()}`, 'success');
|
|
77
|
+
this.results.passed.push('Package installation');
|
|
78
|
+
return true;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
this.log(`Installation failed: ${error.message}`, 'error');
|
|
81
|
+
this.results.failed.push(`Package installation: ${error.message}`);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async testMainExports() {
|
|
87
|
+
this.log('Testing main exports...', 'test');
|
|
88
|
+
|
|
89
|
+
const testFile = join(this.testDir, 'test-exports.mjs');
|
|
90
|
+
const testCode = `
|
|
91
|
+
import {
|
|
92
|
+
Clodo,
|
|
93
|
+
createService,
|
|
94
|
+
validate,
|
|
95
|
+
initialize,
|
|
96
|
+
GenericDataService,
|
|
97
|
+
SchemaManager,
|
|
98
|
+
ModuleManager,
|
|
99
|
+
EnhancedRouter,
|
|
100
|
+
createDomainConfigSchema,
|
|
101
|
+
validateDomainConfig,
|
|
102
|
+
SecurityCLI,
|
|
103
|
+
DeploymentValidator,
|
|
104
|
+
DeploymentAuditor,
|
|
105
|
+
StandardOptions,
|
|
106
|
+
OutputFormatter
|
|
107
|
+
} from '${PACKAGE_NAME}';
|
|
108
|
+
|
|
109
|
+
// Test that exports are defined
|
|
110
|
+
const exports = {
|
|
111
|
+
Clodo,
|
|
112
|
+
createService,
|
|
113
|
+
validate,
|
|
114
|
+
initialize,
|
|
115
|
+
GenericDataService,
|
|
116
|
+
SchemaManager,
|
|
117
|
+
ModuleManager,
|
|
118
|
+
EnhancedRouter,
|
|
119
|
+
createDomainConfigSchema,
|
|
120
|
+
validateDomainConfig,
|
|
121
|
+
SecurityCLI,
|
|
122
|
+
DeploymentValidator,
|
|
123
|
+
DeploymentAuditor,
|
|
124
|
+
StandardOptions,
|
|
125
|
+
OutputFormatter
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
let passed = 0;
|
|
129
|
+
let failed = 0;
|
|
130
|
+
|
|
131
|
+
for (const [name, value] of Object.entries(exports)) {
|
|
132
|
+
if (value !== undefined && value !== null) {
|
|
133
|
+
console.log(\`✅ \${name}\`);
|
|
134
|
+
passed++;
|
|
135
|
+
} else {
|
|
136
|
+
console.log(\`❌ \${name} is undefined\`);
|
|
137
|
+
failed++;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(\`\\nResults: \${passed} passed, \${failed} failed\`);
|
|
142
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
143
|
+
`;
|
|
144
|
+
|
|
145
|
+
await writeFile(testFile, testCode);
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const output = execSync(`node ${testFile}`, {
|
|
149
|
+
cwd: this.testDir,
|
|
150
|
+
encoding: 'utf8',
|
|
151
|
+
timeout: 30000
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
this.log('Main exports test results:', 'info');
|
|
155
|
+
console.log(output);
|
|
156
|
+
this.results.passed.push('Main exports');
|
|
157
|
+
return true;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
this.log(`Main exports test failed: ${error.message}`, 'error');
|
|
160
|
+
if (error.stdout) console.log(error.stdout.toString());
|
|
161
|
+
this.results.failed.push(`Main exports: ${error.message}`);
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async testWorkerIntegration() {
|
|
167
|
+
this.log('Testing worker integration...', 'test');
|
|
168
|
+
|
|
169
|
+
const testFile = join(this.testDir, 'test-worker.mjs');
|
|
170
|
+
const testCode = `
|
|
171
|
+
import { initializeService, createFeatureGuard, createRateLimitGuard } from '${PACKAGE_NAME}/worker';
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
// Test that worker functions are available
|
|
175
|
+
console.log('✅ initializeService:', typeof initializeService);
|
|
176
|
+
console.log('✅ createFeatureGuard:', typeof createFeatureGuard);
|
|
177
|
+
console.log('✅ createRateLimitGuard:', typeof createRateLimitGuard);
|
|
178
|
+
|
|
179
|
+
// Test basic feature guard creation
|
|
180
|
+
const guard = createFeatureGuard('TEST_FEATURE');
|
|
181
|
+
console.log('✅ Created feature guard successfully');
|
|
182
|
+
|
|
183
|
+
// Test rate limit guard creation
|
|
184
|
+
const rateLimit = createRateLimitGuard({ maxRequests: 100, windowMs: 60000 });
|
|
185
|
+
console.log('✅ Created rate limit guard successfully');
|
|
186
|
+
|
|
187
|
+
console.log('\\n✅ Worker integration test passed');
|
|
188
|
+
process.exit(0);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error('❌ Worker integration test failed:', error.message);
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
`;
|
|
194
|
+
|
|
195
|
+
await writeFile(testFile, testCode);
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const output = execSync(`node ${testFile}`, {
|
|
199
|
+
cwd: this.testDir,
|
|
200
|
+
encoding: 'utf8',
|
|
201
|
+
timeout: 30000
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
console.log(output);
|
|
205
|
+
this.results.passed.push('Worker integration');
|
|
206
|
+
return true;
|
|
207
|
+
} catch (error) {
|
|
208
|
+
this.log(`Worker integration test failed: ${error.message}`, 'error');
|
|
209
|
+
if (error.stdout) console.log(error.stdout.toString());
|
|
210
|
+
this.results.failed.push(`Worker integration: ${error.message}`);
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async testCLICommands() {
|
|
216
|
+
this.log('Testing CLI commands...', 'test');
|
|
217
|
+
|
|
218
|
+
const commands = [
|
|
219
|
+
{ name: 'version', cmd: 'clodo-service --version', expect: /\d+\.\d+\.\d+/ },
|
|
220
|
+
{ name: 'help', cmd: 'clodo-service --help', expect: /(Usage|Commands)/ },
|
|
221
|
+
{ name: 'create help', cmd: 'clodo-service create --help', expect: /Create.*service/ },
|
|
222
|
+
{ name: 'validate help', cmd: 'clodo-service validate --help', expect: /Validate.*service/ },
|
|
223
|
+
{ name: 'deploy help', cmd: 'clodo-service deploy --help', expect: /Deploy.*service/ },
|
|
224
|
+
{ name: 'init-config help', cmd: 'clodo-service init-config --help', expect: /Initialize.*config/ },
|
|
225
|
+
];
|
|
226
|
+
|
|
227
|
+
let passed = 0;
|
|
228
|
+
let failed = 0;
|
|
229
|
+
|
|
230
|
+
for (const { name, cmd, expect } of commands) {
|
|
231
|
+
try {
|
|
232
|
+
const output = execSync(`npx ${cmd}`, {
|
|
233
|
+
cwd: this.testDir,
|
|
234
|
+
encoding: 'utf8',
|
|
235
|
+
timeout: 10000
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
if (expect.test(output)) {
|
|
239
|
+
this.log(` ✓ ${name}`, 'success');
|
|
240
|
+
passed++;
|
|
241
|
+
} else {
|
|
242
|
+
this.log(` ✗ ${name} - unexpected output`, 'error');
|
|
243
|
+
failed++;
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
this.log(` ✗ ${name} - ${error.message}`, 'error');
|
|
247
|
+
failed++;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (failed === 0) {
|
|
252
|
+
this.log(`All ${passed} CLI commands working`, 'success');
|
|
253
|
+
this.results.passed.push(`CLI commands (${passed}/${commands.length})`);
|
|
254
|
+
return true;
|
|
255
|
+
} else {
|
|
256
|
+
this.log(`${failed} CLI commands failed`, 'error');
|
|
257
|
+
this.results.failed.push(`CLI commands: ${failed}/${commands.length} failed`);
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async testServiceCreation() {
|
|
263
|
+
this.log('Testing service creation API...', 'test');
|
|
264
|
+
|
|
265
|
+
const testFile = join(this.testDir, 'test-service-api.mjs');
|
|
266
|
+
const testCode = `
|
|
267
|
+
import { Clodo } from '${PACKAGE_NAME}';
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
// Test that Clodo API exists
|
|
271
|
+
console.log('✅ Clodo.createService:', typeof Clodo.createService);
|
|
272
|
+
console.log('✅ Clodo.validate:', typeof Clodo.validate);
|
|
273
|
+
console.log('✅ Clodo.deploy:', typeof Clodo.deploy);
|
|
274
|
+
console.log('✅ Clodo.initialize:', typeof Clodo.initialize);
|
|
275
|
+
console.log('✅ Clodo.getInfo:', typeof Clodo.getInfo);
|
|
276
|
+
|
|
277
|
+
// Test getInfo
|
|
278
|
+
const info = Clodo.getInfo();
|
|
279
|
+
console.log('✅ Framework info:', info.name);
|
|
280
|
+
|
|
281
|
+
if (info.name !== 'Clodo Framework') {
|
|
282
|
+
throw new Error('Framework info incorrect');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
console.log('\\n✅ Service creation API test passed');
|
|
286
|
+
process.exit(0);
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.error('❌ Service API test failed:', error.message);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
`;
|
|
292
|
+
|
|
293
|
+
await writeFile(testFile, testCode);
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
const output = execSync(`node ${testFile}`, {
|
|
297
|
+
cwd: this.testDir,
|
|
298
|
+
encoding: 'utf8',
|
|
299
|
+
timeout: 30000
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
console.log(output);
|
|
303
|
+
this.results.passed.push('Service creation API');
|
|
304
|
+
return true;
|
|
305
|
+
} catch (error) {
|
|
306
|
+
this.log(`Service API test failed: ${error.message}`, 'error');
|
|
307
|
+
if (error.stdout) console.log(error.stdout.toString());
|
|
308
|
+
this.results.failed.push(`Service creation API: ${error.message}`);
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async testConfigurationManagement() {
|
|
314
|
+
this.log('Testing configuration management...', 'test');
|
|
315
|
+
|
|
316
|
+
const testFile = join(this.testDir, 'test-config.mjs');
|
|
317
|
+
const testCode = `
|
|
318
|
+
import { StandardOptions, OutputFormatter } from '${PACKAGE_NAME}';
|
|
319
|
+
|
|
320
|
+
try {
|
|
321
|
+
console.log('✅ StandardOptions:', typeof StandardOptions);
|
|
322
|
+
console.log('✅ OutputFormatter:', typeof OutputFormatter);
|
|
323
|
+
|
|
324
|
+
// Test StandardOptions has required methods
|
|
325
|
+
if (typeof StandardOptions.define !== 'function') {
|
|
326
|
+
throw new Error('StandardOptions.define is not a function');
|
|
327
|
+
}
|
|
328
|
+
console.log('✅ StandardOptions.define exists');
|
|
329
|
+
|
|
330
|
+
// Test OutputFormatter can be instantiated
|
|
331
|
+
const formatter = new OutputFormatter({});
|
|
332
|
+
console.log('✅ OutputFormatter instance created');
|
|
333
|
+
|
|
334
|
+
console.log('\\n✅ Configuration management test passed');
|
|
335
|
+
process.exit(0);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
console.error('❌ Configuration test failed:', error.message);
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
|
340
|
+
`;
|
|
341
|
+
|
|
342
|
+
await writeFile(testFile, testCode);
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
const output = execSync(`node ${testFile}`, {
|
|
346
|
+
cwd: this.testDir,
|
|
347
|
+
encoding: 'utf8',
|
|
348
|
+
timeout: 30000
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
console.log(output);
|
|
352
|
+
this.results.passed.push('Configuration management');
|
|
353
|
+
return true;
|
|
354
|
+
} catch (error) {
|
|
355
|
+
this.log(`Configuration test failed: ${error.message}`, 'error');
|
|
356
|
+
if (error.stdout) console.log(error.stdout.toString());
|
|
357
|
+
this.results.failed.push(`Configuration management: ${error.message}`);
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async testSecurityFeatures() {
|
|
363
|
+
this.log('Testing security features...', 'test');
|
|
364
|
+
|
|
365
|
+
const testFile = join(this.testDir, 'test-security.mjs');
|
|
366
|
+
const testCode = `
|
|
367
|
+
import { SecurityCLI } from '${PACKAGE_NAME}';
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
console.log('✅ SecurityCLI:', typeof SecurityCLI);
|
|
371
|
+
|
|
372
|
+
// Verify SecurityCLI has expected methods
|
|
373
|
+
const securityCli = new SecurityCLI();
|
|
374
|
+
console.log('✅ SecurityCLI instance created');
|
|
375
|
+
|
|
376
|
+
console.log('\\n✅ Security features test passed');
|
|
377
|
+
process.exit(0);
|
|
378
|
+
} catch (error) {
|
|
379
|
+
console.error('❌ Security test failed:', error.message);
|
|
380
|
+
process.exit(1);
|
|
381
|
+
}
|
|
382
|
+
`;
|
|
383
|
+
|
|
384
|
+
await writeFile(testFile, testCode);
|
|
385
|
+
|
|
386
|
+
try {
|
|
387
|
+
const output = execSync(`node ${testFile}`, {
|
|
388
|
+
cwd: this.testDir,
|
|
389
|
+
encoding: 'utf8',
|
|
390
|
+
timeout: 30000
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
console.log(output);
|
|
394
|
+
this.results.passed.push('Security features');
|
|
395
|
+
return true;
|
|
396
|
+
} catch (error) {
|
|
397
|
+
this.log(`Security test failed: ${error.message}`, 'error');
|
|
398
|
+
if (error.stdout) console.log(error.stdout.toString());
|
|
399
|
+
this.results.failed.push(`Security features: ${error.message}`);
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
async testInheritableCapabilities() {
|
|
405
|
+
this.log('Testing inheritable classes and capabilities...', 'test');
|
|
406
|
+
|
|
407
|
+
const testFile = join(this.testDir, 'test-inheritance.mjs');
|
|
408
|
+
const testCode = `
|
|
409
|
+
import {
|
|
410
|
+
SchemaManager,
|
|
411
|
+
ModuleManager,
|
|
412
|
+
EnhancedRouter
|
|
413
|
+
} from '${PACKAGE_NAME}';
|
|
414
|
+
|
|
415
|
+
try {
|
|
416
|
+
let passed = 0;
|
|
417
|
+
let failed = 0;
|
|
418
|
+
|
|
419
|
+
// Note: GenericDataService requires D1 database client and is designed
|
|
420
|
+
// for runtime use with Cloudflare Workers, not standalone inheritance testing
|
|
421
|
+
|
|
422
|
+
// Test SchemaManager extensibility
|
|
423
|
+
try {
|
|
424
|
+
class CustomSchemaManager extends SchemaManager {
|
|
425
|
+
constructor() {
|
|
426
|
+
super();
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
customMethod() {
|
|
430
|
+
return 'custom';
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
const customSchema = new CustomSchemaManager();
|
|
434
|
+
if (customSchema.customMethod() === 'custom') {
|
|
435
|
+
console.log('✅ SchemaManager - extendable with custom methods');
|
|
436
|
+
passed++;
|
|
437
|
+
} else {
|
|
438
|
+
throw new Error('Custom method not working');
|
|
439
|
+
}
|
|
440
|
+
} catch (e) {
|
|
441
|
+
console.log('❌ SchemaManager - not extendable:', e.message);
|
|
442
|
+
failed++;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Test ModuleManager extensibility
|
|
446
|
+
try {
|
|
447
|
+
class CustomModuleManager extends ModuleManager {
|
|
448
|
+
constructor() {
|
|
449
|
+
super();
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
customRegister(name) {
|
|
453
|
+
return \`custom-\${name}\`;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
const customModule = new CustomModuleManager();
|
|
457
|
+
if (customModule.customRegister('test') === 'custom-test') {
|
|
458
|
+
console.log('✅ ModuleManager - extendable with custom methods');
|
|
459
|
+
passed++;
|
|
460
|
+
} else {
|
|
461
|
+
throw new Error('Custom method not working');
|
|
462
|
+
}
|
|
463
|
+
} catch (e) {
|
|
464
|
+
console.log('❌ ModuleManager - not extendable:', e.message);
|
|
465
|
+
failed++;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Test EnhancedRouter extensibility
|
|
469
|
+
try {
|
|
470
|
+
class CustomRouter extends EnhancedRouter {
|
|
471
|
+
constructor() {
|
|
472
|
+
super();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
customRoute(path) {
|
|
476
|
+
return \`/custom\${path}\`;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const customRouter = new CustomRouter();
|
|
480
|
+
if (customRouter.customRoute('/test') === '/custom/test') {
|
|
481
|
+
console.log('✅ EnhancedRouter - extendable with custom methods');
|
|
482
|
+
passed++;
|
|
483
|
+
} else {
|
|
484
|
+
throw new Error('Custom method not working');
|
|
485
|
+
}
|
|
486
|
+
} catch (e) {
|
|
487
|
+
console.log('❌ EnhancedRouter - not extendable:', e.message);
|
|
488
|
+
failed++;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
console.log(\`\\nResults: \${passed} passed, \${failed} failed\`);
|
|
492
|
+
console.log('Note: GenericDataService requires D1 client and is tested in worker integration');
|
|
493
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
494
|
+
} catch (error) {
|
|
495
|
+
console.error('❌ Inheritance test failed:', error.message);
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
`;
|
|
499
|
+
|
|
500
|
+
await writeFile(testFile, testCode);
|
|
501
|
+
|
|
502
|
+
try {
|
|
503
|
+
const output = execSync(`node ${testFile}`, {
|
|
504
|
+
cwd: this.testDir,
|
|
505
|
+
encoding: 'utf8',
|
|
506
|
+
timeout: 30000
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
console.log(output);
|
|
510
|
+
this.results.passed.push('Inheritable capabilities');
|
|
511
|
+
return true;
|
|
512
|
+
} catch (error) {
|
|
513
|
+
this.log(`Inheritance test failed: ${error.message}`, 'error');
|
|
514
|
+
if (error.stdout) console.log(error.stdout.toString());
|
|
515
|
+
this.results.failed.push(`Inheritable capabilities: ${error.message}`);
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
async testDeploymentCapabilities() {
|
|
521
|
+
this.log('Testing deployment and orchestration...', 'test');
|
|
522
|
+
|
|
523
|
+
const testFile = join(this.testDir, 'test-deployment.mjs');
|
|
524
|
+
const testCode = `
|
|
525
|
+
import {
|
|
526
|
+
DeploymentValidator,
|
|
527
|
+
DeploymentAuditor
|
|
528
|
+
} from '${PACKAGE_NAME}';
|
|
529
|
+
|
|
530
|
+
try {
|
|
531
|
+
console.log('✅ DeploymentValidator:', typeof DeploymentValidator);
|
|
532
|
+
console.log('✅ DeploymentAuditor:', typeof DeploymentAuditor);
|
|
533
|
+
|
|
534
|
+
// Test that validators can be instantiated
|
|
535
|
+
const validator = new DeploymentValidator();
|
|
536
|
+
console.log('✅ DeploymentValidator instance created');
|
|
537
|
+
|
|
538
|
+
const auditor = new DeploymentAuditor();
|
|
539
|
+
console.log('✅ DeploymentAuditor instance created');
|
|
540
|
+
|
|
541
|
+
console.log('\\n✅ Deployment capabilities test passed');
|
|
542
|
+
process.exit(0);
|
|
543
|
+
} catch (error) {
|
|
544
|
+
console.error('❌ Deployment test failed:', error.message);
|
|
545
|
+
process.exit(1);
|
|
546
|
+
}
|
|
547
|
+
`;
|
|
548
|
+
|
|
549
|
+
await writeFile(testFile, testCode);
|
|
550
|
+
|
|
551
|
+
try {
|
|
552
|
+
const output = execSync(`node ${testFile}`, {
|
|
553
|
+
cwd: this.testDir,
|
|
554
|
+
encoding: 'utf8',
|
|
555
|
+
timeout: 30000
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
console.log(output);
|
|
559
|
+
this.results.passed.push('Deployment capabilities');
|
|
560
|
+
return true;
|
|
561
|
+
} catch (error) {
|
|
562
|
+
this.log(`Deployment test failed: ${error.message}`, 'error');
|
|
563
|
+
if (error.stdout) console.log(error.stdout.toString());
|
|
564
|
+
this.results.failed.push(`Deployment capabilities: ${error.message}`);
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
async cleanup() {
|
|
570
|
+
if (this.testDir) {
|
|
571
|
+
this.log('Cleaning up test environment...', 'info');
|
|
572
|
+
try {
|
|
573
|
+
await rm(this.testDir, { recursive: true, force: true });
|
|
574
|
+
this.log('Cleanup complete', 'success');
|
|
575
|
+
} catch (error) {
|
|
576
|
+
this.log(`Cleanup warning: ${error.message}`, 'warning');
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
printSummary() {
|
|
582
|
+
console.log('\n' + '='.repeat(60));
|
|
583
|
+
console.log('📊 POST-PUBLISH TEST SUMMARY');
|
|
584
|
+
console.log('='.repeat(60));
|
|
585
|
+
|
|
586
|
+
if (this.results.passed.length > 0) {
|
|
587
|
+
console.log(`\n✅ PASSED (${this.results.passed.length}):`);
|
|
588
|
+
this.results.passed.forEach(test => console.log(` ✓ ${test}`));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if (this.results.failed.length > 0) {
|
|
592
|
+
console.log(`\n❌ FAILED (${this.results.failed.length}):`);
|
|
593
|
+
this.results.failed.forEach(test => console.log(` ✗ ${test}`));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (this.results.skipped.length > 0) {
|
|
597
|
+
console.log(`\n⏭️ SKIPPED (${this.results.skipped.length}):`);
|
|
598
|
+
this.results.skipped.forEach(test => console.log(` - ${test}`));
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
const total = this.results.passed.length + this.results.failed.length;
|
|
602
|
+
const successRate = total > 0 ? ((this.results.passed.length / total) * 100).toFixed(1) : 0;
|
|
603
|
+
|
|
604
|
+
console.log('\n' + '='.repeat(60));
|
|
605
|
+
console.log(`Total: ${total} tests | Success Rate: ${successRate}%`);
|
|
606
|
+
console.log('='.repeat(60));
|
|
607
|
+
|
|
608
|
+
if (this.results.failed.length === 0) {
|
|
609
|
+
console.log('\n🎉 All post-publish tests passed!');
|
|
610
|
+
console.log('✅ Package is ready for production use');
|
|
611
|
+
return true;
|
|
612
|
+
} else {
|
|
613
|
+
console.log('\n⚠️ Some tests failed. Review the failures above.');
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
async run() {
|
|
619
|
+
console.log('╔═══════════════════════════════════════════════════════════╗');
|
|
620
|
+
console.log('║ POST-PUBLISH RELEASE TESTING ║');
|
|
621
|
+
console.log('║ Testing published package from npm registry ║');
|
|
622
|
+
console.log('╚═══════════════════════════════════════════════════════════╝\n');
|
|
623
|
+
|
|
624
|
+
try {
|
|
625
|
+
await this.setupTestEnvironment();
|
|
626
|
+
|
|
627
|
+
const installed = await this.installPublishedPackage();
|
|
628
|
+
if (!installed) {
|
|
629
|
+
this.log('Cannot proceed without successful installation', 'error');
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Run all tests
|
|
634
|
+
await this.testMainExports();
|
|
635
|
+
await this.testWorkerIntegration();
|
|
636
|
+
await this.testCLICommands();
|
|
637
|
+
await this.testServiceCreation();
|
|
638
|
+
await this.testConfigurationManagement();
|
|
639
|
+
await this.testSecurityFeatures();
|
|
640
|
+
await this.testInheritableCapabilities();
|
|
641
|
+
await this.testDeploymentCapabilities();
|
|
642
|
+
|
|
643
|
+
const success = this.printSummary();
|
|
644
|
+
return success;
|
|
645
|
+
|
|
646
|
+
} catch (error) {
|
|
647
|
+
this.log(`Unexpected error: ${error.message}`, 'error');
|
|
648
|
+
console.error(error);
|
|
649
|
+
return false;
|
|
650
|
+
} finally {
|
|
651
|
+
await this.cleanup();
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// Run the tests
|
|
657
|
+
const tester = new PostPublishTester();
|
|
658
|
+
tester.run().then(success => {
|
|
659
|
+
process.exit(success ? 0 : 1);
|
|
660
|
+
}).catch(error => {
|
|
661
|
+
console.error('Fatal error:', error);
|
|
662
|
+
process.exit(1);
|
|
663
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
const incompatiblePatterns = [
|
|
9
|
+
/import.*from.*['"]fs['"]/,
|
|
10
|
+
/import.*from.*['"]path['"]/,
|
|
11
|
+
/import.*from.*['"]child_process['"]/,
|
|
12
|
+
/import.*from.*['"]os['"]/,
|
|
13
|
+
/import.*from.*['"]https['"]/,
|
|
14
|
+
/import.*from.*['"]http['"]/,
|
|
15
|
+
/process\.cwd/,
|
|
16
|
+
/__dirname/,
|
|
17
|
+
/__filename/,
|
|
18
|
+
/readFileSync|writeFileSync|existsSync|mkdirSync|readdirSync|statSync/
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function scanDirectory(dir, results = []) {
|
|
22
|
+
try {
|
|
23
|
+
const items = fs.readdirSync(dir);
|
|
24
|
+
for (const item of items) {
|
|
25
|
+
const fullPath = path.join(dir, item);
|
|
26
|
+
const stat = fs.statSync(fullPath);
|
|
27
|
+
if (stat.isDirectory() && !item.startsWith('.') && item !== 'node_modules') {
|
|
28
|
+
scanDirectory(fullPath, results);
|
|
29
|
+
} else if (item.endsWith('.js')) {
|
|
30
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
31
|
+
const issues = [];
|
|
32
|
+
for (const pattern of incompatiblePatterns) {
|
|
33
|
+
const matches = content.match(pattern);
|
|
34
|
+
if (matches) {
|
|
35
|
+
issues.push(matches[0]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (issues.length > 0) {
|
|
39
|
+
results.push({ file: fullPath, issues });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} catch (e) {}
|
|
44
|
+
return results;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const results = scanDirectory('src');
|
|
48
|
+
console.log('Files with Worker-incompatible code:');
|
|
49
|
+
results.forEach(r => {
|
|
50
|
+
console.log(`\n${r.file}:`);
|
|
51
|
+
r.issues.forEach(issue => console.log(` - ${issue}`));
|
|
52
|
+
});
|