@friggframework/devtools 2.0.0--canary.520.6641121.0 → 2.0.0--canary.522.cbd3d5a.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 (118) hide show
  1. package/frigg-cli/README.md +1 -1
  2. package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +326 -0
  3. package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +337 -0
  4. package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +373 -0
  5. package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +313 -0
  6. package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +269 -0
  7. package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +82 -0
  8. package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +408 -0
  9. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +583 -0
  10. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +314 -0
  11. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +430 -0
  12. package/frigg-cli/__tests__/unit/commands/doctor.test.js +0 -2
  13. package/frigg-cli/__tests__/unit/commands/init.test.js +406 -0
  14. package/frigg-cli/__tests__/unit/commands/install.test.js +21 -17
  15. package/frigg-cli/__tests__/unit/commands/repair.test.js +275 -0
  16. package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +411 -0
  17. package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +405 -0
  18. package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +496 -0
  19. package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +474 -0
  20. package/frigg-cli/__tests__/unit/utils/output.test.js +196 -0
  21. package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +93 -0
  22. package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +93 -0
  23. package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +103 -0
  24. package/frigg-cli/container.js +172 -0
  25. package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +286 -0
  26. package/frigg-cli/doctor-command/index.js +17 -16
  27. package/frigg-cli/domain/entities/ApiModule.js +272 -0
  28. package/frigg-cli/domain/entities/AppDefinition.js +227 -0
  29. package/frigg-cli/domain/entities/Integration.js +198 -0
  30. package/frigg-cli/domain/exceptions/DomainException.js +24 -0
  31. package/frigg-cli/domain/ports/IApiModuleRepository.js +53 -0
  32. package/frigg-cli/domain/ports/IAppDefinitionRepository.js +43 -0
  33. package/frigg-cli/domain/ports/IIntegrationRepository.js +61 -0
  34. package/frigg-cli/domain/services/IntegrationValidator.js +185 -0
  35. package/frigg-cli/domain/value-objects/IntegrationId.js +42 -0
  36. package/frigg-cli/domain/value-objects/IntegrationName.js +60 -0
  37. package/frigg-cli/domain/value-objects/SemanticVersion.js +70 -0
  38. package/frigg-cli/index.js +21 -6
  39. package/frigg-cli/index.test.js +7 -1
  40. package/frigg-cli/infrastructure/UnitOfWork.js +46 -0
  41. package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +197 -0
  42. package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +224 -0
  43. package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +249 -0
  44. package/frigg-cli/infrastructure/adapters/SchemaValidator.js +92 -0
  45. package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +373 -0
  46. package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +116 -0
  47. package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +277 -0
  48. package/frigg-cli/init-command/backend-first-handler.js +124 -42
  49. package/frigg-cli/init-command/index.js +2 -1
  50. package/frigg-cli/init-command/template-handler.js +13 -3
  51. package/frigg-cli/install-command/backend-js.js +3 -3
  52. package/frigg-cli/install-command/environment-variables.js +16 -19
  53. package/frigg-cli/install-command/environment-variables.test.js +12 -13
  54. package/frigg-cli/install-command/index.js +14 -9
  55. package/frigg-cli/install-command/integration-file.js +3 -3
  56. package/frigg-cli/install-command/validate-package.js +5 -9
  57. package/frigg-cli/jest.config.js +4 -1
  58. package/frigg-cli/package-lock.json +16226 -0
  59. package/frigg-cli/repair-command/index.js +101 -128
  60. package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +376 -0
  61. package/frigg-cli/start-command/index.js +246 -2
  62. package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +591 -0
  63. package/frigg-cli/start-command/infrastructure/DockerAdapter.js +306 -0
  64. package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +329 -0
  65. package/frigg-cli/templates/backend/.env.example +62 -0
  66. package/frigg-cli/templates/backend/.eslintrc.json +12 -0
  67. package/frigg-cli/templates/backend/.prettierrc +6 -0
  68. package/frigg-cli/templates/backend/docker-compose.yml +22 -0
  69. package/frigg-cli/templates/backend/index.js +96 -0
  70. package/frigg-cli/templates/backend/infrastructure.js +12 -0
  71. package/frigg-cli/templates/backend/jest.config.js +17 -0
  72. package/frigg-cli/templates/backend/package.json +50 -0
  73. package/frigg-cli/templates/backend/src/api-modules/.gitkeep +10 -0
  74. package/frigg-cli/templates/backend/src/base/.gitkeep +7 -0
  75. package/frigg-cli/templates/backend/src/integrations/.gitkeep +10 -0
  76. package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +65 -0
  77. package/frigg-cli/templates/backend/src/utils/.gitkeep +7 -0
  78. package/frigg-cli/templates/backend/test/setup.js +30 -0
  79. package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
  80. package/frigg-cli/templates/backend/ui-extensions/README.md +77 -0
  81. package/frigg-cli/ui-command/index.js +58 -36
  82. package/frigg-cli/utils/__tests__/repo-detection.test.js +436 -0
  83. package/frigg-cli/utils/output.js +382 -0
  84. package/frigg-cli/utils/repo-detection.js +85 -37
  85. package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +205 -0
  86. package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +104 -0
  87. package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +153 -0
  88. package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +162 -0
  89. package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +152 -0
  90. package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +332 -0
  91. package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +191 -0
  92. package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +146 -0
  93. package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +155 -0
  94. package/frigg-cli/validate-command/adapters/cli/validate-command.js +199 -0
  95. package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +35 -0
  96. package/frigg-cli/validate-command/domain/entities/validation-result.js +74 -0
  97. package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +74 -0
  98. package/frigg-cli/validate-command/domain/value-objects/validation-error.js +68 -0
  99. package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +181 -0
  100. package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +128 -0
  101. package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +113 -0
  102. package/infrastructure/docs/iam-policy-templates.md +1 -1
  103. package/infrastructure/domains/admin-scripts/admin-script-builder.js +200 -0
  104. package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +499 -0
  105. package/infrastructure/domains/admin-scripts/index.js +5 -0
  106. package/infrastructure/domains/networking/vpc-builder.test.js +2 -4
  107. package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
  108. package/infrastructure/domains/shared/cloudformation-discovery.test.js +4 -7
  109. package/infrastructure/domains/shared/resource-discovery.js +5 -5
  110. package/infrastructure/domains/shared/types/app-definition.js +21 -0
  111. package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
  112. package/infrastructure/domains/shared/utilities/base-definition-factory.js +10 -1
  113. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
  114. package/infrastructure/infrastructure-composer.js +2 -0
  115. package/infrastructure/infrastructure-composer.test.js +2 -2
  116. package/management-ui/README.md +245 -109
  117. package/package.json +8 -7
  118. package/frigg-cli/install-command/logger.js +0 -12
