@friggframework/devtools 2.0.0--canary.522.cbd3d5a.0 → 2.0.0--canary.517.21b69ac.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.
Files changed (247) hide show
  1. package/.eslintrc.json +3 -0
  2. package/CHANGELOG.md +132 -0
  3. package/frigg-cli/README.md +1 -1
  4. package/frigg-cli/__tests__/unit/commands/doctor.test.js +2 -0
  5. package/frigg-cli/__tests__/unit/commands/install.test.js +17 -21
  6. package/frigg-cli/doctor-command/index.js +16 -17
  7. package/frigg-cli/index.js +6 -21
  8. package/frigg-cli/index.test.js +1 -7
  9. package/frigg-cli/init-command/backend-first-handler.js +42 -124
  10. package/frigg-cli/init-command/index.js +1 -2
  11. package/frigg-cli/init-command/template-handler.js +3 -13
  12. package/frigg-cli/install-command/backend-js.js +3 -3
  13. package/frigg-cli/install-command/environment-variables.js +19 -16
  14. package/frigg-cli/install-command/environment-variables.test.js +13 -12
  15. package/frigg-cli/install-command/index.js +9 -14
  16. package/frigg-cli/install-command/integration-file.js +3 -3
  17. package/frigg-cli/install-command/logger.js +12 -0
  18. package/frigg-cli/install-command/validate-package.js +9 -5
  19. package/frigg-cli/jest.config.js +1 -4
  20. package/frigg-cli/repair-command/index.js +128 -101
  21. package/frigg-cli/start-command/index.js +2 -246
  22. package/frigg-cli/ui-command/index.js +36 -58
  23. package/frigg-cli/utils/repo-detection.js +37 -85
  24. package/infrastructure/docs/iam-policy-templates.md +1 -1
  25. package/infrastructure/domains/networking/vpc-builder.test.js +4 -2
  26. package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
  27. package/infrastructure/domains/shared/cloudformation-discovery.test.js +7 -4
  28. package/infrastructure/domains/shared/resource-discovery.js +5 -5
  29. package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
  30. package/infrastructure/domains/shared/utilities/base-definition-factory.js +2 -25
  31. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
  32. package/infrastructure/infrastructure-composer.test.js +2 -2
  33. package/layers/prisma/.build-complete +3 -0
  34. package/layers/prisma/nodejs/package.json +8 -0
  35. package/management-ui/.eslintrc.js +22 -0
  36. package/management-ui/README.md +109 -245
  37. package/management-ui/components.json +21 -0
  38. package/management-ui/docs/phase2-integration-guide.md +320 -0
  39. package/management-ui/index.html +13 -0
  40. package/management-ui/package.json +76 -0
  41. package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
  42. package/management-ui/postcss.config.js +6 -0
  43. package/management-ui/server/api/backend.js +256 -0
  44. package/management-ui/server/api/cli.js +315 -0
  45. package/management-ui/server/api/codegen.js +663 -0
  46. package/management-ui/server/api/connections.js +857 -0
  47. package/management-ui/server/api/discovery.js +185 -0
  48. package/management-ui/server/api/environment/index.js +1 -0
  49. package/management-ui/server/api/environment/router.js +378 -0
  50. package/management-ui/server/api/environment.js +328 -0
  51. package/management-ui/server/api/integrations.js +876 -0
  52. package/management-ui/server/api/logs.js +248 -0
  53. package/management-ui/server/api/monitoring.js +282 -0
  54. package/management-ui/server/api/open-ide.js +31 -0
  55. package/management-ui/server/api/project.js +1029 -0
  56. package/management-ui/server/api/users/sessions.js +371 -0
  57. package/management-ui/server/api/users/simulation.js +254 -0
  58. package/management-ui/server/api/users.js +362 -0
  59. package/management-ui/server/api-contract.md +275 -0
  60. package/management-ui/server/index.js +873 -0
  61. package/management-ui/server/middleware/errorHandler.js +93 -0
  62. package/management-ui/server/middleware/security.js +32 -0
  63. package/management-ui/server/processManager.js +296 -0
  64. package/management-ui/server/server.js +346 -0
  65. package/management-ui/server/services/aws-monitor.js +413 -0
  66. package/management-ui/server/services/npm-registry.js +347 -0
  67. package/management-ui/server/services/template-engine.js +538 -0
  68. package/management-ui/server/utils/cliIntegration.js +220 -0
  69. package/management-ui/server/utils/environment/auditLogger.js +471 -0
  70. package/management-ui/server/utils/environment/awsParameterStore.js +275 -0
  71. package/management-ui/server/utils/environment/encryption.js +278 -0
  72. package/management-ui/server/utils/environment/envFileManager.js +286 -0
  73. package/management-ui/server/utils/import-commonjs.js +28 -0
  74. package/management-ui/server/utils/response.js +83 -0
  75. package/management-ui/server/websocket/handler.js +325 -0
  76. package/management-ui/src/App.jsx +25 -0
  77. package/management-ui/src/assets/FriggLogo.svg +1 -0
  78. package/management-ui/src/components/AppRouter.jsx +65 -0
  79. package/management-ui/src/components/Button.jsx +70 -0
  80. package/management-ui/src/components/Card.jsx +97 -0
  81. package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
  82. package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
  83. package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
  84. package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
  85. package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
  86. package/management-ui/src/components/ErrorBoundary.jsx +73 -0
  87. package/management-ui/src/components/IntegrationCard.jsx +481 -0
  88. package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
  89. package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
  90. package/management-ui/src/components/IntegrationStatus.jsx +336 -0
  91. package/management-ui/src/components/Layout.jsx +716 -0
  92. package/management-ui/src/components/LoadingSpinner.jsx +113 -0
  93. package/management-ui/src/components/RepositoryPicker.jsx +248 -0
  94. package/management-ui/src/components/SessionMonitor.jsx +350 -0
  95. package/management-ui/src/components/StatusBadge.jsx +208 -0
  96. package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
  97. package/management-ui/src/components/UserSimulation.jsx +327 -0
  98. package/management-ui/src/components/Welcome.jsx +434 -0
  99. package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
  100. package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
  101. package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
  102. package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
  103. package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
  104. package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
  105. package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
  106. package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
  107. package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
  108. package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
  109. package/management-ui/src/components/codegen/index.js +10 -0
  110. package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
  111. package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
  112. package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
  113. package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
  114. package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
  115. package/management-ui/src/components/connections/index.js +5 -0
  116. package/management-ui/src/components/index.js +21 -0
  117. package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
  118. package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
  119. package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
  120. package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
  121. package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
  122. package/management-ui/src/components/monitoring/index.js +6 -0
  123. package/management-ui/src/components/monitoring/monitoring.css +218 -0
  124. package/management-ui/src/components/theme-provider.jsx +52 -0
  125. package/management-ui/src/components/theme-toggle.jsx +39 -0
  126. package/management-ui/src/components/ui/badge.tsx +36 -0
  127. package/management-ui/src/components/ui/button.test.jsx +56 -0
  128. package/management-ui/src/components/ui/button.tsx +57 -0
  129. package/management-ui/src/components/ui/card.tsx +76 -0
  130. package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
  131. package/management-ui/src/components/ui/select.tsx +157 -0
  132. package/management-ui/src/components/ui/skeleton.jsx +15 -0
  133. package/management-ui/src/hooks/useFrigg.jsx +387 -0
  134. package/management-ui/src/hooks/useSocket.jsx +58 -0
  135. package/management-ui/src/index.css +193 -0
  136. package/management-ui/src/lib/utils.ts +6 -0
  137. package/management-ui/src/main.jsx +10 -0
  138. package/management-ui/src/pages/CodeGeneration.jsx +14 -0
  139. package/management-ui/src/pages/Connections.jsx +252 -0
  140. package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
  141. package/management-ui/src/pages/Dashboard.jsx +311 -0
  142. package/management-ui/src/pages/Environment.jsx +314 -0
  143. package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
  144. package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
  145. package/management-ui/src/pages/IntegrationTest.jsx +742 -0
  146. package/management-ui/src/pages/Integrations.jsx +253 -0
  147. package/management-ui/src/pages/Monitoring.jsx +17 -0
  148. package/management-ui/src/pages/Simulation.jsx +155 -0
  149. package/management-ui/src/pages/Users.jsx +492 -0
  150. package/management-ui/src/services/api.js +41 -0
  151. package/management-ui/src/services/apiModuleService.js +193 -0
  152. package/management-ui/src/services/websocket-handlers.js +120 -0
  153. package/management-ui/src/test/api/project.test.js +273 -0
  154. package/management-ui/src/test/components/Welcome.test.jsx +378 -0
  155. package/management-ui/src/test/mocks/server.js +178 -0
  156. package/management-ui/src/test/setup.js +61 -0
  157. package/management-ui/src/test/utils/test-utils.jsx +134 -0
  158. package/management-ui/src/utils/repository.js +98 -0
  159. package/management-ui/src/utils/repository.test.js +118 -0
  160. package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
  161. package/management-ui/tailwind.config.js +63 -0
  162. package/management-ui/tsconfig.json +37 -0
  163. package/management-ui/tsconfig.node.json +10 -0
  164. package/management-ui/vite.config.js +26 -0
  165. package/management-ui/vitest.config.js +38 -0
  166. package/package.json +7 -17
  167. package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +0 -326
  168. package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +0 -337
  169. package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +0 -373
  170. package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +0 -313
  171. package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +0 -269
  172. package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +0 -82
  173. package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +0 -408
  174. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +0 -583
  175. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +0 -314
  176. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +0 -430
  177. package/frigg-cli/__tests__/unit/commands/init.test.js +0 -406
  178. package/frigg-cli/__tests__/unit/commands/repair.test.js +0 -275
  179. package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +0 -411
  180. package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +0 -405
  181. package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +0 -496
  182. package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +0 -474
  183. package/frigg-cli/__tests__/unit/utils/output.test.js +0 -196
  184. package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +0 -93
  185. package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +0 -93
  186. package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +0 -103
  187. package/frigg-cli/container.js +0 -172
  188. package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +0 -286
  189. package/frigg-cli/domain/entities/ApiModule.js +0 -272
  190. package/frigg-cli/domain/entities/AppDefinition.js +0 -227
  191. package/frigg-cli/domain/entities/Integration.js +0 -198
  192. package/frigg-cli/domain/exceptions/DomainException.js +0 -24
  193. package/frigg-cli/domain/ports/IApiModuleRepository.js +0 -53
  194. package/frigg-cli/domain/ports/IAppDefinitionRepository.js +0 -43
  195. package/frigg-cli/domain/ports/IIntegrationRepository.js +0 -61
  196. package/frigg-cli/domain/services/IntegrationValidator.js +0 -185
  197. package/frigg-cli/domain/value-objects/IntegrationId.js +0 -42
  198. package/frigg-cli/domain/value-objects/IntegrationName.js +0 -60
  199. package/frigg-cli/domain/value-objects/SemanticVersion.js +0 -70
  200. package/frigg-cli/infrastructure/UnitOfWork.js +0 -46
  201. package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +0 -197
  202. package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +0 -224
  203. package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +0 -249
  204. package/frigg-cli/infrastructure/adapters/SchemaValidator.js +0 -92
  205. package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +0 -373
  206. package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +0 -116
  207. package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +0 -277
  208. package/frigg-cli/package-lock.json +0 -16226
  209. package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +0 -376
  210. package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +0 -591
  211. package/frigg-cli/start-command/infrastructure/DockerAdapter.js +0 -306
  212. package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +0 -329
  213. package/frigg-cli/templates/backend/.env.example +0 -62
  214. package/frigg-cli/templates/backend/.eslintrc.json +0 -12
  215. package/frigg-cli/templates/backend/.prettierrc +0 -6
  216. package/frigg-cli/templates/backend/docker-compose.yml +0 -22
  217. package/frigg-cli/templates/backend/index.js +0 -96
  218. package/frigg-cli/templates/backend/infrastructure.js +0 -12
  219. package/frigg-cli/templates/backend/jest.config.js +0 -17
  220. package/frigg-cli/templates/backend/package.json +0 -50
  221. package/frigg-cli/templates/backend/src/api-modules/.gitkeep +0 -10
  222. package/frigg-cli/templates/backend/src/base/.gitkeep +0 -7
  223. package/frigg-cli/templates/backend/src/integrations/.gitkeep +0 -10
  224. package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +0 -65
  225. package/frigg-cli/templates/backend/src/utils/.gitkeep +0 -7
  226. package/frigg-cli/templates/backend/test/setup.js +0 -30
  227. package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
  228. package/frigg-cli/templates/backend/ui-extensions/README.md +0 -77
  229. package/frigg-cli/utils/__tests__/repo-detection.test.js +0 -436
  230. package/frigg-cli/utils/output.js +0 -382
  231. package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +0 -205
  232. package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +0 -104
  233. package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +0 -153
  234. package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +0 -162
  235. package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +0 -152
  236. package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +0 -332
  237. package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +0 -191
  238. package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +0 -146
  239. package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +0 -155
  240. package/frigg-cli/validate-command/adapters/cli/validate-command.js +0 -199
  241. package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +0 -35
  242. package/frigg-cli/validate-command/domain/entities/validation-result.js +0 -74
  243. package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +0 -74
  244. package/frigg-cli/validate-command/domain/value-objects/validation-error.js +0 -68
  245. package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +0 -181
  246. package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +0 -128
  247. package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +0 -113
