@friggframework/devtools 2.0.0-next.2 → 2.0.0-next.21
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/build-command/index.js +52 -0
- package/frigg-cli/deploy-command/index.js +33 -0
- package/frigg-cli/index.js +19 -1
- package/frigg-cli/index.test.js +1 -4
- package/frigg-cli/install-command/index.js +1 -4
- package/frigg-cli/start-command/index.js +24 -4
- package/infrastructure/create-frigg-infrastructure.js +1 -3
- package/infrastructure/serverless-template.js +119 -27
- package/package.json +11 -9
- package/frigg-cli/utils/backend-path.js +0 -26
- 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,52 @@
|
|
|
1
|
+
const { spawnSync } = require('child_process');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function buildCommand(options) {
|
|
5
|
+
console.log('Building the serverless application...');
|
|
6
|
+
console.log('Hello from npm link world')
|
|
7
|
+
const backendPath = path.resolve(process.cwd());
|
|
8
|
+
const infrastructurePath = 'infrastructure.js';
|
|
9
|
+
const command = 'serverless';
|
|
10
|
+
const serverlessArgs = [
|
|
11
|
+
'package',
|
|
12
|
+
'--config',
|
|
13
|
+
infrastructurePath,
|
|
14
|
+
'--stage',
|
|
15
|
+
options.stage
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
// Add support for --verbose option
|
|
19
|
+
if (options.verbose) {
|
|
20
|
+
serverlessArgs.push('--verbose');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log('Running command from ', backendPath);
|
|
24
|
+
console.log('Serverless Command:', command, serverlessArgs.join(' '));
|
|
25
|
+
|
|
26
|
+
const result = spawnSync(command, serverlessArgs, {
|
|
27
|
+
cwd: backendPath,
|
|
28
|
+
stdio: 'inherit',
|
|
29
|
+
shell: true,
|
|
30
|
+
env: {
|
|
31
|
+
...process.env,
|
|
32
|
+
NODE_PATH: path.resolve(backendPath, 'node_modules'),
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (result.status !== 0) {
|
|
37
|
+
console.error(`Serverless build failed with code ${result.status}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// childProcess.on('error', (error) => {
|
|
42
|
+
// console.error(`Error executing command: ${error.message}`);
|
|
43
|
+
// });
|
|
44
|
+
|
|
45
|
+
// childProcess.on('close', (code) => {
|
|
46
|
+
// if (code !== 0) {
|
|
47
|
+
// console.log(`Child process exited with code ${code}`);
|
|
48
|
+
// }
|
|
49
|
+
// });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = { buildCommand };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const { spawn } = require('child_process');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function deployCommand(options) {
|
|
5
|
+
console.log('Deploying the serverless application...');
|
|
6
|
+
const backendPath = path.resolve(process.cwd());
|
|
7
|
+
const infrastructurePath = 'infrastructure.js';
|
|
8
|
+
const command = 'serverless';
|
|
9
|
+
const serverlessArgs = [
|
|
10
|
+
'deploy',
|
|
11
|
+
'--config',
|
|
12
|
+
infrastructurePath,
|
|
13
|
+
'--stage',
|
|
14
|
+
options.stage
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const childProcess = spawn(command, serverlessArgs, {
|
|
18
|
+
cwd: backendPath,
|
|
19
|
+
stdio: 'inherit',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
childProcess.on('error', (error) => {
|
|
23
|
+
console.error(`Error executing command: ${error.message}`);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
childProcess.on('close', (code) => {
|
|
27
|
+
if (code !== 0) {
|
|
28
|
+
console.log(`Child process exited with code ${code}`);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = { deployCommand };
|
package/frigg-cli/index.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const { Command } = require('commander');
|
|
4
4
|
const { installCommand } = require('./install-command');
|
|
5
5
|
const { startCommand } = require('./start-command'); // Assuming you have a startCommand module
|
|
6
|
+
const { buildCommand } = require('./build-command');
|
|
7
|
+
const { deployCommand } = require('./deploy-command');
|
|
6
8
|
|
|
7
9
|
const program = new Command();
|
|
8
10
|
program
|
|
@@ -13,8 +15,24 @@ program
|
|
|
13
15
|
program
|
|
14
16
|
.command('start')
|
|
15
17
|
.description('Run the backend and optional frontend')
|
|
18
|
+
.option('-s, --stage <stage>', 'deployment stage', 'dev')
|
|
19
|
+
.option('-v, --verbose', 'enable verbose output')
|
|
16
20
|
.action(startCommand);
|
|
17
21
|
|
|
22
|
+
program
|
|
23
|
+
.command('build')
|
|
24
|
+
.description('Build the serverless application')
|
|
25
|
+
.option('-s, --stage <stage>', 'deployment stage', 'dev')
|
|
26
|
+
.option('-v, --verbose', 'enable verbose output')
|
|
27
|
+
.action(buildCommand);
|
|
28
|
+
|
|
29
|
+
program
|
|
30
|
+
.command('deploy')
|
|
31
|
+
.description('Deploy the serverless application')
|
|
32
|
+
.option('-s, --stage <stage>', 'deployment stage', 'dev')
|
|
33
|
+
.option('-v, --verbose', 'enable verbose output')
|
|
34
|
+
.action(deployCommand);
|
|
35
|
+
|
|
18
36
|
program.parse(process.argv);
|
|
19
37
|
|
|
20
|
-
module.exports = { installCommand, startCommand };
|
|
38
|
+
module.exports = { installCommand, startCommand, buildCommand, deployCommand };
|
package/frigg-cli/index.test.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
const { Command } = require('commander');
|
|
2
2
|
const { installCommand } = require('./index');
|
|
3
3
|
const { validatePackageExists } = require('./install-command/validate-package');
|
|
4
|
-
const {
|
|
5
|
-
findNearestBackendPackageJson,
|
|
6
|
-
validateBackendPath,
|
|
7
|
-
} = require('./utils/backend-path');
|
|
4
|
+
const { findNearestBackendPackageJson, validateBackendPath } = require('@friggframework/core');
|
|
8
5
|
const { installPackage } = require('./install-command/install-package');
|
|
9
6
|
const { createIntegrationFile } = require('./install-command/integration-file');
|
|
10
7
|
const { updateBackendJsFile } = require('./install-command/backend-js');
|
|
@@ -4,15 +4,12 @@ const { resolve } = require('node:path');
|
|
|
4
4
|
const { updateBackendJsFile } = require('./backend-js');
|
|
5
5
|
const { logInfo, logError } = require('./logger');
|
|
6
6
|
const { commitChanges } = require('./commit-changes');
|
|
7
|
-
const {
|
|
8
|
-
findNearestBackendPackageJson,
|
|
9
|
-
validateBackendPath,
|
|
10
|
-
} = require('../utils/backend-path');
|
|
11
7
|
const { handleEnvVariables } = require('./environment-variables');
|
|
12
8
|
const {
|
|
13
9
|
validatePackageExists,
|
|
14
10
|
searchAndSelectPackage,
|
|
15
11
|
} = require('./validate-package');
|
|
12
|
+
const { findNearestBackendPackageJson, validateBackendPath } = require('@friggframework/core');
|
|
16
13
|
|
|
17
14
|
const installCommand = async (apiModuleName) => {
|
|
18
15
|
try {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
const { spawn } = require('child_process');
|
|
2
|
-
const path = require('path');
|
|
1
|
+
const { spawn } = require('node:child_process');
|
|
2
|
+
const path = require('node:path');
|
|
3
3
|
|
|
4
|
-
function startCommand() {
|
|
4
|
+
function startCommand(options) {
|
|
5
|
+
if (options.verbose) {
|
|
6
|
+
console.log('Verbose mode enabled');
|
|
7
|
+
console.log('Options:', options);
|
|
8
|
+
}
|
|
5
9
|
console.log('Starting backend and optional frontend...');
|
|
6
10
|
// Suppress AWS SDK warning message about maintenance mode
|
|
7
11
|
process.env.AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE = 1;
|
|
@@ -9,7 +13,23 @@ function startCommand() {
|
|
|
9
13
|
console.log(`Starting backend in ${backendPath}...`);
|
|
10
14
|
const infrastructurePath = 'infrastructure.js';
|
|
11
15
|
const command = 'serverless';
|
|
12
|
-
const args = [
|
|
16
|
+
const args = [
|
|
17
|
+
'offline',
|
|
18
|
+
'--config',
|
|
19
|
+
infrastructurePath,
|
|
20
|
+
'--stage',
|
|
21
|
+
options.stage
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
// Add verbose flag to serverless if verbose option is enabled
|
|
25
|
+
if (options.verbose) {
|
|
26
|
+
args.push('--verbose');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (options.verbose) {
|
|
30
|
+
console.log(`Executing command: ${command} ${args.join(' ')}`);
|
|
31
|
+
console.log(`Working directory: ${backendPath}`);
|
|
32
|
+
}
|
|
13
33
|
|
|
14
34
|
const childProcess = spawn(command, args, {
|
|
15
35
|
cwd: backendPath,
|
|
@@ -2,9 +2,7 @@ const path = require('path');
|
|
|
2
2
|
const fs = require('fs-extra');
|
|
3
3
|
const { composeServerlessDefinition } = require('./serverless-template');
|
|
4
4
|
|
|
5
|
-
const {
|
|
6
|
-
findNearestBackendPackageJson,
|
|
7
|
-
} = require('../frigg-cli/utils/backend-path');
|
|
5
|
+
const { findNearestBackendPackageJson } = require('@friggframework/core');
|
|
8
6
|
|
|
9
7
|
function createFriggInfrastructure() {
|
|
10
8
|
const backendPath = findNearestBackendPackageJson();
|
|
@@ -1,12 +1,114 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// Function to find the actual path to node_modules
|
|
5
|
+
const findNodeModulesPath = () => {
|
|
6
|
+
try {
|
|
7
|
+
// Method 1: Try to find node_modules by traversing up from current directory
|
|
8
|
+
let currentDir = process.cwd();
|
|
9
|
+
let nodeModulesPath = null;
|
|
10
|
+
|
|
11
|
+
// Traverse up to 5 levels to find node_modules
|
|
12
|
+
for (let i = 0; i < 5; i++) {
|
|
13
|
+
const potentialPath = path.join(currentDir, 'node_modules');
|
|
14
|
+
if (fs.existsSync(potentialPath)) {
|
|
15
|
+
nodeModulesPath = potentialPath;
|
|
16
|
+
console.log(`Found node_modules at: ${nodeModulesPath} (method 1)`);
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
// Move up one directory
|
|
20
|
+
const parentDir = path.dirname(currentDir);
|
|
21
|
+
if (parentDir === currentDir) {
|
|
22
|
+
// We've reached the root
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
currentDir = parentDir;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Method 2: If method 1 fails, try using npm root command
|
|
29
|
+
if (!nodeModulesPath) {
|
|
30
|
+
try {
|
|
31
|
+
// This requires child_process, so let's require it here
|
|
32
|
+
const { execSync } = require('node:child_process');
|
|
33
|
+
const npmRoot = execSync('npm root', { encoding: 'utf8' }).trim();
|
|
34
|
+
if (fs.existsSync(npmRoot)) {
|
|
35
|
+
nodeModulesPath = npmRoot;
|
|
36
|
+
console.log(`Found node_modules at: ${nodeModulesPath} (method 2)`);
|
|
37
|
+
}
|
|
38
|
+
} catch (npmError) {
|
|
39
|
+
console.error('Error executing npm root:', npmError);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Method 3: If all else fails, check for a package.json and assume node_modules is adjacent
|
|
44
|
+
if (!nodeModulesPath) {
|
|
45
|
+
currentDir = process.cwd();
|
|
46
|
+
for (let i = 0; i < 5; i++) {
|
|
47
|
+
const packageJsonPath = path.join(currentDir, 'package.json');
|
|
48
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
49
|
+
const potentialNodeModules = path.join(currentDir, 'node_modules');
|
|
50
|
+
if (fs.existsSync(potentialNodeModules)) {
|
|
51
|
+
nodeModulesPath = potentialNodeModules;
|
|
52
|
+
console.log(`Found node_modules at: ${nodeModulesPath} (method 3)`);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Move up one directory
|
|
57
|
+
const parentDir = path.dirname(currentDir);
|
|
58
|
+
if (parentDir === currentDir) {
|
|
59
|
+
// We've reached the root
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
currentDir = parentDir;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (nodeModulesPath) {
|
|
67
|
+
return nodeModulesPath;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.warn('Could not find node_modules path, falling back to default');
|
|
71
|
+
return path.resolve(process.cwd(), '../node_modules');
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error('Error finding node_modules path:', error);
|
|
74
|
+
return path.resolve(process.cwd(), '../node_modules');
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Function to modify handler paths to point to the correct node_modules
|
|
79
|
+
const modifyHandlerPaths = (functions) => {
|
|
80
|
+
// Check if we're running in offline mode
|
|
81
|
+
const isOffline = process.argv.includes('offline');
|
|
82
|
+
console.log('isOffline', isOffline);
|
|
83
|
+
|
|
84
|
+
if (!isOffline) {
|
|
85
|
+
console.log('Not in offline mode, skipping handler path modification');
|
|
86
|
+
return functions;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const nodeModulesPath = findNodeModulesPath();
|
|
90
|
+
const modifiedFunctions = { ...functions };
|
|
91
|
+
|
|
92
|
+
for (const functionName of Object.keys(modifiedFunctions)) {
|
|
93
|
+
console.log('functionName', functionName);
|
|
94
|
+
const functionDef = modifiedFunctions[functionName];
|
|
95
|
+
if (functionDef?.handler?.includes('node_modules/')) {
|
|
96
|
+
// Replace node_modules/ with the actual path to node_modules/
|
|
97
|
+
functionDef.handler = functionDef.handler.replace('node_modules/', '../node_modules/');
|
|
98
|
+
console.log(`Updated handler for ${functionName}: ${functionDef.handler}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return modifiedFunctions;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const composeServerlessDefinition = (AppDefinition) => {
|
|
5
106
|
const definition = {
|
|
6
107
|
frameworkVersion: '>=3.17.0',
|
|
7
108
|
service: AppDefinition.name || 'create-frigg-app',
|
|
8
109
|
package: {
|
|
9
110
|
individually: true,
|
|
111
|
+
exclude: ["!**/node_modules/aws-sdk/**", "!**/node_modules/@aws-sdk/**", "!package.json"],
|
|
10
112
|
},
|
|
11
113
|
useDotenv: true,
|
|
12
114
|
provider: {
|
|
@@ -30,6 +132,7 @@ const composeServerlessDefinition = (AppDefinition, IntegrationFactory) => {
|
|
|
30
132
|
],
|
|
31
133
|
},
|
|
32
134
|
plugins: [
|
|
135
|
+
'serverless-jetpack',
|
|
33
136
|
'serverless-dotenv-plugin',
|
|
34
137
|
'serverless-offline-sqs',
|
|
35
138
|
'serverless-offline',
|
|
@@ -50,19 +153,13 @@ const composeServerlessDefinition = (AppDefinition, IntegrationFactory) => {
|
|
|
50
153
|
secretAccessKey: 'root',
|
|
51
154
|
skipCacheInvalidation: false,
|
|
52
155
|
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
includeModules: {
|
|
56
|
-
forceExclude: ['aws-sdk'],
|
|
57
|
-
},
|
|
58
|
-
packager: 'npm',
|
|
59
|
-
excludeFiles: ['src/**/*.test.js', 'test/'],
|
|
156
|
+
jetpack: {
|
|
157
|
+
base: '..',
|
|
60
158
|
},
|
|
61
159
|
},
|
|
62
160
|
functions: {
|
|
63
161
|
defaultWebsocket: {
|
|
64
|
-
handler:
|
|
65
|
-
'/../node_modules/@friggframework/devtools/infrastructure/routers/websocket.handler',
|
|
162
|
+
handler: 'node_modules/@friggframework/core/handlers/routers/websocket.handler',
|
|
66
163
|
events: [
|
|
67
164
|
{
|
|
68
165
|
websocket: {
|
|
@@ -82,8 +179,7 @@ const composeServerlessDefinition = (AppDefinition, IntegrationFactory) => {
|
|
|
82
179
|
],
|
|
83
180
|
},
|
|
84
181
|
auth: {
|
|
85
|
-
handler:
|
|
86
|
-
'/../node_modules/@friggframework/devtools/infrastructure/routers/auth.handler',
|
|
182
|
+
handler: 'node_modules/@friggframework/core/handlers/routers/auth.handler',
|
|
87
183
|
events: [
|
|
88
184
|
{
|
|
89
185
|
http: {
|
|
@@ -109,8 +205,7 @@ const composeServerlessDefinition = (AppDefinition, IntegrationFactory) => {
|
|
|
109
205
|
],
|
|
110
206
|
},
|
|
111
207
|
user: {
|
|
112
|
-
handler:
|
|
113
|
-
'/../node_modules/@friggframework/devtools/infrastructure/routers/user.handler',
|
|
208
|
+
handler: 'node_modules/@friggframework/core/handlers/routers/user.handler',
|
|
114
209
|
events: [
|
|
115
210
|
{
|
|
116
211
|
http: {
|
|
@@ -213,23 +308,16 @@ const composeServerlessDefinition = (AppDefinition, IntegrationFactory) => {
|
|
|
213
308
|
};
|
|
214
309
|
|
|
215
310
|
// Add integration-specific functions and resources
|
|
216
|
-
AppDefinition.integrations
|
|
311
|
+
for (const integration of AppDefinition.integrations) {
|
|
217
312
|
const integrationName = integration.Definition.name;
|
|
218
313
|
|
|
219
314
|
// Add function for the integration
|
|
220
315
|
definition.functions[integrationName] = {
|
|
221
|
-
handler:
|
|
222
|
-
// events: integration.Definition.routes.map((route) => ({
|
|
223
|
-
// http: {
|
|
224
|
-
// path: `/api/${integrationName}-integration${route.path}`,
|
|
225
|
-
// method: route.method || 'ANY',
|
|
226
|
-
// cors: true,
|
|
227
|
-
// },
|
|
228
|
-
// })),
|
|
316
|
+
handler: `node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.${integrationName}.handler`,
|
|
229
317
|
events: [
|
|
230
318
|
{
|
|
231
319
|
http: {
|
|
232
|
-
path: `/api/${integrationName}-integration/{proxy
|
|
320
|
+
path: `/api/${integrationName}-integration/{proxy+}`,
|
|
233
321
|
method: 'ANY',
|
|
234
322
|
cors: true,
|
|
235
323
|
},
|
|
@@ -247,6 +335,7 @@ const composeServerlessDefinition = (AppDefinition, IntegrationFactory) => {
|
|
|
247
335
|
Properties: {
|
|
248
336
|
QueueName: `\${self:custom.${queueReference}}`,
|
|
249
337
|
MessageRetentionPeriod: 60,
|
|
338
|
+
VisibilityTimeout: 1800, // 30 minutes
|
|
250
339
|
RedrivePolicy: {
|
|
251
340
|
maxReceiveCount: 1,
|
|
252
341
|
deadLetterTargetArn: {
|
|
@@ -259,7 +348,7 @@ const composeServerlessDefinition = (AppDefinition, IntegrationFactory) => {
|
|
|
259
348
|
// Add Queue Worker for the integration
|
|
260
349
|
const queueWorkerName = `${integrationName}QueueWorker`;
|
|
261
350
|
definition.functions[queueWorkerName] = {
|
|
262
|
-
handler:
|
|
351
|
+
handler: `node_modules/@friggframework/core/handlers/workers/integration-defined-workers.handlers.${integrationName}.queueWorker`,
|
|
263
352
|
reservedConcurrency: 5,
|
|
264
353
|
events: [
|
|
265
354
|
{
|
|
@@ -277,14 +366,17 @@ const composeServerlessDefinition = (AppDefinition, IntegrationFactory) => {
|
|
|
277
366
|
// Add Queue URL for the integration to the ENVironment variables
|
|
278
367
|
definition.provider.environment = {
|
|
279
368
|
...definition.provider.environment,
|
|
280
|
-
[integrationName.toUpperCase()
|
|
369
|
+
[`${integrationName.toUpperCase()}_QUEUE_URL`]: {
|
|
281
370
|
Ref: queueReference,
|
|
282
371
|
},
|
|
283
372
|
};
|
|
284
373
|
|
|
285
374
|
definition.custom[queueReference] = queueName;
|
|
286
|
-
}
|
|
375
|
+
}
|
|
287
376
|
|
|
377
|
+
// Modify handler paths to point to the correct node_modules location
|
|
378
|
+
definition.functions = modifyHandlerPaths(definition.functions);
|
|
379
|
+
|
|
288
380
|
return definition;
|
|
289
381
|
};
|
|
290
382
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0-next.
|
|
4
|
+
"version": "2.0.0-next.21",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@babel/eslint-parser": "^7.18.9",
|
|
7
7
|
"@babel/parser": "^7.25.3",
|
|
8
8
|
"@babel/traverse": "^7.25.3",
|
|
9
|
-
"@friggframework/
|
|
10
|
-
"@
|
|
11
|
-
"@hapi/boom": "^7.4.11",
|
|
9
|
+
"@friggframework/test": "2.0.0-next.21",
|
|
10
|
+
"@hapi/boom": "^10.0.1",
|
|
12
11
|
"@inquirer/prompts": "^5.3.8",
|
|
13
12
|
"axios": "^1.7.2",
|
|
14
13
|
"body-parser": "^1.20.2",
|
|
@@ -24,16 +23,19 @@
|
|
|
24
23
|
"express": "^4.19.2",
|
|
25
24
|
"express-async-handler": "^1.2.0",
|
|
26
25
|
"fs-extra": "^11.2.0",
|
|
27
|
-
"lodash": "
|
|
26
|
+
"lodash": "4.17.21",
|
|
28
27
|
"serverless-http": "^2.7.0"
|
|
29
28
|
},
|
|
30
29
|
"devDependencies": {
|
|
31
|
-
"@friggframework/eslint-config": "2.0.0-next.
|
|
32
|
-
"@friggframework/prettier-config": "2.0.0-next.
|
|
30
|
+
"@friggframework/eslint-config": "2.0.0-next.21",
|
|
31
|
+
"@friggframework/prettier-config": "2.0.0-next.21",
|
|
32
|
+
"prettier": "^2.7.1",
|
|
33
|
+
"serverless": "3.39.0",
|
|
33
34
|
"serverless-dotenv-plugin": "^6.0.0",
|
|
35
|
+
"serverless-jetpack": "^0.11.2",
|
|
34
36
|
"serverless-offline": "^13.8.0",
|
|
35
37
|
"serverless-offline-sqs": "^8.0.0",
|
|
36
|
-
"serverless-
|
|
38
|
+
"serverless-plugin-monorepo": "^0.11.0"
|
|
37
39
|
},
|
|
38
40
|
"scripts": {
|
|
39
41
|
"lint:fix": "prettier --write --loglevel error . && eslint . --fix",
|
|
@@ -57,5 +59,5 @@
|
|
|
57
59
|
"publishConfig": {
|
|
58
60
|
"access": "public"
|
|
59
61
|
},
|
|
60
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "ad1d397f60175576cb2d939ae6c75533ee5a4c2a"
|
|
61
63
|
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const fs = require('fs-extra');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const PACKAGE_JSON = 'package.json';
|
|
4
|
-
|
|
5
|
-
function findNearestBackendPackageJson() {
|
|
6
|
-
let currentDir = process.cwd();
|
|
7
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
8
|
-
const packageJsonPath = path.join(currentDir, 'backend', PACKAGE_JSON);
|
|
9
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
10
|
-
return packageJsonPath;
|
|
11
|
-
}
|
|
12
|
-
currentDir = path.dirname(currentDir);
|
|
13
|
-
}
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function validateBackendPath(backendPath) {
|
|
18
|
-
if (!backendPath) {
|
|
19
|
-
throw new Error('Could not find a backend package.json file.');
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
module.exports = {
|
|
24
|
-
findNearestBackendPackageJson,
|
|
25
|
-
validateBackendPath,
|
|
26
|
-
};
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
const { createHandler, flushDebugLog } = require('@friggframework/core');
|
|
2
|
-
const express = require('express');
|
|
3
|
-
const bodyParser = require('body-parser');
|
|
4
|
-
const cors = require('cors');
|
|
5
|
-
const Boom = require('@hapi/boom');
|
|
6
|
-
const loadUserManager = require('./routers/middleware/loadUser');
|
|
7
|
-
const serverlessHttp = require('serverless-http');
|
|
8
|
-
|
|
9
|
-
const createApp = (applyMiddleware) => {
|
|
10
|
-
const app = express();
|
|
11
|
-
|
|
12
|
-
app.use(bodyParser.json({ limit: '10mb' }));
|
|
13
|
-
app.use(bodyParser.urlencoded({ extended: true }));
|
|
14
|
-
app.use(
|
|
15
|
-
cors({
|
|
16
|
-
origin: '*',
|
|
17
|
-
credentials: true,
|
|
18
|
-
})
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
app.use(loadUserManager);
|
|
22
|
-
|
|
23
|
-
if (applyMiddleware) applyMiddleware(app);
|
|
24
|
-
|
|
25
|
-
// Handle sending error response and logging server errors to console
|
|
26
|
-
app.use((err, req, res, next) => {
|
|
27
|
-
const boomError = err.isBoom ? err : Boom.boomify(err);
|
|
28
|
-
const {
|
|
29
|
-
output: { statusCode = 500 },
|
|
30
|
-
} = boomError;
|
|
31
|
-
|
|
32
|
-
if (statusCode >= 500) {
|
|
33
|
-
flushDebugLog(boomError);
|
|
34
|
-
res.status(statusCode).json({ error: 'Internal Server Error' });
|
|
35
|
-
} else {
|
|
36
|
-
res.status(statusCode).json({ error: err.message });
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return app;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
function createAppHandler(eventName, router, shouldUseDatabase = true) {
|
|
44
|
-
const app = createApp((app) => {
|
|
45
|
-
app.use(router);
|
|
46
|
-
});
|
|
47
|
-
return createHandler({
|
|
48
|
-
eventName,
|
|
49
|
-
method: serverlessHttp(app),
|
|
50
|
-
shouldUseDatabase,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
module.exports = {
|
|
55
|
-
createApp,
|
|
56
|
-
createAppHandler,
|
|
57
|
-
};
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
const { createFriggBackend, Worker } = require('@friggframework/core');
|
|
2
|
-
const {
|
|
3
|
-
findNearestBackendPackageJson,
|
|
4
|
-
} = require('../frigg-cli/utils/backend-path');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const fs = require('fs-extra');
|
|
7
|
-
|
|
8
|
-
const backendPath = findNearestBackendPackageJson();
|
|
9
|
-
if (!backendPath) {
|
|
10
|
-
throw new Error('Could not find backend package.json');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const backendDir = path.dirname(backendPath);
|
|
14
|
-
const backendFilePath = path.join(backendDir, 'index.js');
|
|
15
|
-
if (!fs.existsSync(backendFilePath)) {
|
|
16
|
-
throw new Error('Could not find index.js');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const backendJsFile = require(backendFilePath);
|
|
20
|
-
const { Router } = require('express');
|
|
21
|
-
const appDefinition = backendJsFile.Definition;
|
|
22
|
-
|
|
23
|
-
const backend = createFriggBackend(appDefinition);
|
|
24
|
-
const loadRouterFromObject = (IntegrationClass, routerObject) => {
|
|
25
|
-
const router = Router();
|
|
26
|
-
const { path, method, event } = routerObject;
|
|
27
|
-
console.log(
|
|
28
|
-
`Registering ${method} ${path} for ${IntegrationClass.Definition.name}`
|
|
29
|
-
);
|
|
30
|
-
router[method.toLowerCase()](path, async (req, res, next) => {
|
|
31
|
-
try {
|
|
32
|
-
const integration = new IntegrationClass({});
|
|
33
|
-
await integration.loadModules();
|
|
34
|
-
await integration.registerEventHandlers();
|
|
35
|
-
const result = await integration.send(event, req.body);
|
|
36
|
-
res.json(result);
|
|
37
|
-
} catch (error) {
|
|
38
|
-
next(error);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
return router;
|
|
43
|
-
};
|
|
44
|
-
const createQueueWorker = (integrationClass) => {
|
|
45
|
-
class QueueWorker extends Worker {
|
|
46
|
-
constructor(params) {
|
|
47
|
-
super(params);
|
|
48
|
-
}
|
|
49
|
-
async _run(params, context) {
|
|
50
|
-
try {
|
|
51
|
-
let instance;
|
|
52
|
-
if (!params.integrationId) {
|
|
53
|
-
instance = new integrationClass({});
|
|
54
|
-
await instance.loadModules();
|
|
55
|
-
// await instance.loadUserActions();
|
|
56
|
-
await instance.registerEventHandlers();
|
|
57
|
-
console.log(
|
|
58
|
-
`${params.event} for ${integrationClass.Definition.name} integration with no integrationId`
|
|
59
|
-
);
|
|
60
|
-
} else {
|
|
61
|
-
instance =
|
|
62
|
-
await integrationClass.getInstanceFromIntegrationId({
|
|
63
|
-
integrationId: params.integrationId,
|
|
64
|
-
});
|
|
65
|
-
console.log(
|
|
66
|
-
`${params.event} for ${instance.integration.config.type} of integrationId: ${params.integrationId}`
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
const res = await instance.send(params.event, {
|
|
70
|
-
data: params.data,
|
|
71
|
-
context,
|
|
72
|
-
});
|
|
73
|
-
return res;
|
|
74
|
-
} catch (error) {
|
|
75
|
-
console.error(
|
|
76
|
-
`Error in ${params.event} for ${integrationClass.Definition.name}:`,
|
|
77
|
-
error
|
|
78
|
-
);
|
|
79
|
-
throw error;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return QueueWorker;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
module.exports = {
|
|
87
|
-
...backend,
|
|
88
|
-
loadRouterFromObject,
|
|
89
|
-
createQueueWorker,
|
|
90
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const { createIntegrationRouter } = require('@friggframework/core');
|
|
2
|
-
const { createAppHandler } = require('./../app-handler-helpers');
|
|
3
|
-
const { requireLoggedInUser } = require('./middleware/requireLoggedInUser');
|
|
4
|
-
const {
|
|
5
|
-
moduleFactory,
|
|
6
|
-
integrationFactory,
|
|
7
|
-
IntegrationHelper,
|
|
8
|
-
} = require('./../backend-utils');
|
|
9
|
-
|
|
10
|
-
const router = createIntegrationRouter({
|
|
11
|
-
factory: { moduleFactory, integrationFactory, IntegrationHelper },
|
|
12
|
-
requireLoggedInUser,
|
|
13
|
-
getUserId: (req) => req.user.getUserId(),
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
router.route('/redirect/:appId').get((req, res) => {
|
|
17
|
-
res.redirect(
|
|
18
|
-
`${process.env.FRONTEND_URI}/redirect/${
|
|
19
|
-
req.params.appId
|
|
20
|
-
}?${new URLSearchParams(req.query)}`
|
|
21
|
-
);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const handler = createAppHandler('HTTP Event: Auth', router);
|
|
25
|
-
|
|
26
|
-
module.exports = { handler, router };
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
const { createIntegrationRouter } = require('@friggframework/core');
|
|
2
|
-
const { createAppHandler } = require('./../app-handler-helpers');
|
|
3
|
-
const { requireLoggedInUser } = require('./middleware/requireLoggedInUser');
|
|
4
|
-
const {
|
|
5
|
-
moduleFactory,
|
|
6
|
-
integrationFactory,
|
|
7
|
-
IntegrationHelper,
|
|
8
|
-
loadRouterFromObject,
|
|
9
|
-
} = require('./../backend-utils');
|
|
10
|
-
const { Router } = require('express');
|
|
11
|
-
|
|
12
|
-
const handlers = {};
|
|
13
|
-
integrationFactory.integrationClasses.forEach((IntegrationClass) => {
|
|
14
|
-
const router = Router();
|
|
15
|
-
const basePath = `/api/${IntegrationClass.Definition.name}-integration`;
|
|
16
|
-
IntegrationClass.Definition.routes.forEach((routeDef) => {
|
|
17
|
-
if (typeof routeDef === 'function') {
|
|
18
|
-
router.use(basePath, routeDef(IntegrationClass));
|
|
19
|
-
} else if (typeof routeDef === 'object') {
|
|
20
|
-
router.use(
|
|
21
|
-
basePath,
|
|
22
|
-
loadRouterFromObject(IntegrationClass, routeDef)
|
|
23
|
-
);
|
|
24
|
-
} else if (routeDef instanceof express.Router) {
|
|
25
|
-
router.use(basePath, routeDef);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
handlers[`${IntegrationClass.Definition.name}`] = {
|
|
30
|
-
handler: createAppHandler(
|
|
31
|
-
`HTTP Event: ${IntegrationClass.Definition.name}`,
|
|
32
|
-
router
|
|
33
|
-
),
|
|
34
|
-
};
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
module.exports = { handlers };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
const catchAsyncError = require('express-async-handler');
|
|
2
|
-
const { User } = require('../../backend-utils');
|
|
3
|
-
|
|
4
|
-
module.exports = catchAsyncError(async (req, res, next) => {
|
|
5
|
-
const authorizationHeader = req.headers.authorization;
|
|
6
|
-
|
|
7
|
-
if (authorizationHeader) {
|
|
8
|
-
// Removes "Bearer " and trims
|
|
9
|
-
const token = authorizationHeader.split(' ')[1].trim();
|
|
10
|
-
// Load user for later middleware/routes to use
|
|
11
|
-
req.user = await User.newUser({ token });
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return next();
|
|
15
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const Boom = require('@hapi/boom');
|
|
2
|
-
|
|
3
|
-
// CheckLoggedIn Middleware
|
|
4
|
-
const requireLoggedInUser = (req, res, next) => {
|
|
5
|
-
if (!req.user || !req.user.isLoggedIn()) {
|
|
6
|
-
throw Boom.unauthorized('Invalid Token');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
next();
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
module.exports = { requireLoggedInUser };
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const express = require('express');
|
|
2
|
-
const { createAppHandler } = require('../app-handler-helpers');
|
|
3
|
-
const { checkRequiredParams } = require('@friggframework/core');
|
|
4
|
-
const { User } = require('../backend-utils');
|
|
5
|
-
const catchAsyncError = require('express-async-handler');
|
|
6
|
-
|
|
7
|
-
const router = express();
|
|
8
|
-
|
|
9
|
-
// define the login endpoint
|
|
10
|
-
router.route('/user/login').post(
|
|
11
|
-
catchAsyncError(async (req, res) => {
|
|
12
|
-
const { username, password } = checkRequiredParams(req.body, [
|
|
13
|
-
'username',
|
|
14
|
-
'password',
|
|
15
|
-
]);
|
|
16
|
-
const user = await User.loginUser({ username, password });
|
|
17
|
-
const token = await user.createUserToken(120);
|
|
18
|
-
res.status(201);
|
|
19
|
-
res.json({ token });
|
|
20
|
-
})
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
router.route('/user/create').post(
|
|
24
|
-
catchAsyncError(async (req, res) => {
|
|
25
|
-
const { username, password } = checkRequiredParams(req.body, [
|
|
26
|
-
'username',
|
|
27
|
-
'password',
|
|
28
|
-
]);
|
|
29
|
-
const user = await User.createIndividualUser({
|
|
30
|
-
username,
|
|
31
|
-
password,
|
|
32
|
-
});
|
|
33
|
-
const token = await user.createUserToken(120);
|
|
34
|
-
res.status(201);
|
|
35
|
-
res.json({ token });
|
|
36
|
-
})
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
const handler = createAppHandler('HTTP Event: User', router);
|
|
40
|
-
|
|
41
|
-
module.exports = { handler, router };
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
const { createHandler } = require('@friggframework/core');
|
|
2
|
-
const { WebsocketConnection } = require('@friggframework/core');
|
|
3
|
-
|
|
4
|
-
const handleWebSocketConnection = async (event, context) => {
|
|
5
|
-
// Handle different WebSocket events
|
|
6
|
-
switch (event.requestContext.eventType) {
|
|
7
|
-
case 'CONNECT':
|
|
8
|
-
// Handle new connection
|
|
9
|
-
try {
|
|
10
|
-
const connectionId = event.requestContext.connectionId;
|
|
11
|
-
await WebsocketConnection.create({ connectionId });
|
|
12
|
-
console.log(`Stored new connection: ${connectionId}`);
|
|
13
|
-
return { statusCode: 200, body: 'Connected.' };
|
|
14
|
-
} catch (error) {
|
|
15
|
-
console.error('Error storing connection:', error);
|
|
16
|
-
return { statusCode: 500, body: 'Error connecting.' };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
case 'DISCONNECT':
|
|
20
|
-
// Handle disconnection
|
|
21
|
-
try {
|
|
22
|
-
const connectionId = event.requestContext.connectionId;
|
|
23
|
-
await WebsocketConnection.deleteOne({ connectionId });
|
|
24
|
-
console.log(`Removed connection: ${connectionId}`);
|
|
25
|
-
return { statusCode: 200, body: 'Disconnected.' };
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.error('Error removing connection:', error);
|
|
28
|
-
return { statusCode: 500, body: 'Error disconnecting.' };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
case 'MESSAGE':
|
|
32
|
-
// Handle incoming message
|
|
33
|
-
const message = JSON.parse(event.body);
|
|
34
|
-
console.log('Received message:', message);
|
|
35
|
-
|
|
36
|
-
// Process the message and send a response
|
|
37
|
-
const responseMessage = { message: 'Message received' };
|
|
38
|
-
return {
|
|
39
|
-
statusCode: 200,
|
|
40
|
-
body: JSON.stringify(responseMessage),
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
default:
|
|
44
|
-
return { statusCode: 400, body: 'Unhandled event type.' };
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const handler = createHandler({
|
|
49
|
-
eventName: 'WebSocket Event',
|
|
50
|
-
method: handleWebSocketConnection,
|
|
51
|
-
shouldUseDatabase: true, // Set to true as we're using the database
|
|
52
|
-
isUserFacingResponse: true, // This is a server-to-server response
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
module.exports = { handler };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const { createHandler } = require('@friggframework/core');
|
|
2
|
-
const { integrationFactory, createQueueWorker } = require('./../backend-utils');
|
|
3
|
-
|
|
4
|
-
const handlers = {};
|
|
5
|
-
integrationFactory.integrationClasses.forEach((IntegrationClass) => {
|
|
6
|
-
const defaultQueueWorker = createQueueWorker(IntegrationClass);
|
|
7
|
-
|
|
8
|
-
handlers[`${IntegrationClass.Definition.name}`] = {
|
|
9
|
-
queueWorker: createHandler({
|
|
10
|
-
eventName: `Queue Worker for ${IntegrationClass.Definition.name}`,
|
|
11
|
-
isUserFacingResponse: false,
|
|
12
|
-
method: async (event, context) => {
|
|
13
|
-
const worker = new defaultQueueWorker();
|
|
14
|
-
await worker.run(event, context);
|
|
15
|
-
return {
|
|
16
|
-
message: 'Successfully processed the Generic Queue Worker',
|
|
17
|
-
input: event,
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
|
-
}),
|
|
21
|
-
};
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
module.exports = { handlers };
|