@@ -0,0 +1,314 @@
1
+ const {FileSystemAppDefinitionRepository} = require('../../../infrastructure/repositories/FileSystemAppDefinitionRepository');
2
+ const {AppDefinition} = require('../../../domain/entities/AppDefinition');
3
+
4
+ describe('FileSystemAppDefinitionRepository', () => {
5
+ let repository;
6
+ let mockFileSystemAdapter;
7
+ let mockSchemaValidator;
8
+ let projectRoot;
9
+
10
+ beforeEach(() => {
11
+ projectRoot = '/test/project';
12
+
13
+ mockFileSystemAdapter = {
14
+ exists: jest.fn(),
15
+ ensureDirectory: jest.fn(),
16
+ writeFile: jest.fn(),
17
+ updateFile: jest.fn(),
18
+ readFile: jest.fn(),
19
+ };
20
+
21
+ mockSchemaValidator = {
22
+ validate: jest.fn(),
23
+ };
24
+
25
+ repository = new FileSystemAppDefinitionRepository(
26
+ mockFileSystemAdapter,
27
+ projectRoot,
28
+ mockSchemaValidator
29
+ );
30
+ });
31
+
32
+ describe('load', () => {
33
+ it('should load app definition from file', async () => {
34
+ const appDefJson = {
35
+ name: 'my-frigg-app',
36
+ version: '1.0.0',
37
+ description: 'Test app',
38
+ integrations: ['integration-1'],
39
+ apiModules: ['salesforce', 'stripe'],
40
+ };
41
+
42
+ mockFileSystemAdapter.exists.mockResolvedValue(true);
43
+ mockFileSystemAdapter.readFile.mockResolvedValue(JSON.stringify(appDefJson));
44
+
45
+ const result = await repository.load();
46
+
47
+ expect(result).toBeInstanceOf(AppDefinition);
48
+ expect(result.name).toBe('my-frigg-app');
49
+ expect(result.version.value).toBe('1.0.0');
50
+ expect(result.integrations).toEqual(['integration-1']);
51
+ expect(result.apiModules).toEqual(['salesforce', 'stripe']);
52
+ });
53
+
54
+ it('should return null if app definition does not exist', async () => {
55
+ mockFileSystemAdapter.exists.mockResolvedValue(false);
56
+
57
+ const result = await repository.load();
58
+
59
+ expect(result).toBeNull();
60
+ });
61
+
62
+ it('should handle missing integrations array', async () => {
63
+ const appDefJson = {
64
+ name: 'my-frigg-app',
65
+ version: '1.0.0',
66
+ // no integrations field
67
+ };
68
+
69
+ mockFileSystemAdapter.exists.mockResolvedValue(true);
70
+ mockFileSystemAdapter.readFile.mockResolvedValue(JSON.stringify(appDefJson));
71
+
72
+ const result = await repository.load();
73
+
74
+ expect(result).toBeInstanceOf(AppDefinition);
75
+ expect(result.integrations).toEqual([]);
76
+ expect(result.apiModules).toEqual([]);
77
+ });
78
+ });
79
+
80
+ describe('save', () => {
81
+ it('should save app definition to file', async () => {
82
+ const appDef = AppDefinition.create({
83
+ name: 'my-frigg-app',
84
+ version: '1.0.0',
85
+ description: 'Test app',
86
+ });
87
+
88
+ mockSchemaValidator.validate.mockResolvedValue({valid: true, errors: []});
89
+ mockFileSystemAdapter.exists.mockResolvedValue(false);
90
+
91
+ await repository.save(appDef);
92
+
93
+ expect(mockFileSystemAdapter.ensureDirectory).toHaveBeenCalledWith(
94
+ '/test/project/backend'
95
+ );
96
+ expect(mockFileSystemAdapter.writeFile).toHaveBeenCalledWith(
97
+ '/test/project/backend/app-definition.json',
98
+ expect.stringContaining('"name": "my-frigg-app"')
99
+ );
100
+ });
101
+
102
+ it('should update existing app definition file', async () => {
103
+ const appDef = AppDefinition.create({
104
+ name: 'my-frigg-app',
105
+ version: '1.0.0',
106
+ description: 'Test app',
107
+ });
108
+
109
+ mockSchemaValidator.validate.mockResolvedValue({valid: true, errors: []});
110
+ mockFileSystemAdapter.exists.mockResolvedValue(true);
111
+
112
+ await repository.save(appDef);
113
+
114
+ expect(mockFileSystemAdapter.updateFile).toHaveBeenCalled();
115
+ expect(mockFileSystemAdapter.writeFile).not.toHaveBeenCalled();
116
+ });
117
+
118
+ it('should throw error if validation fails', async () => {
119
+ const appDef = AppDefinition.create({
120
+ name: 'my-frigg-app',
121
+ version: '1.0.0',
122
+ });
123
+
124
+ // Mock validate to return invalid
125
+ jest.spyOn(appDef, 'validate').mockReturnValue({
126
+ isValid: false,
127
+ errors: ['Invalid configuration'],
128
+ });
129
+
130
+ await expect(repository.save(appDef)).rejects.toThrow(
131
+ 'AppDefinition validation failed'
132
+ );
133
+ });
134
+
135
+ it('should throw error if schema validation fails', async () => {
136
+ const appDef = AppDefinition.create({
137
+ name: 'my-frigg-app',
138
+ version: '1.0.0',
139
+ });
140
+
141
+ mockSchemaValidator.validate.mockResolvedValue({
142
+ valid: false,
143
+ errors: ['Invalid schema'],
144
+ });
145
+
146
+ await expect(repository.save(appDef)).rejects.toThrow(
147
+ 'Schema validation failed'
148
+ );
149
+ });
150
+
151
+ it('should save with integrations and API modules', async () => {
152
+ const appDef = AppDefinition.create({
153
+ name: 'my-frigg-app',
154
+ version: '1.0.0',
155
+ });
156
+
157
+ appDef.registerIntegration('test-integration', {
158
+ name: 'test-integration',
159
+ version: '1.0.0',
160
+ type: 'api',
161
+ });
162
+
163
+ appDef.registerApiModule('salesforce', {
164
+ name: 'salesforce',
165
+ version: '1.0.0',
166
+ authType: 'oauth2',
167
+ });
168
+
169
+ mockSchemaValidator.validate.mockResolvedValue({valid: true, errors: []});
170
+ mockFileSystemAdapter.exists.mockResolvedValue(false);
171
+
172
+ await repository.save(appDef);
173
+
174
+ const writeCall = mockFileSystemAdapter.writeFile.mock.calls[0];
175
+ const savedData = JSON.parse(writeCall[1]);
176
+
177
+ // AppDefinition stores integrations and apiModules as objects
178
+ expect(savedData.integrations).toEqual([{
179
+ name: 'test-integration',
180
+ enabled: true,
181
+ }]);
182
+ // apiModules include name, source, and version object
183
+ expect(savedData.apiModules).toHaveLength(1);
184
+ expect(savedData.apiModules[0].name).toBe('salesforce');
185
+ expect(savedData.apiModules[0].source).toBe('npm'); // default source
186
+ });
187
+
188
+ it('should format JSON with 2-space indentation', async () => {
189
+ const appDef = AppDefinition.create({
190
+ name: 'my-frigg-app',
191
+ version: '1.0.0',
192
+ });
193
+
194
+ mockSchemaValidator.validate.mockResolvedValue({valid: true, errors: []});
195
+ mockFileSystemAdapter.exists.mockResolvedValue(false);
196
+
197
+ await repository.save(appDef);
198
+
199
+ const writeCall = mockFileSystemAdapter.writeFile.mock.calls[0];
200
+ const content = writeCall[1];
201
+
202
+ // Check for 2-space indentation
203
+ expect(content).toMatch(/{\n "name"/);
204
+ });
205
+ });
206
+
207
+ describe('exists', () => {
208
+ it('should return true if app definition exists', async () => {
209
+ mockFileSystemAdapter.exists.mockResolvedValue(true);
210
+
211
+ const result = await repository.exists();
212
+
213
+ expect(result).toBe(true);
214
+ expect(mockFileSystemAdapter.exists).toHaveBeenCalledWith(
215
+ '/test/project/backend/app-definition.json'
216
+ );
217
+ });
218
+
219
+ it('should return false if app definition does not exist', async () => {
220
+ mockFileSystemAdapter.exists.mockResolvedValue(false);
221
+
222
+ const result = await repository.exists();
223
+
224
+ expect(result).toBe(false);
225
+ });
226
+ });
227
+
228
+ describe('create', () => {
229
+ it('should create new app definition', async () => {
230
+ mockFileSystemAdapter.exists.mockResolvedValue(false);
231
+ mockSchemaValidator.validate.mockResolvedValue({valid: true, errors: []});
232
+
233
+ const result = await repository.create({
234
+ name: 'my-frigg-app',
235
+ version: '1.0.0',
236
+ description: 'Test app',
237
+ });
238
+
239
+ expect(result).toBeInstanceOf(AppDefinition);
240
+ expect(result.name).toBe('my-frigg-app');
241
+ expect(mockFileSystemAdapter.writeFile).toHaveBeenCalled();
242
+ });
243
+
244
+ it('should throw error if app definition already exists', async () => {
245
+ mockFileSystemAdapter.exists.mockResolvedValue(true);
246
+
247
+ await expect(
248
+ repository.create({
249
+ name: 'my-frigg-app',
250
+ version: '1.0.0',
251
+ })
252
+ ).rejects.toThrow('App definition already exists');
253
+ });
254
+
255
+ it('should validate and save created app definition', async () => {
256
+ mockFileSystemAdapter.exists.mockResolvedValue(false);
257
+ mockSchemaValidator.validate.mockResolvedValue({valid: true, errors: []});
258
+
259
+ await repository.create({
260
+ name: 'my-frigg-app',
261
+ version: '1.0.0',
262
+ });
263
+
264
+ expect(mockSchemaValidator.validate).toHaveBeenCalledWith(
265
+ 'app-definition',
266
+ expect.any(Object)
267
+ );
268
+ expect(mockFileSystemAdapter.writeFile).toHaveBeenCalled();
269
+ });
270
+ });
271
+
272
+ describe('_toDomainEntity', () => {
273
+ it('should convert JSON to AppDefinition entity', () => {
274
+ const data = {
275
+ name: 'my-frigg-app',
276
+ version: '1.0.0',
277
+ description: 'Test app',
278
+ author: 'Test Author',
279
+ license: 'MIT',
280
+ repository: 'https://github.com/test/repo',
281
+ integrations: ['integration-1'],
282
+ apiModules: ['salesforce'],
283
+ config: {env: 'production'},
284
+ };
285
+
286
+ const result = repository._toDomainEntity(data);
287
+
288
+ expect(result).toBeInstanceOf(AppDefinition);
289
+ expect(result.name).toBe('my-frigg-app');
290
+ expect(result.version.value).toBe('1.0.0');
291
+ expect(result.description).toBe('Test app');
292
+ expect(result.author).toBe('Test Author');
293
+ expect(result.license).toBe('MIT');
294
+ expect(result.repository).toBe('https://github.com/test/repo');
295
+ expect(result.integrations).toEqual(['integration-1']);
296
+ expect(result.apiModules).toEqual(['salesforce']);
297
+ expect(result.config).toEqual({env: 'production'});
298
+ });
299
+
300
+ it('should handle minimal data', () => {
301
+ const data = {
302
+ name: 'my-frigg-app',
303
+ version: '1.0.0',
304
+ };
305
+
306
+ const result = repository._toDomainEntity(data);
307
+
308
+ expect(result).toBeInstanceOf(AppDefinition);
309
+ expect(result.integrations).toEqual([]);
310
+ expect(result.apiModules).toEqual([]);
311
+ expect(result.config).toEqual({});
312
+ });
313
+ });
314
+ });