@friggframework/devtools 2.0.0--canary.522.923dfae.0 → 2.0.0--canary.540.c5ef83f.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 (119) hide show
  1. package/frigg-cli/README.md +1 -1
  2. package/frigg-cli/__tests__/unit/commands/doctor.test.js +2 -0
  3. package/frigg-cli/__tests__/unit/commands/install.test.js +19 -23
  4. package/frigg-cli/__tests__/unit/dependencies.test.js +2 -2
  5. package/frigg-cli/doctor-command/index.js +16 -17
  6. package/frigg-cli/index.js +6 -21
  7. package/frigg-cli/index.test.js +2 -7
  8. package/frigg-cli/init-command/backend-first-handler.js +42 -124
  9. package/frigg-cli/init-command/index.js +1 -2
  10. package/frigg-cli/init-command/template-handler.js +3 -13
  11. package/frigg-cli/install-command/backend-js.js +3 -3
  12. package/frigg-cli/install-command/environment-variables.js +19 -16
  13. package/frigg-cli/install-command/environment-variables.test.js +13 -12
  14. package/frigg-cli/install-command/index.js +9 -14
  15. package/frigg-cli/install-command/integration-file.js +3 -3
  16. package/frigg-cli/install-command/logger.js +12 -0
  17. package/frigg-cli/install-command/validate-package.js +9 -5
  18. package/frigg-cli/jest.config.js +1 -4
  19. package/frigg-cli/repair-command/index.js +128 -101
  20. package/frigg-cli/start-command/index.js +2 -246
  21. package/frigg-cli/ui-command/index.js +36 -58
  22. package/frigg-cli/utils/repo-detection.js +37 -85
  23. package/infrastructure/docs/iam-policy-templates.md +1 -1
  24. package/infrastructure/domains/networking/vpc-builder.test.js +4 -2
  25. package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
  26. package/infrastructure/domains/shared/cloudformation-discovery.test.js +7 -4
  27. package/infrastructure/domains/shared/resource-discovery.js +5 -5
  28. package/infrastructure/domains/shared/types/app-definition.js +0 -21
  29. package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
  30. package/infrastructure/domains/shared/utilities/base-definition-factory.js +1 -10
  31. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
  32. package/infrastructure/infrastructure-composer.test.js +2 -2
  33. package/management-ui/README.md +109 -245
  34. package/package.json +7 -8
  35. package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +0 -326
  36. package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +0 -337
  37. package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +0 -373
  38. package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +0 -313
  39. package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +0 -269
  40. package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +0 -82
  41. package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +0 -408
  42. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +0 -583
  43. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +0 -314
  44. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +0 -383
  45. package/frigg-cli/__tests__/unit/commands/init.test.js +0 -406
  46. package/frigg-cli/__tests__/unit/commands/repair.test.js +0 -275
  47. package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +0 -411
  48. package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +0 -405
  49. package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +0 -496
  50. package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +0 -474
  51. package/frigg-cli/__tests__/unit/utils/output.test.js +0 -196
  52. package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +0 -93
  53. package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +0 -93
  54. package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +0 -103
  55. package/frigg-cli/container.js +0 -172
  56. package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +0 -286
  57. package/frigg-cli/domain/entities/ApiModule.js +0 -272
  58. package/frigg-cli/domain/entities/AppDefinition.js +0 -227
  59. package/frigg-cli/domain/entities/Integration.js +0 -198
  60. package/frigg-cli/domain/exceptions/DomainException.js +0 -24
  61. package/frigg-cli/domain/ports/IApiModuleRepository.js +0 -53
  62. package/frigg-cli/domain/ports/IAppDefinitionRepository.js +0 -43
  63. package/frigg-cli/domain/ports/IIntegrationRepository.js +0 -61
  64. package/frigg-cli/domain/services/IntegrationValidator.js +0 -185
  65. package/frigg-cli/domain/value-objects/IntegrationId.js +0 -42
  66. package/frigg-cli/domain/value-objects/IntegrationName.js +0 -60
  67. package/frigg-cli/domain/value-objects/SemanticVersion.js +0 -70
  68. package/frigg-cli/infrastructure/UnitOfWork.js +0 -46
  69. package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +0 -197
  70. package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +0 -224
  71. package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +0 -249
  72. package/frigg-cli/infrastructure/adapters/SchemaValidator.js +0 -92
  73. package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +0 -373
  74. package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +0 -116
  75. package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +0 -277
  76. package/frigg-cli/package-lock.json +0 -16226
  77. package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +0 -376
  78. package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +0 -591
  79. package/frigg-cli/start-command/infrastructure/DockerAdapter.js +0 -306
  80. package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +0 -329
  81. package/frigg-cli/templates/backend/.env.example +0 -62
  82. package/frigg-cli/templates/backend/.eslintrc.json +0 -12
  83. package/frigg-cli/templates/backend/.prettierrc +0 -6
  84. package/frigg-cli/templates/backend/docker-compose.yml +0 -22
  85. package/frigg-cli/templates/backend/index.js +0 -96
  86. package/frigg-cli/templates/backend/infrastructure.js +0 -12
  87. package/frigg-cli/templates/backend/jest.config.js +0 -17
  88. package/frigg-cli/templates/backend/package.json +0 -50
  89. package/frigg-cli/templates/backend/src/api-modules/.gitkeep +0 -10
  90. package/frigg-cli/templates/backend/src/base/.gitkeep +0 -7
  91. package/frigg-cli/templates/backend/src/integrations/.gitkeep +0 -10
  92. package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +0 -65
  93. package/frigg-cli/templates/backend/src/utils/.gitkeep +0 -7
  94. package/frigg-cli/templates/backend/test/setup.js +0 -30
  95. package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
  96. package/frigg-cli/templates/backend/ui-extensions/README.md +0 -77
  97. package/frigg-cli/utils/__tests__/repo-detection.test.js +0 -436
  98. package/frigg-cli/utils/output.js +0 -382
  99. package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +0 -205
  100. package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +0 -104
  101. package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +0 -153
  102. package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +0 -162
  103. package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +0 -152
  104. package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +0 -332
  105. package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +0 -191
  106. package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +0 -146
  107. package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +0 -155
  108. package/frigg-cli/validate-command/adapters/cli/validate-command.js +0 -199
  109. package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +0 -35
  110. package/frigg-cli/validate-command/domain/entities/validation-result.js +0 -74
  111. package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +0 -74
  112. package/frigg-cli/validate-command/domain/value-objects/validation-error.js +0 -68
  113. package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +0 -181
  114. package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +0 -128
  115. package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +0 -113
  116. package/infrastructure/domains/admin-scripts/admin-script-builder.js +0 -200
  117. package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +0 -499
  118. package/infrastructure/domains/admin-scripts/index.js +0 -5
  119. package/infrastructure/jest.config.js +0 -16
