@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,174 +0,0 @@
1
- /**
2
- * GeneratorRegistry - Manages generator instantiation and registration
3
- *
4
- * Provides centralized generator management with automatic instantiation,
5
- * dependency injection, and configuration management.
6
- */
7
-
8
- import { RouteGenerator } from '../routing/RouteGenerator.js';
9
- import { PackageJsonGenerator } from '../generators/core/PackageJsonGenerator.js';
10
- import { SiteConfigGenerator } from '../generators/core/SiteConfigGenerator.js';
11
- import { WranglerTomlGenerator } from '../generators/config/WranglerTomlGenerator.js';
12
- import { DomainsConfigGenerator } from '../generators/config/DomainsConfigGenerator.js';
13
- import { WorkerIndexGenerator } from '../generators/code/WorkerIndexGenerator.js';
14
- import { ServiceHandlersGenerator } from '../generators/code/ServiceHandlersGenerator.js';
15
- import { ServiceMiddlewareGenerator } from '../generators/code/ServiceMiddlewareGenerator.js';
16
- import { ServiceUtilsGenerator } from '../generators/code/ServiceUtilsGenerator.js';
17
- import { EnvExampleGenerator } from '../generators/config/EnvExampleGenerator.js';
18
- import { ProductionEnvGenerator } from '../generators/config/ProductionEnvGenerator.js';
19
- import { StagingEnvGenerator } from '../generators/config/StagingEnvGenerator.js';
20
- import { DevelopmentEnvGenerator } from '../generators/config/DevelopmentEnvGenerator.js';
21
- import { ServiceSchemaGenerator } from '../generators/schemas/ServiceSchemaGenerator.js';
22
- import { DeployScriptGenerator } from '../generators/scripts/DeployScriptGenerator.js';
23
- import { SetupScriptGenerator } from '../generators/scripts/SetupScriptGenerator.js';
24
- import { HealthCheckScriptGenerator } from '../generators/scripts/HealthCheckScriptGenerator.js';
25
- import { UnitTestsGenerator } from '../generators/testing/UnitTestsGenerator.js';
26
- import { IntegrationTestsGenerator } from '../generators/testing/IntegrationTestsGenerator.js';
27
- import { JestConfigGenerator } from '../generators/testing/JestConfigGenerator.js';
28
- import { EslintConfigGenerator } from '../generators/testing/EslintConfigGenerator.js';
29
- import { ReadmeGenerator } from '../generators/documentation/ReadmeGenerator.js';
30
- import { ApiDocsGenerator } from '../generators/documentation/ApiDocsGenerator.js';
31
- import { DeploymentDocsGenerator } from '../generators/documentation/DeploymentDocsGenerator.js';
32
- import { ConfigurationDocsGenerator } from '../generators/documentation/ConfigurationDocsGenerator.js';
33
- import { CiWorkflowGenerator } from '../generators/cicd/CiWorkflowGenerator.js';
34
- import { DeployWorkflowGenerator } from '../generators/cicd/DeployWorkflowGenerator.js';
35
- import { GitignoreGenerator } from '../generators/tooling/GitignoreGenerator.js';
36
- import { DockerComposeGenerator } from '../generators/tooling/DockerComposeGenerator.js';
37
- import { StaticSiteGenerator } from '../generators/service-types/StaticSiteGenerator.js';
38
- import { join } from 'path';
39
- export class GeneratorRegistry {
40
- constructor(options = {}) {
41
- this.templatesDir = options.templatesDir;
42
- this.outputDir = options.outputDir;
43
- this.generators = new Map();
44
- this.options = options;
45
- this.initializeGenerators();
46
- }
47
-
48
- /**
49
- * Initialize all generators with proper dependencies
50
- */
51
- initializeGenerators() {
52
- // Core generators (no dependencies)
53
- this.register('routeGenerator', () => new RouteGenerator());
54
- this.register('siteConfigGenerator', () => new SiteConfigGenerator({
55
- templatesDir: this.templatesDir,
56
- outputDir: this.outputDir
57
- }));
58
-
59
- // Service-type generators
60
- this.register('staticSiteGenerator', () => new StaticSiteGenerator({
61
- templatesDir: join(this.templatesDir, 'static-site'),
62
- outputDir: this.outputDir
63
- }));
64
-
65
- // Generators with standard config
66
- const standardGenerators = ['packageJsonGenerator', 'wranglerTomlGenerator', 'domainsConfigGenerator', 'workerIndexGenerator', 'serviceHandlersGenerator', 'serviceMiddlewareGenerator', 'serviceUtilsGenerator', 'envExampleGenerator', 'productionEnvGenerator', 'stagingEnvGenerator', 'developmentEnvGenerator', 'serviceSchemaGenerator', 'deployScriptGenerator', 'setupScriptGenerator', 'healthCheckScriptGenerator', 'unitTestsGenerator', 'integrationTestsGenerator', 'jestConfigGenerator', 'eslintConfigGenerator', 'readmeGenerator', 'apiDocsGenerator', 'deploymentDocsGenerator', 'configurationDocsGenerator', 'ciWorkflowGenerator', 'deployWorkflowGenerator', 'gitignoreGenerator', 'dockerComposeGenerator'];
67
- standardGenerators.forEach(name => {
68
- this.register(name, () => this.createStandardGenerator(name));
69
- });
70
-
71
- // Special generators with dependencies
72
- this.register('wranglerTomlGenerator', () => new WranglerTomlGenerator({
73
- templatesDir: this.templatesDir,
74
- outputDir: this.outputDir,
75
- routeGenerator: this.get('routeGenerator'),
76
- siteConfigGenerator: this.get('siteConfigGenerator')
77
- }));
78
- }
79
-
80
- /**
81
- * Register a generator factory function
82
- * @param {string} name - Generator name
83
- * @param {Function} factory - Factory function that returns generator instance
84
- */
85
- register(name, factory) {
86
- this.generators.set(name, factory);
87
- }
88
-
89
- /**
90
- * Get a generator instance (lazy instantiation)
91
- * @param {string} name - Generator name
92
- * @returns {*} - Generator instance
93
- */
94
- get(name) {
95
- const factory = this.generators.get(name);
96
- if (!factory) {
97
- throw new Error(`Generator '${name}' not registered`);
98
- }
99
-
100
- // If factory returns a function, call it to get instance
101
- const instance = typeof factory === 'function' ? factory() : factory;
102
-
103
- // Cache the instance for future use
104
- this.generators.set(name, instance);
105
- return instance;
106
- }
107
-
108
- /**
109
- * Create a standard generator with default configuration
110
- * @param {string} className - Generator class name
111
- * @returns {*} - Generator instance
112
- */
113
- createStandardGenerator(className) {
114
- // Convert camelCase to PascalCase for class name
115
- const pascalCase = className.charAt(0).toUpperCase() + className.slice(1);
116
-
117
- // Import all generator classes (this would be handled by the module system)
118
- const generatorClasses = {
119
- PackageJsonGenerator,
120
- SiteConfigGenerator,
121
- WranglerTomlGenerator,
122
- DomainsConfigGenerator,
123
- WorkerIndexGenerator,
124
- ServiceHandlersGenerator,
125
- ServiceMiddlewareGenerator,
126
- ServiceUtilsGenerator,
127
- EnvExampleGenerator,
128
- ProductionEnvGenerator,
129
- StagingEnvGenerator,
130
- DevelopmentEnvGenerator,
131
- ServiceSchemaGenerator,
132
- DeployScriptGenerator,
133
- SetupScriptGenerator,
134
- HealthCheckScriptGenerator,
135
- UnitTestsGenerator,
136
- IntegrationTestsGenerator,
137
- JestConfigGenerator,
138
- EslintConfigGenerator,
139
- ReadmeGenerator,
140
- ApiDocsGenerator,
141
- DeploymentDocsGenerator,
142
- ConfigurationDocsGenerator,
143
- CiWorkflowGenerator,
144
- DeployWorkflowGenerator,
145
- GitignoreGenerator,
146
- DockerComposeGenerator
147
- };
148
- const GeneratorClass = generatorClasses[pascalCase];
149
- if (!GeneratorClass) {
150
- throw new Error(`Unknown generator class: ${pascalCase}`);
151
- }
152
- return new GeneratorClass({
153
- templatesDir: this.templatesDir,
154
- outputDir: this.outputDir
155
- });
156
- }
157
-
158
- /**
159
- * Get all registered generator names
160
- * @returns {string[]} - Array of generator names
161
- */
162
- getRegisteredNames() {
163
- return Array.from(this.generators.keys());
164
- }
165
-
166
- /**
167
- * Check if a generator is registered
168
- * @param {string} name - Generator name
169
- * @returns {boolean} - True if registered
170
- */
171
- has(name) {
172
- return this.generators.has(name);
173
- }
174
- }
@@ -1,501 +0,0 @@
1
- import { schemaManager } from '../schema/SchemaManager.js';
2
-
3
- /**
4
- * Generic Data Service
5
- * Provides CRUD operations for any configured data model
6
- */
7
- export class GenericDataService {
8
- /**
9
- * Create a new GenericDataService instance
10
- * @param {Object} d1Client - D1 database client
11
- * @param {string} modelName - Name of the model to work with
12
- * @param {Object} options - Configuration options
13
- */
14
- constructor(d1Client, modelName, options = {}) {
15
- this.d1Client = d1Client;
16
- this.modelName = modelName;
17
- this.schema = schemaManager.getModel(modelName);
18
- if (!this.schema) {
19
- throw new Error(`Model '${modelName}' not registered. Use schemaManager.registerModel() first.`);
20
- }
21
-
22
- // Query result caching
23
- this.queryCache = new Map();
24
- this.cacheEnabled = options.cacheEnabled !== false;
25
- this.defaultCacheTTL = options.defaultCacheTTL || 300; // 5 minutes default
26
-
27
- // Security configuration
28
- this.securityConfig = {
29
- maxQueryLimit: options.maxQueryLimit || 1000,
30
- // Maximum records per query
31
- defaultQueryLimit: options.defaultQueryLimit || 100,
32
- // Default records per query
33
- maxBulkOperationSize: options.maxBulkOperationSize || 100,
34
- // Maximum records in bulk operations
35
- enablePagination: options.enablePagination !== false,
36
- // Enable pagination by default
37
- ...options.securityConfig
38
- };
39
- }
40
-
41
- /**
42
- * Generate cache key for query
43
- * @param {string} operation - Operation type
44
- * @param {Object} params - Query parameters
45
- * @returns {string} Cache key
46
- */
47
- generateCacheKey(operation, params = {}) {
48
- return `${this.modelName}:${operation}:${JSON.stringify(params)}`;
49
- }
50
-
51
- /**
52
- * Get cached result if valid
53
- * @param {string} cacheKey - Cache key
54
- * @returns {any|null} Cached result or null if expired/not found
55
- */
56
- getCachedResult(cacheKey) {
57
- if (!this.cacheEnabled) return null;
58
- const cached = this.queryCache.get(cacheKey);
59
- if (!cached) return null;
60
-
61
- // Check if expired
62
- if (Date.now() > cached.expiresAt) {
63
- this.queryCache.delete(cacheKey);
64
- return null;
65
- }
66
- return cached.data;
67
- }
68
-
69
- /**
70
- * Cache query result
71
- * @param {string} cacheKey - Cache key
72
- * @param {any} data - Data to cache
73
- * @param {number} ttl - Time to live in seconds
74
- */
75
- setCachedResult(cacheKey, data, ttl = null) {
76
- if (!this.cacheEnabled) return;
77
- const expiresAt = Date.now() + (ttl || this.defaultCacheTTL) * 1000;
78
- this.queryCache.set(cacheKey, {
79
- data,
80
- expiresAt,
81
- createdAt: Date.now()
82
- });
83
- }
84
-
85
- /**
86
- * Clear cache for specific operations or all cache
87
- * @param {string} operation - Optional: specific operation to clear
88
- * @param {Object} params - Optional: specific parameters to clear
89
- */
90
- clearCache(operation = null, params = null) {
91
- if (operation && params) {
92
- // Clear specific cache entry
93
- const cacheKey = this.generateCacheKey(operation, params);
94
- this.queryCache.delete(cacheKey);
95
- } else if (operation) {
96
- // Clear all cache entries for an operation
97
- for (const [key] of this.queryCache) {
98
- if (key.startsWith(`${this.modelName}:${operation}:`)) {
99
- this.queryCache.delete(key);
100
- }
101
- }
102
- } else {
103
- // Clear all cache
104
- this.queryCache.clear();
105
- }
106
- }
107
-
108
- /**
109
- * Format validation errors into a human-readable message
110
- * @param {Array} errors - Validation errors array
111
- * @returns {string} Formatted error message
112
- */
113
- formatValidationErrors(errors = []) {
114
- if (!Array.isArray(errors) || errors.length === 0) {
115
- return 'Unknown validation error';
116
- }
117
- const details = errors.map(error => {
118
- if (!error) {
119
- return null;
120
- }
121
- if (typeof error === 'string') {
122
- return error;
123
- }
124
- if (Array.isArray(error)) {
125
- return error.map(item => this.formatValidationErrors([item])).join('; ');
126
- }
127
- if (typeof error === 'object') {
128
- const field = error.field || error.path || error.name || 'field';
129
- if (error.message) {
130
- return `${field}: ${error.message}`;
131
- }
132
- if (error.reason) {
133
- return `${field}: ${error.reason}`;
134
- }
135
- if (error.code) {
136
- return `${field}: ${error.code}`;
137
- }
138
- try {
139
- return `${field}: ${JSON.stringify(error)}`;
140
- } catch {
141
- return `${field}: ${String(error)}`;
142
- }
143
- }
144
- return String(error);
145
- }).filter(Boolean);
146
- return details.length > 0 ? details.join('; ') : 'Unknown validation error';
147
- }
148
-
149
- /**
150
- * Create a new record
151
- * @param {Object} data - Record data
152
- * @returns {Promise<Object>} Created record
153
- */
154
- async create(data) {
155
- // Validate data
156
- const validation = schemaManager.validateData(this.modelName, data);
157
- if (!validation.valid) {
158
- const errorMessage = this.formatValidationErrors(validation.errors);
159
- throw new Error(`Validation failed: ${errorMessage}`);
160
- }
161
-
162
- // Generate ID if not provided
163
- const recordData = {
164
- ...validation.data
165
- };
166
- if (!recordData.id) {
167
- recordData.id = this.d1Client.generateId();
168
- }
169
-
170
- // Set timestamps
171
- const now = this.d1Client.getCurrentTimestamp();
172
- if (this.schema.columns.created_at && !recordData.created_at) {
173
- recordData.created_at = now;
174
- }
175
- if (this.schema.columns.updated_at && !recordData.updated_at) {
176
- recordData.updated_at = now;
177
- }
178
-
179
- // Generate SQL
180
- const {
181
- sql,
182
- params
183
- } = schemaManager.generateSQL(this.modelName, 'create', recordData);
184
-
185
- // Execute
186
- const result = await this.d1Client.run(sql, params);
187
- if (result.success) {
188
- // Clear relevant caches after successful creation
189
- this.clearCache('findAll');
190
- return {
191
- ...recordData,
192
- id: recordData.id
193
- };
194
- }
195
- throw new Error('Failed to create record');
196
- }
197
-
198
- /**
199
- * Find records by criteria with advanced options
200
- * @param {Object} criteria - Search criteria
201
- * @param {Array} include - Relationships to include
202
- * @param {Array} fields - Fields to select
203
- * @returns {Promise<Array>} Found records
204
- */
205
- async find(criteria = {}, include = [], fields = null) {
206
- const cacheKey = this.generateCacheKey('find', {
207
- criteria,
208
- include,
209
- fields
210
- });
211
- const cached = this.getCachedResult(cacheKey);
212
- if (cached !== null) {
213
- return cached;
214
- }
215
- let result;
216
- if (include.length > 0) {
217
- result = await this.findWithRelations(criteria, include, fields);
218
- } else {
219
- const {
220
- sql,
221
- params
222
- } = schemaManager.generateSQL(this.modelName, 'read', {
223
- where: criteria,
224
- fields
225
- });
226
- result = await this.d1Client.all(sql, params);
227
- }
228
-
229
- // Cache the result
230
- this.setCachedResult(cacheKey, result);
231
- return result;
232
- }
233
-
234
- /**
235
- * Find all records with pagination and security limits
236
- * @param {Object} options - Query options
237
- * @param {number} options.limit - Maximum records to return (default: configured default, max: configured max)
238
- * @param {number} options.offset - Number of records to skip (default: 0)
239
- * @param {Object} options.orderBy - Sort options {field: 'asc'|'desc'}
240
- * @param {Object} options.where - Filter criteria
241
- * @returns {Promise<Object>} Paginated result with data, total, limit, offset
242
- */
243
- async findAll(options = {}) {
244
- // Apply security limits
245
- const requestedLimit = options.limit !== undefined ? options.limit : this.securityConfig.defaultQueryLimit;
246
-
247
- // Validate limit before applying security constraints
248
- if (requestedLimit <= 0) {
249
- throw new Error(`Invalid limit: ${requestedLimit}. Must be positive.`);
250
- }
251
- const limit = Math.min(requestedLimit, this.securityConfig.maxQueryLimit);
252
- const offset = Math.max(0, options.offset || 0);
253
-
254
- // Prevent excessive offset (basic protection against very large offsets)
255
- if (offset > 1000000) {
256
- throw new Error(`Offset too large: ${offset}. Maximum allowed offset is 1,000,000.`);
257
- }
258
- const queryOptions = {
259
- limit,
260
- offset,
261
- orderBy: options.orderBy,
262
- where: options.where || {}
263
- };
264
- const cacheKey = this.generateCacheKey('findAll', queryOptions);
265
- const cached = this.getCachedResult(cacheKey);
266
- if (cached !== null) {
267
- return cached;
268
- }
269
-
270
- // Build query with pagination
271
- let sql = `SELECT * FROM ${this.schema.tableName}`;
272
- let params = [];
273
-
274
- // Add WHERE clause if provided
275
- if (options.where && Object.keys(options.where).length > 0) {
276
- const conditions = [];
277
- Object.entries(options.where).forEach(([key, value]) => {
278
- conditions.push(`${key} = ?`);
279
- params.push(value);
280
- });
281
- sql += ` WHERE ${conditions.join(' AND ')}`;
282
- }
283
-
284
- // Add ORDER BY if provided
285
- if (options.orderBy && Object.keys(options.orderBy).length > 0) {
286
- const orderClauses = [];
287
- Object.entries(options.orderBy).forEach(([field, direction]) => {
288
- orderClauses.push(`${field} ${direction.toUpperCase()}`);
289
- });
290
- sql += ` ORDER BY ${orderClauses.join(', ')}`;
291
- }
292
-
293
- // Add LIMIT and OFFSET
294
- sql += ` LIMIT ? OFFSET ?`;
295
- params.push(limit, offset);
296
-
297
- // Execute the query
298
- const data = await this.d1Client.all(sql, params);
299
-
300
- // Get total count for pagination (without LIMIT/OFFSET)
301
- let countSql = `SELECT COUNT(*) as total FROM ${this.schema.tableName}`;
302
- let countParams = [];
303
- if (options.where && Object.keys(options.where).length > 0) {
304
- const conditions = [];
305
- Object.entries(options.where).forEach(([key, value]) => {
306
- conditions.push(`${key} = ?`);
307
- countParams.push(value);
308
- });
309
- countSql += ` WHERE ${conditions.join(' AND ')}`;
310
- }
311
- const countResult = await this.d1Client.first(countSql, countParams);
312
- const total = countResult ? countResult.total : 0;
313
- const result = {
314
- data,
315
- pagination: {
316
- total,
317
- limit,
318
- offset,
319
- hasNext: offset + limit < total,
320
- hasPrev: offset > 0,
321
- totalPages: Math.ceil(total / limit),
322
- currentPage: Math.floor(offset / limit) + 1
323
- }
324
- };
325
-
326
- // Cache the result
327
- this.setCachedResult(cacheKey, result);
328
- return result;
329
- }
330
-
331
- /**
332
- * Update a record
333
- * @param {string} id - Record ID
334
- * @param {Object} updates - Fields to update
335
- * @returns {Promise<Object>} Updated record
336
- */
337
- async update(id, updates) {
338
- // Validate updates
339
- const validation = schemaManager.validateData(this.modelName, updates);
340
- if (!validation.valid) {
341
- const errorMessage = this.formatValidationErrors(validation.errors);
342
- throw new Error(`Validation failed: ${errorMessage}`);
343
- }
344
-
345
- // Set updated timestamp
346
- const updateData = {
347
- ...validation.data,
348
- id
349
- };
350
- if (this.schema.columns.updated_at) {
351
- updateData.updated_at = this.d1Client.getCurrentTimestamp();
352
- }
353
-
354
- // Generate SQL
355
- const {
356
- sql,
357
- params
358
- } = schemaManager.generateSQL(this.modelName, 'update', updateData);
359
-
360
- // Execute
361
- const result = await this.d1Client.run(sql, params);
362
- if (result.success) {
363
- // Return updated record
364
- return await this.findById(id);
365
- } else {
366
- throw new Error('Failed to update record');
367
- }
368
- }
369
-
370
- /**
371
- * Delete a record
372
- * @param {string} id - Record ID
373
- * @returns {Promise<boolean>} Success status
374
- */
375
- async delete(id) {
376
- const {
377
- sql,
378
- params
379
- } = schemaManager.generateSQL(this.modelName, 'delete', {
380
- id
381
- });
382
- const result = await this.d1Client.run(sql, params);
383
- return result.success;
384
- }
385
-
386
- /**
387
- * Count records matching criteria
388
- * @param {Object} criteria - Count criteria
389
- * @returns {Promise<number>} Record count
390
- */
391
- async count(criteria = {}) {
392
- let sql = `SELECT COUNT(*) as count FROM ${this.schema.tableName}`;
393
- let params = [];
394
- if (Object.keys(criteria).length > 0) {
395
- const conditions = [];
396
- Object.entries(criteria).forEach(([key, value]) => {
397
- conditions.push(`${key} = ?`);
398
- params.push(value);
399
- });
400
- sql += ` WHERE ${conditions.join(' AND ')}`;
401
- }
402
- const result = await this.d1Client.first(sql, params);
403
- return result?.count || 0;
404
- }
405
-
406
- /**
407
- * Check if record exists
408
- * @param {string} id - Record ID
409
- * @returns {Promise<boolean>} Existence status
410
- */
411
- async exists(id) {
412
- const record = await this.findById(id);
413
- return !!record;
414
- }
415
-
416
- /**
417
- * Get paginated results
418
- * @param {Object} criteria - Search criteria
419
- * @param {Object} pagination - Pagination options
420
- * @returns {Promise<Object>} Paginated results
421
- */
422
- async paginate(criteria = {}, pagination = {}) {
423
- const {
424
- page = 1,
425
- limit = 10
426
- } = pagination;
427
- const offset = (page - 1) * limit;
428
-
429
- // Get total count
430
- const total = await this.count(criteria);
431
-
432
- // Get paginated results
433
- let sql = `SELECT * FROM ${this.schema.tableName}`;
434
- let params = [];
435
- if (Object.keys(criteria).length > 0) {
436
- const conditions = [];
437
- Object.entries(criteria).forEach(([key, value]) => {
438
- conditions.push(`${key} = ?`);
439
- params.push(value);
440
- });
441
- sql += ` WHERE ${conditions.join(' AND ')}`;
442
- }
443
- sql += ` LIMIT ? OFFSET ?`;
444
- params.push(limit, offset);
445
- const records = await this.d1Client.all(sql, params);
446
- return {
447
- data: records,
448
- pagination: {
449
- page,
450
- limit,
451
- total,
452
- totalPages: Math.ceil(total / limit),
453
- hasNext: page * limit < total,
454
- hasPrev: page > 1
455
- }
456
- };
457
- }
458
-
459
- /**
460
- * Find a single record by ID
461
- * @param {string|number} id - Record ID
462
- * @param {Array} include - Relations to include
463
- * @param {Array} fields - Fields to select
464
- * @returns {Promise<Object|null>} Found record or null
465
- */
466
- async findById(id, include = [], fields = null) {
467
- const result = await this.find({
468
- id
469
- }, include, fields);
470
- return result && result.length > 0 ? result[0] : null;
471
- }
472
- }
473
-
474
- /**
475
- * Factory function to create a data service for a model
476
- * @param {Object} d1Client - D1 database client
477
- * @param {string} modelName - Name of the model
478
- * @returns {GenericDataService} Data service instance
479
- */
480
- /**
481
- * Factory function to create a data service for a model
482
- * @param {Object} d1Client - D1 database client
483
- * @param {string} modelName - Name of the model
484
- * @returns {GenericDataService} Data service instance
485
- */
486
- export function createDataService(d1Client, modelName) {
487
- return new GenericDataService(d1Client, modelName);
488
- }
489
-
490
- /**
491
- * Get all available data services
492
- * @returns {Object} Map of model names to service instances
493
- */
494
- export function getAllDataServices() {
495
- const services = {};
496
- // Note: This would require schemaManager to have getAllModels method
497
- // for (const [modelName] of schemaManager.getAllModels()) {
498
- // services[modelName] = new GenericDataService(d1Client, modelName);
499
- // }
500
- return services;
501
- }