@tamyla/clodo-framework 4.0.5 ā 4.0.7
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 +20 -0
- package/dist/lib/shared/cloudflare/ops.js +59 -39
- package/dist/lib/shared/deployment/workflows/interactive-confirmation.js +6 -6
- package/dist/lib/shared/deployment/workflows/interactive-domain-info-gatherer.js +5 -5
- package/dist/lib/shared/deployment/workflows/interactive-validation.js +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## [4.0.7](https://github.com/tamylaa/clodo-framework/compare/v4.0.6...v4.0.7) (2025-12-09)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* correct dynamic import paths in interactive-validation.js ([acbadae](https://github.com/tamylaa/clodo-framework/commit/acbadaefc10cf7efab9dd263f7a40f8db18fccb4))
|
|
7
|
+
* correct import path in interactive-validation.js ([8355677](https://github.com/tamylaa/clodo-framework/commit/83556777a0faa1a85766c0bf4795428d8ba807e6))
|
|
8
|
+
* correct remaining dynamic import paths in interactive-validation.js ([837f0a4](https://github.com/tamylaa/clodo-framework/commit/837f0a48489dbde6b644944950232ec0f424639f))
|
|
9
|
+
* correct Windows PowerShell environment variable handling ([f3c5354](https://github.com/tamylaa/clodo-framework/commit/f3c535449f744a2448b4c1b7d98fc62853a8eaab))
|
|
10
|
+
|
|
11
|
+
## [4.0.6](https://github.com/tamylaa/clodo-framework/compare/v4.0.5...v4.0.6) (2025-12-09)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* add null checks for enterprise deployment methods ([97c3237](https://github.com/tamylaa/clodo-framework/commit/97c32371e97f259f62a82e9f7cc393dab0def7ed))
|
|
17
|
+
* correct URL construction and export missing testing workflow ([19691e1](https://github.com/tamylaa/clodo-framework/commit/19691e1651b3f37762e0564ccbb939c7c22965ad))
|
|
18
|
+
* correct worker URL construction and prevent undefined errors ([5d94f4f](https://github.com/tamylaa/clodo-framework/commit/5d94f4f064d5264f18929a6d2bd0564b0bb5494a))
|
|
19
|
+
* remove duplicate export in InteractiveTestingWorkflow ([db710c2](https://github.com/tamylaa/clodo-framework/commit/db710c2342ac3fd41b73ffd01fdd83ce0e0256f1))
|
|
20
|
+
|
|
1
21
|
## [4.0.5](https://github.com/tamylaa/clodo-framework/compare/v4.0.4...v4.0.5) (2025-12-09)
|
|
2
22
|
|
|
3
23
|
|
|
@@ -171,12 +171,18 @@ export async function listWorkers(options = {}) {
|
|
|
171
171
|
|
|
172
172
|
// Fallback to CLI-based operation
|
|
173
173
|
try {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
174
|
+
if (apiToken) {
|
|
175
|
+
const command = process.platform === 'win32' ? `powershell -Command "$env:CLOUDFLARE_API_TOKEN = '${apiToken}'; npx wrangler list"` : `CLOUDFLARE_API_TOKEN=${apiToken} npx wrangler list`;
|
|
176
|
+
const {
|
|
177
|
+
stdout: list
|
|
178
|
+
} = await executeWithRateLimit(command, 'workers');
|
|
179
|
+
return list;
|
|
180
|
+
} else {
|
|
181
|
+
const {
|
|
182
|
+
stdout: list
|
|
183
|
+
} = await executeWithRateLimit('npx wrangler list', 'workers');
|
|
184
|
+
return list;
|
|
185
|
+
}
|
|
180
186
|
} catch (error) {
|
|
181
187
|
throw new Error(`Failed to list workers: ${error.message}`);
|
|
182
188
|
}
|
|
@@ -244,40 +250,40 @@ export async function deploySecret(key, value, env = 'production', options = {})
|
|
|
244
250
|
}
|
|
245
251
|
|
|
246
252
|
// Fallback to CLI-based operation with API token if available
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
253
|
+
if (apiToken) {
|
|
254
|
+
const command = process.platform === 'win32' ? `powershell -Command "$env:CLOUDFLARE_API_TOKEN = '${apiToken}'; Write-Output '${value}' | npx wrangler secret put ${key} --env ${env}"` : `CLOUDFLARE_API_TOKEN=${apiToken} echo "${value}" | npx wrangler secret put ${key} --env ${env}`;
|
|
255
|
+
await executeWithRateLimit(command, 'workers', 5);
|
|
256
|
+
} else {
|
|
257
|
+
const command = process.platform === 'win32' ? `powershell -Command "Write-Output '${value}' | npx wrangler secret put ${key} --env ${env}"` : `echo "${value}" | npx wrangler secret put ${key} --env ${env}`;
|
|
251
258
|
await executeWithRateLimit(command, 'workers', 5);
|
|
252
|
-
} catch (error) {
|
|
253
|
-
throw new Error(`Secret deployment failed: ${error.message}`);
|
|
254
259
|
}
|
|
255
260
|
}
|
|
256
261
|
export async function deleteSecret(key, env = 'production', options = {}) {
|
|
257
262
|
const {
|
|
258
263
|
apiToken
|
|
259
264
|
} = options;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
try {
|
|
265
|
+
if (apiToken) {
|
|
266
|
+
const command = process.platform === 'win32' ? `powershell -Command "$env:CLOUDFLARE_API_TOKEN = '${apiToken}'; npx wrangler secret delete ${key} --env ${env}"` : `CLOUDFLARE_API_TOKEN=${apiToken} npx wrangler secret delete ${key} --env ${env}`;
|
|
263
267
|
await executeWithRateLimit(command, 'workers');
|
|
264
|
-
}
|
|
265
|
-
|
|
268
|
+
} else {
|
|
269
|
+
await executeWithRateLimit(`npx wrangler secret delete ${key} --env ${env}`, 'workers');
|
|
266
270
|
}
|
|
267
271
|
}
|
|
268
272
|
export async function listSecrets(env = 'production', options = {}) {
|
|
269
273
|
const {
|
|
270
274
|
apiToken
|
|
271
275
|
} = options;
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
try {
|
|
276
|
+
if (apiToken) {
|
|
277
|
+
const command = process.platform === 'win32' ? `powershell -Command "$env:CLOUDFLARE_API_TOKEN = '${apiToken}'; npx wrangler secret list --env ${env}"` : `CLOUDFLARE_API_TOKEN=${apiToken} npx wrangler secret list --env ${env}`;
|
|
275
278
|
const {
|
|
276
279
|
stdout: list
|
|
277
280
|
} = await executeWithRateLimit(command, 'workers');
|
|
278
281
|
return list;
|
|
279
|
-
}
|
|
280
|
-
|
|
282
|
+
} else {
|
|
283
|
+
const {
|
|
284
|
+
stdout: list
|
|
285
|
+
} = await executeWithRateLimit(`npx wrangler secret list --env ${env}`, 'workers');
|
|
286
|
+
return list;
|
|
281
287
|
}
|
|
282
288
|
}
|
|
283
289
|
export async function listDatabases(options = {}) {
|
|
@@ -346,16 +352,26 @@ export async function createDatabase(name, options = {}) {
|
|
|
346
352
|
|
|
347
353
|
// Fallback to CLI-based operation
|
|
348
354
|
try {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
355
|
+
if (apiToken) {
|
|
356
|
+
const command = process.platform === 'win32' ? `powershell -Command "$env:CLOUDFLARE_API_TOKEN = '${apiToken}'; npx wrangler d1 create ${name}"` : `CLOUDFLARE_API_TOKEN=${apiToken} npx wrangler d1 create ${name}`;
|
|
357
|
+
const {
|
|
358
|
+
stdout: output
|
|
359
|
+
} = await executeWithRateLimit(command, 'd1');
|
|
360
|
+
const idMatch = output.match(/database_id = "([^"]+)"/);
|
|
361
|
+
if (!idMatch) {
|
|
362
|
+
throw new Error('Could not extract database ID from creation output');
|
|
363
|
+
}
|
|
364
|
+
return idMatch[1];
|
|
365
|
+
} else {
|
|
366
|
+
const {
|
|
367
|
+
stdout: output
|
|
368
|
+
} = await executeWithRateLimit(`npx wrangler d1 create ${name}`, 'd1');
|
|
369
|
+
const idMatch = output.match(/database_id = "([^"]+)"/);
|
|
370
|
+
if (!idMatch) {
|
|
371
|
+
throw new Error('Could not extract database ID from creation output');
|
|
372
|
+
}
|
|
373
|
+
return idMatch[1];
|
|
357
374
|
}
|
|
358
|
-
return idMatch[1];
|
|
359
375
|
} catch (error) {
|
|
360
376
|
throw new Error(`Database creation failed: ${error.message}`);
|
|
361
377
|
}
|
|
@@ -364,12 +380,13 @@ export async function deleteDatabase(name, options = {}) {
|
|
|
364
380
|
const {
|
|
365
381
|
apiToken
|
|
366
382
|
} = options;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
383
|
+
if (apiToken) {
|
|
384
|
+
// For Windows PowerShell, set environment variable within the command
|
|
385
|
+
const command = process.platform === 'win32' ? `powershell -Command "$env:CLOUDFLARE_API_TOKEN = '${apiToken}'; npx wrangler d1 delete ${name} --skip-confirmation"` : `CLOUDFLARE_API_TOKEN=${apiToken} npx wrangler d1 delete ${name} --skip-confirmation`;
|
|
370
386
|
await executeWithRateLimit(command, 'd1');
|
|
371
|
-
}
|
|
372
|
-
|
|
387
|
+
} else {
|
|
388
|
+
// No API token provided, use default wrangler auth
|
|
389
|
+
await executeWithRateLimit(`npx wrangler d1 delete ${name} --skip-confirmation`, 'd1');
|
|
373
390
|
}
|
|
374
391
|
}
|
|
375
392
|
export async function runMigrations(databaseName, env = 'production', options = {}) {
|
|
@@ -380,9 +397,12 @@ export async function runMigrations(databaseName, env = 'production', options =
|
|
|
380
397
|
try {
|
|
381
398
|
await ensureMonitoringInitialized();
|
|
382
399
|
const result = await errorRecovery.executeWithRecovery(async () => {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
400
|
+
if (apiToken) {
|
|
401
|
+
const command = process.platform === 'win32' ? `powershell -Command "$env:CLOUDFLARE_API_TOKEN = '${apiToken}'; npx wrangler d1 migrations apply ${databaseName} --env ${env} --remote"` : `CLOUDFLARE_API_TOKEN=${apiToken} npx wrangler d1 migrations apply ${databaseName} --env ${env} --remote`;
|
|
402
|
+
await executeWithRateLimit(command, 'd1');
|
|
403
|
+
} else {
|
|
404
|
+
await executeWithRateLimit(`npx wrangler d1 migrations apply ${databaseName} --env ${env} --remote`, 'd1');
|
|
405
|
+
}
|
|
386
406
|
return true;
|
|
387
407
|
}, {
|
|
388
408
|
operationId: `runMigrations_${databaseName}_${env}`
|
|
@@ -78,7 +78,7 @@ export class InteractiveConfirmation {
|
|
|
78
78
|
console.log('2. Run database migrations');
|
|
79
79
|
console.log('3. Deploy Cloudflare Worker');
|
|
80
80
|
console.log('4. Verify deployment health');
|
|
81
|
-
if (config.deployment
|
|
81
|
+
if (config.deployment?.runTests) {
|
|
82
82
|
console.log('5. Run integration tests');
|
|
83
83
|
}
|
|
84
84
|
}
|
|
@@ -147,11 +147,11 @@ export class InteractiveConfirmation {
|
|
|
147
147
|
console.log(`š± Mode: ${config.deploymentMode}`);
|
|
148
148
|
console.log(`ā” Worker: ${config.worker.name}`);
|
|
149
149
|
console.log(`š URL: ${config.worker.url}`);
|
|
150
|
-
console.log(`šļø Database: ${config.database
|
|
151
|
-
console.log(`š Secrets: ${Object.keys(config.secrets.keys).length} configured`);
|
|
150
|
+
console.log(`šļø Database: ${config.database?.name || 'None'} (${config.database?.id || 'No ID'})`);
|
|
151
|
+
console.log(`š Secrets: ${config.secrets?.keys ? Object.keys(config.secrets.keys).length : 0} configured`);
|
|
152
152
|
console.log(`š Deployment ID: ${deploymentState.deploymentId}`);
|
|
153
|
-
console.log(`š Validation: ${config.deployment
|
|
154
|
-
console.log(`š Audit: ${config.deployment
|
|
153
|
+
console.log(`š Validation: ${config.deployment?.validationLevel || 'standard'}`);
|
|
154
|
+
console.log(`š Audit: ${config.deployment?.auditLevel || 'basic'}`);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
/**
|
|
@@ -168,7 +168,7 @@ export class InteractiveConfirmation {
|
|
|
168
168
|
console.log('4. Configuration management');
|
|
169
169
|
console.log('5. Cloudflare Worker deployment with D1 recovery');
|
|
170
170
|
console.log('6. Deployment verification');
|
|
171
|
-
if (config.deployment
|
|
171
|
+
if (config.deployment?.runTests) {
|
|
172
172
|
console.log('7. Comprehensive integration tests');
|
|
173
173
|
}
|
|
174
174
|
console.log(`8. Audit logging and reporting`);
|
|
@@ -93,9 +93,9 @@ export class InteractiveDomainInfoGatherer {
|
|
|
93
93
|
config.worker = config.worker || {};
|
|
94
94
|
config.worker.name = `${config.domain}-data-service`;
|
|
95
95
|
|
|
96
|
-
// Use
|
|
97
|
-
const
|
|
98
|
-
config.worker.url = `https://${config.worker.name}.${
|
|
96
|
+
// Use zone name from credentials for workers.dev subdomain
|
|
97
|
+
const zoneName = config.credentials?.zoneName || `${config.domain}.workers.dev`;
|
|
98
|
+
config.worker.url = `https://${config.worker.name}.${zoneName}`;
|
|
99
99
|
console.log(`\nš§ Generated Configuration:`);
|
|
100
100
|
console.log(` Worker Name: ${config.worker.name}`);
|
|
101
101
|
console.log(` Worker URL: ${config.worker.url}`);
|
|
@@ -114,8 +114,8 @@ export class InteractiveDomainInfoGatherer {
|
|
|
114
114
|
console.log(` š§ Using extracted name: ${customWorkerName}`);
|
|
115
115
|
}
|
|
116
116
|
config.worker.name = customWorkerName;
|
|
117
|
-
const
|
|
118
|
-
config.worker.url = `https://${config.worker.name}.${
|
|
117
|
+
const zoneName = config.credentials?.zoneName || `${config.domain}.workers.dev`;
|
|
118
|
+
config.worker.url = `https://${config.worker.name}.${zoneName}`;
|
|
119
119
|
console.log(`\nā
Updated worker configuration`);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -129,7 +129,7 @@ export class InteractiveValidationWorkflow {
|
|
|
129
129
|
console.log('===========================');
|
|
130
130
|
const {
|
|
131
131
|
askChoice
|
|
132
|
-
} = await import('
|
|
132
|
+
} = await import('../../utils/interactive-prompts.js');
|
|
133
133
|
const choice = await askChoice('How would you like to handle the existing worker?', ['š Overwrite/Update - Deploy new version (recommended)', 'š Rename - Create with a different worker name', 'š Compare - Show differences before deciding', 'š¾ Backup & Update - Create backup before overwriting', 'ā Cancel - Stop deployment'], 0);
|
|
134
134
|
switch (choice) {
|
|
135
135
|
case 0:
|
|
@@ -140,7 +140,7 @@ export class InteractiveValidationWorkflow {
|
|
|
140
140
|
// Rename
|
|
141
141
|
const newName = await this.promptForNewWorkerName(config.worker.name);
|
|
142
142
|
config.worker.name = newName;
|
|
143
|
-
config.worker.url = `https://${newName}.${config.credentials?.zoneName || config.
|
|
143
|
+
config.worker.url = `https://${newName}.${config.credentials?.zoneName || `${config.domain || 'clododev'}.workers.dev`}`;
|
|
144
144
|
console.log(` ā
Will deploy as new worker: ${newName}`);
|
|
145
145
|
return true;
|
|
146
146
|
case 2:
|
|
@@ -168,7 +168,7 @@ export class InteractiveValidationWorkflow {
|
|
|
168
168
|
async promptForNewWorkerName(currentName) {
|
|
169
169
|
const {
|
|
170
170
|
askUser
|
|
171
|
-
} = await import('
|
|
171
|
+
} = await import('../../utils/interactive-prompts.js');
|
|
172
172
|
let newName = await askUser(`Enter new worker name (current: ${currentName})`);
|
|
173
173
|
newName = newName.trim();
|
|
174
174
|
if (!newName) {
|
|
@@ -207,7 +207,7 @@ export class InteractiveValidationWorkflow {
|
|
|
207
207
|
// This is a simplified comparison - in a real implementation,
|
|
208
208
|
// you might fetch the existing worker's configuration
|
|
209
209
|
console.log(` š Existing Worker: ${config.worker.name}`);
|
|
210
|
-
console.log(` š URL: https://${config.worker.name}.${config.credentials?.zoneName || config.
|
|
210
|
+
console.log(` š URL: https://${config.worker.name}.${config.credentials?.zoneName || `${config.domain || 'clododev'}.workers.dev`}`);
|
|
211
211
|
console.log(` š
Last deployed: Unknown (would need API call to check)`);
|
|
212
212
|
console.log(` š§ Environment: ${config.environment || 'production'}`);
|
|
213
213
|
console.log('\n š New Deployment:');
|