@@ -1,373 +0,0 @@
1
- const {ApiModule} = require('../../../domain/entities/ApiModule');
2
- const {DomainException} = require('../../../domain/exceptions/DomainException');
3
-
4
- describe('ApiModule Entity', () => {
5
- describe('create()', () => {
6
- test('successfully creates a new API module with required fields', () => {
7
- const apiModule = ApiModule.create({
8
- name: 'salesforce',
9
- displayName: 'Salesforce',
10
- apiConfig: {
11
- baseUrl: 'https://api.salesforce.com',
12
- authType: 'oauth2',
13
- version: 'v1'
14
- }
15
- });
16
-
17
- expect(apiModule.name).toBe('salesforce');
18
- expect(apiModule.displayName).toBe('Salesforce');
19
- expect(apiModule.apiConfig.baseUrl).toBe('https://api.salesforce.com');
20
- expect(apiModule.apiConfig.authType).toBe('oauth2');
21
- expect(apiModule.apiConfig.version).toBe('v1');
22
- expect(apiModule.version.value).toBe('1.0.0');
23
- expect(apiModule.entities).toEqual({});
24
- expect(apiModule.scopes).toEqual([]);
25
- expect(apiModule.credentials).toEqual([]);
26
- });
27
-
28
- test('generates displayName from name if not provided', () => {
29
- const apiModule = ApiModule.create({
30
- name: 'stripe-payment-api',
31
- apiConfig: {authType: 'api-key'}
32
- });
33
-
34
- expect(apiModule.displayName).toBe('Stripe Payment Api');
35
- });
36
-
37
- test('accepts semantic version', () => {
38
- const apiModule = ApiModule.create({
39
- name: 'hubspot',
40
- version: '2.5.0',
41
- apiConfig: {authType: 'oauth2'}
42
- });
43
-
44
- expect(apiModule.version.value).toBe('2.5.0');
45
- });
46
-
47
- test('throws error when name is missing', () => {
48
- expect(() => {
49
- ApiModule.create({
50
- apiConfig: {authType: 'oauth2'}
51
- });
52
- }).toThrow(DomainException);
53
- });
54
-
55
- test('throws error when name is invalid', () => {
56
- expect(() => {
57
- ApiModule.create({
58
- name: 'Invalid Name!',
59
- apiConfig: {authType: 'oauth2'}
60
- });
61
- }).toThrow();
62
- });
63
-
64
- test('throws error when authType is missing', () => {
65
- expect(() => {
66
- ApiModule.create({
67
- name: 'salesforce',
68
- apiConfig: {}
69
- });
70
- }).toThrow(DomainException);
71
- });
72
- });
73
-
74
- describe('addEntity()', () => {
75
- test('successfully adds an entity', () => {
76
- const apiModule = ApiModule.create({
77
- name: 'salesforce',
78
- apiConfig: {authType: 'oauth2'}
79
- });
80
-
81
- apiModule.addEntity('account', {
82
- label: 'Salesforce Account',
83
- required: true,
84
- fields: ['id', 'name', 'email']
85
- });
86
-
87
- expect(apiModule.hasEntity('account')).toBe(true);
88
- expect(apiModule.entities.account.label).toBe('Salesforce Account');
89
- expect(apiModule.entities.account.required).toBe(true);
90
- expect(apiModule.entities.account.fields).toEqual(['id', 'name', 'email']);
91
- });
92
-
93
- test('generates label from entity name if not provided', () => {
94
- const apiModule = ApiModule.create({
95
- name: 'salesforce',
96
- apiConfig: {authType: 'oauth2'}
97
- });
98
-
99
- apiModule.addEntity('contact', {});
100
-
101
- expect(apiModule.entities.contact.label).toBe('contact');
102
- });
103
-
104
- test('sets required to true by default', () => {
105
- const apiModule = ApiModule.create({
106
- name: 'salesforce',
107
- apiConfig: {authType: 'oauth2'}
108
- });
109
-
110
- apiModule.addEntity('lead', {});
111
-
112
- expect(apiModule.entities.lead.required).toBe(true);
113
- });
114
-
115
- test('throws error when entity already exists', () => {
116
- const apiModule = ApiModule.create({
117
- name: 'salesforce',
118
- apiConfig: {authType: 'oauth2'}
119
- });
120
-
121
- apiModule.addEntity('account', {});
122
-
123
- expect(() => {
124
- apiModule.addEntity('account', {});
125
- }).toThrow(DomainException);
126
- expect(() => {
127
- apiModule.addEntity('account', {});
128
- }).toThrow("Entity 'account' already exists");
129
- });
130
- });
131
-
132
- describe('addEndpoint()', () => {
133
- test('successfully adds an endpoint', () => {
134
- const apiModule = ApiModule.create({
135
- name: 'salesforce',
136
- apiConfig: {authType: 'oauth2'}
137
- });
138
-
139
- apiModule.addEndpoint('getAccount', {
140
- method: 'GET',
141
- path: '/services/data/v1/accounts/:id',
142
- description: 'Get account by ID'
143
- });
144
-
145
- expect(apiModule.hasEndpoint('getAccount')).toBe(true);
146
- expect(apiModule.endpoints.getAccount.method).toBe('GET');
147
- expect(apiModule.endpoints.getAccount.path).toBe('/services/data/v1/accounts/:id');
148
- });
149
-
150
- test('throws error when endpoint already exists', () => {
151
- const apiModule = ApiModule.create({
152
- name: 'salesforce',
153
- apiConfig: {authType: 'oauth2'}
154
- });
155
-
156
- apiModule.addEndpoint('getAccount', {method: 'GET', path: '/accounts'});
157
-
158
- expect(() => {
159
- apiModule.addEndpoint('getAccount', {method: 'POST', path: '/accounts'});
160
- }).toThrow(DomainException);
161
- });
162
- });
163
-
164
- describe('addScope()', () => {
165
- test('successfully adds a scope', () => {
166
- const apiModule = ApiModule.create({
167
- name: 'salesforce',
168
- apiConfig: {authType: 'oauth2'}
169
- });
170
-
171
- apiModule.addScope('read:accounts');
172
-
173
- expect(apiModule.scopes).toContain('read:accounts');
174
- });
175
-
176
- test('prevents duplicate scopes', () => {
177
- const apiModule = ApiModule.create({
178
- name: 'salesforce',
179
- apiConfig: {authType: 'oauth2'}
180
- });
181
-
182
- apiModule.addScope('read:accounts');
183
-
184
- expect(() => {
185
- apiModule.addScope('read:accounts');
186
- }).toThrow(DomainException);
187
- expect(() => {
188
- apiModule.addScope('read:accounts');
189
- }).toThrow("Scope 'read:accounts' already exists");
190
- });
191
- });
192
-
193
- describe('addCredential()', () => {
194
- test('successfully adds a credential', () => {
195
- const apiModule = ApiModule.create({
196
- name: 'salesforce',
197
- apiConfig: {authType: 'oauth2'}
198
- });
199
-
200
- apiModule.addCredential('clientId', {
201
- type: 'string',
202
- description: 'OAuth client ID',
203
- required: true,
204
- envVar: 'SALESFORCE_CLIENT_ID'
205
- });
206
-
207
- expect(apiModule.hasCredential('clientId')).toBe(true);
208
- expect(apiModule.credentials[0].name).toBe('clientId');
209
- expect(apiModule.credentials[0].type).toBe('string');
210
- expect(apiModule.credentials[0].required).toBe(true);
211
- });
212
-
213
- test('sets required to true by default', () => {
214
- const apiModule = ApiModule.create({
215
- name: 'salesforce',
216
- apiConfig: {authType: 'oauth2'}
217
- });
218
-
219
- apiModule.addCredential('apiKey', {type: 'string'});
220
-
221
- expect(apiModule.credentials[0].required).toBe(true);
222
- });
223
-
224
- test('throws error when credential already exists', () => {
225
- const apiModule = ApiModule.create({
226
- name: 'salesforce',
227
- apiConfig: {authType: 'oauth2'}
228
- });
229
-
230
- apiModule.addCredential('clientId', {type: 'string'});
231
-
232
- expect(() => {
233
- apiModule.addCredential('clientId', {type: 'string'});
234
- }).toThrow(DomainException);
235
- });
236
- });
237
-
238
- describe('validate()', () => {
239
- test('validates successfully with required fields', () => {
240
- const apiModule = ApiModule.create({
241
- name: 'salesforce',
242
- displayName: 'Salesforce',
243
- apiConfig: {
244
- authType: 'oauth2',
245
- baseUrl: 'https://api.salesforce.com'
246
- }
247
- });
248
-
249
- const result = apiModule.validate();
250
-
251
- expect(result.isValid).toBe(true);
252
- expect(result.errors).toEqual([]);
253
- });
254
-
255
- test('fails when displayName is empty', () => {
256
- const apiModule = ApiModule.create({
257
- name: 'salesforce',
258
- apiConfig: {authType: 'oauth2'}
259
- });
260
- apiModule.displayName = '';
261
-
262
- const result = apiModule.validate();
263
-
264
- expect(result.isValid).toBe(false);
265
- expect(result.errors).toContain('Display name is required');
266
- });
267
-
268
- test('fails when authType is missing', () => {
269
- const apiModule = ApiModule.create({
270
- name: 'salesforce',
271
- apiConfig: {authType: 'oauth2'}
272
- });
273
- apiModule.apiConfig.authType = '';
274
-
275
- const result = apiModule.validate();
276
-
277
- expect(result.isValid).toBe(false);
278
- expect(result.errors).toContain('Authentication type is required');
279
- });
280
-
281
- test('fails when authType is invalid', () => {
282
- const apiModule = ApiModule.create({
283
- name: 'salesforce',
284
- apiConfig: {authType: 'oauth2'}
285
- });
286
- apiModule.apiConfig.authType = 'invalid-type';
287
-
288
- const result = apiModule.validate();
289
-
290
- expect(result.isValid).toBe(false);
291
- expect(result.errors[0]).toContain('Invalid auth type');
292
- });
293
- });
294
-
295
- describe('toObject()', () => {
296
- test('converts to plain object with all properties', () => {
297
- const apiModule = ApiModule.create({
298
- name: 'salesforce',
299
- displayName: 'Salesforce',
300
- description: 'Salesforce CRM API',
301
- version: '1.2.0',
302
- apiConfig: {
303
- baseUrl: 'https://api.salesforce.com',
304
- authType: 'oauth2',
305
- version: 'v1'
306
- }
307
- });
308
-
309
- apiModule.addEntity('account', {label: 'Account'});
310
- apiModule.addScope('read:accounts');
311
- apiModule.addCredential('clientId', {type: 'string'});
312
-
313
- const obj = apiModule.toObject();
314
-
315
- expect(obj.name).toBe('salesforce');
316
- expect(obj.displayName).toBe('Salesforce');
317
- expect(obj.description).toBe('Salesforce CRM API');
318
- expect(obj.version).toBe('1.2.0');
319
- expect(obj.apiConfig.authType).toBe('oauth2');
320
- expect(obj.entities).toHaveProperty('account');
321
- expect(obj.scopes).toContain('read:accounts');
322
- expect(obj.credentials).toHaveLength(1);
323
- expect(obj.createdAt).toBeInstanceOf(Date);
324
- expect(obj.updatedAt).toBeInstanceOf(Date);
325
- });
326
- });
327
-
328
- describe('toJSON()', () => {
329
- test('converts to JSON format for api-module-definition.json', () => {
330
- const apiModule = ApiModule.create({
331
- name: 'salesforce',
332
- displayName: 'Salesforce',
333
- description: 'Salesforce CRM API',
334
- version: '1.2.0',
335
- apiConfig: {
336
- baseUrl: 'https://api.salesforce.com',
337
- authType: 'oauth2',
338
- version: 'v1'
339
- }
340
- });
341
-
342
- const json = apiModule.toJSON();
343
-
344
- expect(json.name).toBe('salesforce');
345
- expect(json.version).toBe('1.2.0');
346
- expect(json.display.name).toBe('Salesforce');
347
- expect(json.display.description).toBe('Salesforce CRM API');
348
- expect(json.api.authType).toBe('oauth2');
349
- });
350
- });
351
-
352
- describe('fromObject()', () => {
353
- test('reconstructs ApiModule from plain object', () => {
354
- const originalModule = ApiModule.create({
355
- name: 'salesforce',
356
- displayName: 'Salesforce',
357
- version: '1.0.0',
358
- apiConfig: {authType: 'oauth2'}
359
- });
360
-
361
- originalModule.addEntity('account', {label: 'Account'});
362
- originalModule.addScope('read:accounts');
363
-
364
- const obj = originalModule.toObject();
365
- const reconstructed = ApiModule.fromObject(obj);
366
-
367
- expect(reconstructed.name).toBe('salesforce');
368
- expect(reconstructed.displayName).toBe('Salesforce');
369
- expect(reconstructed.hasEntity('account')).toBe(true);
370
- expect(reconstructed.scopes).toContain('read:accounts');
371
- });
372
- });
373
- });
@@ -1,313 +0,0 @@
1
- const {AppDefinition} = require('../../../domain/entities/AppDefinition');
2
- const {DomainException} = require('../../../domain/exceptions/DomainException');
3
-
4
- describe('AppDefinition', () => {
5
- describe('create', () => {
6
- test('creates app definition with minimal props', () => {
7
- const appDef = AppDefinition.create({
8
- name: 'my-app',
9
- version: '1.0.0'
10
- });
11
-
12
- expect(appDef.name).toBe('my-app');
13
- expect(appDef.version.value).toBe('1.0.0');
14
- expect(appDef.integrations).toEqual([]);
15
- expect(appDef.apiModules).toEqual([]);
16
- });
17
-
18
- test('creates app definition with full props', () => {
19
- const appDef = AppDefinition.create({
20
- name: 'my-app',
21
- version: '1.0.0',
22
- description: 'My application',
23
- author: 'John Doe',
24
- license: 'MIT',
25
- repository: {url: 'https://github.com/user/repo'},
26
- config: {feature1: true}
27
- });
28
-
29
- expect(appDef.description).toBe('My application');
30
- expect(appDef.author).toBe('John Doe');
31
- expect(appDef.license).toBe('MIT');
32
- expect(appDef.repository.url).toBe('https://github.com/user/repo');
33
- expect(appDef.config.feature1).toBe(true);
34
- });
35
- });
36
-
37
- describe('registerIntegration', () => {
38
- test('successfully registers new integration', () => {
39
- const appDef = AppDefinition.create({
40
- name: 'my-app',
41
- version: '1.0.0'
42
- });
43
-
44
- appDef.registerIntegration('salesforce-sync');
45
-
46
- expect(appDef.hasIntegration('salesforce-sync')).toBe(true);
47
- expect(appDef.integrations).toHaveLength(1);
48
- expect(appDef.integrations[0].name).toBe('salesforce-sync');
49
- expect(appDef.integrations[0].enabled).toBe(true);
50
- });
51
-
52
- test('throws error when registering duplicate integration', () => {
53
- const appDef = AppDefinition.create({
54
- name: 'my-app',
55
- version: '1.0.0'
56
- });
57
-
58
- appDef.registerIntegration('salesforce-sync');
59
-
60
- expect(() => {
61
- appDef.registerIntegration('salesforce-sync');
62
- }).toThrow(DomainException);
63
- expect(() => {
64
- appDef.registerIntegration('salesforce-sync');
65
- }).toThrow("already registered");
66
- });
67
-
68
- test('updates updatedAt timestamp', () => {
69
- const appDef = AppDefinition.create({
70
- name: 'my-app',
71
- version: '1.0.0'
72
- });
73
-
74
- const beforeTime = appDef.updatedAt.getTime();
75
- appDef.registerIntegration('test-integration');
76
- const afterTime = appDef.updatedAt.getTime();
77
-
78
- expect(afterTime).toBeGreaterThanOrEqual(beforeTime);
79
- });
80
- });
81
-
82
- describe('unregisterIntegration', () => {
83
- test('successfully unregisters integration', () => {
84
- const appDef = AppDefinition.create({
85
- name: 'my-app',
86
- version: '1.0.0'
87
- });
88
-
89
- appDef.registerIntegration('salesforce-sync');
90
- appDef.unregisterIntegration('salesforce-sync');
91
-
92
- expect(appDef.hasIntegration('salesforce-sync')).toBe(false);
93
- expect(appDef.integrations).toHaveLength(0);
94
- });
95
-
96
- test('throws error when unregistering non-existent integration', () => {
97
- const appDef = AppDefinition.create({
98
- name: 'my-app',
99
- version: '1.0.0'
100
- });
101
-
102
- expect(() => {
103
- appDef.unregisterIntegration('non-existent');
104
- }).toThrow(DomainException);
105
- expect(() => {
106
- appDef.unregisterIntegration('non-existent');
107
- }).toThrow("not registered");
108
- });
109
- });
110
-
111
- describe('hasIntegration', () => {
112
- test('returns true for registered integration', () => {
113
- const appDef = AppDefinition.create({
114
- name: 'my-app',
115
- version: '1.0.0'
116
- });
117
-
118
- appDef.registerIntegration('test-integration');
119
-
120
- expect(appDef.hasIntegration('test-integration')).toBe(true);
121
- });
122
-
123
- test('returns false for unregistered integration', () => {
124
- const appDef = AppDefinition.create({
125
- name: 'my-app',
126
- version: '1.0.0'
127
- });
128
-
129
- expect(appDef.hasIntegration('non-existent')).toBe(false);
130
- });
131
- });
132
-
133
- describe('enableIntegration', () => {
134
- test('enables integration', () => {
135
- const appDef = AppDefinition.create({
136
- name: 'my-app',
137
- version: '1.0.0'
138
- });
139
-
140
- appDef.registerIntegration('test-integration');
141
- appDef.disableIntegration('test-integration');
142
- appDef.enableIntegration('test-integration');
143
-
144
- const integration = appDef.integrations.find(i => i.name === 'test-integration');
145
- expect(integration.enabled).toBe(true);
146
- });
147
-
148
- test('throws error for non-existent integration', () => {
149
- const appDef = AppDefinition.create({
150
- name: 'my-app',
151
- version: '1.0.0'
152
- });
153
-
154
- expect(() => {
155
- appDef.enableIntegration('non-existent');
156
- }).toThrow(DomainException);
157
- });
158
- });
159
-
160
- describe('disableIntegration', () => {
161
- test('disables integration', () => {
162
- const appDef = AppDefinition.create({
163
- name: 'my-app',
164
- version: '1.0.0'
165
- });
166
-
167
- appDef.registerIntegration('test-integration');
168
- appDef.disableIntegration('test-integration');
169
-
170
- const integration = appDef.integrations.find(i => i.name === 'test-integration');
171
- expect(integration.enabled).toBe(false);
172
- });
173
-
174
- test('throws error for non-existent integration', () => {
175
- const appDef = AppDefinition.create({
176
- name: 'my-app',
177
- version: '1.0.0'
178
- });
179
-
180
- expect(() => {
181
- appDef.disableIntegration('non-existent');
182
- }).toThrow(DomainException);
183
- });
184
- });
185
-
186
- describe('registerApiModule', () => {
187
- test('registers new API module', () => {
188
- const appDef = AppDefinition.create({
189
- name: 'my-app',
190
- version: '1.0.0'
191
- });
192
-
193
- appDef.registerApiModule('salesforce', '2.0.0', 'npm');
194
-
195
- expect(appDef.hasApiModule('salesforce')).toBe(true);
196
- expect(appDef.apiModules).toHaveLength(1);
197
- expect(appDef.apiModules[0].name).toBe('salesforce');
198
- expect(appDef.apiModules[0].version).toBe('2.0.0');
199
- expect(appDef.apiModules[0].source).toBe('npm');
200
- });
201
-
202
- test('throws error for duplicate API module', () => {
203
- const appDef = AppDefinition.create({
204
- name: 'my-app',
205
- version: '1.0.0'
206
- });
207
-
208
- appDef.registerApiModule('salesforce', '2.0.0');
209
-
210
- expect(() => {
211
- appDef.registerApiModule('salesforce', '3.0.0');
212
- }).toThrow(DomainException);
213
- });
214
- });
215
-
216
- describe('getEnabledIntegrations', () => {
217
- test('returns only enabled integrations', () => {
218
- const appDef = AppDefinition.create({
219
- name: 'my-app',
220
- version: '1.0.0'
221
- });
222
-
223
- appDef.registerIntegration('integration1');
224
- appDef.registerIntegration('integration2');
225
- appDef.registerIntegration('integration3');
226
- appDef.disableIntegration('integration2');
227
-
228
- const enabled = appDef.getEnabledIntegrations();
229
-
230
- expect(enabled).toHaveLength(2);
231
- expect(enabled.map(i => i.name)).toContain('integration1');
232
- expect(enabled.map(i => i.name)).toContain('integration3');
233
- expect(enabled.map(i => i.name)).not.toContain('integration2');
234
- });
235
- });
236
-
237
- describe('validate', () => {
238
- test('passes for valid app definition', () => {
239
- const appDef = AppDefinition.create({
240
- name: 'my-app',
241
- version: '1.0.0',
242
- description: 'A valid app'
243
- });
244
-
245
- const result = appDef.validate();
246
-
247
- expect(result.isValid).toBe(true);
248
- expect(result.errors).toHaveLength(0);
249
- });
250
-
251
- test('fails when name is missing', () => {
252
- const appDef = AppDefinition.create({
253
- name: '',
254
- version: '1.0.0'
255
- });
256
-
257
- const result = appDef.validate();
258
-
259
- expect(result.isValid).toBe(false);
260
- expect(result.errors).toContain('App name is required');
261
- });
262
-
263
- test('fails when name is too long', () => {
264
- const appDef = AppDefinition.create({
265
- name: 'a'.repeat(101),
266
- version: '1.0.0'
267
- });
268
-
269
- const result = appDef.validate();
270
-
271
- expect(result.isValid).toBe(false);
272
- expect(result.errors.some(e => e.includes('100 characters or less'))).toBe(true);
273
- });
274
-
275
- test('fails when description is too long', () => {
276
- const appDef = AppDefinition.create({
277
- name: 'my-app',
278
- version: '1.0.0',
279
- description: 'a'.repeat(1001)
280
- });
281
-
282
- const result = appDef.validate();
283
-
284
- expect(result.isValid).toBe(false);
285
- expect(result.errors.some(e => e.includes('1000 characters or less'))).toBe(true);
286
- });
287
- });
288
-
289
- describe('toJSON', () => {
290
- test('converts to JSON format', () => {
291
- const appDef = AppDefinition.create({
292
- name: 'my-app',
293
- version: '1.0.0',
294
- description: 'Test app',
295
- author: 'John Doe'
296
- });
297
-
298
- appDef.registerIntegration('test-integration');
299
- appDef.registerApiModule('salesforce', '2.0.0', 'npm');
300
-
301
- const json = appDef.toJSON();
302
-
303
- expect(json.name).toBe('my-app');
304
- expect(json.version).toBe('1.0.0');
305
- expect(json.description).toBe('Test app');
306
- expect(json.author).toBe('John Doe');
307
- expect(json.integrations).toHaveLength(1);
308
- expect(json.integrations[0].name).toBe('test-integration');
309
- expect(json.apiModules).toHaveLength(1);
310
- expect(json.apiModules[0].name).toBe('salesforce');
311
- });
312
- });
313
- });