@friggframework/devtools 2.0.0--canary.545.e256e95.0 → 2.0.0--canary.553.dc5f898.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 (129) hide show
  1. package/frigg-cli/README.md +1 -1
  2. package/frigg-cli/__tests__/unit/commands/build.test.js +1 -1
  3. package/frigg-cli/__tests__/unit/commands/doctor.test.js +2 -0
  4. package/frigg-cli/__tests__/unit/commands/install.test.js +19 -23
  5. package/frigg-cli/__tests__/unit/dependencies.test.js +2 -2
  6. package/frigg-cli/build-command/index.js +11 -123
  7. package/frigg-cli/deploy-command/index.js +1 -83
  8. package/frigg-cli/doctor-command/index.js +16 -37
  9. package/frigg-cli/generate-iam-command.js +1 -21
  10. package/frigg-cli/index.js +6 -21
  11. package/frigg-cli/index.test.js +2 -7
  12. package/frigg-cli/init-command/backend-first-handler.js +42 -124
  13. package/frigg-cli/init-command/index.js +1 -2
  14. package/frigg-cli/init-command/template-handler.js +3 -13
  15. package/frigg-cli/install-command/backend-js.js +3 -3
  16. package/frigg-cli/install-command/environment-variables.js +19 -16
  17. package/frigg-cli/install-command/environment-variables.test.js +13 -12
  18. package/frigg-cli/install-command/index.js +9 -14
  19. package/frigg-cli/install-command/integration-file.js +3 -3
  20. package/frigg-cli/install-command/logger.js +12 -0
  21. package/frigg-cli/install-command/validate-package.js +9 -5
  22. package/frigg-cli/jest.config.js +1 -4
  23. package/frigg-cli/repair-command/index.js +128 -121
  24. package/frigg-cli/start-command/index.js +2 -324
  25. package/frigg-cli/ui-command/index.js +36 -58
  26. package/frigg-cli/utils/repo-detection.js +37 -85
  27. package/infrastructure/create-frigg-infrastructure.js +0 -93
  28. package/infrastructure/docs/iam-policy-templates.md +1 -1
  29. package/infrastructure/domains/integration/integration-builder.js +3 -2
  30. package/infrastructure/domains/integration/integration-builder.test.js +54 -2
  31. package/infrastructure/domains/networking/vpc-builder.test.js +4 -2
  32. package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
  33. package/infrastructure/domains/shared/resource-discovery.js +5 -5
  34. package/infrastructure/domains/shared/types/app-definition.js +0 -35
  35. package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
  36. package/infrastructure/domains/shared/utilities/base-definition-factory.js +1 -10
  37. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
  38. package/infrastructure/infrastructure-composer.js +0 -2
  39. package/infrastructure/infrastructure-composer.test.js +6 -5
  40. package/management-ui/README.md +109 -245
  41. package/package.json +7 -8
  42. package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +0 -326
  43. package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +0 -337
  44. package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +0 -373
  45. package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +0 -313
  46. package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +0 -269
  47. package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +0 -82
  48. package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +0 -408
  49. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +0 -583
  50. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +0 -314
  51. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +0 -383
  52. package/frigg-cli/__tests__/unit/commands/init.test.js +0 -406
  53. package/frigg-cli/__tests__/unit/commands/provider-dispatch.test.js +0 -383
  54. package/frigg-cli/__tests__/unit/commands/repair.test.js +0 -275
  55. package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +0 -411
  56. package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +0 -405
  57. package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +0 -496
  58. package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +0 -474
  59. package/frigg-cli/__tests__/unit/utils/output.test.js +0 -196
  60. package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +0 -93
  61. package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +0 -93
  62. package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +0 -103
  63. package/frigg-cli/container.js +0 -172
  64. package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +0 -286
  65. package/frigg-cli/domain/entities/ApiModule.js +0 -272
  66. package/frigg-cli/domain/entities/AppDefinition.js +0 -227
  67. package/frigg-cli/domain/entities/Integration.js +0 -198
  68. package/frigg-cli/domain/exceptions/DomainException.js +0 -24
  69. package/frigg-cli/domain/ports/IApiModuleRepository.js +0 -53
  70. package/frigg-cli/domain/ports/IAppDefinitionRepository.js +0 -43
  71. package/frigg-cli/domain/ports/IIntegrationRepository.js +0 -61
  72. package/frigg-cli/domain/services/IntegrationValidator.js +0 -185
  73. package/frigg-cli/domain/value-objects/IntegrationId.js +0 -42
  74. package/frigg-cli/domain/value-objects/IntegrationName.js +0 -60
  75. package/frigg-cli/domain/value-objects/SemanticVersion.js +0 -70
  76. package/frigg-cli/infrastructure/UnitOfWork.js +0 -46
  77. package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +0 -197
  78. package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +0 -224
  79. package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +0 -249
  80. package/frigg-cli/infrastructure/adapters/SchemaValidator.js +0 -92
  81. package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +0 -373
  82. package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +0 -116
  83. package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +0 -277
  84. package/frigg-cli/package-lock.json +0 -16226
  85. package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +0 -376
  86. package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +0 -591
  87. package/frigg-cli/start-command/infrastructure/DockerAdapter.js +0 -306
  88. package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +0 -329
  89. package/frigg-cli/templates/backend/.env.example +0 -62
  90. package/frigg-cli/templates/backend/.eslintrc.json +0 -12
  91. package/frigg-cli/templates/backend/.prettierrc +0 -6
  92. package/frigg-cli/templates/backend/docker-compose.yml +0 -22
  93. package/frigg-cli/templates/backend/index.js +0 -96
  94. package/frigg-cli/templates/backend/infrastructure.js +0 -12
  95. package/frigg-cli/templates/backend/jest.config.js +0 -17
  96. package/frigg-cli/templates/backend/package.json +0 -50
  97. package/frigg-cli/templates/backend/src/api-modules/.gitkeep +0 -10
  98. package/frigg-cli/templates/backend/src/base/.gitkeep +0 -7
  99. package/frigg-cli/templates/backend/src/integrations/.gitkeep +0 -10
  100. package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +0 -65
  101. package/frigg-cli/templates/backend/src/utils/.gitkeep +0 -7
  102. package/frigg-cli/templates/backend/test/setup.js +0 -30
  103. package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
  104. package/frigg-cli/templates/backend/ui-extensions/README.md +0 -77
  105. package/frigg-cli/utils/__tests__/provider-helper.test.js +0 -55
  106. package/frigg-cli/utils/__tests__/repo-detection.test.js +0 -436
  107. package/frigg-cli/utils/output.js +0 -382
  108. package/frigg-cli/utils/provider-helper.js +0 -75
  109. package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +0 -205
  110. package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +0 -104
  111. package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +0 -153
  112. package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +0 -162
  113. package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +0 -152
  114. package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +0 -332
  115. package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +0 -191
  116. package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +0 -146
  117. package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +0 -155
  118. package/frigg-cli/validate-command/adapters/cli/validate-command.js +0 -199
  119. package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +0 -35
  120. package/frigg-cli/validate-command/domain/entities/validation-result.js +0 -74
  121. package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +0 -74
  122. package/frigg-cli/validate-command/domain/value-objects/validation-error.js +0 -68
  123. package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +0 -181
  124. package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +0 -145
  125. package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +0 -113
  126. package/infrastructure/domains/admin-scripts/admin-script-builder.js +0 -200
  127. package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +0 -499
  128. package/infrastructure/domains/admin-scripts/index.js +0 -5
  129. package/infrastructure/jest.config.js +0 -16
