@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
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST API Worker Template — @tamyla/clodo-framework
|
|
3
|
+
*
|
|
4
|
+
* A fully working REST API worker with CRUD routes, KV storage,
|
|
5
|
+
* CORS, error handling, rate limiting, and health checks.
|
|
6
|
+
*
|
|
7
|
+
* Deploy with: npx wrangler deploy
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
EnhancedRouter,
|
|
12
|
+
createCorsMiddleware,
|
|
13
|
+
createErrorHandler,
|
|
14
|
+
createLogger,
|
|
15
|
+
createRateLimitGuard,
|
|
16
|
+
composeMiddleware,
|
|
17
|
+
HealthChecker,
|
|
18
|
+
createEnvironmentGuard
|
|
19
|
+
} from '@tamyla/clodo-framework';
|
|
20
|
+
|
|
21
|
+
import { getKV, putKV, listKV } from '@tamyla/clodo-framework/utilities';
|
|
22
|
+
|
|
23
|
+
// ── Environment validation ────────────────────────────────────────────
|
|
24
|
+
const envGuard = createEnvironmentGuard({
|
|
25
|
+
required: ['KV_DATA'],
|
|
26
|
+
optional: ['SECRET_KEY', 'DEBUG']
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// ── Router setup ──────────────────────────────────────────────────────
|
|
30
|
+
const router = new EnhancedRouter(null, { autoRegisterGenericRoutes: false });
|
|
31
|
+
|
|
32
|
+
// Apply middleware stack
|
|
33
|
+
router.use(composeMiddleware(
|
|
34
|
+
createCorsMiddleware({ origins: ['*'] }),
|
|
35
|
+
createLogger({ prefix: 'api', level: 'info' }),
|
|
36
|
+
createRateLimitGuard({ maxRequests: 100, windowMs: 60000 }),
|
|
37
|
+
createErrorHandler({ includeStack: false })
|
|
38
|
+
));
|
|
39
|
+
|
|
40
|
+
// ── Health check ──────────────────────────────────────────────────────
|
|
41
|
+
const healthChecker = new HealthChecker();
|
|
42
|
+
healthChecker.addCheck('kv', async (env) => {
|
|
43
|
+
try {
|
|
44
|
+
await env.KV_DATA.get('__health_check__');
|
|
45
|
+
return { status: 'healthy' };
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return { status: 'unhealthy', error: e.message };
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// ── Routes ────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
router.get('/health', async (request, env) => {
|
|
54
|
+
const result = await healthChecker.runChecks();
|
|
55
|
+
return new Response(JSON.stringify(result), {
|
|
56
|
+
headers: { 'Content-Type': 'application/json' }
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
router.get('/api/items', async (request, env) => {
|
|
61
|
+
const list = await listKV(env.KV_DATA, { prefix: 'item:' });
|
|
62
|
+
const items = await Promise.all(
|
|
63
|
+
(list.keys || []).map(async (k) => {
|
|
64
|
+
const val = await getKV(env.KV_DATA, k.name, { type: 'json' });
|
|
65
|
+
return val;
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
return new Response(JSON.stringify({ items, count: items.length }), {
|
|
69
|
+
headers: { 'Content-Type': 'application/json' }
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
router.get('/api/items/:id', async (request, env) => {
|
|
74
|
+
const id = request.params?.id;
|
|
75
|
+
const item = await getKV(env.KV_DATA, `item:${id}`, { type: 'json' });
|
|
76
|
+
if (!item) {
|
|
77
|
+
return new Response(JSON.stringify({ error: 'Item not found' }), { status: 404 });
|
|
78
|
+
}
|
|
79
|
+
return new Response(JSON.stringify(item), {
|
|
80
|
+
headers: { 'Content-Type': 'application/json' }
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
router.post('/api/items', async (request, env) => {
|
|
85
|
+
const body = await request.json();
|
|
86
|
+
const id = crypto.randomUUID();
|
|
87
|
+
const item = { id, ...body, createdAt: new Date().toISOString() };
|
|
88
|
+
await putKV(env.KV_DATA, `item:${id}`, JSON.stringify(item));
|
|
89
|
+
return new Response(JSON.stringify(item), {
|
|
90
|
+
status: 201,
|
|
91
|
+
headers: { 'Content-Type': 'application/json' }
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
router.put('/api/items/:id', async (request, env) => {
|
|
96
|
+
const id = request.params?.id;
|
|
97
|
+
const existing = await getKV(env.KV_DATA, `item:${id}`, { type: 'json' });
|
|
98
|
+
if (!existing) {
|
|
99
|
+
return new Response(JSON.stringify({ error: 'Item not found' }), { status: 404 });
|
|
100
|
+
}
|
|
101
|
+
const body = await request.json();
|
|
102
|
+
const updated = { ...existing, ...body, id, updatedAt: new Date().toISOString() };
|
|
103
|
+
await putKV(env.KV_DATA, `item:${id}`, JSON.stringify(updated));
|
|
104
|
+
return new Response(JSON.stringify(updated), {
|
|
105
|
+
headers: { 'Content-Type': 'application/json' }
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
router.delete('/api/items/:id', async (request, env) => {
|
|
110
|
+
const id = request.params?.id;
|
|
111
|
+
await env.KV_DATA.delete(`item:${id}`);
|
|
112
|
+
return new Response(JSON.stringify({ deleted: true, id }), {
|
|
113
|
+
headers: { 'Content-Type': 'application/json' }
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// ── Worker entry point ────────────────────────────────────────────────
|
|
118
|
+
export default {
|
|
119
|
+
async fetch(request, env, ctx) {
|
|
120
|
+
envGuard.check(env);
|
|
121
|
+
const url = new URL(request.url);
|
|
122
|
+
return router.handleRequest(request.method, url.pathname, request, env, ctx);
|
|
123
|
+
}
|
|
124
|
+
};
|