@tamyla/clodo-framework 1.0.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 +564 -0
- package/LICENSE +21 -0
- package/README.md +1393 -0
- package/bin/README.md +71 -0
- package/bin/clodo-service.js +416 -0
- package/bin/security/security-cli.js +96 -0
- package/bin/service-management/README.md +74 -0
- package/bin/service-management/create-service.js +129 -0
- package/bin/service-management/init-service.js +102 -0
- package/bin/service-management/init-service.js.backup +889 -0
- package/bin/shared/config/customer-cli.js +293 -0
- package/dist/config/ConfigurationManager.js +159 -0
- package/dist/config/CustomerConfigCLI.js +220 -0
- package/dist/config/FeatureManager.js +426 -0
- package/dist/config/customers.js +441 -0
- package/dist/config/domains.js +180 -0
- package/dist/config/features.js +225 -0
- package/dist/config/index.js +6 -0
- package/dist/database/database-orchestrator.js +730 -0
- package/dist/database/index.js +4 -0
- package/dist/deployment/auditor.js +971 -0
- package/dist/deployment/index.js +10 -0
- package/dist/deployment/rollback-manager.js +523 -0
- package/dist/deployment/testers/api-tester.js +80 -0
- package/dist/deployment/testers/auth-tester.js +129 -0
- package/dist/deployment/testers/core.js +217 -0
- package/dist/deployment/testers/database-tester.js +105 -0
- package/dist/deployment/testers/index.js +74 -0
- package/dist/deployment/testers/load-tester.js +120 -0
- package/dist/deployment/testers/performance-tester.js +105 -0
- package/dist/deployment/validator.js +558 -0
- package/dist/deployment/wrangler-deployer.js +574 -0
- package/dist/handlers/GenericRouteHandler.js +532 -0
- package/dist/index.js +39 -0
- package/dist/migration/MigrationAdapters.js +562 -0
- package/dist/modules/ModuleManager.js +668 -0
- package/dist/modules/security.js +98 -0
- package/dist/orchestration/cross-domain-coordinator.js +1083 -0
- package/dist/orchestration/index.js +5 -0
- package/dist/orchestration/modules/DeploymentCoordinator.js +258 -0
- package/dist/orchestration/modules/DomainResolver.js +196 -0
- package/dist/orchestration/modules/StateManager.js +332 -0
- package/dist/orchestration/multi-domain-orchestrator.js +255 -0
- package/dist/routing/EnhancedRouter.js +158 -0
- package/dist/schema/SchemaManager.js +778 -0
- package/dist/security/ConfigurationValidator.js +490 -0
- package/dist/security/DeploymentManager.js +208 -0
- package/dist/security/SecretGenerator.js +142 -0
- package/dist/security/SecurityCLI.js +228 -0
- package/dist/security/index.js +51 -0
- package/dist/security/patterns/environment-rules.js +66 -0
- package/dist/security/patterns/insecure-patterns.js +21 -0
- package/dist/service-management/ConfirmationEngine.js +411 -0
- package/dist/service-management/ErrorTracker.js +294 -0
- package/dist/service-management/GenerationEngine.js +3109 -0
- package/dist/service-management/InputCollector.js +237 -0
- package/dist/service-management/ServiceCreator.js +229 -0
- package/dist/service-management/ServiceInitializer.js +448 -0
- package/dist/service-management/ServiceOrchestrator.js +638 -0
- package/dist/service-management/handlers/ConfigMutator.js +130 -0
- package/dist/service-management/handlers/ConfirmationHandler.js +71 -0
- package/dist/service-management/handlers/GenerationHandler.js +80 -0
- package/dist/service-management/handlers/InputHandler.js +59 -0
- package/dist/service-management/handlers/ValidationHandler.js +203 -0
- package/dist/service-management/index.js +7 -0
- package/dist/services/GenericDataService.js +488 -0
- package/dist/shared/cloudflare/domain-discovery.js +562 -0
- package/dist/shared/cloudflare/domain-manager.js +912 -0
- package/dist/shared/cloudflare/index.js +8 -0
- package/dist/shared/cloudflare/ops.js +387 -0
- package/dist/shared/config/cache.js +1167 -0
- package/dist/shared/config/command-config-manager.js +174 -0
- package/dist/shared/config/customer-cli.js +258 -0
- package/dist/shared/config/index.js +9 -0
- package/dist/shared/config/manager.js +289 -0
- package/dist/shared/database/connection-manager.js +338 -0
- package/dist/shared/database/index.js +7 -0
- package/dist/shared/database/orchestrator.js +632 -0
- package/dist/shared/deployment/auditor.js +971 -0
- package/dist/shared/deployment/index.js +10 -0
- package/dist/shared/deployment/rollback-manager.js +523 -0
- package/dist/shared/deployment/validator.js +558 -0
- package/dist/shared/index.js +32 -0
- package/dist/shared/monitoring/health-checker.js +250 -0
- package/dist/shared/monitoring/index.js +8 -0
- package/dist/shared/monitoring/memory-manager.js +382 -0
- package/dist/shared/monitoring/production-monitor.js +390 -0
- package/dist/shared/production-tester/api-tester.js +80 -0
- package/dist/shared/production-tester/auth-tester.js +129 -0
- package/dist/shared/production-tester/core.js +217 -0
- package/dist/shared/production-tester/database-tester.js +105 -0
- package/dist/shared/production-tester/index.js +74 -0
- package/dist/shared/production-tester/load-tester.js +120 -0
- package/dist/shared/production-tester/performance-tester.js +105 -0
- package/dist/shared/security/api-token-manager.js +296 -0
- package/dist/shared/security/index.js +8 -0
- package/dist/shared/security/secret-generator.js +918 -0
- package/dist/shared/security/secure-token-manager.js +379 -0
- package/dist/shared/utils/error-recovery.js +240 -0
- package/dist/shared/utils/graceful-shutdown-manager.js +380 -0
- package/dist/shared/utils/index.js +9 -0
- package/dist/shared/utils/interactive-prompts.js +134 -0
- package/dist/shared/utils/rate-limiter.js +249 -0
- package/dist/utils/ErrorHandler.js +173 -0
- package/dist/utils/deployment/config-cache.js +1160 -0
- package/dist/utils/deployment/index.js +6 -0
- package/dist/utils/deployment/interactive-prompts.js +97 -0
- package/dist/utils/deployment/secret-generator.js +896 -0
- package/dist/utils/dirname-helper.js +35 -0
- package/dist/utils/domain-config.js +159 -0
- package/dist/utils/error-recovery.js +240 -0
- package/dist/utils/esm-helper.js +52 -0
- package/dist/utils/framework-config.js +481 -0
- package/dist/utils/graceful-shutdown-manager.js +379 -0
- package/dist/utils/health-checker.js +114 -0
- package/dist/utils/index.js +36 -0
- package/dist/utils/prompt-handler.js +98 -0
- package/dist/utils/usage-tracker.js +252 -0
- package/dist/utils/validation.js +112 -0
- package/dist/version/VersionDetector.js +723 -0
- package/dist/worker/index.js +4 -0
- package/dist/worker/integration.js +332 -0
- package/docs/FRAMEWORK-ARCHITECTURE-OVERVIEW.md +206 -0
- package/docs/INTEGRATION_GUIDE.md +2045 -0
- package/docs/README.md +82 -0
- package/docs/SECURITY.md +242 -0
- package/docs/deployment/deployment-guide.md +540 -0
- package/docs/overview.md +280 -0
- package/package.json +176 -0
- package/types/index.d.ts +575 -0
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
import { schemaManager } from '../schema/SchemaManager.js';
|
|
2
|
+
import { createDataService } from '../services/GenericDataService.js';
|
|
3
|
+
import { moduleManager } from '../modules/ModuleManager.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generic Route Handlers
|
|
7
|
+
* Provides reusable CRUD handlers for any configured data model
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export class GenericRouteHandler {
|
|
11
|
+
/**
|
|
12
|
+
* Create a new GenericRouteHandler instance
|
|
13
|
+
* @param {Object} d1Client - D1 database client
|
|
14
|
+
* @param {string} modelName - Name of the model
|
|
15
|
+
* @param {Object} options - Handler options
|
|
16
|
+
*/
|
|
17
|
+
constructor(d1Client, modelName, options = {}) {
|
|
18
|
+
this.d1Client = d1Client;
|
|
19
|
+
this.modelName = modelName;
|
|
20
|
+
this.dataService = createDataService(d1Client, modelName);
|
|
21
|
+
this.options = {
|
|
22
|
+
requireAuth: options.requireAuth !== false,
|
|
23
|
+
// Default to requiring auth
|
|
24
|
+
allowPublicRead: options.allowPublicRead || false,
|
|
25
|
+
customValidators: options.customValidators || {},
|
|
26
|
+
hooks: options.hooks || {},
|
|
27
|
+
...options
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Handle GET /:model - List all records
|
|
33
|
+
* @param {Request} request - HTTP request
|
|
34
|
+
* @returns {Promise<Response>} HTTP response
|
|
35
|
+
*/
|
|
36
|
+
async handleList(request) {
|
|
37
|
+
try {
|
|
38
|
+
// Check authentication if required
|
|
39
|
+
if (this.options.requireAuth && !this.options.allowPublicRead) {
|
|
40
|
+
const authResult = await this._checkAuth(request);
|
|
41
|
+
if (!authResult.authenticated) {
|
|
42
|
+
return new Response(JSON.stringify({
|
|
43
|
+
success: false,
|
|
44
|
+
error: 'Authentication required'
|
|
45
|
+
}), {
|
|
46
|
+
status: 401,
|
|
47
|
+
headers: {
|
|
48
|
+
'Content-Type': 'application/json'
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Parse query parameters
|
|
55
|
+
const url = new URL(request.url);
|
|
56
|
+
const criteria = this._parseQueryCriteria(url.searchParams);
|
|
57
|
+
const pagination = this._parsePagination(url.searchParams);
|
|
58
|
+
|
|
59
|
+
// Execute hooks
|
|
60
|
+
await moduleManager.executeHooks('before.list', {
|
|
61
|
+
model: this.modelName,
|
|
62
|
+
request,
|
|
63
|
+
criteria,
|
|
64
|
+
pagination
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Get data
|
|
68
|
+
let result;
|
|
69
|
+
if (pagination.limit) {
|
|
70
|
+
result = await this.dataService.paginate(criteria, pagination);
|
|
71
|
+
} else {
|
|
72
|
+
const data = await this.dataService.find(criteria);
|
|
73
|
+
result = {
|
|
74
|
+
data,
|
|
75
|
+
pagination: null
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Execute hooks
|
|
80
|
+
await moduleManager.executeHooks('after.list', {
|
|
81
|
+
model: this.modelName,
|
|
82
|
+
request,
|
|
83
|
+
result
|
|
84
|
+
});
|
|
85
|
+
return new Response(JSON.stringify({
|
|
86
|
+
success: true,
|
|
87
|
+
data: result.data,
|
|
88
|
+
pagination: result.pagination
|
|
89
|
+
}), {
|
|
90
|
+
status: 200,
|
|
91
|
+
headers: {
|
|
92
|
+
'Content-Type': 'application/json'
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(`Error in ${this.modelName} list:`, error);
|
|
97
|
+
return new Response(JSON.stringify({
|
|
98
|
+
success: false,
|
|
99
|
+
error: 'Failed to retrieve records',
|
|
100
|
+
message: error.message
|
|
101
|
+
}), {
|
|
102
|
+
status: 500,
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'application/json'
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Handle GET /:model/:id - Get single record
|
|
112
|
+
* @param {Request} request - HTTP request
|
|
113
|
+
* @param {string} id - Record ID
|
|
114
|
+
* @returns {Promise<Response>} HTTP response
|
|
115
|
+
*/
|
|
116
|
+
async handleGet(request, id) {
|
|
117
|
+
try {
|
|
118
|
+
// Check authentication if required
|
|
119
|
+
if (this.options.requireAuth && !this.options.allowPublicRead) {
|
|
120
|
+
const authResult = await this._checkAuth(request);
|
|
121
|
+
if (!authResult.authenticated) {
|
|
122
|
+
return new Response(JSON.stringify({
|
|
123
|
+
success: false,
|
|
124
|
+
error: 'Authentication required'
|
|
125
|
+
}), {
|
|
126
|
+
status: 401,
|
|
127
|
+
headers: {
|
|
128
|
+
'Content-Type': 'application/json'
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Execute hooks
|
|
135
|
+
await moduleManager.executeHooks('before.get', {
|
|
136
|
+
model: this.modelName,
|
|
137
|
+
request,
|
|
138
|
+
id
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Get data
|
|
142
|
+
const record = await this.dataService.findById(id);
|
|
143
|
+
if (!record) {
|
|
144
|
+
return new Response(JSON.stringify({
|
|
145
|
+
success: false,
|
|
146
|
+
error: 'Record not found'
|
|
147
|
+
}), {
|
|
148
|
+
status: 404,
|
|
149
|
+
headers: {
|
|
150
|
+
'Content-Type': 'application/json'
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Execute hooks
|
|
156
|
+
await moduleManager.executeHooks('after.get', {
|
|
157
|
+
model: this.modelName,
|
|
158
|
+
request,
|
|
159
|
+
record
|
|
160
|
+
});
|
|
161
|
+
return new Response(JSON.stringify({
|
|
162
|
+
success: true,
|
|
163
|
+
data: record
|
|
164
|
+
}), {
|
|
165
|
+
status: 200,
|
|
166
|
+
headers: {
|
|
167
|
+
'Content-Type': 'application/json'
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.error(`Error in ${this.modelName} get:`, error);
|
|
172
|
+
return new Response(JSON.stringify({
|
|
173
|
+
success: false,
|
|
174
|
+
error: 'Failed to retrieve record',
|
|
175
|
+
message: error.message
|
|
176
|
+
}), {
|
|
177
|
+
status: 500,
|
|
178
|
+
headers: {
|
|
179
|
+
'Content-Type': 'application/json'
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Handle POST /:model - Create new record
|
|
187
|
+
* @param {Request} request - HTTP request
|
|
188
|
+
* @returns {Promise<Response>} HTTP response
|
|
189
|
+
*/
|
|
190
|
+
async handleCreate(request) {
|
|
191
|
+
try {
|
|
192
|
+
// Check authentication if required
|
|
193
|
+
if (this.options.requireAuth) {
|
|
194
|
+
const authResult = await this._checkAuth(request);
|
|
195
|
+
if (!authResult.authenticated) {
|
|
196
|
+
return new Response(JSON.stringify({
|
|
197
|
+
success: false,
|
|
198
|
+
error: 'Authentication required'
|
|
199
|
+
}), {
|
|
200
|
+
status: 401,
|
|
201
|
+
headers: {
|
|
202
|
+
'Content-Type': 'application/json'
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Parse request body
|
|
209
|
+
const data = await request.json();
|
|
210
|
+
|
|
211
|
+
// Execute hooks
|
|
212
|
+
await moduleManager.executeHooks('before.create', {
|
|
213
|
+
model: this.modelName,
|
|
214
|
+
request,
|
|
215
|
+
data
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Custom validation
|
|
219
|
+
if (this.options.customValidators.create) {
|
|
220
|
+
const validation = await this.options.customValidators.create(data, request);
|
|
221
|
+
if (!validation.valid) {
|
|
222
|
+
return new Response(JSON.stringify({
|
|
223
|
+
success: false,
|
|
224
|
+
error: 'Validation failed',
|
|
225
|
+
details: validation.errors
|
|
226
|
+
}), {
|
|
227
|
+
status: 400,
|
|
228
|
+
headers: {
|
|
229
|
+
'Content-Type': 'application/json'
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Create record
|
|
236
|
+
const record = await this.dataService.create(data);
|
|
237
|
+
|
|
238
|
+
// Execute hooks
|
|
239
|
+
await moduleManager.executeHooks('after.create', {
|
|
240
|
+
model: this.modelName,
|
|
241
|
+
request,
|
|
242
|
+
record
|
|
243
|
+
});
|
|
244
|
+
return new Response(JSON.stringify({
|
|
245
|
+
success: true,
|
|
246
|
+
data: record
|
|
247
|
+
}), {
|
|
248
|
+
status: 201,
|
|
249
|
+
headers: {
|
|
250
|
+
'Content-Type': 'application/json'
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
} catch (error) {
|
|
254
|
+
console.error(`Error in ${this.modelName} create:`, error);
|
|
255
|
+
return new Response(JSON.stringify({
|
|
256
|
+
success: false,
|
|
257
|
+
error: 'Failed to create record',
|
|
258
|
+
message: error.message
|
|
259
|
+
}), {
|
|
260
|
+
status: 500,
|
|
261
|
+
headers: {
|
|
262
|
+
'Content-Type': 'application/json'
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Handle PATCH /:model/:id - Update record
|
|
270
|
+
* @param {Request} request - HTTP request
|
|
271
|
+
* @param {string} id - Record ID
|
|
272
|
+
* @returns {Promise<Response>} HTTP response
|
|
273
|
+
*/
|
|
274
|
+
async handleUpdate(request, id) {
|
|
275
|
+
try {
|
|
276
|
+
// Check authentication if required
|
|
277
|
+
if (this.options.requireAuth) {
|
|
278
|
+
const authResult = await this._checkAuth(request);
|
|
279
|
+
if (!authResult.authenticated) {
|
|
280
|
+
return new Response(JSON.stringify({
|
|
281
|
+
success: false,
|
|
282
|
+
error: 'Authentication required'
|
|
283
|
+
}), {
|
|
284
|
+
status: 401,
|
|
285
|
+
headers: {
|
|
286
|
+
'Content-Type': 'application/json'
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Parse request body
|
|
293
|
+
const updates = await request.json();
|
|
294
|
+
|
|
295
|
+
// Check if record exists
|
|
296
|
+
const existing = await this.dataService.findById(id);
|
|
297
|
+
if (!existing) {
|
|
298
|
+
return new Response(JSON.stringify({
|
|
299
|
+
success: false,
|
|
300
|
+
error: 'Record not found'
|
|
301
|
+
}), {
|
|
302
|
+
status: 404,
|
|
303
|
+
headers: {
|
|
304
|
+
'Content-Type': 'application/json'
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Execute hooks
|
|
310
|
+
await moduleManager.executeHooks('before.update', {
|
|
311
|
+
model: this.modelName,
|
|
312
|
+
request,
|
|
313
|
+
id,
|
|
314
|
+
updates,
|
|
315
|
+
existing
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Custom validation
|
|
319
|
+
if (this.options.customValidators.update) {
|
|
320
|
+
const validation = await this.options.customValidators.update(updates, request, existing);
|
|
321
|
+
if (!validation.valid) {
|
|
322
|
+
return new Response(JSON.stringify({
|
|
323
|
+
success: false,
|
|
324
|
+
error: 'Validation failed',
|
|
325
|
+
details: validation.errors
|
|
326
|
+
}), {
|
|
327
|
+
status: 400,
|
|
328
|
+
headers: {
|
|
329
|
+
'Content-Type': 'application/json'
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Update record
|
|
336
|
+
const record = await this.dataService.update(id, updates);
|
|
337
|
+
|
|
338
|
+
// Execute hooks
|
|
339
|
+
await moduleManager.executeHooks('after.update', {
|
|
340
|
+
model: this.modelName,
|
|
341
|
+
request,
|
|
342
|
+
record
|
|
343
|
+
});
|
|
344
|
+
return new Response(JSON.stringify({
|
|
345
|
+
success: true,
|
|
346
|
+
data: record
|
|
347
|
+
}), {
|
|
348
|
+
status: 200,
|
|
349
|
+
headers: {
|
|
350
|
+
'Content-Type': 'application/json'
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
} catch (error) {
|
|
354
|
+
console.error(`Error in ${this.modelName} update:`, error);
|
|
355
|
+
return new Response(JSON.stringify({
|
|
356
|
+
success: false,
|
|
357
|
+
error: 'Failed to update record',
|
|
358
|
+
message: error.message
|
|
359
|
+
}), {
|
|
360
|
+
status: 500,
|
|
361
|
+
headers: {
|
|
362
|
+
'Content-Type': 'application/json'
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Handle DELETE /:model/:id - Delete record
|
|
370
|
+
* @param {Request} request - HTTP request
|
|
371
|
+
* @param {string} id - Record ID
|
|
372
|
+
* @returns {Promise<Response>} HTTP response
|
|
373
|
+
*/
|
|
374
|
+
async handleDelete(request, id) {
|
|
375
|
+
try {
|
|
376
|
+
// Check authentication if required
|
|
377
|
+
if (this.options.requireAuth) {
|
|
378
|
+
const authResult = await this._checkAuth(request);
|
|
379
|
+
if (!authResult.authenticated) {
|
|
380
|
+
return new Response(JSON.stringify({
|
|
381
|
+
success: false,
|
|
382
|
+
error: 'Authentication required'
|
|
383
|
+
}), {
|
|
384
|
+
status: 401,
|
|
385
|
+
headers: {
|
|
386
|
+
'Content-Type': 'application/json'
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Check if record exists
|
|
393
|
+
const existing = await this.dataService.findById(id);
|
|
394
|
+
if (!existing) {
|
|
395
|
+
return new Response(JSON.stringify({
|
|
396
|
+
success: false,
|
|
397
|
+
error: 'Record not found'
|
|
398
|
+
}), {
|
|
399
|
+
status: 404,
|
|
400
|
+
headers: {
|
|
401
|
+
'Content-Type': 'application/json'
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Execute hooks
|
|
407
|
+
await moduleManager.executeHooks('before.delete', {
|
|
408
|
+
model: this.modelName,
|
|
409
|
+
request,
|
|
410
|
+
id,
|
|
411
|
+
existing
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Delete record
|
|
415
|
+
const success = await this.dataService.delete(id);
|
|
416
|
+
if (success) {
|
|
417
|
+
// Execute hooks
|
|
418
|
+
await moduleManager.executeHooks('after.delete', {
|
|
419
|
+
model: this.modelName,
|
|
420
|
+
request,
|
|
421
|
+
id
|
|
422
|
+
});
|
|
423
|
+
return new Response(JSON.stringify({
|
|
424
|
+
success: true,
|
|
425
|
+
data: {
|
|
426
|
+
id
|
|
427
|
+
}
|
|
428
|
+
}), {
|
|
429
|
+
status: 200,
|
|
430
|
+
headers: {
|
|
431
|
+
'Content-Type': 'application/json'
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
} else {
|
|
435
|
+
throw new Error('Delete operation failed');
|
|
436
|
+
}
|
|
437
|
+
} catch (error) {
|
|
438
|
+
console.error(`Error in ${this.modelName} delete:`, error);
|
|
439
|
+
return new Response(JSON.stringify({
|
|
440
|
+
success: false,
|
|
441
|
+
error: 'Failed to delete record',
|
|
442
|
+
message: error.message
|
|
443
|
+
}), {
|
|
444
|
+
status: 500,
|
|
445
|
+
headers: {
|
|
446
|
+
'Content-Type': 'application/json'
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Check authentication (placeholder - integrate with your auth system)
|
|
454
|
+
* @param {Request} request - HTTP request
|
|
455
|
+
* @returns {Promise<Object>} Auth result
|
|
456
|
+
* @private
|
|
457
|
+
*/
|
|
458
|
+
async _checkAuth(request) {
|
|
459
|
+
// This should integrate with your existing auth middleware
|
|
460
|
+
// For now, return authenticated if there's an authorization header
|
|
461
|
+
const authHeader = request.headers.get('authorization');
|
|
462
|
+
return {
|
|
463
|
+
authenticated: !!authHeader,
|
|
464
|
+
user: authHeader ? {
|
|
465
|
+
id: 'user-from-token'
|
|
466
|
+
} : null
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Parse query parameters into search criteria
|
|
472
|
+
* @param {URLSearchParams} params - Query parameters
|
|
473
|
+
* @returns {Object} Search criteria
|
|
474
|
+
* @private
|
|
475
|
+
*/
|
|
476
|
+
_parseQueryCriteria(params) {
|
|
477
|
+
const criteria = {};
|
|
478
|
+
for (const [key, value] of params.entries()) {
|
|
479
|
+
// Skip pagination params
|
|
480
|
+
if (['page', 'limit', 'offset'].includes(key)) continue;
|
|
481
|
+
|
|
482
|
+
// Handle different query types
|
|
483
|
+
if (key.endsWith('_gt')) {
|
|
484
|
+
const field = key.slice(0, -3);
|
|
485
|
+
criteria[field] = {
|
|
486
|
+
$gt: value
|
|
487
|
+
};
|
|
488
|
+
} else if (key.endsWith('_lt')) {
|
|
489
|
+
const field = key.slice(0, -3);
|
|
490
|
+
criteria[field] = {
|
|
491
|
+
$lt: value
|
|
492
|
+
};
|
|
493
|
+
} else if (key.endsWith('_like')) {
|
|
494
|
+
const field = key.slice(0, -5);
|
|
495
|
+
criteria[field] = {
|
|
496
|
+
$like: value
|
|
497
|
+
};
|
|
498
|
+
} else {
|
|
499
|
+
criteria[key] = value;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return criteria;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Parse pagination parameters
|
|
507
|
+
* @param {URLSearchParams} params - Query parameters
|
|
508
|
+
* @returns {Object} Pagination options
|
|
509
|
+
* @private
|
|
510
|
+
*/
|
|
511
|
+
_parsePagination(params) {
|
|
512
|
+
return {
|
|
513
|
+
page: parseInt(params.get('page')) || 1,
|
|
514
|
+
limit: parseInt(params.get('limit')) || null,
|
|
515
|
+
offset: parseInt(params.get('offset')) || null
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Factory function to create route handlers for all models
|
|
522
|
+
* @param {Object} d1Client - D1 database client
|
|
523
|
+
* @param {Object} options - Global options
|
|
524
|
+
* @returns {Object} Map of model names to handler instances
|
|
525
|
+
*/
|
|
526
|
+
export function createRouteHandlers(d1Client, options = {}) {
|
|
527
|
+
const handlers = {};
|
|
528
|
+
for (const [modelName] of schemaManager.getAllModels()) {
|
|
529
|
+
handlers[modelName] = new GenericRouteHandler(d1Client, modelName, options);
|
|
530
|
+
}
|
|
531
|
+
return handlers;
|
|
532
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Clodo Framework - Main Entry Point
|
|
2
|
+
// Reusable components for Clodo-style software architecture
|
|
3
|
+
|
|
4
|
+
export * from './config/index.js';
|
|
5
|
+
export * from './worker/index.js';
|
|
6
|
+
export * from './utils/index.js';
|
|
7
|
+
export * from './orchestration/index.js';
|
|
8
|
+
|
|
9
|
+
// Core framework classes and utilities
|
|
10
|
+
export { FeatureFlagManager } from './config/features.js';
|
|
11
|
+
export { createDomainConfigSchema, validateDomainConfig, createDefaultDomainConfig } from './utils/domain-config.js';
|
|
12
|
+
export { initializeService, createFeatureGuard } from './worker/integration.js';
|
|
13
|
+
|
|
14
|
+
// Core data and schema components
|
|
15
|
+
export * from './services/GenericDataService.js';
|
|
16
|
+
export * from './schema/SchemaManager.js';
|
|
17
|
+
export * from './modules/ModuleManager.js';
|
|
18
|
+
export * from './routing/EnhancedRouter.js';
|
|
19
|
+
export * from './handlers/GenericRouteHandler.js';
|
|
20
|
+
|
|
21
|
+
// Deployment components (build-time only)
|
|
22
|
+
export { WranglerDeployer } from './deployment/wrangler-deployer.js';
|
|
23
|
+
|
|
24
|
+
// Security components
|
|
25
|
+
export * from './security/index.js';
|
|
26
|
+
|
|
27
|
+
// Framework version info
|
|
28
|
+
export const FRAMEWORK_VERSION = '1.0.0';
|
|
29
|
+
export const FRAMEWORK_NAME = 'Clodo Framework';
|
|
30
|
+
|
|
31
|
+
// Helper for framework initialization
|
|
32
|
+
export const initializeFramework = (options = {}) => {
|
|
33
|
+
console.log(`${FRAMEWORK_NAME} v${FRAMEWORK_VERSION} initialized`);
|
|
34
|
+
return {
|
|
35
|
+
version: FRAMEWORK_VERSION,
|
|
36
|
+
name: FRAMEWORK_NAME,
|
|
37
|
+
options
|
|
38
|
+
};
|
|
39
|
+
};
|