@@ -1,286 +0,0 @@
1
- # Output Class Migration Guide
2
-
3
- This guide shows how to migrate existing CLI commands to use the new unified `Output` class.
4
-
5
- ## Why Migrate?
6
-
7
- The unified `Output` class provides:
8
- - **Consistency**: Same UI patterns across all commands
9
- - **Better UX**: Spinners, progress bars, formatted tables
10
- - **Maintainability**: Single place to update UI behavior
11
- - **Testing**: Easier to mock and test
12
-
13
- ## Before vs After
14
-
15
- ### Before (Inconsistent)
16
-
17
- ```javascript
18
- // install-command/index.js (OLD - plain console.log)
19
- function logError(message, error) {
20
- console.error(message, error);
21
- }
22
-
23
- function logSuccess(message) {
24
- console.log(message);
25
- }
26
-
27
- // Some other command (OLD - using chalk directly)
28
- const chalk = require('chalk');
29
- console.log(chalk.green('✓ Success'));
30
- console.error(chalk.red('✗ Failed'));
31
-
32
- // repair-command (OLD - using readline)
33
- const readline = require('readline');
34
- const rl = readline.createInterface({
35
- input: process.stdin,
36
- output: process.stdout
37
- });
38
- rl.question('Select option: ', (answer) => {
39
- // ...
40
- });
41
- ```
42
-
43
- ### After (Consistent)
44
-
45
- ```javascript
46
- // All commands use the same output utility
47
- const output = require('./utils/output');
48
-
49
- output.success('Operation completed');
50
- output.error('Operation failed', error);
51
-
52
- const spinner = output.spinner('Installing...');
53
- // do work
54
- spinner.succeed('Installed successfully');
55
-
56
- const answer = await output.confirm('Continue with installation?');
57
- ```
58
-
59
- ## Migration Steps
60
-
61
- ### Step 1: Import Output
62
-
63
- Replace all imports of `chalk`, `console`, and `readline`:
64
-
65
- ```diff
66
- - const chalk = require('chalk');
67
- - const readline = require('readline');
68
- + const output = require('../utils/output');
69
- ```
70
-
71
- ### Step 2: Replace Console Methods
72
-
73
- | Old | New |
74
- |-----|-----|
75
- | `console.log('Success')` | `output.success('Success')` |
76
- | `console.error('Error')` | `output.error('Error')` |
77
- | `console.info('Info')` | `output.info('Info')` |
78
- | `console.warn('Warning')` | `output.warn('Warning')` |
79
- | `console.log(chalk.green('✓ Done'))` | `output.success('Done')` |
80
- | `console.error(chalk.red('✗ Failed'))` | `output.error('Failed')` |
81
-
82
- ### Step 3: Replace Chalk Usage
83
-
84
- ```diff
85
- - console.log(chalk.blue('Starting...'));
86
- + output.info('Starting...');
87
-
88
- - console.log(chalk.bold('=== Header ==='));
89
- + output.header('Header');
90
-
91
- - console.log(chalk.yellow('⚠ Warning'));
92
- + output.warn('Warning');
93
- ```
94
-
95
- ### Step 4: Replace Inquirer Prompts
96
-
97
- ```diff
98
- - const { confirm } = require('@inquirer/prompts');
99
- - const answer = await confirm({ message: 'Continue?' });
100
- + const answer = await output.confirm('Continue?');
101
-
102
- - const { select } = require('@inquirer/prompts');
103
- - const choice = await select({
104
- - message: 'Select option',
105
- - choices: ['Option 1', 'Option 2']
106
- - });
107
- + const choice = await output.select('Select option', ['Option 1', 'Option 2']);
108
- ```
109
-
110
- ### Step 5: Replace Readline (repair-command)
111
-
112
- ```diff
113
- - const readline = require('readline');
114
- - const rl = readline.createInterface({
115
- - input: process.stdin,
116
- - output: process.stdout
117
- - });
118
- - rl.question('Select option: ', (answer) => {
119
- - // handle answer
120
- - rl.close();
121
- - });
122
- + const answer = await output.input('Select option:');
123
- + // handle answer (no need to close)
124
- ```
125
-
126
- ### Step 6: Add Spinners for Long Operations
127
-
128
- ```diff
129
- - console.log('Installing dependencies...');
130
- - await installDependencies();
131
- - console.log('Done');
132
- + const spinner = output.spinner('Installing dependencies...');
133
- + await installDependencies();
134
- + spinner.succeed('Dependencies installed');
135
- ```
136
-
137
- ### Step 7: Add Progress Bars
138
-
139
- ```diff
140
- - console.log(`Progress: ${i}/${total}`);
141
- + output.progress(i, total, 'Processing files...');
142
- ```
143
-
144
- ### Step 8: Display Tables
145
-
146
- ```diff
147
- - modules.forEach(mod => {
148
- - console.log(`${mod.name}\t${mod.version}\t${mod.status}`);
149
- - });
150
- + output.table(modules, ['name', 'version', 'status']);
151
- ```
152
-
153
- ## Real Example: install-command
154
-
155
- ### Before
156
-
157
- ```javascript
158
- // install-command/logger.js
159
- function logError(message, error) {
160
- console.error(message, error);
161
- if (error && error.stack) {
162
- console.error(error.stack);
163
- }
164
- }
165
-
166
- function logSuccess(message) {
167
- console.log(message);
168
- }
169
-
170
- function logInfo(message) {
171
- console.log(message);
172
- }
173
-
174
- module.exports = {
175
- logError,
176
- logSuccess,
177
- logInfo
178
- };
179
-
180
- // install-command/index.js
181
- const logger = require('./logger');
182
-
183
- logger.logInfo('Starting installation...');
184
- // ...
185
- logger.logSuccess('Module installed successfully');
186
- ```
187
-
188
- ### After
189
-
190
- ```javascript
191
- // install-command/index.js
192
- const output = require('../utils/output');
193
-
194
- const spinner = output.spinner('Installing module...');
195
- try {
196
- // ... do installation
197
- spinner.succeed('Module installed successfully');
198
- } catch (error) {
199
- spinner.fail('Installation failed');
200
- output.error('Failed to install module', error);
201
- process.exit(1);
202
- }
203
- ```
204
-
205
- **Result**: Delete `install-command/logger.js` (no longer needed!)
206
-
207
- ## Commands to Migrate
208
-
209
- Priority order based on usage and inconsistency:
210
-
211
- 1. **install-command** (HIGH) - Uses plain console.log, has trivial logger wrapper
212
- 2. **repair-command** (HIGH) - Uses readline instead of inquirer
213
- 3. **doctor-command** (MEDIUM) - Long-running, needs spinners
214
- 4. **deploy-command** (MEDIUM) - Long-running, needs progress indication
215
- 5. **start-command** (LOW) - Already uses chalk consistently
216
- 6. **generate-command** (LOW) - Uses inquirer, but inconsistent colors
217
- 7. **build-command** (LOW) - Simple command, less output
218
-
219
- ## Testing Your Migration
220
-
221
- After migrating a command:
222
-
223
- 1. **Run the command** manually to verify output looks correct
224
- 2. **Update tests** to mock `output` instead of `console`/`chalk`/`inquirer`
225
- 3. **Check for** color consistency, spinner behavior, error messages
226
-
227
- ### Test Example
228
-
229
- ```javascript
230
- // Before
231
- jest.spyOn(console, 'log');
232
- await myCommand();
233
- expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Success'));
234
-
235
- // After
236
- const output = require('../utils/output');
237
- jest.spyOn(output, 'success');
238
- await myCommand();
239
- expect(output.success).toHaveBeenCalledWith('Operation completed');
240
- ```
241
-
242
- ## Output API Reference
243
-
244
- ### Messages
245
- - `output.success(message)` - Green checkmark + message
246
- - `output.error(message, error?)` - Red X + message (+ stack trace if DEBUG=1)
247
- - `output.info(message)` - Blue info icon + message
248
- - `output.warn(message)` - Yellow warning icon + message
249
- - `output.debug(message)` - Gray message (only if DEBUG=1)
250
-
251
- ### Formatting
252
- - `output.header(title)` - Bold cyan title with underline
253
- - `output.separator()` - Gray horizontal line
254
- - `output.newline()` - Blank line
255
- - `output.table(data, columns?)` - Formatted table
256
- - `output.keyValue(object)` - Key-value pairs
257
- - `output.json(data, indent?)` - Syntax-highlighted JSON
258
-
259
- ### Interactive
260
- - `output.confirm(message, default?)` - Yes/no question
261
- - `output.input(message, default?, validate?)` - Text input
262
- - `output.select(message, choices, default?)` - Single selection
263
- - `output.checkbox(message, choices)` - Multiple selection
264
- - `output.password(message, validate?)` - Password input
265
-
266
- ### Progress
267
- - `output.spinner(text)` - Returns {update, succeed, fail, stop}
268
- - `output.progress(current, total, message?)` - Progress bar
269
-
270
- ### Compatibility
271
- - `output.log(...args)` - Raw console.log (for gradual migration)
272
-
273
- ## Benefits After Migration
274
-
275
- - ✅ **32% less code** - Remove logger wrappers and boilerplate
276
- - ✅ **100% consistency** - All commands look and feel the same
277
- - ✅ **Better UX** - Spinners, progress bars, formatted tables
278
- - ✅ **Easier testing** - Mock one module instead of many
279
- - ✅ **Maintainable** - Update UI in one place
280
-
281
- ## Questions?
282
-
283
- See:
284
- - `utils/output.js` - Full implementation
285
- - `__tests__/unit/utils/output.test.js` - Test examples
286
- - `FRIGG_CLI_ANALYSIS_REPORT.md` - Why we created this
@@ -1,272 +0,0 @@
1
- const {DomainException} = require('../exceptions/DomainException');
2
- const {SemanticVersion} = require('../value-objects/SemanticVersion');
3
-
4
- /**
5
- * ApiModule Entity
6
- *
7
- * Represents an API module that can be used by integrations
8
- * API modules are reusable API clients for external services
9
- */
10
- class ApiModule {
11
- constructor(props) {
12
- this.name = props.name; // kebab-case name
13
- this.version = props.version instanceof SemanticVersion ?
14
- props.version : new SemanticVersion(props.version || '1.0.0');
15
- this.displayName = props.displayName || this._generateDisplayName();
16
- this.description = props.description || '';
17
- this.author = props.author || '';
18
- this.license = props.license || 'UNLICENSED';
19
- this.apiConfig = props.apiConfig || {
20
- baseUrl: '',
21
- authType: 'oauth2',
22
- version: 'v1'
23
- };
24
- this.entities = props.entities || {}; // Database entities this module needs
25
- this.scopes = props.scopes || []; // OAuth scopes required
26
- this.credentials = props.credentials || []; // Required credentials
27
- this.endpoints = props.endpoints || {}; // API endpoints
28
- this.createdAt = props.createdAt || new Date();
29
- this.updatedAt = props.updatedAt || new Date();
30
- }
31
-
32
- /**
33
- * Factory method to create a new ApiModule
34
- */
35
- static create(props) {
36
- if (!props.name) {
37
- throw new DomainException('API module name is required');
38
- }
39
-
40
- // Validate name format
41
- const namePattern = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
42
- if (!namePattern.test(props.name)) {
43
- throw new DomainException('API module name must be kebab-case');
44
- }
45
-
46
- // Validate authType is provided
47
- if (!props.apiConfig || !props.apiConfig.authType) {
48
- throw new DomainException('Authentication type is required');
49
- }
50
-
51
- return new ApiModule(props);
52
- }
53
-
54
- /**
55
- * Reconstruct ApiModule from plain object
56
- */
57
- static fromObject(obj) {
58
- return new ApiModule({
59
- ...obj,
60
- version: obj.version,
61
- createdAt: new Date(obj.createdAt),
62
- updatedAt: new Date(obj.updatedAt)
63
- });
64
- }
65
-
66
- /**
67
- * Add an entity configuration
68
- * Entities are database records that store API credentials and state
69
- *
70
- * @param {string} entityName - Entity name (e.g., 'credential', 'user')
71
- * @param {object} config - Entity configuration
72
- */
73
- addEntity(entityName, config = {}) {
74
- if (this.hasEntity(entityName)) {
75
- throw new DomainException(`Entity '${entityName}' already exists`);
76
- }
77
-
78
- this.entities[entityName] = {
79
- type: entityName,
80
- label: config.label || entityName,
81
- required: config.required !== false,
82
- fields: config.fields || [],
83
- ...config
84
- };
85
-
86
- this.updatedAt = new Date();
87
- return this;
88
- }
89
-
90
- /**
91
- * Check if entity exists
92
- */
93
- hasEntity(entityName) {
94
- return entityName in this.entities;
95
- }
96
-
97
- /**
98
- * Add an endpoint definition
99
- */
100
- addEndpoint(name, config) {
101
- if (this.hasEndpoint(name)) {
102
- throw new DomainException(`Endpoint '${name}' already exists`);
103
- }
104
-
105
- this.endpoints[name] = {
106
- method: config.method || 'GET',
107
- path: config.path,
108
- description: config.description || '',
109
- parameters: config.parameters || [],
110
- response: config.response || {},
111
- ...config
112
- };
113
-
114
- this.updatedAt = new Date();
115
- return this;
116
- }
117
-
118
- /**
119
- * Check if endpoint exists
120
- */
121
- hasEndpoint(name) {
122
- return name in this.endpoints;
123
- }
124
-
125
- /**
126
- * Add required OAuth scope
127
- */
128
- addScope(scope) {
129
- if (this.scopes.includes(scope)) {
130
- throw new DomainException(`Scope '${scope}' already exists`);
131
- }
132
- this.scopes.push(scope);
133
- this.updatedAt = new Date();
134
- return this;
135
- }
136
-
137
- /**
138
- * Add required credential
139
- */
140
- addCredential(name, config = {}) {
141
- const existing = this.credentials.find(c => c.name === name);
142
- if (existing) {
143
- throw new DomainException(`Credential '${name}' already exists`);
144
- }
145
-
146
- this.credentials.push({
147
- name,
148
- type: config.type || 'string',
149
- required: config.required !== false,
150
- description: config.description || '',
151
- example: config.example || '',
152
- envVar: config.envVar || '',
153
- ...config
154
- });
155
-
156
- this.updatedAt = new Date();
157
- return this;
158
- }
159
-
160
- /**
161
- * Check if credential exists
162
- */
163
- hasCredential(name) {
164
- return this.credentials.some(c => c.name === name);
165
- }
166
-
167
- /**
168
- * Validate API module business rules
169
- */
170
- validate() {
171
- const errors = [];
172
-
173
- // Name validation (kebab-case)
174
- if (!this.name || this.name.trim().length === 0) {
175
- errors.push('API module name is required');
176
- }
177
-
178
- const namePattern = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
179
- if (this.name && !namePattern.test(this.name)) {
180
- errors.push('API module name must be kebab-case');
181
- }
182
-
183
- // Display name validation
184
- if (!this.displayName || this.displayName.trim().length === 0) {
185
- errors.push('Display name is required');
186
- }
187
-
188
- // Description validation
189
- if (this.description && this.description.length > 1000) {
190
- errors.push('Description must be 1000 characters or less');
191
- }
192
-
193
- // API config validation
194
- if (!this.apiConfig.baseUrl) {
195
- // Warning: base URL should be provided, but not required at creation
196
- }
197
-
198
- // Auth type validation
199
- if (!this.apiConfig.authType || this.apiConfig.authType.trim().length === 0) {
200
- errors.push('Authentication type is required');
201
- } else {
202
- const validAuthTypes = ['oauth2', 'api-key', 'basic', 'token', 'custom'];
203
- if (!validAuthTypes.includes(this.apiConfig.authType)) {
204
- errors.push(`Invalid auth type. Must be one of: ${validAuthTypes.join(', ')}`);
205
- }
206
- }
207
-
208
- return {
209
- isValid: errors.length === 0,
210
- errors
211
- };
212
- }
213
-
214
- /**
215
- * Convert to plain object
216
- */
217
- toObject() {
218
- return {
219
- name: this.name,
220
- version: this.version.value,
221
- displayName: this.displayName,
222
- description: this.description,
223
- author: this.author,
224
- license: this.license,
225
- apiConfig: this.apiConfig,
226
- entities: this.entities,
227
- scopes: this.scopes,
228
- credentials: this.credentials,
229
- endpoints: this.endpoints,
230
- createdAt: this.createdAt,
231
- updatedAt: this.updatedAt
232
- };
233
- }
234
-
235
- /**
236
- * Convert to JSON format (for api-module definition files)
237
- */
238
- toJSON() {
239
- return {
240
- name: this.name,
241
- version: this.version.value,
242
- display: {
243
- name: this.displayName,
244
- description: this.description
245
- },
246
- api: {
247
- baseUrl: this.apiConfig.baseUrl,
248
- authType: this.apiConfig.authType,
249
- version: this.apiConfig.version
250
- },
251
- entities: this.entities,
252
- auth: {
253
- type: this.apiConfig.authType,
254
- scopes: this.scopes,
255
- credentials: this.credentials
256
- },
257
- endpoints: this.endpoints
258
- };
259
- }
260
-
261
- /**
262
- * Generate display name from kebab-case name
263
- */
264
- _generateDisplayName() {
265
- return this.name
266
- .split('-')
267
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
268
- .join(' ');
269
- }
270
- }
271
-
272
- module.exports = {ApiModule};