@friggframework/devtools 2.0.0--canary.546.74db90f.0 → 2.0.0--canary.545.e7becd9.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.
- package/frigg-cli/README.md +1 -1
- package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +326 -0
- package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +337 -0
- package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +373 -0
- package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +313 -0
- package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +269 -0
- package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +82 -0
- package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +408 -0
- package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +583 -0
- package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +314 -0
- package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +383 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +1 -1
- package/frigg-cli/__tests__/unit/commands/doctor.test.js +0 -2
- package/frigg-cli/__tests__/unit/commands/init.test.js +406 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +23 -19
- package/frigg-cli/__tests__/unit/commands/provider-dispatch.test.js +383 -0
- package/frigg-cli/__tests__/unit/commands/repair.test.js +275 -0
- package/frigg-cli/__tests__/unit/dependencies.test.js +2 -2
- package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +411 -0
- package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +405 -0
- package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +496 -0
- package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +474 -0
- package/frigg-cli/__tests__/unit/utils/output.test.js +196 -0
- package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +93 -0
- package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +93 -0
- package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +103 -0
- package/frigg-cli/build-command/index.js +123 -11
- package/frigg-cli/container.js +172 -0
- package/frigg-cli/deploy-command/index.js +83 -1
- package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +286 -0
- package/frigg-cli/doctor-command/index.js +37 -16
- package/frigg-cli/domain/entities/ApiModule.js +272 -0
- package/frigg-cli/domain/entities/AppDefinition.js +227 -0
- package/frigg-cli/domain/entities/Integration.js +198 -0
- package/frigg-cli/domain/exceptions/DomainException.js +24 -0
- package/frigg-cli/domain/ports/IApiModuleRepository.js +53 -0
- package/frigg-cli/domain/ports/IAppDefinitionRepository.js +43 -0
- package/frigg-cli/domain/ports/IIntegrationRepository.js +61 -0
- package/frigg-cli/domain/services/IntegrationValidator.js +185 -0
- package/frigg-cli/domain/value-objects/IntegrationId.js +42 -0
- package/frigg-cli/domain/value-objects/IntegrationName.js +60 -0
- package/frigg-cli/domain/value-objects/SemanticVersion.js +70 -0
- package/frigg-cli/generate-iam-command.js +21 -1
- package/frigg-cli/index.js +21 -6
- package/frigg-cli/index.test.js +7 -2
- package/frigg-cli/infrastructure/UnitOfWork.js +46 -0
- package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +197 -0
- package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +224 -0
- package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +249 -0
- package/frigg-cli/infrastructure/adapters/SchemaValidator.js +92 -0
- package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +373 -0
- package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +116 -0
- package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +277 -0
- package/frigg-cli/init-command/backend-first-handler.js +124 -42
- package/frigg-cli/init-command/index.js +2 -1
- package/frigg-cli/init-command/template-handler.js +13 -3
- package/frigg-cli/install-command/backend-js.js +3 -3
- package/frigg-cli/install-command/environment-variables.js +16 -19
- package/frigg-cli/install-command/environment-variables.test.js +12 -13
- package/frigg-cli/install-command/index.js +14 -9
- package/frigg-cli/install-command/integration-file.js +3 -3
- package/frigg-cli/install-command/validate-package.js +5 -9
- package/frigg-cli/jest.config.js +4 -1
- package/frigg-cli/package-lock.json +16226 -0
- package/frigg-cli/repair-command/index.js +121 -128
- package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +376 -0
- package/frigg-cli/start-command/index.js +324 -2
- package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +591 -0
- package/frigg-cli/start-command/infrastructure/DockerAdapter.js +306 -0
- package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +329 -0
- package/frigg-cli/templates/backend/.env.example +62 -0
- package/frigg-cli/templates/backend/.eslintrc.json +12 -0
- package/frigg-cli/templates/backend/.prettierrc +6 -0
- package/frigg-cli/templates/backend/docker-compose.yml +22 -0
- package/frigg-cli/templates/backend/index.js +96 -0
- package/frigg-cli/templates/backend/infrastructure.js +12 -0
- package/frigg-cli/templates/backend/jest.config.js +17 -0
- package/frigg-cli/templates/backend/package.json +50 -0
- package/frigg-cli/templates/backend/src/api-modules/.gitkeep +10 -0
- package/frigg-cli/templates/backend/src/base/.gitkeep +7 -0
- package/frigg-cli/templates/backend/src/integrations/.gitkeep +10 -0
- package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +65 -0
- package/frigg-cli/templates/backend/src/utils/.gitkeep +7 -0
- package/frigg-cli/templates/backend/test/setup.js +30 -0
- package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
- package/frigg-cli/templates/backend/ui-extensions/README.md +77 -0
- package/frigg-cli/ui-command/index.js +58 -36
- package/frigg-cli/utils/__tests__/provider-helper.test.js +55 -0
- package/frigg-cli/utils/__tests__/repo-detection.test.js +436 -0
- package/frigg-cli/utils/output.js +382 -0
- package/frigg-cli/utils/provider-helper.js +75 -0
- package/frigg-cli/utils/repo-detection.js +85 -37
- package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +205 -0
- package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +104 -0
- package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +153 -0
- package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +162 -0
- package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +152 -0
- package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +332 -0
- package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +191 -0
- package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +146 -0
- package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +155 -0
- package/frigg-cli/validate-command/adapters/cli/validate-command.js +199 -0
- package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +35 -0
- package/frigg-cli/validate-command/domain/entities/validation-result.js +74 -0
- package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +74 -0
- package/frigg-cli/validate-command/domain/value-objects/validation-error.js +68 -0
- package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +181 -0
- package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +128 -0
- package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +113 -0
- package/infrastructure/create-frigg-infrastructure.js +93 -0
- package/infrastructure/docs/iam-policy-templates.md +1 -1
- package/infrastructure/domains/admin-scripts/admin-script-builder.js +200 -0
- package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +499 -0
- package/infrastructure/domains/admin-scripts/index.js +5 -0
- package/infrastructure/domains/networking/vpc-builder.test.js +2 -4
- package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +4 -7
- package/infrastructure/domains/shared/resource-discovery.js +5 -5
- package/infrastructure/domains/shared/types/app-definition.js +21 -0
- package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +10 -1
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
- package/infrastructure/infrastructure-composer.js +2 -0
- package/infrastructure/infrastructure-composer.test.js +2 -2
- package/infrastructure/jest.config.js +16 -0
- package/management-ui/README.md +245 -109
- package/package.json +8 -7
- package/frigg-cli/install-command/logger.js +0 -12
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
version: '3.8'
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
postgres:
|
|
5
|
+
image: postgres:15-alpine
|
|
6
|
+
container_name: frigg-postgres
|
|
7
|
+
environment:
|
|
8
|
+
POSTGRES_USER: frigg
|
|
9
|
+
POSTGRES_PASSWORD: frigg
|
|
10
|
+
POSTGRES_DB: frigg
|
|
11
|
+
ports:
|
|
12
|
+
- "5432:5432"
|
|
13
|
+
volumes:
|
|
14
|
+
- postgres_data:/var/lib/postgresql/data
|
|
15
|
+
healthcheck:
|
|
16
|
+
test: ["CMD-SHELL", "pg_isready -U frigg"]
|
|
17
|
+
interval: 5s
|
|
18
|
+
timeout: 5s
|
|
19
|
+
retries: 5
|
|
20
|
+
|
|
21
|
+
volumes:
|
|
22
|
+
postgres_data:
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frigg Application Definition
|
|
3
|
+
*
|
|
4
|
+
* This file defines your Frigg integration application.
|
|
5
|
+
* Configure integrations, authentication, and infrastructure settings here.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Import your integrations here
|
|
9
|
+
// const ExampleIntegration = require('./src/integrations/ExampleIntegration');
|
|
10
|
+
|
|
11
|
+
const appDefinition = {
|
|
12
|
+
// Application metadata
|
|
13
|
+
label: 'My Frigg Application',
|
|
14
|
+
name: 'my-frigg-app',
|
|
15
|
+
|
|
16
|
+
// Deployment mode: 'managed' (recommended) or 'custom'
|
|
17
|
+
managementMode: 'managed',
|
|
18
|
+
|
|
19
|
+
// VPC isolation strategy: 'isolated' (each stage separate) or 'shared'
|
|
20
|
+
vpcIsolation: 'isolated',
|
|
21
|
+
|
|
22
|
+
// Your integrations - add Integration classes here
|
|
23
|
+
integrations: [
|
|
24
|
+
// Add your integrations here as you install them
|
|
25
|
+
// Example:
|
|
26
|
+
// ExampleIntegration,
|
|
27
|
+
],
|
|
28
|
+
|
|
29
|
+
// User authentication configuration
|
|
30
|
+
user: {
|
|
31
|
+
usePassword: true,
|
|
32
|
+
primary: 'organization',
|
|
33
|
+
individualUserRequired: true,
|
|
34
|
+
organizationUserRequired: true,
|
|
35
|
+
authModes: {
|
|
36
|
+
friggToken: true, // Support web UI login
|
|
37
|
+
sharedSecret: true, // Enable backend-to-backend API communication
|
|
38
|
+
adopterJwt: false, // Set true to use your own JWT tokens
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
// Encryption settings
|
|
43
|
+
encryption: {
|
|
44
|
+
fieldLevelEncryptionMethod: 'kms', // KMS encryption for production
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// VPC configuration
|
|
48
|
+
vpc: {
|
|
49
|
+
enable: true,
|
|
50
|
+
enableVPCEndpoints: true,
|
|
51
|
+
selfHeal: true,
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// Database configuration (PostgreSQL via Aurora Serverless)
|
|
55
|
+
database: {
|
|
56
|
+
postgres: {
|
|
57
|
+
enable: true,
|
|
58
|
+
publiclyAccessible: false,
|
|
59
|
+
database: 'postgres',
|
|
60
|
+
minCapacity: 0.5,
|
|
61
|
+
maxCapacity: 1,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// SSM Parameter Store (optional)
|
|
66
|
+
ssm: {
|
|
67
|
+
enable: false,
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Environment variables required by your application
|
|
71
|
+
// Set these in your .env file or deployment environment
|
|
72
|
+
environment: {
|
|
73
|
+
// Core Configuration
|
|
74
|
+
BASE_URL: true,
|
|
75
|
+
DATABASE_URL: true,
|
|
76
|
+
DATABASE_USER: true,
|
|
77
|
+
DATABASE_PASSWORD: true,
|
|
78
|
+
REDIRECT_URI: true,
|
|
79
|
+
HEALTH_API_KEY: true,
|
|
80
|
+
ADMIN_API_KEY: true,
|
|
81
|
+
FRIGG_API_KEY: true,
|
|
82
|
+
FRIGG_APP_USER_ID: true,
|
|
83
|
+
|
|
84
|
+
// AWS Configuration
|
|
85
|
+
AWS_REGION: true,
|
|
86
|
+
S3_BUCKET_NAME: true,
|
|
87
|
+
|
|
88
|
+
// Add your integration-specific environment variables here
|
|
89
|
+
// EXAMPLE_CLIENT_ID: true,
|
|
90
|
+
// EXAMPLE_CLIENT_SECRET: true,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
module.exports = {
|
|
95
|
+
Definition: appDefinition,
|
|
96
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frigg Infrastructure Configuration
|
|
3
|
+
*
|
|
4
|
+
* This file exports the serverless configuration for your Frigg application.
|
|
5
|
+
* The createFriggInfrastructure function reads your app definition and
|
|
6
|
+
* generates the appropriate serverless.yml configuration.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { createFriggInfrastructure } = require('@friggframework/devtools');
|
|
10
|
+
|
|
11
|
+
// Serverless supports async configuration by exporting a promise
|
|
12
|
+
module.exports = createFriggInfrastructure();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
testEnvironment: 'node',
|
|
3
|
+
testMatch: ['**/test/**/*.test.js', '**/test/**/*.spec.js'],
|
|
4
|
+
testPathIgnorePatterns: ['/node_modules/'],
|
|
5
|
+
collectCoverageFrom: [
|
|
6
|
+
'src/**/*.js',
|
|
7
|
+
'!src/**/*.test.js',
|
|
8
|
+
'!src/**/*.spec.js',
|
|
9
|
+
],
|
|
10
|
+
coverageDirectory: 'coverage',
|
|
11
|
+
coverageReporters: ['text', 'lcov', 'html'],
|
|
12
|
+
verbose: true,
|
|
13
|
+
testTimeout: 30000,
|
|
14
|
+
setupFilesAfterEnv: ['./test/setup.js'],
|
|
15
|
+
// Jest groups for selective testing
|
|
16
|
+
runner: 'groups',
|
|
17
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "frigg-backend",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"prettier": "@friggframework/prettier-config",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "jest --group=-interactive --group=-live-api",
|
|
8
|
+
"test:full": "jest",
|
|
9
|
+
"test:unit": "jest --config jest.unit.config.js",
|
|
10
|
+
"test:watch": "jest --watch",
|
|
11
|
+
"test:coverage": "jest --coverage",
|
|
12
|
+
"lint": "eslint .",
|
|
13
|
+
"lint:fix": "prettier --write --loglevel error . && eslint . --fix",
|
|
14
|
+
"format": "prettier --write --loglevel error .",
|
|
15
|
+
"backend-start": "sls offline --stage dev --config serverless.js",
|
|
16
|
+
"docker:start": "docker compose up -d",
|
|
17
|
+
"docker:stop": "docker compose down",
|
|
18
|
+
"frigg:start": "frigg start",
|
|
19
|
+
"frigg:deploy": "frigg deploy",
|
|
20
|
+
"frigg:db:setup": "frigg db:setup"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@friggframework/core": "2.0.0-next.58",
|
|
24
|
+
"axios": "^1.6.0",
|
|
25
|
+
"body-parser": "^1.20.3",
|
|
26
|
+
"cors": "^2.8.5",
|
|
27
|
+
"express": "^4.21.2",
|
|
28
|
+
"express-async-handler": "^1.2.0",
|
|
29
|
+
"node-cache": "^5.1.2",
|
|
30
|
+
"serverless-http": "^2.7.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@friggframework/devtools": "2.0.0-next.58",
|
|
34
|
+
"@friggframework/eslint-config": "2.0.0-next.58",
|
|
35
|
+
"@friggframework/prettier-config": "2.0.0-next.58",
|
|
36
|
+
"@friggframework/serverless-plugin": "2.0.0-next.58",
|
|
37
|
+
"@friggframework/test": "2.0.0-next.58",
|
|
38
|
+
"@prisma/client": "^6.0.0",
|
|
39
|
+
"dotenv": "^16.4.5",
|
|
40
|
+
"esbuild": "^0.25.0",
|
|
41
|
+
"jest": "^29.7.0",
|
|
42
|
+
"nock": "^13.5.4",
|
|
43
|
+
"osls": "^3.40.1",
|
|
44
|
+
"prettier": "3.5.3",
|
|
45
|
+
"prisma": "^6.0.0",
|
|
46
|
+
"serverless-dotenv-plugin": "^6.0.0",
|
|
47
|
+
"serverless-esbuild": "^1.55.1",
|
|
48
|
+
"serverless-offline": "^13.8.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# This directory is for custom API modules
|
|
2
|
+
#
|
|
3
|
+
# API modules define how to connect with external APIs.
|
|
4
|
+
# Most integrations use published @friggframework/api-module-* packages.
|
|
5
|
+
#
|
|
6
|
+
# Only create custom API modules here if:
|
|
7
|
+
# - You're integrating with a proprietary API
|
|
8
|
+
# - No published module exists for your service
|
|
9
|
+
#
|
|
10
|
+
# Use 'frigg generate:api-module' to create new API modules
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# This directory contains your Integration classes
|
|
2
|
+
# Each integration connects your application with a third-party API module
|
|
3
|
+
#
|
|
4
|
+
# Example structure:
|
|
5
|
+
# src/integrations/
|
|
6
|
+
# SalesforceIntegration.js
|
|
7
|
+
# HubSpotIntegration.js
|
|
8
|
+
# SlackIntegration.js
|
|
9
|
+
#
|
|
10
|
+
# Use 'frigg generate:integration' to create new integrations
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example Integration
|
|
3
|
+
*
|
|
4
|
+
* This is a template showing how to create an Integration class.
|
|
5
|
+
* An Integration connects your application with a third-party API module.
|
|
6
|
+
*
|
|
7
|
+
* To create your own integration:
|
|
8
|
+
* 1. Install the API module: npm install @friggframework/api-module-<name>
|
|
9
|
+
* 2. Copy this file and rename it (e.g., SalesforceIntegration.js)
|
|
10
|
+
* 3. Update the imports and class to use your API module
|
|
11
|
+
* 4. Register it in index.js
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { Integration } = require('@friggframework/core');
|
|
15
|
+
// const { Api, Entity } = require('@friggframework/api-module-example');
|
|
16
|
+
|
|
17
|
+
class ExampleIntegration extends Integration {
|
|
18
|
+
static Definition = {
|
|
19
|
+
name: 'example',
|
|
20
|
+
version: '1.0.0',
|
|
21
|
+
supportedVersions: ['1.0.0'],
|
|
22
|
+
|
|
23
|
+
// Events this integration can emit
|
|
24
|
+
events: ['SYNC_COMPLETED', 'DATA_UPDATED', 'ERROR_OCCURRED'],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create API instance for this integration
|
|
29
|
+
* @param {Object} params - Parameters from the credential
|
|
30
|
+
*/
|
|
31
|
+
static async getInstance(params) {
|
|
32
|
+
// Return your API module instance
|
|
33
|
+
// return new Api(params);
|
|
34
|
+
throw new Error('ExampleIntegration.getInstance() not implemented');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Process incoming webhook events
|
|
39
|
+
* @param {Object} event - The webhook event data
|
|
40
|
+
*/
|
|
41
|
+
async processWebhook(event) {
|
|
42
|
+
// Handle webhook events from the third-party service
|
|
43
|
+
console.log('Processing webhook:', event);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Perform initial sync after user connects
|
|
48
|
+
* @param {Object} options - Sync options
|
|
49
|
+
*/
|
|
50
|
+
async initialSync(options = {}) {
|
|
51
|
+
// Sync initial data from the third-party service
|
|
52
|
+
console.log('Performing initial sync');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Handle OAuth callback
|
|
57
|
+
* @param {Object} callbackParams - OAuth callback parameters
|
|
58
|
+
*/
|
|
59
|
+
async handleCallback(callbackParams) {
|
|
60
|
+
// Process OAuth callback and store credentials
|
|
61
|
+
console.log('Handling OAuth callback');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = ExampleIntegration;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jest Test Setup
|
|
3
|
+
*
|
|
4
|
+
* This file runs before each test file and sets up the testing environment.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const dotenv = require('dotenv');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
// Load test environment variables
|
|
11
|
+
dotenv.config({ path: path.join(__dirname, '..', '.env.test') });
|
|
12
|
+
|
|
13
|
+
// Set test environment
|
|
14
|
+
process.env.NODE_ENV = 'test';
|
|
15
|
+
|
|
16
|
+
// Global test timeout
|
|
17
|
+
jest.setTimeout(30000);
|
|
18
|
+
|
|
19
|
+
// Silence console logs during tests (optional - comment out for debugging)
|
|
20
|
+
// global.console = {
|
|
21
|
+
// ...console,
|
|
22
|
+
// log: jest.fn(),
|
|
23
|
+
// info: jest.fn(),
|
|
24
|
+
// warn: jest.fn(),
|
|
25
|
+
// };
|
|
26
|
+
|
|
27
|
+
// Clean up after all tests
|
|
28
|
+
afterAll(async () => {
|
|
29
|
+
// Add any global cleanup here
|
|
30
|
+
});
|
|
File without changes
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# UI Extensions
|
|
2
|
+
|
|
3
|
+
This directory contains custom UI extensions for external platform integrations. Each subdirectory represents a separate integration-specific package.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
When integrating with platforms that provide their own UI extension frameworks (like Attio, HubSpot, Salesforce, etc.), you can build and manage those extension packages here.
|
|
8
|
+
|
|
9
|
+
## Directory Structure
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
ui-extensions/
|
|
13
|
+
├── README.md # This file
|
|
14
|
+
├── attio/ # Attio UI extension (if using Attio)
|
|
15
|
+
├── hubspot/ # HubSpot UI extension (if using HubSpot)
|
|
16
|
+
├── salesforce/ # Salesforce Lightning component (if using Salesforce)
|
|
17
|
+
└── <platform>/ # Other platform-specific extensions
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Getting Started
|
|
21
|
+
|
|
22
|
+
Each platform extension is a separate npm package. To create one:
|
|
23
|
+
|
|
24
|
+
1. **Create the extension directory:**
|
|
25
|
+
```bash
|
|
26
|
+
mkdir ui-extensions/<platform-name>
|
|
27
|
+
cd ui-extensions/<platform-name>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
2. **Initialize the package:**
|
|
31
|
+
Follow the platform's SDK documentation to set up the extension package.
|
|
32
|
+
|
|
33
|
+
3. **Develop and test:**
|
|
34
|
+
Each extension has its own build and development scripts.
|
|
35
|
+
|
|
36
|
+
## Example: Attio Extension
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd ui-extensions/attio
|
|
40
|
+
npm install
|
|
41
|
+
npm run dev # Start development server
|
|
42
|
+
npm run build # Build for production
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Example: HubSpot Extension
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cd ui-extensions/hubspot
|
|
49
|
+
npm install
|
|
50
|
+
npx hs project create --template=react-app
|
|
51
|
+
npm run dev
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Workspace Integration
|
|
55
|
+
|
|
56
|
+
Add extensions as workspaces in the root `package.json`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"workspaces": [
|
|
61
|
+
"ui-extensions/*"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Platform Documentation
|
|
67
|
+
|
|
68
|
+
- [Attio Apps](https://developers.attio.com)
|
|
69
|
+
- [HubSpot UI Extensions](https://developers.hubspot.com/docs/platform/ui-extensions-overview)
|
|
70
|
+
- [Salesforce Lightning Components](https://developer.salesforce.com/docs/atlas.en-us.lightning.meta)
|
|
71
|
+
- [Monday.com Apps](https://developer.monday.com/apps)
|
|
72
|
+
|
|
73
|
+
## Notes
|
|
74
|
+
|
|
75
|
+
- Each extension is independent and can be deployed separately
|
|
76
|
+
- Extensions typically have their own build tools and test suites
|
|
77
|
+
- Keep platform-specific code isolated to its respective directory
|
|
@@ -2,16 +2,19 @@ const open = require('open');
|
|
|
2
2
|
const chalk = require('chalk');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const ProcessManager = require('../utils/process-manager');
|
|
5
|
-
const {
|
|
6
|
-
getCurrentRepositoryInfo,
|
|
7
|
-
discoverFriggRepositories,
|
|
5
|
+
const {
|
|
6
|
+
getCurrentRepositoryInfo,
|
|
7
|
+
discoverFriggRepositories,
|
|
8
8
|
promptRepositorySelection,
|
|
9
|
-
formatRepositoryInfo
|
|
9
|
+
formatRepositoryInfo
|
|
10
10
|
} = require('../utils/repo-detection');
|
|
11
11
|
|
|
12
12
|
async function uiCommand(options) {
|
|
13
|
-
const { port =
|
|
14
|
-
|
|
13
|
+
const { port = 3210, open: shouldOpen = true, repo: specifiedRepo, dev = false } = options;
|
|
14
|
+
|
|
15
|
+
// Fix: --no-open should set open to false, not use the default true
|
|
16
|
+
const shouldOpenBrowser = options.open !== false;
|
|
17
|
+
|
|
15
18
|
let targetRepo = null;
|
|
16
19
|
let workingDirectory = process.cwd();
|
|
17
20
|
|
|
@@ -25,7 +28,7 @@ async function uiCommand(options) {
|
|
|
25
28
|
// Check if we're already in a Frigg repository
|
|
26
29
|
console.log(chalk.blue('Detecting Frigg repository...'));
|
|
27
30
|
const currentRepo = await getCurrentRepositoryInfo();
|
|
28
|
-
|
|
31
|
+
|
|
29
32
|
if (currentRepo) {
|
|
30
33
|
console.log(chalk.green(`✓ Found Frigg repository: ${formatRepositoryInfo(currentRepo)}`));
|
|
31
34
|
if (currentRepo.currentSubPath) {
|
|
@@ -37,40 +40,40 @@ async function uiCommand(options) {
|
|
|
37
40
|
// Discover Frigg repositories
|
|
38
41
|
console.log(chalk.yellow('Current directory is not a Frigg repository.'));
|
|
39
42
|
console.log(chalk.blue('Searching for Frigg repositories...'));
|
|
40
|
-
|
|
43
|
+
|
|
41
44
|
const discoveredRepos = await discoverFriggRepositories();
|
|
42
|
-
|
|
45
|
+
|
|
43
46
|
if (discoveredRepos.length === 0) {
|
|
44
47
|
console.log(chalk.red('No Frigg repositories found. Please create one first.'));
|
|
45
48
|
process.exit(1);
|
|
46
49
|
}
|
|
47
|
-
|
|
50
|
+
|
|
48
51
|
// For UI command, we'll let the UI handle repository selection
|
|
49
52
|
// Set a placeholder and pass the discovered repos via environment
|
|
50
|
-
targetRepo = {
|
|
51
|
-
name: 'Multiple Repositories Available',
|
|
53
|
+
targetRepo = {
|
|
54
|
+
name: 'Multiple Repositories Available',
|
|
52
55
|
path: process.cwd(),
|
|
53
56
|
isMultiRepo: true,
|
|
54
57
|
availableRepos: discoveredRepos
|
|
55
58
|
};
|
|
56
59
|
workingDirectory = process.cwd();
|
|
57
|
-
|
|
60
|
+
|
|
58
61
|
console.log(chalk.blue(`Found ${discoveredRepos.length} Frigg repositories. You'll be able to select one in the UI.`));
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
console.log(chalk.blue('🚀 Starting Frigg Management UI...'));
|
|
63
|
-
|
|
66
|
+
|
|
64
67
|
const processManager = new ProcessManager();
|
|
65
|
-
|
|
68
|
+
|
|
66
69
|
try {
|
|
67
70
|
const managementUiPath = path.join(__dirname, '../../management-ui');
|
|
68
|
-
|
|
71
|
+
|
|
69
72
|
// Check if we're in development mode
|
|
70
73
|
// For CLI usage, we prefer development mode unless explicitly set to production
|
|
71
74
|
const fs = require('fs');
|
|
72
75
|
const isDevelopment = dev || process.env.NODE_ENV !== 'production';
|
|
73
|
-
|
|
76
|
+
|
|
74
77
|
if (isDevelopment) {
|
|
75
78
|
const env = {
|
|
76
79
|
...process.env,
|
|
@@ -80,15 +83,15 @@ async function uiCommand(options) {
|
|
|
80
83
|
REPOSITORY_INFO: JSON.stringify(targetRepo),
|
|
81
84
|
AVAILABLE_REPOSITORIES: targetRepo.isMultiRepo ? JSON.stringify(targetRepo.availableRepos) : null
|
|
82
85
|
};
|
|
83
|
-
|
|
84
|
-
// Start backend server
|
|
86
|
+
|
|
87
|
+
// Start backend server with nodemon for auto-restart
|
|
85
88
|
processManager.spawnProcess(
|
|
86
89
|
'backend',
|
|
87
90
|
'npm',
|
|
88
|
-
['run', 'server'],
|
|
91
|
+
['run', 'server:dev'],
|
|
89
92
|
{ cwd: managementUiPath, env }
|
|
90
93
|
);
|
|
91
|
-
|
|
94
|
+
|
|
92
95
|
// Start frontend dev server
|
|
93
96
|
processManager.spawnProcess(
|
|
94
97
|
'frontend',
|
|
@@ -96,52 +99,71 @@ async function uiCommand(options) {
|
|
|
96
99
|
['run', 'dev'],
|
|
97
100
|
{ cwd: managementUiPath, env }
|
|
98
101
|
);
|
|
99
|
-
|
|
100
|
-
// Wait for
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
|
|
103
|
+
// Wait for backend to be ready by polling health endpoint
|
|
104
|
+
const maxAttempts = 20;
|
|
105
|
+
const delayMs = 250;
|
|
106
|
+
let backendReady = false;
|
|
107
|
+
|
|
108
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
109
|
+
try {
|
|
110
|
+
const response = await fetch(`http://localhost:${port}/api/health`);
|
|
111
|
+
if (response.ok) {
|
|
112
|
+
backendReady = true;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
// Backend not ready yet, wait and retry
|
|
117
|
+
}
|
|
118
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!backendReady) {
|
|
122
|
+
console.warn('⚠️ Backend health check timed out, but continuing anyway...');
|
|
123
|
+
}
|
|
124
|
+
|
|
103
125
|
// Display clean status
|
|
104
126
|
processManager.printStatus(
|
|
105
127
|
'http://localhost:5173',
|
|
106
128
|
`http://localhost:${port}`,
|
|
107
129
|
targetRepo.name
|
|
108
130
|
);
|
|
109
|
-
|
|
131
|
+
|
|
110
132
|
// Open browser if requested
|
|
111
|
-
if (
|
|
133
|
+
if (shouldOpenBrowser) {
|
|
112
134
|
setTimeout(() => {
|
|
113
135
|
open('http://localhost:5173');
|
|
114
136
|
}, 1000);
|
|
115
137
|
}
|
|
116
|
-
|
|
138
|
+
|
|
117
139
|
} else {
|
|
118
140
|
// Production mode - just start the backend server
|
|
119
141
|
const { FriggManagementServer } = await import('../../management-ui/server/index.js');
|
|
120
|
-
|
|
121
|
-
const server = new FriggManagementServer({
|
|
122
|
-
port,
|
|
142
|
+
|
|
143
|
+
const server = new FriggManagementServer({
|
|
144
|
+
port,
|
|
123
145
|
projectRoot: workingDirectory,
|
|
124
146
|
repositoryInfo: targetRepo,
|
|
125
147
|
availableRepositories: targetRepo.isMultiRepo ? targetRepo.availableRepos : null
|
|
126
148
|
});
|
|
127
149
|
await server.start();
|
|
128
|
-
|
|
150
|
+
|
|
129
151
|
processManager.printStatus(
|
|
130
152
|
`http://localhost:${port}`,
|
|
131
153
|
`http://localhost:${port}/api`,
|
|
132
154
|
targetRepo.name
|
|
133
155
|
);
|
|
134
|
-
|
|
135
|
-
if (
|
|
156
|
+
|
|
157
|
+
if (shouldOpenBrowser) {
|
|
136
158
|
setTimeout(() => {
|
|
137
159
|
open(`http://localhost:${port}`);
|
|
138
160
|
}, 1000);
|
|
139
161
|
}
|
|
140
162
|
}
|
|
141
|
-
|
|
163
|
+
|
|
142
164
|
// Keep the process running
|
|
143
165
|
process.stdin.resume();
|
|
144
|
-
|
|
166
|
+
|
|
145
167
|
} catch (error) {
|
|
146
168
|
console.error(chalk.red('Failed to start Management UI:'), error.message);
|
|
147
169
|
if (error.code === 'EADDRINUSE') {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { loadProviderForCli, loadCliAppDefinition } = require('../provider-helper');
|
|
3
|
+
|
|
4
|
+
describe('provider-helper', () => {
|
|
5
|
+
describe('loadCliAppDefinition', () => {
|
|
6
|
+
it('returns null when no index.js exists', () => {
|
|
7
|
+
const result = loadCliAppDefinition('/nonexistent/path');
|
|
8
|
+
expect(result).toBeNull();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('returns null when index.js has no Definition export', () => {
|
|
12
|
+
// Use a directory that has an index.js but no Definition
|
|
13
|
+
const result = loadCliAppDefinition(
|
|
14
|
+
path.join(__dirname, '..', '..')
|
|
15
|
+
);
|
|
16
|
+
// frigg-cli/index.js doesn't export Definition
|
|
17
|
+
expect(result).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('loadProviderForCli', () => {
|
|
22
|
+
it('returns null when no appDefinition found', () => {
|
|
23
|
+
// Run from a directory with no Frigg app
|
|
24
|
+
const originalCwd = process.cwd();
|
|
25
|
+
try {
|
|
26
|
+
process.chdir('/tmp');
|
|
27
|
+
const result = loadProviderForCli();
|
|
28
|
+
expect(result).toBeNull();
|
|
29
|
+
} finally {
|
|
30
|
+
process.chdir(originalCwd);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns null provider for aws (default)', () => {
|
|
35
|
+
// Mock: loadCliAppDefinition returns an appDef with provider: 'aws'
|
|
36
|
+
jest.mock('../provider-helper', () => {
|
|
37
|
+
const original = jest.requireActual('../provider-helper');
|
|
38
|
+
return {
|
|
39
|
+
...original,
|
|
40
|
+
loadProviderForCli: (options) => {
|
|
41
|
+
// Simulate AWS provider (no provider field defaults to aws)
|
|
42
|
+
return { appDefinition: { provider: 'aws' }, provider: null, providerName: 'aws' };
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const { loadProviderForCli: mocked } = require('../provider-helper');
|
|
48
|
+
const result = mocked();
|
|
49
|
+
expect(result.providerName).toBe('aws');
|
|
50
|
+
expect(result.provider).toBeNull();
|
|
51
|
+
|
|
52
|
+
jest.restoreAllMocks();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|