@@ -1,185 +0,0 @@
1
- const {DomainException, ValidationException} = require('../exceptions/DomainException');
2
-
3
- /**
4
- * IntegrationValidator Domain Service
5
- *
6
- * Centralizes validation logic that involves multiple entities or external checks
7
- * Complements the entity's self-validation by handling cross-cutting concerns
8
- */
9
- class IntegrationValidator {
10
- constructor(integrationRepository) {
11
- this.integrationRepository = integrationRepository;
12
- }
13
-
14
- /**
15
- * Validate that integration name is unique
16
- * @param {IntegrationName} name - Integration name to check
17
- * @returns {Promise<{isValid: boolean, errors: string[]}>}
18
- */
19
- async validateUniqueness(name) {
20
- const exists = await this.integrationRepository.exists(name);
21
-
22
- if (exists) {
23
- return {
24
- isValid: false,
25
- errors: [`Integration with name '${name.value}' already exists`]
26
- };
27
- }
28
-
29
- return {
30
- isValid: true,
31
- errors: []
32
- };
33
- }
34
-
35
- /**
36
- * Validate integration against business rules
37
- * Combines entity validation with domain-level rules
38
- *
39
- * @param {Integration} integration - Integration entity to validate
40
- * @returns {Promise<{isValid: boolean, errors: string[]}>}
41
- */
42
- async validate(integration) {
43
- const errors = [];
44
-
45
- // 1. Entity self-validation
46
- const entityValidation = integration.validate();
47
- if (!entityValidation.isValid) {
48
- errors.push(...entityValidation.errors);
49
- }
50
-
51
- // 2. Uniqueness check
52
- const uniquenessValidation = await this.validateUniqueness(integration.name);
53
- if (!uniquenessValidation.isValid) {
54
- errors.push(...uniquenessValidation.errors);
55
- }
56
-
57
- // 3. Additional domain rules
58
- const domainRules = this.validateDomainRules(integration);
59
- if (!domainRules.isValid) {
60
- errors.push(...domainRules.errors);
61
- }
62
-
63
- return {
64
- isValid: errors.length === 0,
65
- errors
66
- };
67
- }
68
-
69
- /**
70
- * Validate domain-specific business rules
71
- * These are rules that apply across the domain, not just to one entity
72
- *
73
- * @param {Integration} integration
74
- * @returns {{isValid: boolean, errors: string[]}}
75
- */
76
- validateDomainRules(integration) {
77
- const errors = [];
78
-
79
- // Rule: Webhook integrations must have webhook capability
80
- if (integration.type === 'webhook' && !integration.capabilities.webhooks) {
81
- errors.push('Webhook integrations must have webhooks capability enabled');
82
- }
83
-
84
- // Rule: Sync integrations should have bidirectional capability
85
- if (integration.type === 'sync' && integration.capabilities.sync && !integration.capabilities.sync.bidirectional) {
86
- // This is a warning, not an error - sync can be unidirectional
87
- // But we'll log it for the developer's awareness
88
- }
89
-
90
- // Rule: OAuth2 integrations must have auth capability
91
- if (integration.capabilities.auth && integration.capabilities.auth.includes('oauth2')) {
92
- // This is good - OAuth2 should be in auth array
93
- }
94
-
95
- // Rule: Integrations with realtime capability should have websocket requirements
96
- if (integration.capabilities.realtime) {
97
- if (!integration.requirements || !integration.requirements.websocket) {
98
- // Warn but don't fail - they might add it later
99
- }
100
- }
101
-
102
- // Rule: Integration should have at least one entity or be marked as entityless
103
- if (Object.keys(integration.entities).length === 0) {
104
- // This is unusual but not invalid - might be a transform-only integration
105
- // We don't add an error, just note it
106
- }
107
-
108
- return {
109
- isValid: errors.length === 0,
110
- errors
111
- };
112
- }
113
-
114
- /**
115
- * Validate integration configuration before update
116
- * Ensures updates don't violate domain rules
117
- *
118
- * @param {Integration} existingIntegration
119
- * @param {Integration} updatedIntegration
120
- * @returns {{isValid: boolean, errors: string[]}}
121
- */
122
- validateUpdate(existingIntegration, updatedIntegration) {
123
- const errors = [];
124
-
125
- // Rule: Cannot change integration name
126
- if (!existingIntegration.name.equals(updatedIntegration.name)) {
127
- errors.push('Integration name cannot be changed after creation');
128
- }
129
-
130
- // Rule: Version must be incremented, not decremented
131
- if (existingIntegration.version.isGreaterThan(updatedIntegration.version)) {
132
- errors.push('Cannot downgrade integration version');
133
- }
134
-
135
- // Rule: Cannot remove entities that have existing data
136
- // (This would require checking with a data repository in real implementation)
137
- const removedEntities = Object.keys(existingIntegration.entities)
138
- .filter(key => !updatedIntegration.entities[key]);
139
-
140
- if (removedEntities.length > 0) {
141
- errors.push(`Cannot remove entities with potential existing data: ${removedEntities.join(', ')}`);
142
- }
143
-
144
- return {
145
- isValid: errors.length === 0,
146
- errors
147
- };
148
- }
149
-
150
- /**
151
- * Validate API module addition
152
- * Ensures API module can be safely added to integration
153
- *
154
- * @param {Integration} integration
155
- * @param {string} moduleName
156
- * @param {string} moduleVersion
157
- * @returns {{isValid: boolean, errors: string[]}}
158
- */
159
- validateApiModuleAddition(integration, moduleName, moduleVersion) {
160
- const errors = [];
161
-
162
- // Check if module already exists
163
- if (integration.hasApiModule(moduleName)) {
164
- errors.push(`API module '${moduleName}' is already added to this integration`);
165
- }
166
-
167
- // Validate module name format
168
- if (!moduleName || moduleName.trim().length === 0) {
169
- errors.push('API module name is required');
170
- }
171
-
172
- // Validate version format (should be semantic version)
173
- const versionPattern = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/;
174
- if (!versionPattern.test(moduleVersion)) {
175
- errors.push(`Invalid API module version format: ${moduleVersion}. Must be semantic version (e.g., 1.0.0)`);
176
- }
177
-
178
- return {
179
- isValid: errors.length === 0,
180
- errors
181
- };
182
- }
183
- }
184
-
185
- module.exports = {IntegrationValidator};
@@ -1,42 +0,0 @@
1
- const {DomainException} = require('../exceptions/DomainException');
2
- const crypto = require('crypto');
3
-
4
- /**
5
- * IntegrationId Value Object
6
- * Unique identifier for integrations
7
- */
8
- class IntegrationId {
9
- constructor(value) {
10
- if (value) {
11
- // Use provided ID
12
- if (typeof value !== 'string' || value.length === 0) {
13
- throw new DomainException('Integration ID must be a non-empty string');
14
- }
15
- this._value = value;
16
- } else {
17
- // Generate new ID
18
- this._value = crypto.randomUUID();
19
- }
20
- }
21
-
22
- get value() {
23
- return this._value;
24
- }
25
-
26
- equals(other) {
27
- if (!(other instanceof IntegrationId)) {
28
- return false;
29
- }
30
- return this._value === other._value;
31
- }
32
-
33
- toString() {
34
- return this._value;
35
- }
36
-
37
- static generate() {
38
- return new IntegrationId();
39
- }
40
- }
41
-
42
- module.exports = {IntegrationId};
@@ -1,60 +0,0 @@
1
- const {DomainException} = require('../exceptions/DomainException');
2
-
3
- /**
4
- * IntegrationName Value Object
5
- * Ensures integration names follow kebab-case format
6
- */
7
- class IntegrationName {
8
- constructor(value) {
9
- if (!value || typeof value !== 'string') {
10
- throw new DomainException('Integration name must be a non-empty string');
11
- }
12
-
13
- this._value = value;
14
- this._validate();
15
- }
16
-
17
- _validate() {
18
- const rules = [
19
- {
20
- test: () => /^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(this._value),
21
- message: 'Name must be kebab-case (lowercase letters, numbers, and hyphens only)'
22
- },
23
- {
24
- test: () => this._value.length >= 2 && this._value.length <= 100,
25
- message: 'Name must be between 2 and 100 characters'
26
- },
27
- {
28
- test: () => !this._value.startsWith('-') && !this._value.endsWith('-'),
29
- message: 'Name cannot start or end with a hyphen'
30
- },
31
- {
32
- test: () => !this._value.includes('--'),
33
- message: 'Name cannot contain consecutive hyphens'
34
- }
35
- ];
36
-
37
- for (const rule of rules) {
38
- if (!rule.test()) {
39
- throw new DomainException(rule.message);
40
- }
41
- }
42
- }
43
-
44
- get value() {
45
- return this._value;
46
- }
47
-
48
- equals(other) {
49
- if (!(other instanceof IntegrationName)) {
50
- return false;
51
- }
52
- return this._value === other._value;
53
- }
54
-
55
- toString() {
56
- return this._value;
57
- }
58
- }
59
-
60
- module.exports = {IntegrationName};
@@ -1,70 +0,0 @@
1
- const {DomainException} = require('../exceptions/DomainException');
2
- const semver = require('semver');
3
-
4
- /**
5
- * SemanticVersion Value Object
6
- * Ensures versions follow semantic versioning
7
- */
8
- class SemanticVersion {
9
- constructor(value) {
10
- if (!value || typeof value !== 'string') {
11
- throw new DomainException('Version must be a non-empty string');
12
- }
13
-
14
- if (!semver.valid(value)) {
15
- throw new DomainException(
16
- `Invalid semantic version: ${value}. Must follow format X.Y.Z (e.g., 1.0.0)`
17
- );
18
- }
19
-
20
- this._value = value;
21
- this._parsed = semver.parse(value);
22
- }
23
-
24
- get value() {
25
- return this._value;
26
- }
27
-
28
- get major() {
29
- return this._parsed.major;
30
- }
31
-
32
- get minor() {
33
- return this._parsed.minor;
34
- }
35
-
36
- get patch() {
37
- return this._parsed.patch;
38
- }
39
-
40
- get prerelease() {
41
- return this._parsed.prerelease;
42
- }
43
-
44
- equals(other) {
45
- if (!(other instanceof SemanticVersion)) {
46
- return false;
47
- }
48
- return this._value === other._value;
49
- }
50
-
51
- isGreaterThan(other) {
52
- if (!(other instanceof SemanticVersion)) {
53
- throw new DomainException('Can only compare with another SemanticVersion');
54
- }
55
- return semver.gt(this._value, other._value);
56
- }
57
-
58
- isLessThan(other) {
59
- if (!(other instanceof SemanticVersion)) {
60
- throw new DomainException('Can only compare with another SemanticVersion');
61
- }
62
- return semver.lt(this._value, other._value);
63
- }
64
-
65
- toString() {
66
- return this._value;
67
- }
68
- }
69
-
70
- module.exports = {SemanticVersion};
@@ -1,46 +0,0 @@
1
- /**
2
- * UnitOfWork
3
- * Coordinates transactions across repositories
4
- */
5
- class UnitOfWork {
6
- constructor(fileSystemAdapter) {
7
- this.fileSystemAdapter = fileSystemAdapter;
8
- this.repositories = new Map();
9
- }
10
-
11
- /**
12
- * Register a repository
13
- */
14
- registerRepository(name, repository) {
15
- this.repositories.set(name, repository);
16
- return this;
17
- }
18
-
19
- /**
20
- * Commit all tracked operations
21
- */
22
- async commit() {
23
- try {
24
- await this.fileSystemAdapter.commit();
25
- return {success: true};
26
- } catch (error) {
27
- throw new Error(`Failed to commit transaction: ${error.message}`);
28
- }
29
- }
30
-
31
- /**
32
- * Rollback all tracked operations
33
- */
34
- async rollback() {
35
- return await this.fileSystemAdapter.rollback();
36
- }
37
-
38
- /**
39
- * Clear tracked operations without commit/rollback
40
- */
41
- clear() {
42
- this.fileSystemAdapter.clear();
43
- }
44
- }
45
-
46
- module.exports = {UnitOfWork};
@@ -1,197 +0,0 @@
1
- const path = require('path');
2
- const fs = require('fs-extra');
3
-
4
- /**
5
- * BackendJsUpdater
6
- *
7
- * Infrastructure service for updating backend.js file with new integrations
8
- * Uses AST manipulation to safely add integration imports and registrations
9
- */
10
- class BackendJsUpdater {
11
- constructor(fileSystemAdapter, backendPath) {
12
- this.fileSystemAdapter = fileSystemAdapter;
13
- this.backendPath = backendPath;
14
- this.indexJsPath = path.join(backendPath, 'index.js');
15
- }
16
-
17
- /**
18
- * Register an integration in backend/index.js
19
- * @param {string} integrationName - kebab-case integration name
20
- * @returns {Promise<void>}
21
- */
22
- async registerIntegration(integrationName) {
23
- if (!await this.fileSystemAdapter.exists(this.indexJsPath)) {
24
- throw new Error('backend/index.js not found');
25
- }
26
-
27
- const className = this._toClassName(integrationName);
28
- const importPath = `./src/integrations/${className}Integration`;
29
-
30
- await this.fileSystemAdapter.updateFile(this.indexJsPath, (content) => {
31
- return this._addIntegration(content, className, integrationName, importPath);
32
- });
33
- }
34
-
35
- /**
36
- * Remove an integration from backend/index.js
37
- * @param {string} integrationName
38
- * @returns {Promise<void>}
39
- */
40
- async unregisterIntegration(integrationName) {
41
- if (!await this.fileSystemAdapter.exists(this.indexJsPath)) {
42
- throw new Error('backend/index.js not found');
43
- }
44
-
45
- const className = this._toClassName(integrationName);
46
-
47
- await this.fileSystemAdapter.updateFile(this.indexJsPath, (content) => {
48
- return this._removeIntegration(content, className, integrationName);
49
- });
50
- }
51
-
52
- /**
53
- * Add integration to backend.js content
54
- * Simple string manipulation approach (can be replaced with AST parsing if needed)
55
- *
56
- * @param {string} content - Current backend.js content
57
- * @param {string} className - Integration class name
58
- * @param {string} integrationName - kebab-case name
59
- * @param {string} importPath - relative import path
60
- * @returns {string} - Updated content
61
- */
62
- _addIntegration(content, className, integrationName, importPath) {
63
- // Check if integration is already registered
64
- if (content.includes(`const ${className}Integration`)) {
65
- console.warn(`Integration ${integrationName} is already registered in backend.js`);
66
- return content;
67
- }
68
-
69
- let updated = content;
70
-
71
- // 1. Add import statement after other integration imports
72
- const importRegex = /(const \w+Integration = require\('\.\/src\/integrations\/[^']+'\);)/g;
73
- const importMatches = [...content.matchAll(importRegex)];
74
-
75
- if (importMatches.length > 0) {
76
- // Add after last integration import
77
- const lastImport = importMatches[importMatches.length - 1];
78
- const insertIndex = lastImport.index + lastImport[0].length;
79
- const importStatement = `\nconst ${className}Integration = require('${importPath}');`;
80
- updated = updated.slice(0, insertIndex) + importStatement + updated.slice(insertIndex);
81
- } else {
82
- // No existing imports - add at the top after requires
83
- const requiresRegex = /const .+ = require\([^)]+\);/g;
84
- const requireMatches = [...content.matchAll(requiresRegex)];
85
- if (requireMatches.length > 0) {
86
- const lastRequire = requireMatches[requireMatches.length - 1];
87
- const insertIndex = lastRequire.index + lastRequire[0].length;
88
- const importStatement = `\n\n// Integrations\nconst ${className}Integration = require('${importPath}');`;
89
- updated = updated.slice(0, insertIndex) + importStatement + updated.slice(insertIndex);
90
- }
91
- }
92
-
93
- // 2. Add to integrations array
94
- // Look for patterns:
95
- // - const integrations = [...]
96
- // - integrations: [...] (inside appDefinition object)
97
-
98
- // Try standalone array first
99
- const standaloneArrayRegex = /const integrations = \[([\s\S]*?)\];/;
100
- let match = updated.match(standaloneArrayRegex);
101
-
102
- if (match) {
103
- const currentArray = match[1];
104
- const newEntry = `\n ${className}Integration,`;
105
-
106
- // Check if it's an empty array
107
- if (currentArray.trim() === '') {
108
- updated = updated.replace(standaloneArrayRegex, `const integrations = [${newEntry}\n];`);
109
- } else {
110
- // Add to existing array
111
- const insertAt = match.index + match[0].length - 2; // Before ];
112
- updated = updated.slice(0, insertAt) + ',' + newEntry + updated.slice(insertAt);
113
- }
114
- } else {
115
- // Try appDefinition pattern
116
- const appDefArrayRegex = /integrations:\s*\[([\s\S]*?)\]/;
117
- match = updated.match(appDefArrayRegex);
118
-
119
- if (match) {
120
- const currentArray = match[1];
121
- const newEntry = `\n ${className}Integration,`;
122
-
123
- // Check if array is empty or has only comments
124
- const hasOnlyComments = currentArray.trim() === '' ||
125
- currentArray.trim().split('\n').every(line => line.trim().startsWith('//'));
126
-
127
- if (hasOnlyComments) {
128
- // Replace entire array content
129
- updated = updated.replace(appDefArrayRegex, `integrations: [${newEntry}\n ]`);
130
- } else {
131
- // Add to existing array - find the last entry and add comma if needed
132
- const lines = currentArray.split('\n');
133
- const lastNonEmptyLine = lines.reverse().find(line => line.trim() && !line.trim().startsWith('//'));
134
- const needsComma = lastNonEmptyLine && !lastNonEmptyLine.trim().endsWith(',');
135
- const comma = needsComma ? ',' : '';
136
-
137
- const insertAt = match.index + match[0].length - 1; // Before ]
138
- updated = updated.slice(0, insertAt) + comma + newEntry + '\n ' + updated.slice(insertAt);
139
- }
140
- } else {
141
- // No integrations array found - this is a problem
142
- console.warn('Could not find integrations array in backend/index.js');
143
- }
144
- }
145
-
146
- return updated;
147
- }
148
-
149
- /**
150
- * Remove integration from backend.js content
151
- *
152
- * @param {string} content
153
- * @param {string} className
154
- * @param {string} integrationName
155
- * @returns {string}
156
- */
157
- _removeIntegration(content, className, integrationName) {
158
- let updated = content;
159
-
160
- // 1. Remove import statement
161
- const importRegex = new RegExp(`\\nconst ${className}Integration = require\\([^)]+\\);`, 'g');
162
- updated = updated.replace(importRegex, '');
163
-
164
- // 2. Remove from integrations array
165
- const arrayEntryRegex = new RegExp(`,?\\s*${className}Integration,?`, 'g');
166
- updated = updated.replace(arrayEntryRegex, '');
167
-
168
- // Clean up extra commas
169
- updated = updated.replace(/,\s*,/g, ',');
170
- updated = updated.replace(/\[\s*,/g, '[');
171
- updated = updated.replace(/,\s*\]/g, ']');
172
-
173
- return updated;
174
- }
175
-
176
- /**
177
- * Convert kebab-case to ClassName
178
- * @param {string} kebabCase
179
- * @returns {string}
180
- */
181
- _toClassName(kebabCase) {
182
- return kebabCase
183
- .split('-')
184
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
185
- .join('');
186
- }
187
-
188
- /**
189
- * Check if backend/index.js exists
190
- * @returns {Promise<boolean>}
191
- */
192
- async exists() {
193
- return await this.fileSystemAdapter.exists(this.indexJsPath);
194
- }
195
- }
196
-
197
- module.exports = {BackendJsUpdater};