@friggframework/devtools 2.0.0-next.4 → 2.0.0-next.41
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.
- package/frigg-cli/.eslintrc.js +141 -0
- package/frigg-cli/__tests__/jest.config.js +102 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
- package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
- package/frigg-cli/__tests__/utils/command-tester.js +170 -0
- package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
- package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
- package/frigg-cli/__tests__/utils/test-setup.js +286 -0
- package/frigg-cli/build-command/index.js +54 -0
- package/frigg-cli/deploy-command/index.js +175 -0
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
- package/frigg-cli/generate-command/azure-generator.js +43 -0
- package/frigg-cli/generate-command/gcp-generator.js +47 -0
- package/frigg-cli/generate-command/index.js +332 -0
- package/frigg-cli/generate-command/terraform-generator.js +555 -0
- package/frigg-cli/generate-iam-command.js +115 -0
- package/frigg-cli/index.js +47 -1
- package/frigg-cli/index.test.js +1 -4
- package/frigg-cli/init-command/backend-first-handler.js +756 -0
- package/frigg-cli/init-command/index.js +93 -0
- package/frigg-cli/init-command/template-handler.js +143 -0
- package/frigg-cli/install-command/index.js +1 -4
- package/frigg-cli/package.json +51 -0
- package/frigg-cli/start-command/index.js +30 -4
- package/frigg-cli/start-command/start-command.test.js +155 -0
- package/frigg-cli/test/init-command.test.js +180 -0
- package/frigg-cli/test/npm-registry.test.js +319 -0
- package/frigg-cli/ui-command/index.js +154 -0
- package/frigg-cli/utils/app-resolver.js +319 -0
- package/frigg-cli/utils/backend-path.js +16 -17
- package/frigg-cli/utils/npm-registry.js +167 -0
- package/frigg-cli/utils/process-manager.js +199 -0
- package/frigg-cli/utils/repo-detection.js +405 -0
- package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +268 -0
- package/infrastructure/GENERATE-IAM-DOCS.md +278 -0
- package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
- package/infrastructure/README.md +443 -0
- package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
- package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
- package/infrastructure/__tests__/helpers/test-utils.js +277 -0
- package/infrastructure/aws-discovery.js +1176 -0
- package/infrastructure/aws-discovery.test.js +1220 -0
- package/infrastructure/build-time-discovery.js +206 -0
- package/infrastructure/build-time-discovery.test.js +378 -0
- package/infrastructure/create-frigg-infrastructure.js +3 -5
- package/infrastructure/env-validator.js +77 -0
- package/infrastructure/frigg-deployment-iam-stack.yaml +401 -0
- package/infrastructure/iam-generator.js +836 -0
- package/infrastructure/iam-generator.test.js +172 -0
- package/infrastructure/iam-policy-basic.json +218 -0
- package/infrastructure/iam-policy-full.json +288 -0
- package/infrastructure/integration.test.js +383 -0
- package/infrastructure/run-discovery.js +110 -0
- package/infrastructure/serverless-template.js +1493 -138
- package/infrastructure/serverless-template.test.js +1804 -0
- package/management-ui/.eslintrc.js +22 -0
- package/management-ui/README.md +203 -0
- package/management-ui/components.json +21 -0
- package/management-ui/docs/phase2-integration-guide.md +320 -0
- package/management-ui/index.html +13 -0
- package/management-ui/package-lock.json +16517 -0
- package/management-ui/package.json +76 -0
- package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
- package/management-ui/postcss.config.js +6 -0
- package/management-ui/server/api/backend.js +256 -0
- package/management-ui/server/api/cli.js +315 -0
- package/management-ui/server/api/codegen.js +663 -0
- package/management-ui/server/api/connections.js +857 -0
- package/management-ui/server/api/discovery.js +185 -0
- package/management-ui/server/api/environment/index.js +1 -0
- package/management-ui/server/api/environment/router.js +378 -0
- package/management-ui/server/api/environment.js +328 -0
- package/management-ui/server/api/integrations.js +876 -0
- package/management-ui/server/api/logs.js +248 -0
- package/management-ui/server/api/monitoring.js +282 -0
- package/management-ui/server/api/open-ide.js +31 -0
- package/management-ui/server/api/project.js +1029 -0
- package/management-ui/server/api/users/sessions.js +371 -0
- package/management-ui/server/api/users/simulation.js +254 -0
- package/management-ui/server/api/users.js +362 -0
- package/management-ui/server/api-contract.md +275 -0
- package/management-ui/server/index.js +873 -0
- package/management-ui/server/middleware/errorHandler.js +93 -0
- package/management-ui/server/middleware/security.js +32 -0
- package/management-ui/server/processManager.js +296 -0
- package/management-ui/server/server.js +346 -0
- package/management-ui/server/services/aws-monitor.js +413 -0
- package/management-ui/server/services/npm-registry.js +347 -0
- package/management-ui/server/services/template-engine.js +538 -0
- package/management-ui/server/utils/cliIntegration.js +220 -0
- package/management-ui/server/utils/environment/auditLogger.js +471 -0
- package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
- package/management-ui/server/utils/environment/encryption.js +278 -0
- package/management-ui/server/utils/environment/envFileManager.js +286 -0
- package/management-ui/server/utils/import-commonjs.js +28 -0
- package/management-ui/server/utils/response.js +83 -0
- package/management-ui/server/websocket/handler.js +325 -0
- package/management-ui/src/App.jsx +109 -0
- package/management-ui/src/assets/FriggLogo.svg +1 -0
- package/management-ui/src/components/AppRouter.jsx +65 -0
- package/management-ui/src/components/Button.jsx +70 -0
- package/management-ui/src/components/Card.jsx +97 -0
- package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
- package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
- package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
- package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
- package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
- package/management-ui/src/components/ErrorBoundary.jsx +73 -0
- package/management-ui/src/components/IntegrationCard.jsx +481 -0
- package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
- package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
- package/management-ui/src/components/IntegrationStatus.jsx +336 -0
- package/management-ui/src/components/Layout.jsx +716 -0
- package/management-ui/src/components/LoadingSpinner.jsx +113 -0
- package/management-ui/src/components/RepositoryPicker.jsx +248 -0
- package/management-ui/src/components/SessionMonitor.jsx +350 -0
- package/management-ui/src/components/StatusBadge.jsx +208 -0
- package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
- package/management-ui/src/components/UserSimulation.jsx +327 -0
- package/management-ui/src/components/Welcome.jsx +434 -0
- package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
- package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
- package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
- package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
- package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
- package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
- package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
- package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
- package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
- package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
- package/management-ui/src/components/codegen/index.js +10 -0
- package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
- package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
- package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
- package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
- package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
- package/management-ui/src/components/connections/index.js +5 -0
- package/management-ui/src/components/index.js +21 -0
- package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
- package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
- package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
- package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
- package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
- package/management-ui/src/components/monitoring/index.js +6 -0
- package/management-ui/src/components/monitoring/monitoring.css +218 -0
- package/management-ui/src/components/theme-provider.jsx +52 -0
- package/management-ui/src/components/theme-toggle.jsx +39 -0
- package/management-ui/src/components/ui/badge.tsx +36 -0
- package/management-ui/src/components/ui/button.test.jsx +56 -0
- package/management-ui/src/components/ui/button.tsx +57 -0
- package/management-ui/src/components/ui/card.tsx +76 -0
- package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
- package/management-ui/src/components/ui/select.tsx +157 -0
- package/management-ui/src/components/ui/skeleton.jsx +15 -0
- package/management-ui/src/hooks/useFrigg.jsx +601 -0
- package/management-ui/src/hooks/useSocket.jsx +58 -0
- package/management-ui/src/index.css +193 -0
- package/management-ui/src/lib/utils.ts +6 -0
- package/management-ui/src/main.jsx +10 -0
- package/management-ui/src/pages/CodeGeneration.jsx +14 -0
- package/management-ui/src/pages/Connections.jsx +252 -0
- package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
- package/management-ui/src/pages/Dashboard.jsx +311 -0
- package/management-ui/src/pages/Environment.jsx +314 -0
- package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
- package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
- package/management-ui/src/pages/IntegrationTest.jsx +742 -0
- package/management-ui/src/pages/Integrations.jsx +253 -0
- package/management-ui/src/pages/Monitoring.jsx +17 -0
- package/management-ui/src/pages/Simulation.jsx +155 -0
- package/management-ui/src/pages/Users.jsx +492 -0
- package/management-ui/src/services/api.js +41 -0
- package/management-ui/src/services/apiModuleService.js +193 -0
- package/management-ui/src/services/websocket-handlers.js +120 -0
- package/management-ui/src/test/api/project.test.js +273 -0
- package/management-ui/src/test/components/Welcome.test.jsx +378 -0
- package/management-ui/src/test/mocks/server.js +178 -0
- package/management-ui/src/test/setup.js +61 -0
- package/management-ui/src/test/utils/test-utils.jsx +134 -0
- package/management-ui/src/utils/repository.js +98 -0
- package/management-ui/src/utils/repository.test.js +118 -0
- package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
- package/management-ui/tailwind.config.js +63 -0
- package/management-ui/tsconfig.json +37 -0
- package/management-ui/tsconfig.node.json +10 -0
- package/management-ui/vite.config.js +26 -0
- package/management-ui/vitest.config.js +38 -0
- package/package.json +20 -9
- package/infrastructure/app-handler-helpers.js +0 -57
- package/infrastructure/backend-utils.js +0 -90
- package/infrastructure/routers/auth.js +0 -26
- package/infrastructure/routers/integration-defined-routers.js +0 -37
- package/infrastructure/routers/middleware/loadUser.js +0 -15
- package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
- package/infrastructure/routers/user.js +0 -41
- package/infrastructure/routers/websocket.js +0 -55
- package/infrastructure/workers/integration-defined-workers.js +0 -24
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2 Integration Workflows
|
|
3
|
+
*
|
|
4
|
+
* This module implements complete user workflows that integrate all Phase 2 features:
|
|
5
|
+
* - Integration discovery → Installation → Configuration → Connection
|
|
6
|
+
* - User creation → Credential generation → Entity management
|
|
7
|
+
* - Environment setup → Testing → Deployment preparation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import IntegrationDiscoveryService from '../../../core/integrations/discovery/integration-discovery-service.js';
|
|
11
|
+
import IntegrationInstallerService from '../../../core/integrations/discovery/integration-installer-service.js';
|
|
12
|
+
import { EventEmitter } from 'events';
|
|
13
|
+
|
|
14
|
+
export class Phase2IntegrationWorkflows extends EventEmitter {
|
|
15
|
+
constructor(config = {}) {
|
|
16
|
+
super();
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.discoveryService = new IntegrationDiscoveryService();
|
|
19
|
+
this.installerService = new IntegrationInstallerService();
|
|
20
|
+
this.workflows = new Map();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Complete integration setup workflow
|
|
25
|
+
* Discovers → Installs → Configures → Tests an integration
|
|
26
|
+
*/
|
|
27
|
+
async setupIntegration(integrationName, options = {}) {
|
|
28
|
+
const workflowId = this.generateWorkflowId();
|
|
29
|
+
const workflow = {
|
|
30
|
+
id: workflowId,
|
|
31
|
+
type: 'integration-setup',
|
|
32
|
+
integration: integrationName,
|
|
33
|
+
status: 'started',
|
|
34
|
+
steps: [],
|
|
35
|
+
startTime: Date.now()
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
this.workflows.set(workflowId, workflow);
|
|
39
|
+
this.emit('workflow:started', workflow);
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
// Step 1: Discover integration details
|
|
43
|
+
await this.executeStep(workflow, 'discover', async () => {
|
|
44
|
+
const details = await this.discoveryService.getIntegrationDetails(
|
|
45
|
+
`@friggframework/api-module-${integrationName}`
|
|
46
|
+
);
|
|
47
|
+
workflow.integrationDetails = details;
|
|
48
|
+
return details;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Step 2: Install integration
|
|
52
|
+
await this.executeStep(workflow, 'install', async () => {
|
|
53
|
+
const result = await this.installerService.installIntegration({
|
|
54
|
+
packageName: workflow.integrationDetails.name,
|
|
55
|
+
version: workflow.integrationDetails.version
|
|
56
|
+
});
|
|
57
|
+
workflow.installResult = result;
|
|
58
|
+
return result;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Step 3: Configure integration
|
|
62
|
+
await this.executeStep(workflow, 'configure', async () => {
|
|
63
|
+
const config = await this.configureIntegration(
|
|
64
|
+
integrationName,
|
|
65
|
+
workflow.integrationDetails,
|
|
66
|
+
options.config || {}
|
|
67
|
+
);
|
|
68
|
+
workflow.configuration = config;
|
|
69
|
+
return config;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Step 4: Create test user
|
|
73
|
+
await this.executeStep(workflow, 'create-test-user', async () => {
|
|
74
|
+
const user = await this.createTestUser({
|
|
75
|
+
integration: integrationName,
|
|
76
|
+
name: options.testUserName || `Test User for ${integrationName}`,
|
|
77
|
+
email: options.testUserEmail || `test-${integrationName}@frigg.test`
|
|
78
|
+
});
|
|
79
|
+
workflow.testUser = user;
|
|
80
|
+
return user;
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Step 5: Generate credentials
|
|
84
|
+
await this.executeStep(workflow, 'generate-credentials', async () => {
|
|
85
|
+
const credentials = await this.generateTestCredentials(
|
|
86
|
+
workflow.testUser.id,
|
|
87
|
+
integrationName,
|
|
88
|
+
workflow.integrationDetails.integrationMetadata
|
|
89
|
+
);
|
|
90
|
+
workflow.credentials = credentials;
|
|
91
|
+
return credentials;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Step 6: Create connection
|
|
95
|
+
await this.executeStep(workflow, 'create-connection', async () => {
|
|
96
|
+
const connection = await this.createConnection({
|
|
97
|
+
userId: workflow.testUser.id,
|
|
98
|
+
integrationName,
|
|
99
|
+
credentials: workflow.credentials,
|
|
100
|
+
config: workflow.configuration
|
|
101
|
+
});
|
|
102
|
+
workflow.connection = connection;
|
|
103
|
+
return connection;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Step 7: Test connection
|
|
107
|
+
await this.executeStep(workflow, 'test-connection', async () => {
|
|
108
|
+
const testResult = await this.testConnection(workflow.connection.id);
|
|
109
|
+
workflow.testResult = testResult;
|
|
110
|
+
return testResult;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Step 8: Setup environment variables
|
|
114
|
+
await this.executeStep(workflow, 'setup-environment', async () => {
|
|
115
|
+
const envVars = await this.setupEnvironmentVariables(
|
|
116
|
+
integrationName,
|
|
117
|
+
workflow.configuration,
|
|
118
|
+
options.environment || 'development'
|
|
119
|
+
);
|
|
120
|
+
workflow.environmentVariables = envVars;
|
|
121
|
+
return envVars;
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
workflow.status = 'completed';
|
|
125
|
+
workflow.endTime = Date.now();
|
|
126
|
+
workflow.duration = workflow.endTime - workflow.startTime;
|
|
127
|
+
|
|
128
|
+
this.emit('workflow:completed', workflow);
|
|
129
|
+
return workflow;
|
|
130
|
+
|
|
131
|
+
} catch (error) {
|
|
132
|
+
workflow.status = 'failed';
|
|
133
|
+
workflow.error = {
|
|
134
|
+
message: error.message,
|
|
135
|
+
step: workflow.steps[workflow.steps.length - 1]?.name || 'unknown',
|
|
136
|
+
stack: error.stack
|
|
137
|
+
};
|
|
138
|
+
workflow.endTime = Date.now();
|
|
139
|
+
workflow.duration = workflow.endTime - workflow.startTime;
|
|
140
|
+
|
|
141
|
+
this.emit('workflow:failed', workflow);
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Bulk integration management workflow
|
|
148
|
+
* Handles multiple integrations in parallel with optimized performance
|
|
149
|
+
*/
|
|
150
|
+
async bulkIntegrationSetup(integrations, options = {}) {
|
|
151
|
+
const workflowId = this.generateWorkflowId();
|
|
152
|
+
const workflow = {
|
|
153
|
+
id: workflowId,
|
|
154
|
+
type: 'bulk-integration-setup',
|
|
155
|
+
integrations,
|
|
156
|
+
status: 'started',
|
|
157
|
+
results: [],
|
|
158
|
+
startTime: Date.now()
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
this.workflows.set(workflowId, workflow);
|
|
162
|
+
this.emit('workflow:started', workflow);
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
// Process integrations in batches for optimal performance
|
|
166
|
+
const batchSize = options.batchSize || 3;
|
|
167
|
+
const batches = this.createBatches(integrations, batchSize);
|
|
168
|
+
|
|
169
|
+
for (const [batchIndex, batch] of batches.entries()) {
|
|
170
|
+
this.emit('workflow:progress', {
|
|
171
|
+
workflowId,
|
|
172
|
+
batch: batchIndex + 1,
|
|
173
|
+
totalBatches: batches.length,
|
|
174
|
+
processing: batch
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const batchResults = await Promise.allSettled(
|
|
178
|
+
batch.map(integration =>
|
|
179
|
+
this.setupIntegration(integration.name, integration.options)
|
|
180
|
+
)
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
workflow.results.push(...batchResults.map((result, index) => ({
|
|
184
|
+
integration: batch[index].name,
|
|
185
|
+
status: result.status,
|
|
186
|
+
result: result.status === 'fulfilled' ? result.value : null,
|
|
187
|
+
error: result.status === 'rejected' ? result.reason : null
|
|
188
|
+
})));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
workflow.status = 'completed';
|
|
192
|
+
workflow.endTime = Date.now();
|
|
193
|
+
workflow.duration = workflow.endTime - workflow.startTime;
|
|
194
|
+
workflow.summary = {
|
|
195
|
+
total: integrations.length,
|
|
196
|
+
successful: workflow.results.filter(r => r.status === 'fulfilled').length,
|
|
197
|
+
failed: workflow.results.filter(r => r.status === 'rejected').length
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
this.emit('workflow:completed', workflow);
|
|
201
|
+
return workflow;
|
|
202
|
+
|
|
203
|
+
} catch (error) {
|
|
204
|
+
workflow.status = 'failed';
|
|
205
|
+
workflow.error = error;
|
|
206
|
+
this.emit('workflow:failed', workflow);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Development environment setup workflow
|
|
213
|
+
* Prepares a complete local development environment
|
|
214
|
+
*/
|
|
215
|
+
async setupDevelopmentEnvironment(options = {}) {
|
|
216
|
+
const workflowId = this.generateWorkflowId();
|
|
217
|
+
const workflow = {
|
|
218
|
+
id: workflowId,
|
|
219
|
+
type: 'development-setup',
|
|
220
|
+
status: 'started',
|
|
221
|
+
steps: [],
|
|
222
|
+
startTime: Date.now()
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
this.workflows.set(workflowId, workflow);
|
|
226
|
+
this.emit('workflow:started', workflow);
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
// Step 1: Discover recommended integrations
|
|
230
|
+
await this.executeStep(workflow, 'discover-recommended', async () => {
|
|
231
|
+
const recommended = await this.getRecommendedIntegrations(options.projectType);
|
|
232
|
+
workflow.recommendedIntegrations = recommended;
|
|
233
|
+
return recommended;
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Step 2: Install core integrations
|
|
237
|
+
const coreIntegrations = options.integrations || workflow.recommendedIntegrations.slice(0, 3);
|
|
238
|
+
await this.executeStep(workflow, 'install-core', async () => {
|
|
239
|
+
const results = await this.bulkIntegrationSetup(
|
|
240
|
+
coreIntegrations.map(name => ({ name, options: {} }))
|
|
241
|
+
);
|
|
242
|
+
workflow.coreIntegrations = results;
|
|
243
|
+
return results;
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Step 3: Create test user pool
|
|
247
|
+
await this.executeStep(workflow, 'create-user-pool', async () => {
|
|
248
|
+
const users = await this.createTestUserPool({
|
|
249
|
+
count: options.testUserCount || 5,
|
|
250
|
+
integrations: coreIntegrations
|
|
251
|
+
});
|
|
252
|
+
workflow.testUsers = users;
|
|
253
|
+
return users;
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Step 4: Setup mock data
|
|
257
|
+
await this.executeStep(workflow, 'setup-mock-data', async () => {
|
|
258
|
+
const mockData = await this.setupMockData({
|
|
259
|
+
users: workflow.testUsers,
|
|
260
|
+
integrations: coreIntegrations,
|
|
261
|
+
dataTypes: options.mockDataTypes || ['contacts', 'messages', 'tasks']
|
|
262
|
+
});
|
|
263
|
+
workflow.mockData = mockData;
|
|
264
|
+
return mockData;
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Step 5: Configure environment
|
|
268
|
+
await this.executeStep(workflow, 'configure-environment', async () => {
|
|
269
|
+
const envConfig = await this.configureDevelopmentEnvironment({
|
|
270
|
+
integrations: coreIntegrations,
|
|
271
|
+
apiKeys: options.apiKeys || {},
|
|
272
|
+
features: options.features || ['debug', 'verbose-logging', 'hot-reload']
|
|
273
|
+
});
|
|
274
|
+
workflow.environmentConfig = envConfig;
|
|
275
|
+
return envConfig;
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Step 6: Validate setup
|
|
279
|
+
await this.executeStep(workflow, 'validate-setup', async () => {
|
|
280
|
+
const validation = await this.validateDevelopmentSetup(workflow);
|
|
281
|
+
workflow.validation = validation;
|
|
282
|
+
return validation;
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
workflow.status = 'completed';
|
|
286
|
+
workflow.endTime = Date.now();
|
|
287
|
+
workflow.duration = workflow.endTime - workflow.startTime;
|
|
288
|
+
|
|
289
|
+
this.emit('workflow:completed', workflow);
|
|
290
|
+
return workflow;
|
|
291
|
+
|
|
292
|
+
} catch (error) {
|
|
293
|
+
workflow.status = 'failed';
|
|
294
|
+
workflow.error = error;
|
|
295
|
+
this.emit('workflow:failed', workflow);
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Migration workflow for existing projects
|
|
302
|
+
* Migrates from create-frigg-app to new management UI
|
|
303
|
+
*/
|
|
304
|
+
async migrateProject(projectPath, options = {}) {
|
|
305
|
+
const workflowId = this.generateWorkflowId();
|
|
306
|
+
const workflow = {
|
|
307
|
+
id: workflowId,
|
|
308
|
+
type: 'project-migration',
|
|
309
|
+
projectPath,
|
|
310
|
+
status: 'started',
|
|
311
|
+
steps: [],
|
|
312
|
+
startTime: Date.now()
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
this.workflows.set(workflowId, workflow);
|
|
316
|
+
this.emit('workflow:started', workflow);
|
|
317
|
+
|
|
318
|
+
try {
|
|
319
|
+
// Step 1: Analyze existing project
|
|
320
|
+
await this.executeStep(workflow, 'analyze-project', async () => {
|
|
321
|
+
const analysis = await this.analyzeExistingProject(projectPath);
|
|
322
|
+
workflow.projectAnalysis = analysis;
|
|
323
|
+
return analysis;
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Step 2: Backup current state
|
|
327
|
+
await this.executeStep(workflow, 'backup-project', async () => {
|
|
328
|
+
const backup = await this.backupProject(projectPath);
|
|
329
|
+
workflow.backupPath = backup.path;
|
|
330
|
+
return backup;
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Step 3: Migrate integrations
|
|
334
|
+
await this.executeStep(workflow, 'migrate-integrations', async () => {
|
|
335
|
+
const migrations = await this.migrateIntegrations(
|
|
336
|
+
workflow.projectAnalysis.integrations,
|
|
337
|
+
options.integrationMapping || {}
|
|
338
|
+
);
|
|
339
|
+
workflow.integrationMigrations = migrations;
|
|
340
|
+
return migrations;
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Step 4: Update configuration
|
|
344
|
+
await this.executeStep(workflow, 'update-configuration', async () => {
|
|
345
|
+
const config = await this.updateProjectConfiguration({
|
|
346
|
+
projectPath,
|
|
347
|
+
newStructure: true,
|
|
348
|
+
managementUI: true,
|
|
349
|
+
preserveCustom: options.preserveCustom !== false
|
|
350
|
+
});
|
|
351
|
+
workflow.configuration = config;
|
|
352
|
+
return config;
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// Step 5: Migrate environment variables
|
|
356
|
+
await this.executeStep(workflow, 'migrate-environment', async () => {
|
|
357
|
+
const envMigration = await this.migrateEnvironmentVariables(
|
|
358
|
+
projectPath,
|
|
359
|
+
workflow.projectAnalysis.environment
|
|
360
|
+
);
|
|
361
|
+
workflow.environmentMigration = envMigration;
|
|
362
|
+
return envMigration;
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Step 6: Test migration
|
|
366
|
+
await this.executeStep(workflow, 'test-migration', async () => {
|
|
367
|
+
const tests = await this.testMigratedProject(projectPath);
|
|
368
|
+
workflow.testResults = tests;
|
|
369
|
+
return tests;
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
workflow.status = 'completed';
|
|
373
|
+
workflow.endTime = Date.now();
|
|
374
|
+
workflow.duration = workflow.endTime - workflow.startTime;
|
|
375
|
+
|
|
376
|
+
this.emit('workflow:completed', workflow);
|
|
377
|
+
return workflow;
|
|
378
|
+
|
|
379
|
+
} catch (error) {
|
|
380
|
+
// Rollback on failure
|
|
381
|
+
if (workflow.backupPath) {
|
|
382
|
+
await this.rollbackProject(projectPath, workflow.backupPath);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
workflow.status = 'failed';
|
|
386
|
+
workflow.error = error;
|
|
387
|
+
this.emit('workflow:failed', workflow);
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Helper methods
|
|
393
|
+
|
|
394
|
+
async executeStep(workflow, stepName, stepFunction) {
|
|
395
|
+
const step = {
|
|
396
|
+
name: stepName,
|
|
397
|
+
status: 'started',
|
|
398
|
+
startTime: Date.now()
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
workflow.steps.push(step);
|
|
402
|
+
this.emit('step:started', { workflowId: workflow.id, step });
|
|
403
|
+
|
|
404
|
+
try {
|
|
405
|
+
const result = await stepFunction();
|
|
406
|
+
step.status = 'completed';
|
|
407
|
+
step.endTime = Date.now();
|
|
408
|
+
step.duration = step.endTime - step.startTime;
|
|
409
|
+
step.result = result;
|
|
410
|
+
|
|
411
|
+
this.emit('step:completed', { workflowId: workflow.id, step });
|
|
412
|
+
return result;
|
|
413
|
+
|
|
414
|
+
} catch (error) {
|
|
415
|
+
step.status = 'failed';
|
|
416
|
+
step.endTime = Date.now();
|
|
417
|
+
step.duration = step.endTime - step.startTime;
|
|
418
|
+
step.error = {
|
|
419
|
+
message: error.message,
|
|
420
|
+
stack: error.stack
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
this.emit('step:failed', { workflowId: workflow.id, step });
|
|
424
|
+
throw error;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async configureIntegration(integrationName, details, userConfig) {
|
|
429
|
+
// Merge default configuration with user config
|
|
430
|
+
const defaultConfig = this.getDefaultIntegrationConfig(integrationName, details);
|
|
431
|
+
const config = { ...defaultConfig, ...userConfig };
|
|
432
|
+
|
|
433
|
+
// Validate configuration
|
|
434
|
+
const validation = await this.validateIntegrationConfig(integrationName, config);
|
|
435
|
+
if (!validation.valid) {
|
|
436
|
+
throw new Error(`Invalid configuration: ${validation.errors.join(', ')}`);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Save configuration
|
|
440
|
+
await this.saveIntegrationConfig(integrationName, config);
|
|
441
|
+
return config;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
async createTestUser(options) {
|
|
445
|
+
const user = {
|
|
446
|
+
id: this.generateUserId(),
|
|
447
|
+
name: options.name,
|
|
448
|
+
email: options.email,
|
|
449
|
+
integration: options.integration,
|
|
450
|
+
isDummy: true,
|
|
451
|
+
testId: `test-${options.integration}-${Date.now()}`,
|
|
452
|
+
createdAt: new Date().toISOString()
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
// Store user in runtime memory
|
|
456
|
+
await this.storeTestUser(user);
|
|
457
|
+
return user;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
async generateTestCredentials(userId, integrationName, metadata) {
|
|
461
|
+
const authType = metadata.authType || 'oauth2';
|
|
462
|
+
|
|
463
|
+
const credentials = {
|
|
464
|
+
userId,
|
|
465
|
+
integrationName,
|
|
466
|
+
authType,
|
|
467
|
+
createdAt: new Date().toISOString(),
|
|
468
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString() // 1 hour
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
switch (authType) {
|
|
472
|
+
case 'oauth2':
|
|
473
|
+
credentials.accessToken = this.generateTestToken('access');
|
|
474
|
+
credentials.refreshToken = this.generateTestToken('refresh');
|
|
475
|
+
credentials.scope = metadata.requiredScopes || [];
|
|
476
|
+
break;
|
|
477
|
+
case 'api-key':
|
|
478
|
+
credentials.apiKey = this.generateTestToken('api');
|
|
479
|
+
break;
|
|
480
|
+
case 'basic':
|
|
481
|
+
credentials.username = `test-user-${userId}`;
|
|
482
|
+
credentials.password = this.generateTestToken('password');
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return credentials;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
async createConnection(options) {
|
|
490
|
+
const connection = {
|
|
491
|
+
id: this.generateConnectionId(),
|
|
492
|
+
userId: options.userId,
|
|
493
|
+
integrationName: options.integrationName,
|
|
494
|
+
credentials: options.credentials,
|
|
495
|
+
config: options.config,
|
|
496
|
+
status: 'active',
|
|
497
|
+
createdAt: new Date().toISOString(),
|
|
498
|
+
lastSync: null,
|
|
499
|
+
entities: []
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
// Store connection
|
|
503
|
+
await this.storeConnection(connection);
|
|
504
|
+
return connection;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
async testConnection(connectionId) {
|
|
508
|
+
// Simulate connection test
|
|
509
|
+
const testStart = Date.now();
|
|
510
|
+
|
|
511
|
+
// Random delay to simulate API call
|
|
512
|
+
await new Promise(resolve => setTimeout(resolve, Math.random() * 500 + 100));
|
|
513
|
+
|
|
514
|
+
const testResult = {
|
|
515
|
+
connectionId,
|
|
516
|
+
healthy: Math.random() > 0.1, // 90% success rate for testing
|
|
517
|
+
latency: Date.now() - testStart,
|
|
518
|
+
timestamp: new Date().toISOString(),
|
|
519
|
+
details: {
|
|
520
|
+
apiVersion: '2.0',
|
|
521
|
+
rateLimits: {
|
|
522
|
+
remaining: 1000,
|
|
523
|
+
reset: new Date(Date.now() + 3600000).toISOString()
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
if (!testResult.healthy) {
|
|
529
|
+
testResult.error = 'Connection test failed: API returned 401 Unauthorized';
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return testResult;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
async setupEnvironmentVariables(integrationName, config, environment) {
|
|
536
|
+
const envVars = {};
|
|
537
|
+
|
|
538
|
+
// Generate environment-specific variables
|
|
539
|
+
const prefix = integrationName.toUpperCase().replace(/-/g, '_');
|
|
540
|
+
|
|
541
|
+
Object.entries(config).forEach(([key, value]) => {
|
|
542
|
+
const envKey = `${prefix}_${key.toUpperCase()}`;
|
|
543
|
+
envVars[envKey] = value;
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// Add environment-specific settings
|
|
547
|
+
envVars[`${prefix}_ENVIRONMENT`] = environment;
|
|
548
|
+
envVars[`${prefix}_DEBUG`] = environment === 'development' ? 'true' : 'false';
|
|
549
|
+
|
|
550
|
+
// Write to .env file
|
|
551
|
+
await this.updateEnvironmentFile(envVars);
|
|
552
|
+
|
|
553
|
+
return envVars;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Utility methods
|
|
557
|
+
|
|
558
|
+
generateWorkflowId() {
|
|
559
|
+
return `workflow-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
generateUserId() {
|
|
563
|
+
return `user-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
generateConnectionId() {
|
|
567
|
+
return `conn-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
generateTestToken(type) {
|
|
571
|
+
const prefix = {
|
|
572
|
+
access: 'at',
|
|
573
|
+
refresh: 'rt',
|
|
574
|
+
api: 'ak',
|
|
575
|
+
password: 'pw'
|
|
576
|
+
}[type] || 'tk';
|
|
577
|
+
|
|
578
|
+
return `${prefix}_test_${Date.now()}_${Math.random().toString(36).substr(2, 16)}`;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
createBatches(items, batchSize) {
|
|
582
|
+
const batches = [];
|
|
583
|
+
for (let i = 0; i < items.length; i += batchSize) {
|
|
584
|
+
batches.push(items.slice(i, i + batchSize));
|
|
585
|
+
}
|
|
586
|
+
return batches;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
getDefaultIntegrationConfig(integrationName, details) {
|
|
590
|
+
// Return sensible defaults based on integration type
|
|
591
|
+
const configs = {
|
|
592
|
+
slack: {
|
|
593
|
+
clientId: 'test-client-id',
|
|
594
|
+
clientSecret: 'test-client-secret',
|
|
595
|
+
signingSecret: 'test-signing-secret',
|
|
596
|
+
webhookUrl: 'http://localhost:3001/webhooks/slack'
|
|
597
|
+
},
|
|
598
|
+
hubspot: {
|
|
599
|
+
clientId: 'test-client-id',
|
|
600
|
+
clientSecret: 'test-client-secret',
|
|
601
|
+
portalId: '12345678',
|
|
602
|
+
scopes: ['contacts', 'deals']
|
|
603
|
+
},
|
|
604
|
+
salesforce: {
|
|
605
|
+
clientId: 'test-client-id',
|
|
606
|
+
clientSecret: 'test-client-secret',
|
|
607
|
+
loginUrl: 'https://test.salesforce.com',
|
|
608
|
+
apiVersion: 'v56.0'
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
return configs[integrationName] || {
|
|
613
|
+
apiKey: 'test-api-key',
|
|
614
|
+
baseUrl: `https://api.${integrationName}.com`
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
async validateIntegrationConfig(integrationName, config) {
|
|
619
|
+
const errors = [];
|
|
620
|
+
|
|
621
|
+
// Basic validation
|
|
622
|
+
if (!config || typeof config !== 'object') {
|
|
623
|
+
errors.push('Configuration must be an object');
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Integration-specific validation
|
|
627
|
+
switch (integrationName) {
|
|
628
|
+
case 'slack':
|
|
629
|
+
if (!config.clientId) errors.push('clientId is required');
|
|
630
|
+
if (!config.clientSecret) errors.push('clientSecret is required');
|
|
631
|
+
break;
|
|
632
|
+
case 'hubspot':
|
|
633
|
+
if (!config.portalId) errors.push('portalId is required');
|
|
634
|
+
if (!config.clientId) errors.push('clientId is required');
|
|
635
|
+
break;
|
|
636
|
+
default:
|
|
637
|
+
if (!config.apiKey && !config.clientId) {
|
|
638
|
+
errors.push('Either apiKey or clientId is required');
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
return {
|
|
643
|
+
valid: errors.length === 0,
|
|
644
|
+
errors
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Placeholder methods for data persistence
|
|
649
|
+
async storeTestUser(user) {
|
|
650
|
+
// In a real implementation, this would store to a database or file
|
|
651
|
+
return user;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
async storeConnection(connection) {
|
|
655
|
+
// In a real implementation, this would store to a database or file
|
|
656
|
+
return connection;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
async saveIntegrationConfig(integrationName, config) {
|
|
660
|
+
// In a real implementation, this would save to a config file
|
|
661
|
+
return config;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
async updateEnvironmentFile(envVars) {
|
|
665
|
+
// In a real implementation, this would update the .env file
|
|
666
|
+
return envVars;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
async getRecommendedIntegrations(projectType) {
|
|
670
|
+
const recommendations = {
|
|
671
|
+
'e-commerce': ['stripe', 'shopify', 'mailchimp', 'google-analytics'],
|
|
672
|
+
'saas': ['stripe', 'hubspot', 'slack', 'intercom'],
|
|
673
|
+
'enterprise': ['salesforce', 'slack', 'jira', 'okta'],
|
|
674
|
+
'default': ['slack', 'google-drive', 'github']
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
return recommendations[projectType] || recommendations.default;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
async createTestUserPool(options) {
|
|
681
|
+
const users = [];
|
|
682
|
+
for (let i = 0; i < options.count; i++) {
|
|
683
|
+
const integration = options.integrations[i % options.integrations.length];
|
|
684
|
+
const user = await this.createTestUser({
|
|
685
|
+
name: `Test User ${i + 1}`,
|
|
686
|
+
email: `test${i + 1}@frigg.test`,
|
|
687
|
+
integration
|
|
688
|
+
});
|
|
689
|
+
users.push(user);
|
|
690
|
+
}
|
|
691
|
+
return users;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
async setupMockData(options) {
|
|
695
|
+
// Generate mock data for testing
|
|
696
|
+
const mockData = {
|
|
697
|
+
users: options.users,
|
|
698
|
+
dataTypes: options.dataTypes,
|
|
699
|
+
generated: {}
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
for (const dataType of options.dataTypes) {
|
|
703
|
+
mockData.generated[dataType] = await this.generateMockData(dataType, options);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return mockData;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
async generateMockData(dataType, options) {
|
|
710
|
+
const generators = {
|
|
711
|
+
contacts: () => ({
|
|
712
|
+
id: Math.random().toString(36).substr(2, 9),
|
|
713
|
+
name: `Contact ${Math.floor(Math.random() * 1000)}`,
|
|
714
|
+
email: `contact${Math.floor(Math.random() * 1000)}@example.com`,
|
|
715
|
+
createdAt: new Date().toISOString()
|
|
716
|
+
}),
|
|
717
|
+
messages: () => ({
|
|
718
|
+
id: Math.random().toString(36).substr(2, 9),
|
|
719
|
+
from: options.users[Math.floor(Math.random() * options.users.length)].email,
|
|
720
|
+
subject: `Test Message ${Math.floor(Math.random() * 1000)}`,
|
|
721
|
+
body: 'This is a test message generated for development.',
|
|
722
|
+
timestamp: new Date().toISOString()
|
|
723
|
+
}),
|
|
724
|
+
tasks: () => ({
|
|
725
|
+
id: Math.random().toString(36).substr(2, 9),
|
|
726
|
+
title: `Task ${Math.floor(Math.random() * 1000)}`,
|
|
727
|
+
assignee: options.users[Math.floor(Math.random() * options.users.length)].id,
|
|
728
|
+
status: ['pending', 'in-progress', 'completed'][Math.floor(Math.random() * 3)],
|
|
729
|
+
dueDate: new Date(Date.now() + Math.random() * 7 * 24 * 60 * 60 * 1000).toISOString()
|
|
730
|
+
})
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
const generator = generators[dataType] || (() => ({ type: dataType, data: {} }));
|
|
734
|
+
const count = 10; // Generate 10 items of each type
|
|
735
|
+
|
|
736
|
+
return Array(count).fill(null).map(() => generator());
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
async configureDevelopmentEnvironment(options) {
|
|
740
|
+
const config = {
|
|
741
|
+
NODE_ENV: 'development',
|
|
742
|
+
DEBUG: 'true',
|
|
743
|
+
LOG_LEVEL: 'debug'
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
// Add integration-specific config
|
|
747
|
+
for (const integration of options.integrations) {
|
|
748
|
+
const prefix = integration.toUpperCase().replace(/-/g, '_');
|
|
749
|
+
if (options.apiKeys[integration]) {
|
|
750
|
+
config[`${prefix}_API_KEY`] = options.apiKeys[integration];
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// Add feature flags
|
|
755
|
+
for (const feature of options.features) {
|
|
756
|
+
config[`FEATURE_${feature.toUpperCase().replace(/-/g, '_')}`] = 'true';
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
return config;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
async validateDevelopmentSetup(workflow) {
|
|
763
|
+
const validation = {
|
|
764
|
+
valid: true,
|
|
765
|
+
checks: [],
|
|
766
|
+
warnings: []
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
// Check integrations
|
|
770
|
+
const integrationCheck = {
|
|
771
|
+
name: 'Integrations',
|
|
772
|
+
passed: workflow.coreIntegrations && workflow.coreIntegrations.summary.successful > 0,
|
|
773
|
+
message: `${workflow.coreIntegrations?.summary.successful || 0} integrations installed successfully`
|
|
774
|
+
};
|
|
775
|
+
validation.checks.push(integrationCheck);
|
|
776
|
+
|
|
777
|
+
// Check test users
|
|
778
|
+
const userCheck = {
|
|
779
|
+
name: 'Test Users',
|
|
780
|
+
passed: workflow.testUsers && workflow.testUsers.length > 0,
|
|
781
|
+
message: `${workflow.testUsers?.length || 0} test users created`
|
|
782
|
+
};
|
|
783
|
+
validation.checks.push(userCheck);
|
|
784
|
+
|
|
785
|
+
// Check environment
|
|
786
|
+
const envCheck = {
|
|
787
|
+
name: 'Environment',
|
|
788
|
+
passed: workflow.environmentConfig && Object.keys(workflow.environmentConfig).length > 0,
|
|
789
|
+
message: 'Environment variables configured'
|
|
790
|
+
};
|
|
791
|
+
validation.checks.push(envCheck);
|
|
792
|
+
|
|
793
|
+
// Add warnings for optional features
|
|
794
|
+
if (!workflow.mockData || Object.keys(workflow.mockData.generated).length === 0) {
|
|
795
|
+
validation.warnings.push('No mock data generated - testing may be limited');
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
validation.valid = validation.checks.every(check => check.passed);
|
|
799
|
+
return validation;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// Project migration methods
|
|
803
|
+
async analyzeExistingProject(projectPath) {
|
|
804
|
+
// Analyze create-frigg-app project structure
|
|
805
|
+
return {
|
|
806
|
+
version: '0.1.0', // Mock version
|
|
807
|
+
integrations: ['slack', 'hubspot'], // Mock detected integrations
|
|
808
|
+
environment: {
|
|
809
|
+
NODE_ENV: 'development',
|
|
810
|
+
// Mock environment variables
|
|
811
|
+
},
|
|
812
|
+
customizations: {
|
|
813
|
+
// Detect any custom code
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
async backupProject(projectPath) {
|
|
819
|
+
const backupPath = `${projectPath}.backup.${Date.now()}`;
|
|
820
|
+
// In real implementation, would copy project files
|
|
821
|
+
return { path: backupPath, timestamp: new Date().toISOString() };
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
async migrateIntegrations(oldIntegrations, mapping) {
|
|
825
|
+
const migrations = [];
|
|
826
|
+
for (const oldIntegration of oldIntegrations) {
|
|
827
|
+
const newIntegration = mapping[oldIntegration] || oldIntegration;
|
|
828
|
+
migrations.push({
|
|
829
|
+
old: oldIntegration,
|
|
830
|
+
new: newIntegration,
|
|
831
|
+
status: 'migrated'
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
return migrations;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
async updateProjectConfiguration(options) {
|
|
838
|
+
// Update project configuration for new structure
|
|
839
|
+
return {
|
|
840
|
+
updated: true,
|
|
841
|
+
files: ['package.json', 'frigg.config.js'],
|
|
842
|
+
changes: {
|
|
843
|
+
structure: 'Updated to new project structure',
|
|
844
|
+
scripts: 'Added management UI scripts',
|
|
845
|
+
dependencies: 'Updated Frigg dependencies'
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
async migrateEnvironmentVariables(projectPath, oldEnv) {
|
|
851
|
+
// Migrate environment variables to new format
|
|
852
|
+
const migrated = {};
|
|
853
|
+
for (const [key, value] of Object.entries(oldEnv)) {
|
|
854
|
+
// Apply any necessary transformations
|
|
855
|
+
migrated[key] = value;
|
|
856
|
+
}
|
|
857
|
+
return migrated;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
async testMigratedProject(projectPath) {
|
|
861
|
+
// Run tests on migrated project
|
|
862
|
+
return {
|
|
863
|
+
passed: true,
|
|
864
|
+
tests: [
|
|
865
|
+
{ name: 'Structure validation', passed: true },
|
|
866
|
+
{ name: 'Dependency check', passed: true },
|
|
867
|
+
{ name: 'Configuration validation', passed: true },
|
|
868
|
+
{ name: 'Integration connectivity', passed: true }
|
|
869
|
+
]
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
async rollbackProject(projectPath, backupPath) {
|
|
874
|
+
// Restore project from backup
|
|
875
|
+
console.log(`Rolling back project from ${backupPath}`);
|
|
876
|
+
return true;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Export singleton instance for convenience
|
|
881
|
+
export const phase2Workflows = new Phase2IntegrationWorkflows();
|
|
882
|
+
|
|
883
|
+
// Also export class for testing and custom instances
|
|
884
|
+
export default Phase2IntegrationWorkflows;
|