@tamyla/clodo-framework 4.4.1 → 4.5.0
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 +2 -1851
- package/README.md +44 -18
- package/dist/cli/commands/add.js +325 -0
- package/dist/config/service-schema-config.js +98 -5
- package/dist/index.js +22 -3
- package/dist/middleware/Composer.js +2 -1
- package/dist/middleware/factories.js +445 -0
- package/dist/middleware/index.js +4 -1
- package/dist/modules/ModuleManager.js +6 -2
- package/dist/routing/EnhancedRouter.js +185 -44
- package/dist/routing/RequestContext.js +393 -0
- package/dist/schema/SchemaManager.js +6 -2
- package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +79 -223
- package/dist/service-management/generators/code/WorkerIndexGenerator.js +241 -98
- package/dist/service-management/generators/config/WranglerTomlGenerator.js +130 -89
- package/dist/simple-api.js +4 -4
- package/dist/utilities/index.js +134 -1
- package/dist/validation/environmentGuard.js +172 -0
- package/package.json +4 -1
- package/scripts/repro-clodo.js +123 -0
- package/templates/ai-worker/package.json +19 -0
- package/templates/ai-worker/src/index.js +160 -0
- package/templates/cron-worker/package.json +19 -0
- package/templates/cron-worker/src/index.js +211 -0
- package/templates/edge-proxy/package.json +18 -0
- package/templates/edge-proxy/src/index.js +150 -0
- package/templates/minimal/package.json +17 -0
- package/templates/minimal/src/index.js +40 -0
- package/templates/queue-processor/package.json +19 -0
- package/templates/queue-processor/src/index.js +213 -0
- package/templates/rest-api/.dev.vars +2 -0
- package/templates/rest-api/package.json +19 -0
- package/templates/rest-api/src/index.js +124 -0
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ A comprehensive framework for building enterprise-grade software architecture on
|
|
|
23
23
|
- **[Programmatic API](docs/api/PROGRAMMATIC_API.md)** - Complete programmatic usage
|
|
24
24
|
- **[Parameter Reference](docs/api/parameter_reference.md)** - All parameters and validation
|
|
25
25
|
- **[Error Reference](docs/errors.md)** - Error codes and troubleshooting
|
|
26
|
+
- **[Utilities Guide](docs/utilities/README.md)** - Cloudflare API extensions and integrations
|
|
26
27
|
|
|
27
28
|
### 📖 **Guides & Migration**
|
|
28
29
|
- **[Getting Started](docs/HOWTO_CONSUME_CLODO_FRAMEWORK.md)** - Step-by-step tutorial
|
|
@@ -137,6 +138,16 @@ The Clodo Framework has undergone rigorous validation to ensure it delivers on i
|
|
|
137
138
|
- **Configuration Override**: Environment-specific settings
|
|
138
139
|
- **Template Enhancement**: Service-specific customizations
|
|
139
140
|
|
|
141
|
+
### Cloudflare API Utilities (v4.4.0+)
|
|
142
|
+
- **AI Integration**: Workers AI for text generation, analysis, and embeddings
|
|
143
|
+
- **Storage Solutions**: R2 object storage and KV key-value store
|
|
144
|
+
- **Real-time Features**: Queues for messaging, Durable Objects for state
|
|
145
|
+
- **Advanced Analytics**: Custom metrics and performance monitoring
|
|
146
|
+
- **Email Processing**: Inbound/outbound email handling
|
|
147
|
+
- **Vector Databases**: AI-powered semantic search capabilities
|
|
148
|
+
|
|
149
|
+
> **💡 Utilities are optional extensions** - use them when you need advanced Cloudflare features. See [Utilities Guide](docs/utilities/README.md) for integration examples.
|
|
150
|
+
|
|
140
151
|
## 🚀 Three-Tier Service Creation
|
|
141
152
|
|
|
142
153
|
The Clodo Framework implements a sophisticated three-tier service creation process that transforms your requirements into production-ready Cloudflare services:
|
|
@@ -264,30 +275,45 @@ The project is organized for maximum clarity and maintainability:
|
|
|
264
275
|
|
|
265
276
|
```
|
|
266
277
|
clodo-framework/
|
|
267
|
-
├── docs/
|
|
268
|
-
├──
|
|
269
|
-
│ ├──
|
|
270
|
-
│ ├──
|
|
271
|
-
│ ├──
|
|
272
|
-
│
|
|
273
|
-
|
|
274
|
-
│ ├──
|
|
275
|
-
│ ├──
|
|
276
|
-
│ ├──
|
|
277
|
-
│ ├──
|
|
278
|
-
│
|
|
279
|
-
├──
|
|
280
|
-
├──
|
|
281
|
-
├──
|
|
282
|
-
├──
|
|
283
|
-
└──
|
|
278
|
+
├── docs/ # 📖 Public documentation
|
|
279
|
+
│ ├── strategic/ # Business strategy & planning
|
|
280
|
+
│ ├── utilities/ # Utility integration guides
|
|
281
|
+
│ ├── api/ # API reference & guides
|
|
282
|
+
│ ├── integration/ # Integration & migration guides
|
|
283
|
+
│ └── phases/ # Framework development phases
|
|
284
|
+
├── i-docs/ # 📚 Internal documentation (organized by category)
|
|
285
|
+
│ ├── architecture/ # Design docs, audits, specs
|
|
286
|
+
│ ├── development/ # Dev guides, improvements
|
|
287
|
+
│ ├── testing/ # Test plans, validation
|
|
288
|
+
│ ├── deployment/ # Deployment analysis, fixes
|
|
289
|
+
│ ├── roadmap/ # Strategic planning
|
|
290
|
+
│ ├── guides/ # Integration guides
|
|
291
|
+
│ ├── session-reports/ # Development sessions
|
|
292
|
+
│ ├── phases/ # Phase completions
|
|
293
|
+
│ ├── analysis/ # Technical analysis
|
|
294
|
+
│ └── licensing/ # License information
|
|
295
|
+
├── src/ # 💻 Source code
|
|
296
|
+
├── test/ # ✅ Test suites (Latest CI: 115 suites; 2113 tests passed, 4 skipped)
|
|
297
|
+
├── cli/ # 🔧 CLI tools & commands
|
|
298
|
+
├── examples/ # 📚 Usage examples & demos
|
|
299
|
+
├── config/ # ⚙️ Configuration files & examples
|
|
300
|
+
├── scripts/ # 🛠️ Build & utility scripts
|
|
301
|
+
├── templates/ # 📋 Service templates
|
|
302
|
+
├── dist/ # 📦 Built distribution
|
|
303
|
+
├── lib/ # 📚 Compiled libraries
|
|
304
|
+
├── .logs/ # 📝 Log files (hidden)
|
|
305
|
+
├── .tmp/ # 🗂️ Temporary files (hidden)
|
|
306
|
+
├── backups/ # 💾 Backup files
|
|
307
|
+
├── deployments/ # 🚀 Deployment artifacts
|
|
308
|
+
├── secrets/ # 🔐 Secret management
|
|
309
|
+
└── coverage/ # 📊 Test coverage reports
|
|
284
310
|
|
|
285
311
|
```
|
|
286
312
|
|
|
287
313
|
**Quality Metrics:**
|
|
288
314
|
- ✅ **Latest CI (2026-02-04): 115 test suites passed; 4 tests skipped; 2113/2117 tests passed**
|
|
289
315
|
- ✅ **CLI tests:** passing (all CLI-specific tests passed in the latest run)
|
|
290
|
-
- ✅ **Clean architecture** (no
|
|
316
|
+
- ✅ **Clean architecture** (organized file structure, no clutter in root)
|
|
291
317
|
- ✅ **Configuration-based** (no hard-coded values in source)
|
|
292
318
|
|
|
293
319
|
## 📚 Incremental Adoption
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* clodo add — Incremental enhancement command
|
|
4
|
+
*
|
|
5
|
+
* Adds Cloudflare bindings, middleware, and features to an existing
|
|
6
|
+
* Clodo-generated Worker project without regenerating from scratch.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx clodo add ai # Add Workers AI binding
|
|
10
|
+
* npx clodo add kv # Add KV namespace
|
|
11
|
+
* npx clodo add kv:users # Add KV with custom binding name
|
|
12
|
+
* npx clodo add d1 # Add D1 database
|
|
13
|
+
* npx clodo add r2 # Add R2 storage
|
|
14
|
+
* npx clodo add vectorize # Add Vectorize index
|
|
15
|
+
* npx clodo add queues # Add Queue producer/consumer
|
|
16
|
+
* npx clodo add cron # Add scheduled handler
|
|
17
|
+
* npx clodo add auth:bearer # Add bearer token middleware
|
|
18
|
+
* npx clodo add auth:apikey # Add API key middleware
|
|
19
|
+
* npx clodo add email # Add Email Workers
|
|
20
|
+
* npx clodo add hyperdrive # Add Hyperdrive (Postgres)
|
|
21
|
+
* npx clodo add analytics # Add Analytics Engine
|
|
22
|
+
* npx clodo add browser # Add Browser Rendering
|
|
23
|
+
*
|
|
24
|
+
* @module cli/commands/add
|
|
25
|
+
*/
|
|
26
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
27
|
+
import { join, resolve } from 'path';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* TOML snippets for each feature binding
|
|
31
|
+
*/
|
|
32
|
+
const BINDING_TOML = {
|
|
33
|
+
ai: `
|
|
34
|
+
# ═══ Workers AI ════════════════════════════════════════════════════
|
|
35
|
+
[ai]
|
|
36
|
+
binding = "AI"`,
|
|
37
|
+
kv: (bindingName = 'KV') => `
|
|
38
|
+
# ═══ KV Namespace ══════════════════════════════════════════════════
|
|
39
|
+
[[kv_namespaces]]
|
|
40
|
+
binding = "${bindingName}"
|
|
41
|
+
id = ""`,
|
|
42
|
+
d1: (dbName = 'my-db') => `
|
|
43
|
+
# ═══ D1 Database ═══════════════════════════════════════════════════
|
|
44
|
+
[[d1_databases]]
|
|
45
|
+
binding = "DB"
|
|
46
|
+
database_name = "${dbName}"
|
|
47
|
+
database_id = ""`,
|
|
48
|
+
r2: (bucketName = 'my-storage') => `
|
|
49
|
+
# ═══ R2 Object Storage ═════════════════════════════════════════════
|
|
50
|
+
[[r2_buckets]]
|
|
51
|
+
binding = "R2_STORAGE"
|
|
52
|
+
bucket_name = "${bucketName}"`,
|
|
53
|
+
vectorize: (indexName = 'my-index') => `
|
|
54
|
+
# ═══ Vectorize ═════════════════════════════════════════════════════
|
|
55
|
+
[[vectorize]]
|
|
56
|
+
binding = "VECTORIZE_INDEX"
|
|
57
|
+
index_name = "${indexName}"`,
|
|
58
|
+
queues: (queueName = 'my-queue') => `
|
|
59
|
+
# ═══ Queues ════════════════════════════════════════════════════════
|
|
60
|
+
[[queues.producers]]
|
|
61
|
+
binding = "QUEUE"
|
|
62
|
+
queue = "${queueName}"
|
|
63
|
+
|
|
64
|
+
[[queues.consumers]]
|
|
65
|
+
queue = "${queueName}"
|
|
66
|
+
max_batch_size = 10
|
|
67
|
+
max_batch_timeout = 30
|
|
68
|
+
max_retries = 3`,
|
|
69
|
+
cron: `
|
|
70
|
+
# ═══ Cron Triggers ═════════════════════════════════════════════════
|
|
71
|
+
[triggers]
|
|
72
|
+
crons = ["*/5 * * * *"]`,
|
|
73
|
+
email: `
|
|
74
|
+
# ═══ Email Workers ═════════════════════════════════════════════════
|
|
75
|
+
[send_email]
|
|
76
|
+
binding = "EMAIL"`,
|
|
77
|
+
hyperdrive: `
|
|
78
|
+
# ═══ Hyperdrive ════════════════════════════════════════════════════
|
|
79
|
+
[[hyperdrive]]
|
|
80
|
+
binding = "HYPERDRIVE"
|
|
81
|
+
id = ""`,
|
|
82
|
+
analytics: (workerName = 'my-worker') => `
|
|
83
|
+
# ═══ Analytics Engine ══════════════════════════════════════════════
|
|
84
|
+
[[analytics_engine_datasets]]
|
|
85
|
+
binding = "ANALYTICS"
|
|
86
|
+
dataset = "${workerName}-analytics"`,
|
|
87
|
+
browser: `
|
|
88
|
+
# ═══ Browser Rendering ═════════════════════════════════════════════
|
|
89
|
+
[browser]
|
|
90
|
+
binding = "BROWSER"`
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Import snippets to add to the worker entry point
|
|
95
|
+
*/
|
|
96
|
+
const IMPORT_SNIPPETS = {
|
|
97
|
+
ai: {
|
|
98
|
+
framework: [],
|
|
99
|
+
utilities: ['runAIModel', 'streamAIResponse'],
|
|
100
|
+
envBinding: 'AI'
|
|
101
|
+
},
|
|
102
|
+
kv: {
|
|
103
|
+
framework: [],
|
|
104
|
+
utilities: ['getKV', 'putKV', 'listKV', 'deleteKV'],
|
|
105
|
+
envBinding: 'KV'
|
|
106
|
+
},
|
|
107
|
+
d1: {
|
|
108
|
+
framework: [],
|
|
109
|
+
utilities: [],
|
|
110
|
+
envBinding: 'DB'
|
|
111
|
+
},
|
|
112
|
+
r2: {
|
|
113
|
+
framework: [],
|
|
114
|
+
utilities: ['putR2Object', 'getR2Object'],
|
|
115
|
+
envBinding: 'R2_STORAGE'
|
|
116
|
+
},
|
|
117
|
+
vectorize: {
|
|
118
|
+
framework: [],
|
|
119
|
+
utilities: ['queryVectors', 'upsertVectors'],
|
|
120
|
+
envBinding: 'VECTORIZE_INDEX'
|
|
121
|
+
},
|
|
122
|
+
queues: {
|
|
123
|
+
framework: [],
|
|
124
|
+
utilities: [],
|
|
125
|
+
envBinding: 'QUEUE'
|
|
126
|
+
},
|
|
127
|
+
'auth:bearer': {
|
|
128
|
+
framework: ['createBearerAuth'],
|
|
129
|
+
utilities: [],
|
|
130
|
+
envBinding: null
|
|
131
|
+
},
|
|
132
|
+
'auth:apikey': {
|
|
133
|
+
framework: ['createApiKeyAuth'],
|
|
134
|
+
utilities: [],
|
|
135
|
+
envBinding: null
|
|
136
|
+
},
|
|
137
|
+
email: {
|
|
138
|
+
framework: [],
|
|
139
|
+
utilities: ['sendEmail'],
|
|
140
|
+
envBinding: 'EMAIL'
|
|
141
|
+
},
|
|
142
|
+
hyperdrive: {
|
|
143
|
+
framework: [],
|
|
144
|
+
utilities: [],
|
|
145
|
+
envBinding: 'HYPERDRIVE'
|
|
146
|
+
},
|
|
147
|
+
analytics: {
|
|
148
|
+
framework: [],
|
|
149
|
+
utilities: [],
|
|
150
|
+
envBinding: 'ANALYTICS'
|
|
151
|
+
},
|
|
152
|
+
browser: {
|
|
153
|
+
framework: [],
|
|
154
|
+
utilities: [],
|
|
155
|
+
envBinding: 'BROWSER'
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Parse feature argument (e.g., "kv:users" → { feature: "kv", name: "users" })
|
|
161
|
+
*/
|
|
162
|
+
function parseFeatureArg(arg) {
|
|
163
|
+
const [feature, name] = arg.split(':');
|
|
164
|
+
return {
|
|
165
|
+
feature: feature.toLowerCase(),
|
|
166
|
+
name
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Add a feature to an existing project
|
|
172
|
+
*/
|
|
173
|
+
export async function addFeature(featureArg, options = {}) {
|
|
174
|
+
const cwd = options.cwd || process.cwd();
|
|
175
|
+
const {
|
|
176
|
+
feature,
|
|
177
|
+
name
|
|
178
|
+
} = parseFeatureArg(featureArg);
|
|
179
|
+
const results = {
|
|
180
|
+
feature,
|
|
181
|
+
wranglerUpdated: false,
|
|
182
|
+
envGuardUpdated: false,
|
|
183
|
+
importsAdded: [],
|
|
184
|
+
instructions: []
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// 1. Update wrangler.toml
|
|
188
|
+
const wranglerPath = join(cwd, 'wrangler.toml');
|
|
189
|
+
if (existsSync(wranglerPath)) {
|
|
190
|
+
const wranglerContent = readFileSync(wranglerPath, 'utf8');
|
|
191
|
+
|
|
192
|
+
// Check if binding already exists
|
|
193
|
+
const bindingCheck = {
|
|
194
|
+
ai: '[ai]',
|
|
195
|
+
kv: '[[kv_namespaces]]',
|
|
196
|
+
d1: '[[d1_databases]]',
|
|
197
|
+
r2: '[[r2_buckets]]',
|
|
198
|
+
vectorize: '[[vectorize]]',
|
|
199
|
+
queues: '[[queues.',
|
|
200
|
+
cron: '[triggers]',
|
|
201
|
+
email: '[send_email]',
|
|
202
|
+
hyperdrive: '[[hyperdrive]]',
|
|
203
|
+
analytics: '[[analytics_engine_datasets]]',
|
|
204
|
+
browser: '[browser]'
|
|
205
|
+
};
|
|
206
|
+
const baseFeature = feature.includes(':') ? feature.split(':')[0] : feature;
|
|
207
|
+
if (bindingCheck[baseFeature] && wranglerContent.includes(bindingCheck[baseFeature])) {
|
|
208
|
+
results.instructions.push(`⚠️ ${baseFeature} binding already exists in wrangler.toml`);
|
|
209
|
+
} else {
|
|
210
|
+
const tomlSnippet = typeof BINDING_TOML[baseFeature] === 'function' ? BINDING_TOML[baseFeature](name || undefined) : BINDING_TOML[baseFeature];
|
|
211
|
+
if (tomlSnippet) {
|
|
212
|
+
writeFileSync(wranglerPath, wranglerContent.trimEnd() + '\n' + tomlSnippet + '\n', 'utf8');
|
|
213
|
+
results.wranglerUpdated = true;
|
|
214
|
+
results.instructions.push(`✅ Added ${baseFeature} binding to wrangler.toml`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
results.instructions.push('⚠️ No wrangler.toml found. Create one first with: npx clodo create');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 2. Show import suggestions
|
|
222
|
+
const importInfo = IMPORT_SNIPPETS[feature] || IMPORT_SNIPPETS[feature.split(':')[0]];
|
|
223
|
+
if (importInfo) {
|
|
224
|
+
if (importInfo.framework.length > 0) {
|
|
225
|
+
results.importsAdded.push(`import { ${importInfo.framework.join(', ')} } from '@tamyla/clodo-framework';`);
|
|
226
|
+
results.instructions.push(`📦 Add to your worker: import { ${importInfo.framework.join(', ')} } from '@tamyla/clodo-framework';`);
|
|
227
|
+
}
|
|
228
|
+
if (importInfo.utilities.length > 0) {
|
|
229
|
+
results.importsAdded.push(`import { ${importInfo.utilities.join(', ')} } from '@tamyla/clodo-framework/utilities';`);
|
|
230
|
+
results.instructions.push(`📦 Add to your worker: import { ${importInfo.utilities.join(', ')} } from '@tamyla/clodo-framework/utilities';`);
|
|
231
|
+
}
|
|
232
|
+
if (importInfo.envBinding) {
|
|
233
|
+
results.instructions.push(`🔧 Add '${importInfo.envBinding}' to your createEnvironmentGuard({ required: [...] })`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 3. Feature-specific setup instructions
|
|
238
|
+
const setupInstructions = {
|
|
239
|
+
ai: '🚀 Workers AI is ready! Use env.AI.run(model, options) in your handler.',
|
|
240
|
+
kv: `🚀 Run: wrangler kv namespace create "${name || 'KV'}" to create the namespace, then paste the ID.`,
|
|
241
|
+
d1: `🚀 Run: wrangler d1 create "${name || 'my-db'}" to create the database.`,
|
|
242
|
+
r2: `🚀 Run: wrangler r2 bucket create "${name || 'my-storage'}" to create the bucket.`,
|
|
243
|
+
vectorize: `🚀 Run: wrangler vectorize create "${name || 'my-index'}" --dimensions 768 --metric cosine`,
|
|
244
|
+
queues: `🚀 Queue "${name || 'my-queue'}" will be auto-created on first deploy.`,
|
|
245
|
+
cron: '🚀 Cron trigger added. Implement the scheduled() handler in your worker.',
|
|
246
|
+
'auth:bearer': '🔐 Add createBearerAuth({ token: env.SECRET_KEY }) to your middleware stack.',
|
|
247
|
+
'auth:apikey': '🔐 Add createApiKeyAuth({ keys: [env.API_KEY] }) to your middleware stack.',
|
|
248
|
+
email: '🚀 Email binding ready. Use env.EMAIL.send() in your handler.',
|
|
249
|
+
hyperdrive: '🚀 Run: wrangler hyperdrive create <name> --connection-string "postgres://..."',
|
|
250
|
+
analytics: '🚀 Analytics Engine ready. Use env.ANALYTICS.writeDataPoint() in your handler.',
|
|
251
|
+
browser: '🚀 Browser Rendering ready. Use env.BROWSER in your handler.'
|
|
252
|
+
};
|
|
253
|
+
if (setupInstructions[feature]) {
|
|
254
|
+
results.instructions.push(setupInstructions[feature]);
|
|
255
|
+
}
|
|
256
|
+
return results;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* CLI entry point for `clodo add`
|
|
261
|
+
*/
|
|
262
|
+
export function registerAddCommand(program) {
|
|
263
|
+
program.command('add <feature>').description('Add a Cloudflare binding or feature to your existing Worker project').option('-d, --dir <path>', 'Project directory', '.').option('--dry-run', 'Show what would change without modifying files').action(async (feature, options) => {
|
|
264
|
+
console.log(`\n🔧 Adding "${feature}" to your Worker project...\n`);
|
|
265
|
+
const results = await addFeature(feature, {
|
|
266
|
+
cwd: resolve(options.dir),
|
|
267
|
+
dryRun: options.dryRun
|
|
268
|
+
});
|
|
269
|
+
for (const instruction of results.instructions) {
|
|
270
|
+
console.log(` ${instruction}`);
|
|
271
|
+
}
|
|
272
|
+
console.log('');
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* List all available features for `clodo add`
|
|
278
|
+
*/
|
|
279
|
+
export function listAvailableFeatures() {
|
|
280
|
+
return [{
|
|
281
|
+
name: 'ai',
|
|
282
|
+
description: 'Workers AI (text generation, embeddings, etc.)'
|
|
283
|
+
}, {
|
|
284
|
+
name: 'kv',
|
|
285
|
+
description: 'KV Namespace (key-value storage)',
|
|
286
|
+
syntax: 'kv[:binding_name]'
|
|
287
|
+
}, {
|
|
288
|
+
name: 'd1',
|
|
289
|
+
description: 'D1 Database (SQLite)',
|
|
290
|
+
syntax: 'd1[:db_name]'
|
|
291
|
+
}, {
|
|
292
|
+
name: 'r2',
|
|
293
|
+
description: 'R2 Object Storage',
|
|
294
|
+
syntax: 'r2[:bucket_name]'
|
|
295
|
+
}, {
|
|
296
|
+
name: 'vectorize',
|
|
297
|
+
description: 'Vectorize (vector database)',
|
|
298
|
+
syntax: 'vectorize[:index_name]'
|
|
299
|
+
}, {
|
|
300
|
+
name: 'queues',
|
|
301
|
+
description: 'Queues (message queue)',
|
|
302
|
+
syntax: 'queues[:queue_name]'
|
|
303
|
+
}, {
|
|
304
|
+
name: 'cron',
|
|
305
|
+
description: 'Cron Triggers (scheduled jobs)'
|
|
306
|
+
}, {
|
|
307
|
+
name: 'auth:bearer',
|
|
308
|
+
description: 'Bearer token authentication middleware'
|
|
309
|
+
}, {
|
|
310
|
+
name: 'auth:apikey',
|
|
311
|
+
description: 'API key authentication middleware'
|
|
312
|
+
}, {
|
|
313
|
+
name: 'email',
|
|
314
|
+
description: 'Email Workers (send email)'
|
|
315
|
+
}, {
|
|
316
|
+
name: 'hyperdrive',
|
|
317
|
+
description: 'Hyperdrive (Postgres connection pool)'
|
|
318
|
+
}, {
|
|
319
|
+
name: 'analytics',
|
|
320
|
+
description: 'Analytics Engine (custom metrics)'
|
|
321
|
+
}, {
|
|
322
|
+
name: 'browser',
|
|
323
|
+
description: 'Browser Rendering API'
|
|
324
|
+
}];
|
|
325
|
+
}
|
|
@@ -2,8 +2,28 @@
|
|
|
2
2
|
// Allows runtime overrides for enums and features to keep validation flexible and configurable
|
|
3
3
|
|
|
4
4
|
let config = {
|
|
5
|
-
serviceTypes: ['api-service', 'data-service', 'worker', 'pages', 'gateway', 'generic'
|
|
6
|
-
|
|
5
|
+
serviceTypes: ['api-service', 'data-service', 'worker', 'pages', 'gateway', 'generic',
|
|
6
|
+
// New real-world Cloudflare Worker patterns
|
|
7
|
+
'ai-worker', 'queue-processor', 'cron-worker', 'edge-proxy'],
|
|
8
|
+
features: [
|
|
9
|
+
// Storage & Databases
|
|
10
|
+
'd1', 'kv', 'r2',
|
|
11
|
+
// AI & ML
|
|
12
|
+
'ai', 'vectorize',
|
|
13
|
+
// Messaging & Events
|
|
14
|
+
'queues', 'cron',
|
|
15
|
+
// Compute
|
|
16
|
+
'durableObject', 'durableObjects',
|
|
17
|
+
// Communication
|
|
18
|
+
'email', 'ws',
|
|
19
|
+
// Networking
|
|
20
|
+
'hyperdrive', 'browser',
|
|
21
|
+
// Observability
|
|
22
|
+
'metrics', 'analytics',
|
|
23
|
+
// Infrastructure
|
|
24
|
+
'pages',
|
|
25
|
+
// Legacy (kept for backward compatibility)
|
|
26
|
+
'upstash']
|
|
7
27
|
};
|
|
8
28
|
export function getConfig() {
|
|
9
29
|
return {
|
|
@@ -16,7 +36,80 @@ export function setConfig(updates = {}) {
|
|
|
16
36
|
}
|
|
17
37
|
export function resetConfig() {
|
|
18
38
|
config = {
|
|
19
|
-
serviceTypes: ['api-service', 'data-service', 'worker', 'pages', 'gateway', 'generic'],
|
|
20
|
-
features: ['d1', '
|
|
39
|
+
serviceTypes: ['api-service', 'data-service', 'worker', 'pages', 'gateway', 'generic', 'ai-worker', 'queue-processor', 'cron-worker', 'edge-proxy'],
|
|
40
|
+
features: ['d1', 'kv', 'r2', 'ai', 'vectorize', 'queues', 'cron', 'durableObject', 'durableObjects', 'email', 'ws', 'hyperdrive', 'browser', 'metrics', 'analytics', 'pages', 'upstash']
|
|
21
41
|
};
|
|
22
|
-
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Maps feature names to their wrangler.toml binding configuration.
|
|
46
|
+
* Used by scaffold generators to produce correct wrangler.toml output.
|
|
47
|
+
*/
|
|
48
|
+
export const FEATURE_BINDING_MAP = {
|
|
49
|
+
ai: {
|
|
50
|
+
toml: '[ai]\nbinding = "AI"',
|
|
51
|
+
envType: 'Ai',
|
|
52
|
+
binding: 'AI'
|
|
53
|
+
},
|
|
54
|
+
vectorize: {
|
|
55
|
+
toml: '[[vectorize]]\nbinding = "VECTORIZE_INDEX"\nindex_name = "my-index"',
|
|
56
|
+
envType: 'VectorizeIndex',
|
|
57
|
+
binding: 'VECTORIZE_INDEX'
|
|
58
|
+
},
|
|
59
|
+
kv: {
|
|
60
|
+
toml: '[[kv_namespaces]]\nbinding = "KV_DATA"\nid = ""',
|
|
61
|
+
envType: 'KVNamespace',
|
|
62
|
+
binding: 'KV_DATA'
|
|
63
|
+
},
|
|
64
|
+
d1: {
|
|
65
|
+
toml: '[[d1_databases]]\nbinding = "DB"\ndatabase_name = ""\ndatabase_id = ""',
|
|
66
|
+
envType: 'D1Database',
|
|
67
|
+
binding: 'DB'
|
|
68
|
+
},
|
|
69
|
+
r2: {
|
|
70
|
+
toml: '[[r2_buckets]]\nbinding = "R2_STORAGE"\nbucket_name = ""',
|
|
71
|
+
envType: 'R2Bucket',
|
|
72
|
+
binding: 'R2_STORAGE'
|
|
73
|
+
},
|
|
74
|
+
queues: {
|
|
75
|
+
toml: '[[queues.producers]]\nbinding = "QUEUE"\nqueue = "my-queue"\n\n[[queues.consumers]]\nqueue = "my-queue"\nmax_batch_size = 10\nmax_batch_timeout = 30',
|
|
76
|
+
envType: 'Queue',
|
|
77
|
+
binding: 'QUEUE'
|
|
78
|
+
},
|
|
79
|
+
durableObject: {
|
|
80
|
+
toml: '[[durable_objects.bindings]]\nname = "MY_DURABLE_OBJECT"\nclass_name = "MyDurableObject"',
|
|
81
|
+
envType: 'DurableObjectNamespace',
|
|
82
|
+
binding: 'MY_DURABLE_OBJECT'
|
|
83
|
+
},
|
|
84
|
+
durableObjects: {
|
|
85
|
+
toml: '[[durable_objects.bindings]]\nname = "MY_DURABLE_OBJECT"\nclass_name = "MyDurableObject"',
|
|
86
|
+
envType: 'DurableObjectNamespace',
|
|
87
|
+
binding: 'MY_DURABLE_OBJECT'
|
|
88
|
+
},
|
|
89
|
+
email: {
|
|
90
|
+
toml: '[send_email]\nname = "EMAIL"\ndestination_address = ""',
|
|
91
|
+
envType: 'SendEmail',
|
|
92
|
+
binding: 'EMAIL'
|
|
93
|
+
},
|
|
94
|
+
hyperdrive: {
|
|
95
|
+
toml: '[[hyperdrive]]\nbinding = "HYPERDRIVE"\nid = ""',
|
|
96
|
+
envType: 'Hyperdrive',
|
|
97
|
+
binding: 'HYPERDRIVE'
|
|
98
|
+
},
|
|
99
|
+
browser: {
|
|
100
|
+
toml: '[browser]\nbinding = "BROWSER"',
|
|
101
|
+
envType: 'Fetcher',
|
|
102
|
+
binding: 'BROWSER'
|
|
103
|
+
},
|
|
104
|
+
analytics: {
|
|
105
|
+
toml: '[[analytics_engine_datasets]]\nbinding = "ANALYTICS"\ndataset = "my-dataset"',
|
|
106
|
+
envType: 'AnalyticsEngineDataset',
|
|
107
|
+
binding: 'ANALYTICS'
|
|
108
|
+
},
|
|
109
|
+
cron: {
|
|
110
|
+
// Cron doesn't add bindings, it adds triggers
|
|
111
|
+
toml: '[triggers]\ncrons = ["*/5 * * * *"]',
|
|
112
|
+
envType: null,
|
|
113
|
+
binding: null
|
|
114
|
+
}
|
|
115
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,18 @@ export { createDomainConfigSchema, validateDomainConfig, createDefaultDomainConf
|
|
|
15
15
|
export { initializeService } from './worker/integration.js';
|
|
16
16
|
export { autoConfigureFramework } from './version/VersionDetector.js';
|
|
17
17
|
|
|
18
|
+
// ─── NEW: Middleware Factories & Composition ─────────────────────────
|
|
19
|
+
export { createCorsMiddleware, createErrorHandler, createRateLimitGuard, createLogger, createBearerAuth, createApiKeyAuth, composeMiddleware } from './middleware/factories.js';
|
|
20
|
+
|
|
21
|
+
// ─── NEW: Environment Guard ──────────────────────────────────────────
|
|
22
|
+
export { EnvironmentGuard, createEnvironmentGuard } from './validation/environmentGuard.js';
|
|
23
|
+
|
|
24
|
+
// ─── NEW: RequestContext (Hono-style) ────────────────────────────────
|
|
25
|
+
export { RequestContext, createRequestContext } from './routing/RequestContext.js';
|
|
26
|
+
|
|
27
|
+
// ─── NEW: Feature-to-binding mapping ─────────────────────────────────
|
|
28
|
+
export { FEATURE_BINDING_MAP } from './config/service-schema-config.js';
|
|
29
|
+
|
|
18
30
|
// Core data and schema components
|
|
19
31
|
export * from './services/GenericDataService.js';
|
|
20
32
|
export * from './schema/SchemaManager.js';
|
|
@@ -62,12 +74,19 @@ export { classifyError, getRecoverySuggestions } from './lib/shared/error-handli
|
|
|
62
74
|
export { FrameworkInfo } from './version/FrameworkInfo.js';
|
|
63
75
|
export { TemplateRuntime } from './utils/TemplateRuntime.js';
|
|
64
76
|
export { HealthChecker } from './monitoring/HealthChecker.js';
|
|
65
|
-
export const FRAMEWORK_VERSION = '
|
|
77
|
+
export const FRAMEWORK_VERSION = '4.4.1';
|
|
66
78
|
export const FRAMEWORK_NAME = 'Clodo Framework';
|
|
67
79
|
|
|
68
|
-
//
|
|
80
|
+
// ─── Compatibility Constants (for consistent wrangler.toml generation) ──
|
|
81
|
+
export const RECOMMENDED_COMPATIBILITY_DATE = '2024-12-01';
|
|
82
|
+
export const MINIMUM_COMPATIBILITY_DATE = '2023-06-01';
|
|
83
|
+
export const RECOMMENDED_COMPATIBILITY_FLAGS = ['nodejs_compat'];
|
|
84
|
+
|
|
85
|
+
// Helper for framework initialization (silent by default, verbose with DEBUG)
|
|
69
86
|
export const initializeFramework = (options = {}) => {
|
|
70
|
-
|
|
87
|
+
if (options.verbose || typeof process !== 'undefined' && process.env?.DEBUG) {
|
|
88
|
+
console.log(`${FRAMEWORK_NAME} v${FRAMEWORK_VERSION} initialized`);
|
|
89
|
+
}
|
|
71
90
|
return {
|
|
72
91
|
version: FRAMEWORK_VERSION,
|
|
73
92
|
name: FRAMEWORK_NAME,
|
|
@@ -26,7 +26,8 @@ export class MiddlewareComposer {
|
|
|
26
26
|
// Postprocess in reverse order
|
|
27
27
|
for (const m of chain.slice().reverse()) {
|
|
28
28
|
if (typeof m.postprocess === 'function') {
|
|
29
|
-
|
|
29
|
+
// Pass the original request as the second argument so postprocess can access per-request state
|
|
30
|
+
const updated = await m.postprocess(response, request);
|
|
30
31
|
// Allow middleware to replace response
|
|
31
32
|
if (updated instanceof Response) response = updated;
|
|
32
33
|
}
|