@friggframework/devtools 2.0.0--canary.461.c89a166.0 → 2.0.0--canary.461.1b7292f.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/infrastructure/domains/integration/integration-builder.test.js +1 -1
- package/infrastructure/domains/security/kms-discovery.test.js +5 -4
- package/infrastructure/domains/shared/cloudformation-discovery.js +23 -3
- package/infrastructure/domains/shared/utilities/handler-path-resolver.js +7 -2
- package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +21 -12
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +6 -2
- package/infrastructure/domains/shared/validation/env-validator.js +2 -1
- package/package.json +6 -6
|
@@ -247,7 +247,7 @@ describe('IntegrationBuilder', () => {
|
|
|
247
247
|
|
|
248
248
|
const result = await integrationBuilder.build(appDefinition, {});
|
|
249
249
|
|
|
250
|
-
expect(result.functions.testQueueWorker.timeout).toBe(
|
|
250
|
+
expect(result.functions.testQueueWorker.timeout).toBe(900); // 15 minutes (Lambda max)
|
|
251
251
|
});
|
|
252
252
|
|
|
253
253
|
it('should set queue worker reserved concurrency', async () => {
|
|
@@ -61,10 +61,11 @@ describe('KmsDiscovery', () => {
|
|
|
61
61
|
|
|
62
62
|
const result = await kmsDiscovery.discover({});
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
expect(result.
|
|
66
|
-
expect(result.
|
|
67
|
-
expect(result.
|
|
64
|
+
// When no keys found, properties are undefined (not explicitly set to null)
|
|
65
|
+
expect(result.kmsKeyId).toBeFalsy();
|
|
66
|
+
expect(result.kmsKeyArn).toBeFalsy();
|
|
67
|
+
expect(result.defaultKmsKeyId).toBeFalsy();
|
|
68
|
+
expect(result.kmsKeyAlias).toBeFalsy();
|
|
68
69
|
});
|
|
69
70
|
|
|
70
71
|
it('should handle KMS key without alias', async () => {
|
|
@@ -40,9 +40,9 @@ class CloudFormationDiscovery {
|
|
|
40
40
|
this._extractFromOutputs(stack.Outputs, discovered);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
// Extract from resources
|
|
43
|
+
// Extract from resources (now async to query AWS for details)
|
|
44
44
|
if (resources && resources.length > 0) {
|
|
45
|
-
this._extractFromResources(resources, discovered);
|
|
45
|
+
await this._extractFromResources(resources, discovered);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
return discovered;
|
|
@@ -107,10 +107,30 @@ class CloudFormationDiscovery {
|
|
|
107
107
|
* @param {Array} resources - CloudFormation stack resources
|
|
108
108
|
* @param {Object} discovered - Object to populate with discovered resources
|
|
109
109
|
*/
|
|
110
|
-
_extractFromResources(resources, discovered) {
|
|
110
|
+
async _extractFromResources(resources, discovered) {
|
|
111
111
|
for (const resource of resources) {
|
|
112
112
|
const { LogicalResourceId, PhysicalResourceId, ResourceType } = resource;
|
|
113
113
|
|
|
114
|
+
// Security Group - use to get VPC ID
|
|
115
|
+
if (LogicalResourceId === 'FriggLambdaSecurityGroup' && ResourceType === 'AWS::EC2::SecurityGroup') {
|
|
116
|
+
discovered.securityGroupId = PhysicalResourceId;
|
|
117
|
+
// Query security group to get VPC ID
|
|
118
|
+
if (this.provider && !discovered.vpcId) {
|
|
119
|
+
try {
|
|
120
|
+
const sgDetails = await this.provider.getEC2Client().send(
|
|
121
|
+
new (require('@aws-sdk/client-ec2').DescribeSecurityGroupsCommand)({
|
|
122
|
+
GroupIds: [PhysicalResourceId]
|
|
123
|
+
})
|
|
124
|
+
);
|
|
125
|
+
if (sgDetails.SecurityGroups && sgDetails.SecurityGroups.length > 0) {
|
|
126
|
+
discovered.vpcId = sgDetails.SecurityGroups[0].VpcId;
|
|
127
|
+
}
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.warn(`Could not get VPC from security group: ${error.message}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
114
134
|
// Aurora cluster
|
|
115
135
|
if (LogicalResourceId === 'FriggAuroraCluster' && ResourceType === 'AWS::RDS::DBCluster') {
|
|
116
136
|
discovered.auroraClusterId = PhysicalResourceId;
|
|
@@ -112,14 +112,19 @@ function modifyHandlerPaths(functions) {
|
|
|
112
112
|
|
|
113
113
|
if (!isOffline) {
|
|
114
114
|
console.log('Not in offline mode, skipping handler path modification');
|
|
115
|
-
|
|
115
|
+
// Return shallow copy to prevent mutations (DDD immutability principle)
|
|
116
|
+
return { ...functions };
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
// In offline mode, don't modify the handler paths at all
|
|
119
120
|
// serverless-offline will resolve node_modules paths from the working directory
|
|
120
121
|
console.log('Offline mode detected - keeping original handler paths for serverless-offline');
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
// Return deep copy to prevent mutations (DDD immutability principle)
|
|
124
|
+
return Object.entries(functions).reduce((acc, [key, value]) => {
|
|
125
|
+
acc[key] = { ...value };
|
|
126
|
+
return acc;
|
|
127
|
+
}, {});
|
|
123
128
|
}
|
|
124
129
|
|
|
125
130
|
module.exports = {
|
|
@@ -58,20 +58,21 @@ describe('Handler Path Resolver', () => {
|
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
it('should use npm root if directory search fails (method 2)', () => {
|
|
61
|
-
process.cwd = jest.fn().mockReturnValue('/
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
process.cwd = jest.fn().mockReturnValue('/some/unusual/directory');
|
|
62
|
+
|
|
64
63
|
const { execSync } = require('node:child_process');
|
|
65
|
-
|
|
64
|
+
// npm root returns a different path
|
|
65
|
+
execSync.mockReturnValue('/usr/local/lib/node_modules\n');
|
|
66
66
|
|
|
67
|
-
//
|
|
68
|
-
fs.existsSync.mockImplementation((p) =>
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
// Mock to fail directory searches but succeed for npm root result
|
|
68
|
+
fs.existsSync = jest.fn().mockImplementation((p) => {
|
|
69
|
+
// Only succeed for the npm root path (not under /some/unusual/directory)
|
|
70
|
+
return p === '/usr/local/lib/node_modules';
|
|
71
|
+
});
|
|
71
72
|
|
|
72
73
|
const result = findNodeModulesPath();
|
|
73
74
|
|
|
74
|
-
expect(result).toBe('/
|
|
75
|
+
expect(result).toBe('/usr/local/lib/node_modules');
|
|
75
76
|
expect(execSync).toHaveBeenCalledWith('npm root', { encoding: 'utf8' });
|
|
76
77
|
});
|
|
77
78
|
|
|
@@ -129,13 +130,21 @@ describe('Handler Path Resolver', () => {
|
|
|
129
130
|
});
|
|
130
131
|
|
|
131
132
|
it('should handle errors during search', () => {
|
|
132
|
-
process.cwd = jest.fn().
|
|
133
|
-
|
|
133
|
+
process.cwd = jest.fn().mockReturnValue('/project');
|
|
134
|
+
// Mock fs.existsSync to throw an error
|
|
135
|
+
fs.existsSync = jest.fn().mockImplementation(() => {
|
|
136
|
+
throw new Error('fs error');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const { execSync } = require('node:child_process');
|
|
140
|
+
execSync.mockImplementation(() => {
|
|
141
|
+
throw new Error('npm error');
|
|
134
142
|
});
|
|
135
143
|
|
|
136
144
|
const result = findNodeModulesPath();
|
|
137
145
|
|
|
138
|
-
|
|
146
|
+
// Should fallback to default path even when search methods fail
|
|
147
|
+
expect(result).toBe(path.resolve('/project', '../node_modules'));
|
|
139
148
|
});
|
|
140
149
|
});
|
|
141
150
|
|
|
@@ -92,8 +92,10 @@ describe('Prisma Layer Manager', () => {
|
|
|
92
92
|
|
|
93
93
|
await ensurePrismaLayerExists();
|
|
94
94
|
|
|
95
|
+
// console.log is called with 2 args: message + path
|
|
95
96
|
expect(consoleSpy).toHaveBeenCalledWith(
|
|
96
|
-
expect.stringContaining('already exists')
|
|
97
|
+
expect.stringContaining('already exists'),
|
|
98
|
+
expect.any(String)
|
|
97
99
|
);
|
|
98
100
|
|
|
99
101
|
consoleSpy.mockRestore();
|
|
@@ -123,8 +125,10 @@ describe('Prisma Layer Manager', () => {
|
|
|
123
125
|
|
|
124
126
|
await expect(ensurePrismaLayerExists()).rejects.toThrow();
|
|
125
127
|
|
|
128
|
+
// console.error is called with 2 args: message + error
|
|
126
129
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
127
|
-
expect.stringContaining('Failed to build')
|
|
130
|
+
expect.stringContaining('Failed to build'),
|
|
131
|
+
expect.any(String)
|
|
128
132
|
);
|
|
129
133
|
|
|
130
134
|
consoleErrorSpy.mockRestore();
|
|
@@ -23,7 +23,8 @@ const validateEnvironmentVariables = (AppDefinition) => {
|
|
|
23
23
|
|
|
24
24
|
for (const [key, value] of Object.entries(AppDefinition.environment)) {
|
|
25
25
|
if (value === true) {
|
|
26
|
-
if (
|
|
26
|
+
// Use 'in' operator to check if key exists (undefined = missing, empty string = present)
|
|
27
|
+
if (key in process.env) {
|
|
27
28
|
results.valid.push(key);
|
|
28
29
|
} else {
|
|
29
30
|
results.missing.push(key);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.461.
|
|
4
|
+
"version": "2.0.0--canary.461.1b7292f.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-ec2": "^3.835.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.835.0",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"@babel/eslint-parser": "^7.18.9",
|
|
12
12
|
"@babel/parser": "^7.25.3",
|
|
13
13
|
"@babel/traverse": "^7.25.3",
|
|
14
|
-
"@friggframework/schemas": "2.0.0--canary.461.
|
|
15
|
-
"@friggframework/test": "2.0.0--canary.461.
|
|
14
|
+
"@friggframework/schemas": "2.0.0--canary.461.1b7292f.0",
|
|
15
|
+
"@friggframework/test": "2.0.0--canary.461.1b7292f.0",
|
|
16
16
|
"@hapi/boom": "^10.0.1",
|
|
17
17
|
"@inquirer/prompts": "^5.3.8",
|
|
18
18
|
"axios": "^1.7.2",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"serverless-http": "^2.7.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@friggframework/eslint-config": "2.0.0--canary.461.
|
|
38
|
-
"@friggframework/prettier-config": "2.0.0--canary.461.
|
|
37
|
+
"@friggframework/eslint-config": "2.0.0--canary.461.1b7292f.0",
|
|
38
|
+
"@friggframework/prettier-config": "2.0.0--canary.461.1b7292f.0",
|
|
39
39
|
"aws-sdk-client-mock": "^4.1.0",
|
|
40
40
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
41
41
|
"jest": "^30.1.3",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "1b7292f30e11b350a075d5dcecded3c8c0f21167"
|
|
74
74
|
}
|