@tamyla/clodo-framework 3.1.21 → 3.1.22

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.
Files changed (169) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +53 -0
  3. package/dist/bin/clodo-service.js +47 -15
  4. package/dist/bin/commands/deploy.js +115 -83
  5. package/dist/bin/commands/helpers/deployment-ui.js +138 -0
  6. package/dist/bin/commands/helpers/deployment-verification.js +251 -0
  7. package/dist/bin/commands/helpers/error-recovery.js +80 -0
  8. package/dist/bin/commands/helpers/resource-detection.js +113 -0
  9. package/dist/bin/commands/validate.js +1 -1
  10. package/dist/bin/security/security-cli.js +1 -1
  11. package/dist/bin/shared/cache/configuration-cache.js +82 -0
  12. package/dist/bin/shared/cloudflare/domain-manager.js +1 -1
  13. package/dist/bin/shared/cloudflare/index.js +1 -1
  14. package/dist/bin/shared/cloudflare/ops.js +6 -4
  15. package/dist/bin/shared/config/ConfigurationManager.js +23 -1
  16. package/dist/bin/shared/config/command-config-manager.js +19 -3
  17. package/dist/bin/shared/config/index.js +1 -1
  18. package/dist/bin/shared/deployment/credential-collector.js +30 -7
  19. package/dist/bin/shared/deployment/index.js +2 -2
  20. package/dist/bin/shared/deployment/rollback-manager.js +4 -520
  21. package/dist/bin/shared/deployment/utilities/d1-error-recovery.js +177 -0
  22. package/dist/bin/shared/deployment/validator.js +40 -10
  23. package/dist/bin/shared/deployment/workflows/deployment-summary.js +214 -0
  24. package/dist/bin/shared/deployment/workflows/interactive-confirmation.js +188 -0
  25. package/dist/bin/shared/deployment/workflows/interactive-database-workflow.js +234 -0
  26. package/dist/bin/shared/deployment/workflows/interactive-domain-info-gatherer.js +240 -0
  27. package/dist/bin/shared/deployment/workflows/interactive-secret-workflow.js +228 -0
  28. package/dist/bin/shared/deployment/workflows/interactive-testing-workflow.js +235 -0
  29. package/dist/bin/shared/deployment/workflows/interactive-validation.js +218 -0
  30. package/dist/bin/shared/error-handling/error-classifier.js +46 -0
  31. package/dist/bin/shared/monitoring/health-checker.js +129 -1
  32. package/dist/bin/shared/monitoring/memory-manager.js +17 -6
  33. package/dist/bin/shared/routing/domain-router.js +1 -1
  34. package/dist/bin/shared/utils/deployment-validator.js +97 -0
  35. package/dist/bin/shared/utils/formatters.js +10 -0
  36. package/dist/bin/shared/utils/index.js +13 -1
  37. package/dist/bin/shared/utils/interactive-prompts.js +34 -18
  38. package/dist/bin/shared/utils/progress-manager.js +2 -2
  39. package/dist/bin/shared/utils/progress-spinner.js +53 -0
  40. package/dist/bin/shared/utils/sensitive-redactor.js +91 -0
  41. package/dist/bin/shared/validation/ValidationRegistry.js +1 -1
  42. package/dist/security/index.js +1 -1
  43. package/dist/security/patterns/insecure-patterns.js +1 -1
  44. package/dist/utils/constants.js +102 -0
  45. package/dist/utils/deployment/wrangler-config-manager.js +215 -48
  46. package/dist/utils/framework-config.js +2 -2
  47. package/dist/utils/interactive-prompts.js +10 -59
  48. package/package.json +16 -8
  49. package/dist/bin/clodo-service-old.js +0 -868
  50. package/dist/bin/clodo-service-test.js +0 -10
  51. package/dist/bin/commands/assess.js +0 -91
  52. package/dist/bin/commands/create.js +0 -77
  53. package/dist/bin/commands/diagnose.js +0 -83
  54. package/dist/bin/commands/helpers.js +0 -138
  55. package/dist/bin/commands/update.js +0 -75
  56. package/dist/bin/database/deployment-db-manager.js +0 -423
  57. package/dist/bin/database/enterprise-db-manager.js +0 -457
  58. package/dist/bin/database/wrangler-d1-manager.js +0 -685
  59. package/dist/bin/deployment/enterprise-deploy.js +0 -877
  60. package/dist/bin/deployment/master-deploy.js +0 -1376
  61. package/dist/bin/deployment/modular-enterprise-deploy.js +0 -466
  62. package/dist/bin/deployment/modules/DeploymentConfiguration.js +0 -395
  63. package/dist/bin/deployment/modules/DeploymentOrchestrator.js +0 -492
  64. package/dist/bin/deployment/modules/EnvironmentManager.js +0 -517
  65. package/dist/bin/deployment/modules/MonitoringIntegration.js +0 -560
  66. package/dist/bin/deployment/modules/ValidationManager.js +0 -342
  67. package/dist/bin/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
  68. package/dist/bin/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
  69. package/dist/bin/deployment/orchestration/PortfolioOrchestrator.js +0 -273
  70. package/dist/bin/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
  71. package/dist/bin/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
  72. package/dist/bin/deployment/test-interactive-utils.js +0 -66
  73. package/dist/bin/portfolio/portfolio-manager.js +0 -487
  74. package/dist/bin/service-management/create-service.js +0 -122
  75. package/dist/bin/service-management/init-service.js +0 -79
  76. package/dist/config/customers.js +0 -623
  77. package/dist/config/domains.js +0 -186
  78. package/dist/config/index.js +0 -6
  79. package/dist/database/database-orchestrator.js +0 -795
  80. package/dist/database/index.js +0 -4
  81. package/dist/deployment/index.js +0 -11
  82. package/dist/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
  83. package/dist/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
  84. package/dist/deployment/orchestration/PortfolioOrchestrator.js +0 -273
  85. package/dist/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
  86. package/dist/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
  87. package/dist/deployment/orchestration/index.js +0 -17
  88. package/dist/deployment/rollback-manager.js +0 -36
  89. package/dist/deployment/wrangler-deployer.js +0 -640
  90. package/dist/handlers/GenericRouteHandler.js +0 -532
  91. package/dist/migration/MigrationAdapters.js +0 -562
  92. package/dist/modules/ModuleManager.js +0 -668
  93. package/dist/modules/security.js +0 -96
  94. package/dist/orchestration/cross-domain-coordinator.js +0 -1083
  95. package/dist/orchestration/index.js +0 -5
  96. package/dist/orchestration/modules/DeploymentCoordinator.js +0 -368
  97. package/dist/orchestration/modules/DomainResolver.js +0 -198
  98. package/dist/orchestration/modules/StateManager.js +0 -332
  99. package/dist/orchestration/multi-domain-orchestrator.js +0 -724
  100. package/dist/routing/EnhancedRouter.js +0 -158
  101. package/dist/schema/SchemaManager.js +0 -778
  102. package/dist/service-management/ConfirmationEngine.js +0 -412
  103. package/dist/service-management/ErrorTracker.js +0 -299
  104. package/dist/service-management/GenerationEngine.js +0 -447
  105. package/dist/service-management/InputCollector.js +0 -619
  106. package/dist/service-management/ServiceCreator.js +0 -265
  107. package/dist/service-management/ServiceInitializer.js +0 -453
  108. package/dist/service-management/ServiceOrchestrator.js +0 -633
  109. package/dist/service-management/generators/BaseGenerator.js +0 -233
  110. package/dist/service-management/generators/GeneratorRegistry.js +0 -254
  111. package/dist/service-management/generators/cicd/CiWorkflowGenerator.js +0 -87
  112. package/dist/service-management/generators/cicd/DeployWorkflowGenerator.js +0 -106
  113. package/dist/service-management/generators/code/ServiceHandlersGenerator.js +0 -235
  114. package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +0 -116
  115. package/dist/service-management/generators/code/ServiceUtilsGenerator.js +0 -246
  116. package/dist/service-management/generators/code/WorkerIndexGenerator.js +0 -143
  117. package/dist/service-management/generators/config/DevelopmentEnvGenerator.js +0 -101
  118. package/dist/service-management/generators/config/DomainsConfigGenerator.js +0 -175
  119. package/dist/service-management/generators/config/EnvExampleGenerator.js +0 -178
  120. package/dist/service-management/generators/config/ProductionEnvGenerator.js +0 -97
  121. package/dist/service-management/generators/config/StagingEnvGenerator.js +0 -97
  122. package/dist/service-management/generators/config/WranglerTomlGenerator.js +0 -238
  123. package/dist/service-management/generators/core/PackageJsonGenerator.js +0 -243
  124. package/dist/service-management/generators/core/SiteConfigGenerator.js +0 -115
  125. package/dist/service-management/generators/documentation/ApiDocsGenerator.js +0 -331
  126. package/dist/service-management/generators/documentation/ConfigurationDocsGenerator.js +0 -294
  127. package/dist/service-management/generators/documentation/DeploymentDocsGenerator.js +0 -244
  128. package/dist/service-management/generators/documentation/ReadmeGenerator.js +0 -196
  129. package/dist/service-management/generators/schemas/ServiceSchemaGenerator.js +0 -190
  130. package/dist/service-management/generators/scripts/DeployScriptGenerator.js +0 -123
  131. package/dist/service-management/generators/scripts/HealthCheckScriptGenerator.js +0 -101
  132. package/dist/service-management/generators/scripts/SetupScriptGenerator.js +0 -88
  133. package/dist/service-management/generators/service-types/StaticSiteGenerator.js +0 -342
  134. package/dist/service-management/generators/testing/EslintConfigGenerator.js +0 -85
  135. package/dist/service-management/generators/testing/IntegrationTestsGenerator.js +0 -237
  136. package/dist/service-management/generators/testing/JestConfigGenerator.js +0 -72
  137. package/dist/service-management/generators/testing/UnitTestsGenerator.js +0 -277
  138. package/dist/service-management/generators/tooling/DockerComposeGenerator.js +0 -71
  139. package/dist/service-management/generators/tooling/GitignoreGenerator.js +0 -143
  140. package/dist/service-management/generators/utils/FileWriter.js +0 -179
  141. package/dist/service-management/generators/utils/PathResolver.js +0 -157
  142. package/dist/service-management/generators/utils/ServiceManifestGenerator.js +0 -111
  143. package/dist/service-management/generators/utils/TemplateEngine.js +0 -185
  144. package/dist/service-management/generators/utils/index.js +0 -18
  145. package/dist/service-management/handlers/ConfirmationHandler.js +0 -71
  146. package/dist/service-management/handlers/GenerationHandler.js +0 -80
  147. package/dist/service-management/handlers/InputHandler.js +0 -59
  148. package/dist/service-management/handlers/ValidationHandler.js +0 -203
  149. package/dist/service-management/index.js +0 -14
  150. package/dist/service-management/routing/DomainRouteMapper.js +0 -311
  151. package/dist/service-management/routing/RouteGenerator.js +0 -266
  152. package/dist/service-management/routing/WranglerRoutesBuilder.js +0 -273
  153. package/dist/service-management/routing/index.js +0 -14
  154. package/dist/service-management/services/DirectoryStructureService.js +0 -56
  155. package/dist/service-management/services/GenerationCoordinator.js +0 -208
  156. package/dist/service-management/services/GeneratorRegistry.js +0 -174
  157. package/dist/services/GenericDataService.js +0 -501
  158. package/dist/ui-structures/concepts/second-order-acquisition-strategy.md +0 -286
  159. package/dist/ui-structures/concepts/service-lifecycle-management.md +0 -150
  160. package/dist/ui-structures/concepts/service-manifest-guide.md +0 -309
  161. package/dist/ui-structures/concepts/three-tier-categorization-strategy.md +0 -231
  162. package/dist/ui-structures/creation/automated-generation-ui.json +0 -246
  163. package/dist/ui-structures/creation/core-inputs-ui.json +0 -217
  164. package/dist/ui-structures/creation/smart-confirmable-ui.json +0 -451
  165. package/dist/ui-structures/reference/absolutely-required-inputs.json +0 -315
  166. package/dist/ui-structures/reference/service-manifest-template.json +0 -342
  167. package/dist/version/VersionDetector.js +0 -723
  168. package/dist/worker/index.js +0 -4
  169. package/dist/worker/integration.js +0 -351
