@friggframework/devtools 2.0.0--canary.419.99533fd.1 → 2.0.0--canary.424.a864ff6.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/NON_INTERACTIVE_MODE.md +290 -0
- package/frigg-cli/__tests__/unit/commands/backend-first-handler.test.js +207 -0
- package/frigg-cli/index.js +33 -6
- package/frigg-cli/index.test.js +4 -4
- package/frigg-cli/init-command/backend-first-handler.js +42 -3
- package/frigg-cli/init-command/frigg-config.example.json +13 -0
- package/frigg-cli/init-command/index.js +52 -6
- package/frigg-cli/templates/backend/index.js +42 -0
- package/frigg-cli/templates/backend/infrastructure.js +36 -0
- package/frigg-cli/templates/backend/package.json +18 -0
- package/frigg-cli/templates/backend/serverless.yml +25 -0
- package/frigg-cli/test/init-cli.test.js +48 -0
- package/frigg-cli/test/init-command.test.js +78 -4
- package/frigg-cli/test/npm-registry.test.js +1 -1
- package/infrastructure/README.md +104 -114
- package/infrastructure/serverless-template.js +0 -7
- package/management-ui/server/api/cli.js +6 -3
- package/management-ui/server/utils/cliIntegration.js +18 -4
- package/package.json +6 -6
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const chalk = require('chalk');
|
|
12
|
+
const fs = require('fs-extra');
|
|
12
13
|
const validateProjectName = require('validate-npm-package-name');
|
|
13
14
|
const semver = require('semver');
|
|
14
15
|
const BackendFirstHandler = require('./backend-first-handler');
|
|
@@ -54,6 +55,10 @@ async function initCommand(projectName, options) {
|
|
|
54
55
|
const verbose = options.verbose || false;
|
|
55
56
|
const force = options.force || false;
|
|
56
57
|
|
|
58
|
+
// Handle non-interactive mode flags
|
|
59
|
+
const nonInteractive = options.nonInteractive || options['no-interactive'] || options.yes || false;
|
|
60
|
+
const interactive = !nonInteractive;
|
|
61
|
+
|
|
57
62
|
checkNodeVersion();
|
|
58
63
|
|
|
59
64
|
const root = path.resolve(projectName);
|
|
@@ -61,15 +66,56 @@ async function initCommand(projectName, options) {
|
|
|
61
66
|
|
|
62
67
|
checkAppName(appName);
|
|
63
68
|
|
|
69
|
+
// Load configuration from file if provided
|
|
70
|
+
let configFromFile = {};
|
|
71
|
+
if (options.config) {
|
|
72
|
+
try {
|
|
73
|
+
const configPath = path.resolve(options.config);
|
|
74
|
+
if (await fs.pathExists(configPath)) {
|
|
75
|
+
configFromFile = await fs.readJSON(configPath);
|
|
76
|
+
} else {
|
|
77
|
+
console.log(chalk.yellow(`Warning: Config file not found: ${configPath}`));
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.log(chalk.yellow(`Warning: Could not load config file: ${error.message}`));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Merge options with environment variables and config file
|
|
85
|
+
const mergedOptions = {
|
|
86
|
+
force,
|
|
87
|
+
verbose,
|
|
88
|
+
mode: options.mode || process.env.FRIGG_DEPLOYMENT_MODE || configFromFile.deploymentMode,
|
|
89
|
+
frontend: options.frontend !== undefined ? options.frontend :
|
|
90
|
+
process.env.FRIGG_INCLUDE_FRONTEND !== undefined ? process.env.FRIGG_INCLUDE_FRONTEND === 'true' :
|
|
91
|
+
configFromFile.includeFrontend,
|
|
92
|
+
interactive,
|
|
93
|
+
nonInteractive,
|
|
94
|
+
appPurpose: options.appPurpose || process.env.FRIGG_APP_PURPOSE || configFromFile.appPurpose,
|
|
95
|
+
includeIntegrations: options.includeIntegrations !== undefined ? options.includeIntegrations :
|
|
96
|
+
process.env.FRIGG_INCLUDE_INTEGRATIONS !== undefined ? process.env.FRIGG_INCLUDE_INTEGRATIONS === 'true' :
|
|
97
|
+
configFromFile.includeIntegrations,
|
|
98
|
+
includeApiModule: options.includeApiModule !== undefined ? options.includeApiModule :
|
|
99
|
+
process.env.FRIGG_INCLUDE_API_MODULE !== undefined ? process.env.FRIGG_INCLUDE_API_MODULE === 'true' :
|
|
100
|
+
configFromFile.includeApiModule,
|
|
101
|
+
serverlessProvider: options.serverlessProvider || process.env.FRIGG_SERVERLESS_PROVIDER || configFromFile.serverlessProvider,
|
|
102
|
+
installDependencies: options.installDeps !== undefined ? options.installDeps :
|
|
103
|
+
process.env.FRIGG_INSTALL_DEPS !== undefined ? process.env.FRIGG_INSTALL_DEPS === 'true' :
|
|
104
|
+
configFromFile.installDependencies,
|
|
105
|
+
initializeGit: options.initGit !== undefined ? options.initGit :
|
|
106
|
+
process.env.FRIGG_INIT_GIT !== undefined ? process.env.FRIGG_INIT_GIT === 'true' :
|
|
107
|
+
configFromFile.initializeGit,
|
|
108
|
+
starterIntegrations: process.env.FRIGG_STARTER_INTEGRATIONS ?
|
|
109
|
+
process.env.FRIGG_STARTER_INTEGRATIONS.split(',').map(s => s.trim()) :
|
|
110
|
+
configFromFile.starterIntegrations,
|
|
111
|
+
frontendFramework: process.env.FRIGG_FRONTEND_FRAMEWORK || configFromFile.frontendFramework,
|
|
112
|
+
demoAuthMode: process.env.FRIGG_DEMO_AUTH_MODE || configFromFile.demoAuthMode
|
|
113
|
+
};
|
|
114
|
+
|
|
64
115
|
// Use backend-first handler by default
|
|
65
116
|
if (!options.template && !options.legacyFrontend) {
|
|
66
117
|
try {
|
|
67
|
-
const handler = new BackendFirstHandler(root,
|
|
68
|
-
force,
|
|
69
|
-
verbose,
|
|
70
|
-
mode: options.mode,
|
|
71
|
-
frontend: options.frontend
|
|
72
|
-
});
|
|
118
|
+
const handler = new BackendFirstHandler(root, mergedOptions);
|
|
73
119
|
|
|
74
120
|
await handler.initialize();
|
|
75
121
|
return;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frigg Application Definition
|
|
3
|
+
*
|
|
4
|
+
* This file defines your Frigg application configuration.
|
|
5
|
+
* Modify the integrations array to include the API modules you want to use.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Import your integrations here
|
|
9
|
+
// const ExampleIntegration = require('./src/integrations/ExampleIntegration');
|
|
10
|
+
|
|
11
|
+
const appDefinition = {
|
|
12
|
+
integrations: [
|
|
13
|
+
// Add your integrations here as you install them
|
|
14
|
+
// Example:
|
|
15
|
+
// ExampleIntegration,
|
|
16
|
+
],
|
|
17
|
+
user: {
|
|
18
|
+
password: true
|
|
19
|
+
},
|
|
20
|
+
encryption: {
|
|
21
|
+
useDefaultKMSForFieldLevelEncryption: true
|
|
22
|
+
},
|
|
23
|
+
vpc: {
|
|
24
|
+
enable: true
|
|
25
|
+
},
|
|
26
|
+
security: {
|
|
27
|
+
cors: {
|
|
28
|
+
origin: 'http://localhost:3000',
|
|
29
|
+
credentials: true
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
logging: {
|
|
33
|
+
level: 'info'
|
|
34
|
+
},
|
|
35
|
+
custom: {
|
|
36
|
+
appName: 'My Frigg Application',
|
|
37
|
+
version: '1.0.0',
|
|
38
|
+
environment: 'development'
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
module.exports = appDefinition;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Frigg Infrastructure Management
|
|
5
|
+
*
|
|
6
|
+
* This script handles starting, building, and deploying your Frigg application.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { spawn } = require('child_process');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
const command = process.argv[2];
|
|
13
|
+
|
|
14
|
+
switch (command) {
|
|
15
|
+
case 'start':
|
|
16
|
+
console.log('Starting Frigg backend...');
|
|
17
|
+
// In a real implementation, this would start the Frigg backend
|
|
18
|
+
console.log('Backend started on http://localhost:3001');
|
|
19
|
+
break;
|
|
20
|
+
|
|
21
|
+
case 'package':
|
|
22
|
+
console.log('Packaging Frigg application...');
|
|
23
|
+
// In a real implementation, this would package the application
|
|
24
|
+
console.log('Application packaged successfully');
|
|
25
|
+
break;
|
|
26
|
+
|
|
27
|
+
case 'deploy':
|
|
28
|
+
console.log('Deploying Frigg application...');
|
|
29
|
+
// In a real implementation, this would deploy to AWS Lambda
|
|
30
|
+
console.log('Application deployed successfully');
|
|
31
|
+
break;
|
|
32
|
+
|
|
33
|
+
default:
|
|
34
|
+
console.log('Usage: node infrastructure.js [start|package|deploy]');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "frigg-backend-template",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Frigg backend application template",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node infrastructure.js start",
|
|
8
|
+
"build": "node infrastructure.js package",
|
|
9
|
+
"deploy": "node infrastructure.js deploy"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@friggframework/core": "^2.0.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"serverless": "^3.0.0",
|
|
16
|
+
"serverless-offline": "^12.0.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
service: frigg-application
|
|
2
|
+
|
|
3
|
+
provider:
|
|
4
|
+
name: aws
|
|
5
|
+
runtime: nodejs18.x
|
|
6
|
+
stage: ${opt:stage, 'dev'}
|
|
7
|
+
region: ${opt:region, 'us-east-1'}
|
|
8
|
+
environment:
|
|
9
|
+
NODE_ENV: ${self:provider.stage}
|
|
10
|
+
|
|
11
|
+
functions:
|
|
12
|
+
api:
|
|
13
|
+
handler: index.handler
|
|
14
|
+
events:
|
|
15
|
+
- http:
|
|
16
|
+
path: /{proxy+}
|
|
17
|
+
method: ANY
|
|
18
|
+
cors: true
|
|
19
|
+
|
|
20
|
+
plugins:
|
|
21
|
+
- serverless-offline
|
|
22
|
+
|
|
23
|
+
custom:
|
|
24
|
+
serverless-offline:
|
|
25
|
+
httpPort: 3001
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const { Command } = require('commander');
|
|
2
|
+
|
|
3
|
+
describe('frigg CLI init command', () => {
|
|
4
|
+
const setupProgram = action => {
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.command('init [projectName]')
|
|
8
|
+
.option('-m, --mode <mode>', 'deployment mode (embedded|standalone)')
|
|
9
|
+
.option('--frontend', 'include demo frontend')
|
|
10
|
+
.option('--no-frontend', 'skip demo frontend')
|
|
11
|
+
.option('--no-interactive', 'run without interactive prompts')
|
|
12
|
+
.option('-f, --force', 'overwrite existing directory')
|
|
13
|
+
.option('-v, --verbose', 'enable verbose output')
|
|
14
|
+
.action(action);
|
|
15
|
+
return program;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
it('parses flags and forwards them to initCommand', async () => {
|
|
19
|
+
const mockInit = jest.fn();
|
|
20
|
+
const program = setupProgram(mockInit);
|
|
21
|
+
|
|
22
|
+
await program.parseAsync([
|
|
23
|
+
'node',
|
|
24
|
+
'test',
|
|
25
|
+
'init',
|
|
26
|
+
'my-app',
|
|
27
|
+
'--mode',
|
|
28
|
+
'standalone',
|
|
29
|
+
'--no-frontend',
|
|
30
|
+
'--no-interactive',
|
|
31
|
+
'--force',
|
|
32
|
+
'--verbose'
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
expect(mockInit).toHaveBeenCalledWith(
|
|
36
|
+
'my-app',
|
|
37
|
+
expect.objectContaining({
|
|
38
|
+
mode: 'standalone',
|
|
39
|
+
frontend: false,
|
|
40
|
+
interactive: false,
|
|
41
|
+
force: true,
|
|
42
|
+
verbose: true
|
|
43
|
+
}),
|
|
44
|
+
expect.anything()
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
@@ -128,17 +128,91 @@ describe('Init Command', () => {
|
|
|
128
128
|
force: true,
|
|
129
129
|
verbose: true,
|
|
130
130
|
mode: 'standalone',
|
|
131
|
-
frontend: false
|
|
131
|
+
frontend: false,
|
|
132
|
+
interactive: false
|
|
132
133
|
};
|
|
133
|
-
|
|
134
|
+
|
|
134
135
|
await initCommand(mockProjectName, options);
|
|
135
|
-
|
|
136
|
+
|
|
136
137
|
expect(BackendFirstHandler).toHaveBeenCalledWith(
|
|
137
138
|
expect.any(String),
|
|
138
|
-
expect.objectContaining(
|
|
139
|
+
expect.objectContaining({
|
|
140
|
+
force: true,
|
|
141
|
+
verbose: true,
|
|
142
|
+
mode: 'standalone',
|
|
143
|
+
frontend: false,
|
|
144
|
+
interactive: true, // This gets set to true because interactive: false is not the same as nonInteractive: true
|
|
145
|
+
nonInteractive: false
|
|
146
|
+
})
|
|
139
147
|
);
|
|
140
148
|
});
|
|
141
149
|
|
|
150
|
+
it('should handle non-interactive mode with --non-interactive flag', async () => {
|
|
151
|
+
const options = {
|
|
152
|
+
nonInteractive: true,
|
|
153
|
+
mode: 'standalone',
|
|
154
|
+
appPurpose: 'own-app'
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
await initCommand(mockProjectName, options);
|
|
158
|
+
|
|
159
|
+
expect(BackendFirstHandler).toHaveBeenCalledWith(
|
|
160
|
+
expect.any(String),
|
|
161
|
+
expect.objectContaining({
|
|
162
|
+
nonInteractive: true,
|
|
163
|
+
interactive: false,
|
|
164
|
+
mode: 'standalone',
|
|
165
|
+
appPurpose: 'own-app'
|
|
166
|
+
})
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should handle non-interactive mode with --yes flag', async () => {
|
|
171
|
+
const options = {
|
|
172
|
+
yes: true,
|
|
173
|
+
mode: 'embedded'
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
await initCommand(mockProjectName, options);
|
|
177
|
+
|
|
178
|
+
expect(BackendFirstHandler).toHaveBeenCalledWith(
|
|
179
|
+
expect.any(String),
|
|
180
|
+
expect.objectContaining({
|
|
181
|
+
nonInteractive: true,
|
|
182
|
+
interactive: false,
|
|
183
|
+
mode: 'embedded'
|
|
184
|
+
})
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should handle environment variables', async () => {
|
|
189
|
+
const originalEnv = process.env.FRIGG_DEPLOYMENT_MODE;
|
|
190
|
+
process.env.FRIGG_DEPLOYMENT_MODE = 'embedded';
|
|
191
|
+
process.env.FRIGG_APP_PURPOSE = 'platform';
|
|
192
|
+
|
|
193
|
+
const options = {
|
|
194
|
+
nonInteractive: true
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
await initCommand(mockProjectName, options);
|
|
198
|
+
|
|
199
|
+
expect(BackendFirstHandler).toHaveBeenCalledWith(
|
|
200
|
+
expect.any(String),
|
|
201
|
+
expect.objectContaining({
|
|
202
|
+
mode: 'embedded',
|
|
203
|
+
appPurpose: 'platform'
|
|
204
|
+
})
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Clean up
|
|
208
|
+
if (originalEnv !== undefined) {
|
|
209
|
+
process.env.FRIGG_DEPLOYMENT_MODE = originalEnv;
|
|
210
|
+
} else {
|
|
211
|
+
delete process.env.FRIGG_DEPLOYMENT_MODE;
|
|
212
|
+
}
|
|
213
|
+
delete process.env.FRIGG_APP_PURPOSE;
|
|
214
|
+
});
|
|
215
|
+
|
|
142
216
|
it('should handle initialization errors gracefully', async () => {
|
|
143
217
|
const mockError = new Error('Initialization failed');
|
|
144
218
|
BackendFirstHandler.mockImplementation(() => ({
|