@@ -1,778 +0,0 @@
1
- /**
2
- * Configurable Schema System
3
- * Allows defining data models externally for maximum reusability
4
- */
5
-
6
- export class SchemaManager {
7
- constructor() {
8
- this.schemas = new Map();
9
- this.relationships = new Map();
10
-
11
- // Schema caching for performance
12
- this.schemaCache = new Map();
13
- this.sqlCache = new Map();
14
- this.cacheEnabled = true;
15
-
16
- // Validation cache
17
- this.validationCache = new Map();
18
- this.cacheStats = {
19
- hits: 0,
20
- misses: 0,
21
- validationHits: 0,
22
- validationMisses: 0
23
- };
24
- }
25
-
26
- /**
27
- * Register a data model schema
28
- * @param {string} modelName - Name of the model
29
- * @param {Object} schema - Schema definition
30
- */
31
- registerModel(modelName, schema) {
32
- // Clear caches when schema is updated
33
- this.clearSchemaCache(modelName);
34
- const processedSchema = {
35
- name: modelName,
36
- tableName: schema.tableName || modelName.toLowerCase(),
37
- columns: schema.columns || {},
38
- indexes: schema.indexes || [],
39
- relationships: schema.relationships || {},
40
- hooks: schema.hooks || {},
41
- validation: schema.validation || {},
42
- ...schema
43
- };
44
- this.schemas.set(modelName, processedSchema);
45
- this.schemaCache.set(modelName, processedSchema);
46
-
47
- // Register relationships
48
- if (schema.relationships) {
49
- Object.entries(schema.relationships).forEach(([relName, relConfig]) => {
50
- this.relationships.set(`${modelName}.${relName}`, {
51
- from: modelName,
52
- to: relConfig.model,
53
- type: relConfig.type || 'belongsTo',
54
- foreignKey: relConfig.foreignKey,
55
- localKey: relConfig.localKey || 'id'
56
- });
57
- });
58
- }
59
- console.log(`✅ Registered model: ${modelName}`);
60
- }
61
-
62
- /**
63
- * Get a registered model schema
64
- * @param {string} modelName - Name of the model
65
- * @returns {Object} Schema definition
66
- */
67
- getModel(modelName) {
68
- // Check cache first
69
- if (this.cacheEnabled && this.schemaCache.has(modelName)) {
70
- return this.schemaCache.get(modelName);
71
- }
72
-
73
- // Get from main storage
74
- const schema = this.schemas.get(modelName);
75
-
76
- // Cache if found
77
- if (schema && this.cacheEnabled) {
78
- this.schemaCache.set(modelName, schema);
79
- }
80
- return schema;
81
- }
82
-
83
- /**
84
- * Get all registered models
85
- * @returns {Map} All schemas
86
- */
87
- getAllModels() {
88
- return this.schemas;
89
- }
90
-
91
- /**
92
- * Check if a model exists
93
- * @param {string} modelName - Name of the model
94
- * @returns {boolean}
95
- */
96
- hasModel(modelName) {
97
- return this.schemas.has(modelName);
98
- }
99
-
100
- /**
101
- * Get relationship definition
102
- * @param {string} modelName - Source model
103
- * @param {string} relationshipName - Relationship name
104
- * @returns {Object} Relationship definition
105
- */
106
- getRelationship(modelName, relationshipName) {
107
- return this.relationships.get(`${modelName}.${relationshipName}`);
108
- }
109
-
110
- /**
111
- * Generate SQL for model operations
112
- * @param {string} modelName - Model name
113
- * @param {string} operation - Operation type (create, read, update, delete)
114
- * @param {Object} params - Operation parameters
115
- * @returns {Object} SQL query object with sql and params properties
116
- */
117
- generateSQL(modelName, operation, params = {}) {
118
- // Generate cache key for this operation
119
- const cacheKey = this.generateCacheKey(modelName, operation, params);
120
-
121
- // Check SQL cache first
122
- if (this.cacheEnabled && this.sqlCache.has(cacheKey)) {
123
- this.cacheStats.hits++;
124
- return this.sqlCache.get(cacheKey);
125
- }
126
- this.cacheStats.misses++;
127
- const schema = this.getModel(modelName);
128
- if (!schema) {
129
- throw new Error(`Model '${modelName}' not found`);
130
- }
131
- const tableName = schema.tableName;
132
- const columns = Object.keys(schema.columns);
133
- let result;
134
- let parameterMapping = [];
135
- switch (operation) {
136
- case 'create':
137
- {
138
- const insertColumns = columns.filter(col => params[col] !== undefined);
139
- const placeholders = insertColumns.map(() => '?');
140
- result = {
141
- sql: `INSERT INTO ${tableName} (${insertColumns.join(', ')}) VALUES (${placeholders.join(', ')})`,
142
- params: insertColumns.map(col => params[col])
143
- };
144
- parameterMapping = insertColumns;
145
- break;
146
- }
147
- case 'read':
148
- {
149
- let whereClause = '';
150
- let whereParams = [];
151
- if (params.id) {
152
- whereClause = 'WHERE id = ?';
153
- whereParams = [params.id];
154
- parameterMapping = ['id'];
155
- } else if (params.where) {
156
- const conditions = [];
157
- Object.entries(params.where).forEach(([key, value]) => {
158
- conditions.push(`${key} = ?`);
159
- whereParams.push(value);
160
- parameterMapping.push(`where.${key}`);
161
- });
162
- whereClause = `WHERE ${conditions.join(' AND ')}`;
163
- }
164
- const selectFields = params.fields ? params.fields.join(', ') : columns.join(', ');
165
- result = {
166
- sql: `SELECT ${selectFields} FROM ${tableName} ${whereClause}`,
167
- params: whereParams
168
- };
169
- break;
170
- }
171
- case 'update':
172
- {
173
- const updateColumns = columns.filter(col => params[col] !== undefined && col !== 'id');
174
- const setClause = updateColumns.map(col => `${col} = ?`).join(', ');
175
- const updateParams = updateColumns.map(col => params[col]);
176
- result = {
177
- sql: `UPDATE ${tableName} SET ${setClause} WHERE id = ?`,
178
- params: [...updateParams, params.id]
179
- };
180
- parameterMapping = [...updateColumns, 'id'];
181
- break;
182
- }
183
- case 'delete':
184
- {
185
- result = {
186
- sql: `DELETE FROM ${tableName} WHERE id = ?`,
187
- params: [params.id]
188
- };
189
- parameterMapping = ['id'];
190
- break;
191
- }
192
- default:
193
- throw new Error(`Unknown operation: ${operation}`);
194
- }
195
-
196
- // Cache the SQL template for future use
197
- if (this.cacheEnabled) {
198
- this.sqlCache.set(cacheKey, {
199
- sql: result.sql,
200
- params: result.params,
201
- parameterMapping
202
- });
203
- }
204
- return result;
205
- }
206
-
207
- /**
208
- * Clear schema cache for specific model or all models
209
- * @param {string} modelName - Optional: specific model to clear
210
- */
211
- clearSchemaCache(modelName = null) {
212
- if (modelName) {
213
- this.schemaCache.delete(modelName);
214
- // Clear related SQL cache entries
215
- for (const [key] of this.sqlCache) {
216
- if (key.startsWith(`${modelName}:`)) {
217
- this.sqlCache.delete(key);
218
- }
219
- }
220
- } else {
221
- this.schemaCache.clear();
222
- this.sqlCache.clear();
223
- }
224
- }
225
-
226
- /**
227
- * Generate cache key for SQL queries
228
- * @param {string} modelName - Model name
229
- * @param {string} operation - Operation type
230
- * @param {Object} params - Query parameters
231
- * @returns {string} Cache key
232
- */
233
- generateCacheKey(modelName, operation, params = {}) {
234
- return `${modelName}:${operation}:${JSON.stringify(params)}`;
235
- }
236
-
237
- /**
238
- * Enhanced validation with comprehensive error reporting
239
- * @param {string} modelName - Model name
240
- * @param {Object} data - Data to validate
241
- * @returns {Object} Detailed validation result
242
- */
243
- validateData(modelName, data) {
244
- const schema = this.getModel(modelName);
245
- if (!schema) {
246
- return {
247
- valid: false,
248
- errors: [{
249
- field: '_model',
250
- message: `Model '${modelName}' not found`,
251
- code: 'MODEL_NOT_FOUND'
252
- }],
253
- fieldErrors: {},
254
- data: null
255
- };
256
- }
257
- const errors = [];
258
- const validatedData = {
259
- ...data
260
- };
261
- const fieldErrors = {};
262
-
263
- // Check required fields
264
- if (schema.validation?.required) {
265
- schema.validation.required.forEach(field => {
266
- if (data[field] === undefined || data[field] === null || data[field] === '') {
267
- const error = {
268
- field,
269
- message: `Field '${field}' is required`,
270
- code: 'REQUIRED_FIELD_MISSING',
271
- value: data[field]
272
- };
273
- errors.push(error);
274
- fieldErrors[field] = fieldErrors[field] || [];
275
- fieldErrors[field].push(error);
276
- }
277
- });
278
- }
279
-
280
- // Validate each field against schema
281
- Object.entries(schema.columns).forEach(([fieldName, fieldConfig]) => {
282
- if (data[fieldName] !== undefined && data[fieldName] !== null) {
283
- const value = data[fieldName];
284
- const validationResult = this._validateField(fieldName, value, fieldConfig, schema);
285
- if (!validationResult.valid) {
286
- validationResult.errors.forEach(error => {
287
- errors.push(error);
288
- fieldErrors[fieldName] = fieldErrors[fieldName] || [];
289
- fieldErrors[fieldName].push(error);
290
- });
291
- }
292
-
293
- // Apply transformations
294
- if (validationResult.transformed !== undefined) {
295
- validatedData[fieldName] = validationResult.transformed;
296
- }
297
- }
298
- });
299
-
300
- // Custom validation rules
301
- if (schema.validation?.custom) {
302
- Object.entries(schema.validation.custom).forEach(([ruleName, ruleConfig]) => {
303
- const result = this._validateCustomRule(ruleName, ruleConfig, data, validatedData);
304
- if (!result.valid) {
305
- result.errors.forEach(error => {
306
- errors.push(error);
307
- const field = error.field || '_custom';
308
- fieldErrors[field] = fieldErrors[field] || [];
309
- fieldErrors[field].push(error);
310
- });
311
- }
312
- });
313
- }
314
- return {
315
- valid: errors.length === 0,
316
- errors,
317
- fieldErrors,
318
- data: validatedData
319
- };
320
- }
321
-
322
- /**
323
- * Validate individual field
324
- * @param {string} fieldName - Field name
325
- * @param {any} value - Field value
326
- * @param {Object} fieldConfig - Field configuration
327
- * @returns {Object} Field validation result
328
- * @private
329
- */
330
- _validateField(fieldName, value, fieldConfig) {
331
- const errors = [];
332
- let transformedValue = value;
333
-
334
- // Type validation
335
- if (fieldConfig.type) {
336
- const typeValidation = this._validateFieldType(fieldName, value, fieldConfig.type);
337
- if (!typeValidation.valid) {
338
- errors.push(...typeValidation.errors);
339
- } else if (typeValidation.transformed !== undefined) {
340
- transformedValue = typeValidation.transformed;
341
- }
342
- }
343
-
344
- // Length validation
345
- if (fieldConfig.minLength || fieldConfig.maxLength) {
346
- const lengthValidation = this._validateFieldLength(fieldName, transformedValue, fieldConfig);
347
- if (!lengthValidation.valid) {
348
- errors.push(...lengthValidation.errors);
349
- }
350
- }
351
-
352
- // Pattern validation
353
- if (fieldConfig.pattern) {
354
- const patternValidation = this._validateFieldPattern(fieldName, transformedValue, fieldConfig.pattern);
355
- if (!patternValidation.valid) {
356
- errors.push(...patternValidation.errors);
357
- }
358
- }
359
- return {
360
- valid: errors.length === 0,
361
- errors,
362
- transformed: transformedValue !== value ? transformedValue : undefined
363
- };
364
- }
365
-
366
- /**
367
- * Validate field type
368
- * @param {string} fieldName - Field name
369
- * @param {any} value - Field value
370
- * @param {string} expectedType - Expected type
371
- * @returns {Object} Type validation result
372
- * @private
373
- */
374
- _validateFieldType(fieldName, value, expectedType) {
375
- const errors = [];
376
- let transformedValue = value;
377
- switch (expectedType) {
378
- case 'text':
379
- if (typeof value !== 'string') {
380
- transformedValue = String(value);
381
- }
382
- // Trim whitespace for text fields
383
- if (typeof transformedValue === 'string') {
384
- transformedValue = transformedValue.trim();
385
- }
386
- break;
387
- case 'integer':
388
- if (!Number.isInteger(Number(value))) {
389
- errors.push({
390
- field: fieldName,
391
- message: `Field '${fieldName}' must be an integer`,
392
- code: 'INVALID_TYPE',
393
- value
394
- });
395
- } else {
396
- transformedValue = parseInt(value, 10);
397
- }
398
- break;
399
- case 'real':
400
- if (isNaN(Number(value))) {
401
- errors.push({
402
- field: fieldName,
403
- message: `Field '${fieldName}' must be a number`,
404
- code: 'INVALID_TYPE',
405
- value
406
- });
407
- } else {
408
- transformedValue = parseFloat(value);
409
- }
410
- break;
411
- case 'blob':
412
- // No specific validation for blob type
413
- break;
414
- default:
415
- console.warn(`Unknown field type: ${expectedType} for field ${fieldName}`);
416
- }
417
- return {
418
- valid: errors.length === 0,
419
- errors,
420
- transformed: transformedValue !== value ? transformedValue : undefined
421
- };
422
- }
423
-
424
- /**
425
- * Validate field length constraints
426
- * @param {string} fieldName - Field name
427
- * @param {any} value - Field value
428
- * @param {Object} fieldConfig - Field configuration
429
- * @returns {Object} Length validation result
430
- * @private
431
- */
432
- _validateFieldLength(fieldName, value, fieldConfig) {
433
- const errors = [];
434
- const stringValue = String(value);
435
- if (fieldConfig.minLength && stringValue.length < fieldConfig.minLength) {
436
- errors.push({
437
- field: fieldName,
438
- message: `Field '${fieldName}' must be at least ${fieldConfig.minLength} characters`,
439
- code: 'MIN_LENGTH_VIOLATION',
440
- value
441
- });
442
- }
443
- if (fieldConfig.maxLength && stringValue.length > fieldConfig.maxLength) {
444
- errors.push({
445
- field: fieldName,
446
- message: `Field '${fieldName}' cannot exceed ${fieldConfig.maxLength} characters`,
447
- code: 'MAX_LENGTH_VIOLATION',
448
- value
449
- });
450
- }
451
- return {
452
- valid: errors.length === 0,
453
- errors
454
- };
455
- }
456
-
457
- /**
458
- * Validate field pattern
459
- * @param {string} fieldName - Field name
460
- * @param {any} value - Field value
461
- * @param {RegExp|string} pattern - Pattern to match
462
- * @returns {Object} Pattern validation result
463
- * @private
464
- */
465
- _validateFieldPattern(fieldName, value, pattern) {
466
- const errors = [];
467
- const stringValue = String(value);
468
- const regex = pattern instanceof RegExp ? pattern : new RegExp(pattern);
469
- if (!regex.test(stringValue)) {
470
- errors.push({
471
- field: fieldName,
472
- message: `Field '${fieldName}' does not match required pattern`,
473
- code: 'PATTERN_MISMATCH',
474
- value,
475
- pattern: pattern.toString()
476
- });
477
- }
478
- return {
479
- valid: errors.length === 0,
480
- errors
481
- };
482
- }
483
-
484
- /**
485
- * Validate custom rules
486
- * @param {string} ruleName - Rule name
487
- * @param {Object} ruleConfig - Rule configuration
488
- * @param {Object} originalData - Original data
489
- * @param {Object} validatedData - Validated data so far
490
- * @returns {Object} Custom validation result
491
- * @private
492
- */
493
- _validateCustomRule(ruleName, ruleConfig, originalData, validatedData) {
494
- const errors = [];
495
- try {
496
- if (typeof ruleConfig === 'function') {
497
- const result = ruleConfig(originalData, validatedData);
498
- if (result !== true) {
499
- errors.push({
500
- field: '_custom',
501
- message: typeof result === 'string' ? result : `Custom rule '${ruleName}' failed`,
502
- code: 'CUSTOM_RULE_VIOLATION',
503
- rule: ruleName
504
- });
505
- }
506
- } else if (ruleConfig.validator && typeof ruleConfig.validator === 'function') {
507
- const result = ruleConfig.validator(originalData, validatedData);
508
- if (result !== true) {
509
- errors.push({
510
- field: ruleConfig.field || '_custom',
511
- message: result || ruleConfig.message || `Custom rule '${ruleName}' failed`,
512
- code: 'CUSTOM_RULE_VIOLATION',
513
- rule: ruleName
514
- });
515
- }
516
- }
517
- } catch (error) {
518
- errors.push({
519
- field: '_custom',
520
- message: `Custom rule '${ruleName}' threw an error: ${error.message}`,
521
- code: 'CUSTOM_RULE_ERROR',
522
- rule: ruleName
523
- });
524
- }
525
- return {
526
- valid: errors.length === 0,
527
- errors
528
- };
529
- }
530
-
531
- /**
532
- * Extract template parameters for SQL caching
533
- * @param {Object} params - Full parameters
534
- * @param {string} operation - Operation type
535
- * @returns {Object} Template parameters for caching
536
- * @private
537
- */
538
- _extractTemplateParams(params, operation) {
539
- const templateParams = {};
540
- switch (operation) {
541
- case 'create':
542
- templateParams.columns = Object.keys(params).filter(key => key !== 'id');
543
- break;
544
- case 'read':
545
- templateParams.hasId = !!params.id;
546
- templateParams.hasWhere = !!params.where;
547
- templateParams.whereKeys = params.where ? Object.keys(params.where) : [];
548
- templateParams.fields = params.fields || null;
549
- break;
550
- case 'update':
551
- templateParams.columns = Object.keys(params).filter(key => key !== 'id');
552
- break;
553
- case 'delete':
554
- templateParams.hasId = !!params.id;
555
- break;
556
- }
557
- return templateParams;
558
- }
559
-
560
- /**
561
- * Bind actual parameter values to cached SQL template
562
- * @param {Object} template - Cached SQL template
563
- * @param {Object} params - Actual parameters
564
- * @returns {Array} Bound parameters
565
- * @private
566
- */
567
- _bindParametersToTemplate(template, params) {
568
- if (!template.parameterMapping) {
569
- return template.params || [];
570
- }
571
- return template.parameterMapping.map(paramPath => {
572
- if (paramPath.startsWith('where.')) {
573
- const key = paramPath.substring(6);
574
- return params.where[key];
575
- }
576
- return params[paramPath];
577
- });
578
- }
579
- }
580
-
581
- // Create singleton instance
582
- export const schemaManager = new SchemaManager();
583
-
584
- // Pre-register existing models for backward compatibility
585
- schemaManager.registerModel('users', {
586
- tableName: 'users',
587
- columns: {
588
- id: {
589
- type: 'text',
590
- primaryKey: true
591
- },
592
- email: {
593
- type: 'text',
594
- unique: true,
595
- required: true
596
- },
597
- name: {
598
- type: 'text'
599
- },
600
- is_email_verified: {
601
- type: 'integer',
602
- default: 0
603
- },
604
- created_at: {
605
- type: 'text',
606
- required: true
607
- },
608
- updated_at: {
609
- type: 'text',
610
- required: true
611
- }
612
- },
613
- indexes: ['email'],
614
- validation: {
615
- required: ['email']
616
- }
617
- });
618
- schemaManager.registerModel('magic_links', {
619
- tableName: 'magic_links',
620
- columns: {
621
- id: {
622
- type: 'text',
623
- primaryKey: true
624
- },
625
- token: {
626
- type: 'text',
627
- unique: true,
628
- required: true
629
- },
630
- user_id: {
631
- type: 'text',
632
- required: true
633
- },
634
- email: {
635
- type: 'text',
636
- required: true
637
- },
638
- expires_at: {
639
- type: 'text',
640
- required: true
641
- },
642
- used: {
643
- type: 'integer',
644
- default: 0
645
- },
646
- created_at: {
647
- type: 'text',
648
- required: true
649
- }
650
- },
651
- relationships: {
652
- user: {
653
- model: 'users',
654
- type: 'belongsTo',
655
- foreignKey: 'user_id'
656
- }
657
- },
658
- indexes: ['token', 'user_id', 'expires_at']
659
- });
660
- schemaManager.registerModel('tokens', {
661
- tableName: 'tokens',
662
- columns: {
663
- id: {
664
- type: 'text',
665
- primaryKey: true
666
- },
667
- token: {
668
- type: 'text',
669
- unique: true,
670
- required: true
671
- },
672
- user_id: {
673
- type: 'text',
674
- required: true
675
- },
676
- type: {
677
- type: 'text',
678
- required: true
679
- },
680
- expires_at: {
681
- type: 'text'
682
- },
683
- created_at: {
684
- type: 'text',
685
- required: true
686
- }
687
- },
688
- relationships: {
689
- user: {
690
- model: 'users',
691
- type: 'belongsTo',
692
- foreignKey: 'user_id'
693
- }
694
- },
695
- indexes: ['token', 'user_id', 'type']
696
- });
697
- schemaManager.registerModel('files', {
698
- tableName: 'files',
699
- columns: {
700
- id: {
701
- type: 'text',
702
- primaryKey: true
703
- },
704
- filename: {
705
- type: 'text',
706
- required: true
707
- },
708
- original_name: {
709
- type: 'text',
710
- required: true
711
- },
712
- mime_type: {
713
- type: 'text',
714
- required: true
715
- },
716
- size: {
717
- type: 'integer',
718
- required: true
719
- },
720
- user_id: {
721
- type: 'text',
722
- required: true
723
- },
724
- path: {
725
- type: 'text',
726
- required: true
727
- },
728
- status: {
729
- type: 'text',
730
- default: 'uploaded'
731
- },
732
- created_at: {
733
- type: 'text',
734
- required: true
735
- },
736
- updated_at: {
737
- type: 'text',
738
- required: true
739
- }
740
- },
741
- relationships: {
742
- user: {
743
- model: 'users',
744
- type: 'belongsTo',
745
- foreignKey: 'user_id'
746
- }
747
- },
748
- indexes: ['user_id', 'status']
749
- });
750
- schemaManager.registerModel('logs', {
751
- tableName: 'logs',
752
- columns: {
753
- id: {
754
- type: 'text',
755
- primaryKey: true
756
- },
757
- level: {
758
- type: 'text',
759
- required: true
760
- },
761
- message: {
762
- type: 'text',
763
- required: true
764
- },
765
- user_id: {
766
- type: 'text'
767
- },
768
- timestamp: {
769
- type: 'text',
770
- required: true
771
- },
772
- metadata: {
773
- type: 'text'
774
- }
775
- },
776
- indexes: ['level', 'user_id', 'timestamp']
777
- });
778
- console.log('✅ Schema Manager initialized with existing models');