@friggframework/devtools 2.0.0-next.42 → 2.0.0-next.44

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.
@@ -3,9 +3,14 @@ const fs = require('fs');
3
3
  const { AWSDiscovery } = require('./aws-discovery');
4
4
 
5
5
  const shouldRunDiscovery = (AppDefinition) => {
6
- console.log('⚙️ Checking FRIGG_SKIP_AWS_DISCOVERY:', process.env.FRIGG_SKIP_AWS_DISCOVERY);
6
+ console.log(
7
+ '⚙️ Checking FRIGG_SKIP_AWS_DISCOVERY:',
8
+ process.env.FRIGG_SKIP_AWS_DISCOVERY
9
+ );
7
10
  if (process.env.FRIGG_SKIP_AWS_DISCOVERY === 'true') {
8
- console.log('⚙️ Skipping AWS discovery because FRIGG_SKIP_AWS_DISCOVERY is set.');
11
+ console.log(
12
+ '⚙️ Skipping AWS discovery because FRIGG_SKIP_AWS_DISCOVERY is set.'
13
+ );
9
14
  return false;
10
15
  }
11
16
 
@@ -55,11 +60,17 @@ const getAppEnvironmentVars = (AppDefinition) => {
55
60
  }
56
61
 
57
62
  if (envKeys.length > 0) {
58
- console.log(` Found ${envKeys.length} environment variables: ${envKeys.join(', ')}`);
63
+ console.log(
64
+ ` Found ${envKeys.length} environment variables: ${envKeys.join(
65
+ ', '
66
+ )}`
67
+ );
59
68
  }
60
69
  if (skippedKeys.length > 0) {
61
70
  console.log(
62
- ` ⚠️ Skipped ${skippedKeys.length} reserved AWS Lambda variables: ${skippedKeys.join(', ')}`
71
+ ` ⚠️ Skipped ${
72
+ skippedKeys.length
73
+ } reserved AWS Lambda variables: ${skippedKeys.join(', ')}`
63
74
  );
64
75
  }
65
76
 
@@ -75,7 +86,9 @@ const findNodeModulesPath = () => {
75
86
  const potentialPath = path.join(currentDir, 'node_modules');
76
87
  if (fs.existsSync(potentialPath)) {
77
88
  nodeModulesPath = potentialPath;
78
- console.log(`Found node_modules at: ${nodeModulesPath} (method 1)`);
89
+ console.log(
90
+ `Found node_modules at: ${nodeModulesPath} (method 1)`
91
+ );
79
92
  break;
80
93
  }
81
94
  const parentDir = path.dirname(currentDir);
@@ -86,10 +99,14 @@ const findNodeModulesPath = () => {
86
99
  if (!nodeModulesPath) {
87
100
  try {
88
101
  const { execSync } = require('node:child_process');
89
- const npmRoot = execSync('npm root', { encoding: 'utf8' }).trim();
102
+ const npmRoot = execSync('npm root', {
103
+ encoding: 'utf8',
104
+ }).trim();
90
105
  if (fs.existsSync(npmRoot)) {
91
106
  nodeModulesPath = npmRoot;
92
- console.log(`Found node_modules at: ${nodeModulesPath} (method 2)`);
107
+ console.log(
108
+ `Found node_modules at: ${nodeModulesPath} (method 2)`
109
+ );
93
110
  }
94
111
  } catch (npmError) {
95
112
  console.error('Error executing npm root:', npmError);
@@ -101,10 +118,15 @@ const findNodeModulesPath = () => {
101
118
  for (let i = 0; i < 5; i++) {
102
119
  const packageJsonPath = path.join(currentDir, 'package.json');
103
120
  if (fs.existsSync(packageJsonPath)) {
104
- const potentialNodeModules = path.join(currentDir, 'node_modules');
121
+ const potentialNodeModules = path.join(
122
+ currentDir,
123
+ 'node_modules'
124
+ );
105
125
  if (fs.existsSync(potentialNodeModules)) {
106
126
  nodeModulesPath = potentialNodeModules;
107
- console.log(`Found node_modules at: ${nodeModulesPath} (method 3)`);
127
+ console.log(
128
+ `Found node_modules at: ${nodeModulesPath} (method 3)`
129
+ );
108
130
  break;
109
131
  }
110
132
  }
@@ -118,7 +140,9 @@ const findNodeModulesPath = () => {
118
140
  return nodeModulesPath;
119
141
  }
120
142
 
121
- console.warn('Could not find node_modules path, falling back to default');
143
+ console.warn(
144
+ 'Could not find node_modules path, falling back to default'
145
+ );
122
146
  return path.resolve(process.cwd(), '../node_modules');
123
147
  } catch (error) {
124
148
  console.error('Error finding node_modules path:', error);
@@ -143,8 +167,13 @@ const modifyHandlerPaths = (functions) => {
143
167
  const functionDef = modifiedFunctions[functionName];
144
168
  if (functionDef?.handler?.includes('node_modules/')) {
145
169
  const relativePath = path.relative(process.cwd(), nodeModulesPath);
146
- functionDef.handler = functionDef.handler.replace('node_modules/', `${relativePath}/`);
147
- console.log(`Updated handler for ${functionName}: ${functionDef.handler}`);
170
+ functionDef.handler = functionDef.handler.replace(
171
+ 'node_modules/',
172
+ `${relativePath}/`
173
+ );
174
+ console.log(
175
+ `Updated handler for ${functionName}: ${functionDef.handler}`
176
+ );
148
177
  }
149
178
  }
150
179
 
@@ -160,7 +189,10 @@ const createVPCInfrastructure = (AppDefinition) => {
160
189
  EnableDnsHostnames: true,
161
190
  EnableDnsSupport: true,
162
191
  Tags: [
163
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-vpc' },
192
+ {
193
+ Key: 'Name',
194
+ Value: '${self:service}-${self:provider.stage}-vpc',
195
+ },
164
196
  { Key: 'ManagedBy', Value: 'Frigg' },
165
197
  { Key: 'Service', Value: '${self:service}' },
166
198
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -171,7 +203,10 @@ const createVPCInfrastructure = (AppDefinition) => {
171
203
  Type: 'AWS::EC2::InternetGateway',
172
204
  Properties: {
173
205
  Tags: [
174
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-igw' },
206
+ {
207
+ Key: 'Name',
208
+ Value: '${self:service}-${self:provider.stage}-igw',
209
+ },
175
210
  { Key: 'ManagedBy', Value: 'Frigg' },
176
211
  { Key: 'Service', Value: '${self:service}' },
177
212
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -193,7 +228,10 @@ const createVPCInfrastructure = (AppDefinition) => {
193
228
  AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
194
229
  MapPublicIpOnLaunch: true,
195
230
  Tags: [
196
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-public-subnet' },
231
+ {
232
+ Key: 'Name',
233
+ Value: '${self:service}-${self:provider.stage}-public-subnet',
234
+ },
197
235
  { Key: 'ManagedBy', Value: 'Frigg' },
198
236
  { Key: 'Service', Value: '${self:service}' },
199
237
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -208,7 +246,10 @@ const createVPCInfrastructure = (AppDefinition) => {
208
246
  CidrBlock: '10.0.2.0/24',
209
247
  AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
210
248
  Tags: [
211
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-subnet-1' },
249
+ {
250
+ Key: 'Name',
251
+ Value: '${self:service}-${self:provider.stage}-private-subnet-1',
252
+ },
212
253
  { Key: 'ManagedBy', Value: 'Frigg' },
213
254
  { Key: 'Service', Value: '${self:service}' },
214
255
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -223,7 +264,10 @@ const createVPCInfrastructure = (AppDefinition) => {
223
264
  CidrBlock: '10.0.3.0/24',
224
265
  AvailabilityZone: { 'Fn::Select': [1, { 'Fn::GetAZs': '' }] },
225
266
  Tags: [
226
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-subnet-2' },
267
+ {
268
+ Key: 'Name',
269
+ Value: '${self:service}-${self:provider.stage}-private-subnet-2',
270
+ },
227
271
  { Key: 'ManagedBy', Value: 'Frigg' },
228
272
  { Key: 'Service', Value: '${self:service}' },
229
273
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -236,7 +280,10 @@ const createVPCInfrastructure = (AppDefinition) => {
236
280
  Properties: {
237
281
  Domain: 'vpc',
238
282
  Tags: [
239
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-eip' },
283
+ {
284
+ Key: 'Name',
285
+ Value: '${self:service}-${self:provider.stage}-nat-eip',
286
+ },
240
287
  { Key: 'ManagedBy', Value: 'Frigg' },
241
288
  { Key: 'Service', Value: '${self:service}' },
242
289
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -247,10 +294,15 @@ const createVPCInfrastructure = (AppDefinition) => {
247
294
  FriggNATGateway: {
248
295
  Type: 'AWS::EC2::NatGateway',
249
296
  Properties: {
250
- AllocationId: { 'Fn::GetAtt': ['FriggNATGatewayEIP', 'AllocationId'] },
297
+ AllocationId: {
298
+ 'Fn::GetAtt': ['FriggNATGatewayEIP', 'AllocationId'],
299
+ },
251
300
  SubnetId: { Ref: 'FriggPublicSubnet' },
252
301
  Tags: [
253
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-gateway' },
302
+ {
303
+ Key: 'Name',
304
+ Value: '${self:service}-${self:provider.stage}-nat-gateway',
305
+ },
254
306
  { Key: 'ManagedBy', Value: 'Frigg' },
255
307
  { Key: 'Service', Value: '${self:service}' },
256
308
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -262,7 +314,10 @@ const createVPCInfrastructure = (AppDefinition) => {
262
314
  Properties: {
263
315
  VpcId: { Ref: 'FriggVPC' },
264
316
  Tags: [
265
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-public-rt' },
317
+ {
318
+ Key: 'Name',
319
+ Value: '${self:service}-${self:provider.stage}-public-rt',
320
+ },
266
321
  { Key: 'ManagedBy', Value: 'Frigg' },
267
322
  { Key: 'Service', Value: '${self:service}' },
268
323
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -291,7 +346,10 @@ const createVPCInfrastructure = (AppDefinition) => {
291
346
  Properties: {
292
347
  VpcId: { Ref: 'FriggVPC' },
293
348
  Tags: [
294
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-rt' },
349
+ {
350
+ Key: 'Name',
351
+ Value: '${self:service}-${self:provider.stage}-private-rt',
352
+ },
295
353
  { Key: 'ManagedBy', Value: 'Frigg' },
296
354
  { Key: 'Service', Value: '${self:service}' },
297
355
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -327,14 +385,47 @@ const createVPCInfrastructure = (AppDefinition) => {
327
385
  GroupDescription: 'Security group for Frigg Lambda functions',
328
386
  VpcId: { Ref: 'FriggVPC' },
329
387
  SecurityGroupEgress: [
330
- { IpProtocol: 'tcp', FromPort: 443, ToPort: 443, CidrIp: '0.0.0.0/0', Description: 'HTTPS outbound' },
331
- { IpProtocol: 'tcp', FromPort: 80, ToPort: 80, CidrIp: '0.0.0.0/0', Description: 'HTTP outbound' },
332
- { IpProtocol: 'tcp', FromPort: 53, ToPort: 53, CidrIp: '0.0.0.0/0', Description: 'DNS TCP' },
333
- { IpProtocol: 'udp', FromPort: 53, ToPort: 53, CidrIp: '0.0.0.0/0', Description: 'DNS UDP' },
334
- { IpProtocol: 'tcp', FromPort: 27017, ToPort: 27017, CidrIp: '0.0.0.0/0', Description: 'MongoDB outbound' },
388
+ {
389
+ IpProtocol: 'tcp',
390
+ FromPort: 443,
391
+ ToPort: 443,
392
+ CidrIp: '0.0.0.0/0',
393
+ Description: 'HTTPS outbound',
394
+ },
395
+ {
396
+ IpProtocol: 'tcp',
397
+ FromPort: 80,
398
+ ToPort: 80,
399
+ CidrIp: '0.0.0.0/0',
400
+ Description: 'HTTP outbound',
401
+ },
402
+ {
403
+ IpProtocol: 'tcp',
404
+ FromPort: 53,
405
+ ToPort: 53,
406
+ CidrIp: '0.0.0.0/0',
407
+ Description: 'DNS TCP',
408
+ },
409
+ {
410
+ IpProtocol: 'udp',
411
+ FromPort: 53,
412
+ ToPort: 53,
413
+ CidrIp: '0.0.0.0/0',
414
+ Description: 'DNS UDP',
415
+ },
416
+ {
417
+ IpProtocol: 'tcp',
418
+ FromPort: 27017,
419
+ ToPort: 27017,
420
+ CidrIp: '0.0.0.0/0',
421
+ Description: 'MongoDB outbound',
422
+ },
335
423
  ],
336
424
  Tags: [
337
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-lambda-sg' },
425
+ {
426
+ Key: 'Name',
427
+ Value: '${self:service}-${self:provider.stage}-lambda-sg',
428
+ },
338
429
  { Key: 'ManagedBy', Value: 'Frigg' },
339
430
  { Key: 'Service', Value: '${self:service}' },
340
431
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -371,8 +462,13 @@ const createVPCInfrastructure = (AppDefinition) => {
371
462
  VpcId: { Ref: 'FriggVPC' },
372
463
  ServiceName: 'com.amazonaws.${self:provider.region}.kms',
373
464
  VpcEndpointType: 'Interface',
374
- SubnetIds: [{ Ref: 'FriggPrivateSubnet1' }, { Ref: 'FriggPrivateSubnet2' }],
375
- SecurityGroupIds: [{ Ref: 'FriggVPCEndpointSecurityGroup' }],
465
+ SubnetIds: [
466
+ { Ref: 'FriggPrivateSubnet1' },
467
+ { Ref: 'FriggPrivateSubnet2' },
468
+ ],
469
+ SecurityGroupIds: [
470
+ { Ref: 'FriggVPCEndpointSecurityGroup' },
471
+ ],
376
472
  PrivateDnsEnabled: true,
377
473
  },
378
474
  };
@@ -382,9 +478,13 @@ const createVPCInfrastructure = (AppDefinition) => {
382
478
  Type: 'AWS::EC2::VPCEndpoint',
383
479
  Properties: {
384
480
  VpcId: { Ref: 'FriggVPC' },
385
- ServiceName: 'com.amazonaws.${self:provider.region}.secretsmanager',
481
+ ServiceName:
482
+ 'com.amazonaws.${self:provider.region}.secretsmanager',
386
483
  VpcEndpointType: 'Interface',
387
- SubnetIds: [{ Ref: 'FriggPrivateSubnet1' }, { Ref: 'FriggPrivateSubnet2' }],
484
+ SubnetIds: [
485
+ { Ref: 'FriggPrivateSubnet1' },
486
+ { Ref: 'FriggPrivateSubnet2' },
487
+ ],
388
488
  SecurityGroupIds: [{ Ref: 'FriggVPCEndpointSecurityGroup' }],
389
489
  PrivateDnsEnabled: true,
390
490
  },
@@ -393,14 +493,17 @@ const createVPCInfrastructure = (AppDefinition) => {
393
493
  vpcResources.FriggVPCEndpointSecurityGroup = {
394
494
  Type: 'AWS::EC2::SecurityGroup',
395
495
  Properties: {
396
- GroupDescription: 'Security group for Frigg VPC Endpoints - allows HTTPS from Lambda functions',
496
+ GroupDescription:
497
+ 'Security group for Frigg VPC Endpoints - allows HTTPS from Lambda functions',
397
498
  VpcId: { Ref: 'FriggVPC' },
398
499
  SecurityGroupIngress: [
399
500
  {
400
501
  IpProtocol: 'tcp',
401
502
  FromPort: 443,
402
503
  ToPort: 443,
403
- SourceSecurityGroupId: { Ref: 'FriggLambdaSecurityGroup' },
504
+ SourceSecurityGroupId: {
505
+ Ref: 'FriggLambdaSecurityGroup',
506
+ },
404
507
  Description: 'HTTPS from Lambda security group',
405
508
  },
406
509
  {
@@ -412,12 +515,18 @@ const createVPCInfrastructure = (AppDefinition) => {
412
515
  },
413
516
  ],
414
517
  Tags: [
415
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-vpc-endpoint-sg' },
518
+ {
519
+ Key: 'Name',
520
+ Value: '${self:service}-${self:provider.stage}-vpc-endpoint-sg',
521
+ },
416
522
  { Key: 'ManagedBy', Value: 'Frigg' },
417
523
  { Key: 'Service', Value: '${self:service}' },
418
524
  { Key: 'Stage', Value: '${self:provider.stage}' },
419
525
  { Key: 'Type', Value: 'VPCEndpoint' },
420
- { Key: 'Purpose', Value: 'Allow Lambda functions to access VPC endpoints' },
526
+ {
527
+ Key: 'Purpose',
528
+ Value: 'Allow Lambda functions to access VPC endpoints',
529
+ },
421
530
  ],
422
531
  },
423
532
  };
@@ -447,13 +556,18 @@ const gatherDiscoveredResources = async (AppDefinition) => {
447
556
  if (discoveredResources.defaultVpcId) {
448
557
  console.log(` VPC: ${discoveredResources.defaultVpcId}`);
449
558
  }
450
- if (discoveredResources.privateSubnetId1 && discoveredResources.privateSubnetId2) {
559
+ if (
560
+ discoveredResources.privateSubnetId1 &&
561
+ discoveredResources.privateSubnetId2
562
+ ) {
451
563
  console.log(
452
564
  ` Subnets: ${discoveredResources.privateSubnetId1}, ${discoveredResources.privateSubnetId2}`
453
565
  );
454
566
  }
455
567
  if (discoveredResources.defaultSecurityGroupId) {
456
- console.log(` Security Group: ${discoveredResources.defaultSecurityGroupId}`);
568
+ console.log(
569
+ ` Security Group: ${discoveredResources.defaultSecurityGroupId}`
570
+ );
457
571
  }
458
572
  if (discoveredResources.defaultKmsKeyId) {
459
573
  console.log(` KMS Key: ${discoveredResources.defaultKmsKeyId}`);
@@ -492,7 +606,11 @@ const buildEnvironment = (appEnvironmentVars, discoveredResources) => {
492
606
  return environment;
493
607
  };
494
608
 
495
- const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResources) => {
609
+ const createBaseDefinition = (
610
+ AppDefinition,
611
+ appEnvironmentVars,
612
+ discoveredResources
613
+ ) => {
496
614
  const region = process.env.AWS_REGION || 'us-east-1';
497
615
 
498
616
  return {
@@ -500,7 +618,11 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
500
618
  service: AppDefinition.name || 'create-frigg-app',
501
619
  package: {
502
620
  individually: true,
503
- exclude: ['!**/node_modules/aws-sdk/**', '!**/node_modules/@aws-sdk/**', '!package.json'],
621
+ exclude: [
622
+ '!**/node_modules/aws-sdk/**',
623
+ '!**/node_modules/@aws-sdk/**',
624
+ '!package.json',
625
+ ],
504
626
  },
505
627
  useDotenv: true,
506
628
  provider: {
@@ -509,7 +631,10 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
509
631
  timeout: 30,
510
632
  region,
511
633
  stage: '${opt:stage}',
512
- environment: buildEnvironment(appEnvironmentVars, discoveredResources),
634
+ environment: buildEnvironment(
635
+ appEnvironmentVars,
636
+ discoveredResources
637
+ ),
513
638
  iamRoleStatements: [
514
639
  {
515
640
  Effect: 'Allow',
@@ -518,13 +643,20 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
518
643
  },
519
644
  {
520
645
  Effect: 'Allow',
521
- Action: ['sqs:SendMessage', 'sqs:SendMessageBatch', 'sqs:GetQueueUrl', 'sqs:GetQueueAttributes'],
646
+ Action: [
647
+ 'sqs:SendMessage',
648
+ 'sqs:SendMessageBatch',
649
+ 'sqs:GetQueueUrl',
650
+ 'sqs:GetQueueAttributes',
651
+ ],
522
652
  Resource: [
523
653
  { 'Fn::GetAtt': ['InternalErrorQueue', 'Arn'] },
524
654
  {
525
655
  'Fn::Join': [
526
656
  ':',
527
- ['arn:aws:sqs:${self:provider.region}:*:${self:service}--${self:provider.stage}-*Queue'],
657
+ [
658
+ 'arn:aws:sqs:${self:provider.region}:*:${self:service}--${self:provider.stage}-*Queue',
659
+ ],
528
660
  ],
529
661
  },
530
662
  ],
@@ -543,7 +675,8 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
543
675
  },
544
676
  },
545
677
  plugins: [
546
- 'serverless-jetpack',
678
+ // Temporarily disabled Jetpack - it ignores package.patterns in dependency mode
679
+ // 'serverless-jetpack',
547
680
  'serverless-dotenv-plugin',
548
681
  'serverless-offline-sqs',
549
682
  'serverless-offline',
@@ -564,25 +697,36 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
564
697
  secretAccessKey: 'root',
565
698
  skipCacheInvalidation: false,
566
699
  },
567
- jetpack: {
568
- base: '..',
569
- },
700
+ // Jetpack config removed - testing with standard Serverless packaging
701
+ // jetpack: {
702
+ // base: '..',
703
+ // },
570
704
  },
571
705
  functions: {
572
706
  auth: {
573
- handler: 'node_modules/@friggframework/core/handlers/routers/auth.handler',
707
+ handler:
708
+ 'node_modules/@friggframework/core/handlers/routers/auth.handler',
574
709
  events: [
575
710
  { httpApi: { path: '/api/integrations', method: 'ANY' } },
576
- { httpApi: { path: '/api/integrations/{proxy+}', method: 'ANY' } },
711
+ {
712
+ httpApi: {
713
+ path: '/api/integrations/{proxy+}',
714
+ method: 'ANY',
715
+ },
716
+ },
577
717
  { httpApi: { path: '/api/authorize', method: 'ANY' } },
578
718
  ],
579
719
  },
580
720
  user: {
581
- handler: 'node_modules/@friggframework/core/handlers/routers/user.handler',
582
- events: [{ httpApi: { path: '/user/{proxy+}', method: 'ANY' } }],
721
+ handler:
722
+ 'node_modules/@friggframework/core/handlers/routers/user.handler',
723
+ events: [
724
+ { httpApi: { path: '/user/{proxy+}', method: 'ANY' } },
725
+ ],
583
726
  },
584
727
  health: {
585
- handler: 'node_modules/@friggframework/core/handlers/routers/health.handler',
728
+ handler:
729
+ 'node_modules/@friggframework/core/handlers/routers/health.handler',
586
730
  events: [
587
731
  { httpApi: { path: '/health', method: 'GET' } },
588
732
  { httpApi: { path: '/health/{proxy+}', method: 'GET' } },
@@ -594,7 +738,8 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
594
738
  InternalErrorQueue: {
595
739
  Type: 'AWS::SQS::Queue',
596
740
  Properties: {
597
- QueueName: '${self:service}-internal-error-queue-${self:provider.stage}',
741
+ QueueName:
742
+ '${self:service}-internal-error-queue-${self:provider.stage}',
598
743
  MessageRetentionPeriod: 300,
599
744
  },
600
745
  },
@@ -604,7 +749,9 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
604
749
  Subscription: [
605
750
  {
606
751
  Protocol: 'sqs',
607
- Endpoint: { 'Fn::GetAtt': ['InternalErrorQueue', 'Arn'] },
752
+ Endpoint: {
753
+ 'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
754
+ },
608
755
  },
609
756
  ],
610
757
  },
@@ -620,10 +767,22 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
620
767
  Sid: 'Allow Dead Letter SNS to publish to SQS',
621
768
  Effect: 'Allow',
622
769
  Principal: { Service: 'sns.amazonaws.com' },
623
- Resource: { 'Fn::GetAtt': ['InternalErrorQueue', 'Arn'] },
624
- Action: ['SQS:SendMessage', 'SQS:SendMessageBatch'],
770
+ Resource: {
771
+ 'Fn::GetAtt': [
772
+ 'InternalErrorQueue',
773
+ 'Arn',
774
+ ],
775
+ },
776
+ Action: [
777
+ 'SQS:SendMessage',
778
+ 'SQS:SendMessageBatch',
779
+ ],
625
780
  Condition: {
626
- ArnEquals: { 'aws:SourceArn': { Ref: 'InternalErrorBridgeTopic' } },
781
+ ArnEquals: {
782
+ 'aws:SourceArn': {
783
+ Ref: 'InternalErrorBridgeTopic',
784
+ },
785
+ },
627
786
  },
628
787
  },
629
788
  ],
@@ -653,24 +812,33 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
653
812
  };
654
813
  };
655
814
 
656
- const applyKmsConfiguration = (definition, AppDefinition, discoveredResources) => {
815
+ const applyKmsConfiguration = (
816
+ definition,
817
+ AppDefinition,
818
+ discoveredResources
819
+ ) => {
657
820
  if (AppDefinition.encryption?.fieldLevelEncryptionMethod !== 'kms') {
658
821
  return;
659
822
  }
660
823
 
661
824
  // Skip KMS configuration for local development when AWS discovery is disabled
662
825
  if (process.env.FRIGG_SKIP_AWS_DISCOVERY === 'true') {
663
- console.log('⚙️ Skipping KMS configuration for local development (FRIGG_SKIP_AWS_DISCOVERY is set)');
826
+ console.log(
827
+ '⚙️ Skipping KMS configuration for local development (FRIGG_SKIP_AWS_DISCOVERY is set)'
828
+ );
664
829
  return;
665
830
  }
666
831
 
667
832
  if (discoveredResources.defaultKmsKeyId) {
668
- console.log(`Using existing KMS key: ${discoveredResources.defaultKmsKeyId}`);
833
+ console.log(
834
+ `Using existing KMS key: ${discoveredResources.defaultKmsKeyId}`
835
+ );
669
836
  definition.resources.Resources.FriggKMSKeyAlias = {
670
837
  Type: 'AWS::KMS::Alias',
671
838
  DeletionPolicy: 'Retain',
672
839
  Properties: {
673
- AliasName: 'alias/${self:service}-${self:provider.stage}-frigg-kms',
840
+ AliasName:
841
+ 'alias/${self:service}-${self:provider.stage}-frigg-kms',
674
842
  TargetKeyId: discoveredResources.defaultKmsKeyId,
675
843
  },
676
844
  };
@@ -703,7 +871,10 @@ const applyKmsConfiguration = (definition, AppDefinition, discoveredResources) =
703
871
  Sid: 'AllowRootAccountAdmin',
704
872
  Effect: 'Allow',
705
873
  Principal: {
706
- AWS: { 'Fn::Sub': 'arn:aws:iam::${AWS::AccountId}:root' },
874
+ AWS: {
875
+ 'Fn::Sub':
876
+ 'arn:aws:iam::${AWS::AccountId}:root',
877
+ },
707
878
  },
708
879
  Action: 'kms:*',
709
880
  Resource: '*',
@@ -712,20 +883,32 @@ const applyKmsConfiguration = (definition, AppDefinition, discoveredResources) =
712
883
  Sid: 'AllowLambdaService',
713
884
  Effect: 'Allow',
714
885
  Principal: { Service: 'lambda.amazonaws.com' },
715
- Action: ['kms:GenerateDataKey', 'kms:Decrypt', 'kms:DescribeKey'],
886
+ Action: [
887
+ 'kms:GenerateDataKey',
888
+ 'kms:Decrypt',
889
+ 'kms:DescribeKey',
890
+ ],
716
891
  Resource: '*',
717
892
  Condition: {
718
893
  StringEquals: {
719
- 'kms:ViaService': `lambda.${process.env.AWS_REGION || 'us-east-1'}.amazonaws.com`,
894
+ 'kms:ViaService': `lambda.${
895
+ process.env.AWS_REGION || 'us-east-1'
896
+ }.amazonaws.com`,
720
897
  },
721
898
  },
722
899
  },
723
900
  ],
724
901
  },
725
902
  Tags: [
726
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-frigg-kms-key' },
903
+ {
904
+ Key: 'Name',
905
+ Value: '${self:service}-${self:provider.stage}-frigg-kms-key',
906
+ },
727
907
  { Key: 'ManagedBy', Value: 'Frigg' },
728
- { Key: 'Purpose', Value: 'Field-level encryption for Frigg application' },
908
+ {
909
+ Key: 'Purpose',
910
+ Value: 'Field-level encryption for Frigg application',
911
+ },
729
912
  ],
730
913
  },
731
914
  };
@@ -734,7 +917,8 @@ const applyKmsConfiguration = (definition, AppDefinition, discoveredResources) =
734
917
  Type: 'AWS::KMS::Alias',
735
918
  DeletionPolicy: 'Retain',
736
919
  Properties: {
737
- AliasName: 'alias/${self:service}-${self:provider.stage}-frigg-kms',
920
+ AliasName:
921
+ 'alias/${self:service}-${self:provider.stage}-frigg-kms',
738
922
  TargetKeyId: { 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] },
739
923
  },
740
924
  };
@@ -745,7 +929,9 @@ const applyKmsConfiguration = (definition, AppDefinition, discoveredResources) =
745
929
  Resource: [{ 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] }],
746
930
  });
747
931
 
748
- definition.provider.environment.KMS_KEY_ARN = { 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] };
932
+ definition.provider.environment.KMS_KEY_ARN = {
933
+ 'Fn::GetAtt': ['FriggKMSKey', 'Arn'],
934
+ };
749
935
  definition.custom.kmsGrants = {
750
936
  kmsKeyId: { 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] },
751
937
  };
@@ -754,13 +940,16 @@ const applyKmsConfiguration = (definition, AppDefinition, discoveredResources) =
754
940
  definition.plugins.push('serverless-kms-grants');
755
941
  if (!definition.custom.kmsGrants) {
756
942
  definition.custom.kmsGrants = {
757
- kmsKeyId: discoveredResources.defaultKmsKeyId || '${env:AWS_DISCOVERY_KMS_KEY_ID}',
943
+ kmsKeyId:
944
+ discoveredResources.defaultKmsKeyId ||
945
+ '${env:AWS_DISCOVERY_KMS_KEY_ID}',
758
946
  };
759
947
  }
760
948
 
761
949
  if (!definition.provider.environment.KMS_KEY_ARN) {
762
950
  definition.provider.environment.KMS_KEY_ARN =
763
- discoveredResources.defaultKmsKeyId || '${env:AWS_DISCOVERY_KMS_KEY_ID}';
951
+ discoveredResources.defaultKmsKeyId ||
952
+ '${env:AWS_DISCOVERY_KMS_KEY_ID}';
764
953
  }
765
954
  };
766
955
 
@@ -777,7 +966,9 @@ const healVpcConfiguration = (discoveredResources, AppDefinition) => {
777
966
  return healingReport;
778
967
  }
779
968
 
780
- console.log('🔧 Self-healing mode enabled - checking for VPC misconfigurations...');
969
+ console.log(
970
+ '🔧 Self-healing mode enabled - checking for VPC misconfigurations...'
971
+ );
781
972
 
782
973
  if (discoveredResources.natGatewayInPrivateSubnet) {
783
974
  healingReport.warnings.push(
@@ -787,7 +978,9 @@ const healVpcConfiguration = (discoveredResources, AppDefinition) => {
787
978
  'NAT Gateway should be recreated in a public subnet for proper internet connectivity'
788
979
  );
789
980
  discoveredResources.needsNewNatGateway = true;
790
- healingReport.healed.push('Marked NAT Gateway for recreation in public subnet');
981
+ healingReport.healed.push(
982
+ 'Marked NAT Gateway for recreation in public subnet'
983
+ );
791
984
  }
792
985
 
793
986
  if (discoveredResources.elasticIpAlreadyAssociated) {
@@ -796,10 +989,14 @@ const healVpcConfiguration = (discoveredResources, AppDefinition) => {
796
989
  );
797
990
 
798
991
  if (discoveredResources.existingNatGatewayId) {
799
- healingReport.healed.push('Will reuse existing NAT Gateway instead of creating a new one');
992
+ healingReport.healed.push(
993
+ 'Will reuse existing NAT Gateway instead of creating a new one'
994
+ );
800
995
  discoveredResources.reuseExistingNatGateway = true;
801
996
  } else {
802
- healingReport.healed.push('Will allocate a new Elastic IP for NAT Gateway');
997
+ healingReport.healed.push(
998
+ 'Will allocate a new Elastic IP for NAT Gateway'
999
+ );
803
1000
  discoveredResources.allocateNewElasticIp = true;
804
1001
  }
805
1002
  }
@@ -823,19 +1020,25 @@ const healVpcConfiguration = (discoveredResources, AppDefinition) => {
823
1020
  healingReport.warnings.push(
824
1021
  'Subnet configuration mismatch detected - Lambda functions require private subnets'
825
1022
  );
826
- healingReport.healed.push('Will create proper route table configuration for subnet isolation');
1023
+ healingReport.healed.push(
1024
+ 'Will create proper route table configuration for subnet isolation'
1025
+ );
827
1026
  }
828
1027
 
829
1028
  if (discoveredResources.orphanedElasticIps?.length > 0) {
830
1029
  healingReport.warnings.push(
831
1030
  `Found ${discoveredResources.orphanedElasticIps.length} orphaned Elastic IPs`
832
1031
  );
833
- healingReport.recommendations.push('Consider releasing orphaned Elastic IPs to avoid charges');
1032
+ healingReport.recommendations.push(
1033
+ 'Consider releasing orphaned Elastic IPs to avoid charges'
1034
+ );
834
1035
  }
835
1036
 
836
1037
  if (healingReport.criticalActions.length > 0) {
837
1038
  console.log('🚨 CRITICAL ACTIONS:');
838
- healingReport.criticalActions.forEach((action) => console.log(` - ${action}`));
1039
+ healingReport.criticalActions.forEach((action) =>
1040
+ console.log(` - ${action}`)
1041
+ );
839
1042
  }
840
1043
 
841
1044
  if (healingReport.healed.length > 0) {
@@ -845,12 +1048,16 @@ const healVpcConfiguration = (discoveredResources, AppDefinition) => {
845
1048
 
846
1049
  if (healingReport.warnings.length > 0) {
847
1050
  console.log('⚠️ Issues detected:');
848
- healingReport.warnings.forEach((warning) => console.log(` - ${warning}`));
1051
+ healingReport.warnings.forEach((warning) =>
1052
+ console.log(` - ${warning}`)
1053
+ );
849
1054
  }
850
1055
 
851
1056
  if (healingReport.recommendations.length > 0) {
852
1057
  console.log('💡 Recommendations:');
853
- healingReport.recommendations.forEach((rec) => console.log(` - ${rec}`));
1058
+ healingReport.recommendations.forEach((rec) =>
1059
+ console.log(` - ${rec}`)
1060
+ );
854
1061
  }
855
1062
 
856
1063
  return healingReport;
@@ -863,7 +1070,9 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
863
1070
 
864
1071
  // Skip VPC configuration for local development when AWS discovery is disabled
865
1072
  if (process.env.FRIGG_SKIP_AWS_DISCOVERY === 'true') {
866
- console.log('⚙️ Skipping VPC configuration for local development (FRIGG_SKIP_AWS_DISCOVERY is set)');
1073
+ console.log(
1074
+ '⚙️ Skipping VPC configuration for local development (FRIGG_SKIP_AWS_DISCOVERY is set)'
1075
+ );
867
1076
  return;
868
1077
  }
869
1078
 
@@ -880,9 +1089,16 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
880
1089
  });
881
1090
 
882
1091
  if (Object.keys(discoveredResources).length > 0) {
883
- const healingReport = healVpcConfiguration(discoveredResources, AppDefinition);
1092
+ const healingReport = healVpcConfiguration(
1093
+ discoveredResources,
1094
+ AppDefinition
1095
+ );
884
1096
  if (healingReport.errors.length > 0 && !AppDefinition.vpc?.selfHeal) {
885
- throw new Error(`VPC configuration errors detected: ${healingReport.errors.join(', ')}`);
1097
+ throw new Error(
1098
+ `VPC configuration errors detected: ${healingReport.errors.join(
1099
+ ', '
1100
+ )}`
1101
+ );
886
1102
  }
887
1103
  }
888
1104
 
@@ -899,15 +1115,21 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
899
1115
  const vpcResources = createVPCInfrastructure(AppDefinition);
900
1116
  Object.assign(definition.resources.Resources, vpcResources);
901
1117
  vpcId = { Ref: 'FriggVPC' };
902
- vpcConfig.securityGroupIds = AppDefinition.vpc.securityGroupIds || [{ Ref: 'FriggLambdaSecurityGroup' }];
1118
+ vpcConfig.securityGroupIds = AppDefinition.vpc.securityGroupIds || [
1119
+ { Ref: 'FriggLambdaSecurityGroup' },
1120
+ ];
903
1121
  } else if (vpcManagement === 'use-existing') {
904
1122
  if (!AppDefinition.vpc.vpcId) {
905
- throw new Error('VPC management is set to "use-existing" but no vpcId was provided');
1123
+ throw new Error(
1124
+ 'VPC management is set to "use-existing" but no vpcId was provided'
1125
+ );
906
1126
  }
907
1127
  vpcId = AppDefinition.vpc.vpcId;
908
1128
  vpcConfig.securityGroupIds =
909
1129
  AppDefinition.vpc.securityGroupIds ||
910
- (discoveredResources.defaultSecurityGroupId ? [discoveredResources.defaultSecurityGroupId] : []);
1130
+ (discoveredResources.defaultSecurityGroupId
1131
+ ? [discoveredResources.defaultSecurityGroupId]
1132
+ : []);
911
1133
  } else {
912
1134
  if (!discoveredResources.defaultVpcId) {
913
1135
  throw new Error(
@@ -917,11 +1139,15 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
917
1139
  vpcId = discoveredResources.defaultVpcId;
918
1140
  vpcConfig.securityGroupIds =
919
1141
  AppDefinition.vpc.securityGroupIds ||
920
- (discoveredResources.defaultSecurityGroupId ? [discoveredResources.defaultSecurityGroupId] : []);
1142
+ (discoveredResources.defaultSecurityGroupId
1143
+ ? [discoveredResources.defaultSecurityGroupId]
1144
+ : []);
921
1145
  }
922
1146
 
923
- const defaultSubnetManagement = vpcManagement === 'create-new' ? 'create' : 'discover';
924
- let subnetManagement = AppDefinition.vpc.subnets?.management || defaultSubnetManagement;
1147
+ const defaultSubnetManagement =
1148
+ vpcManagement === 'create-new' ? 'create' : 'discover';
1149
+ let subnetManagement =
1150
+ AppDefinition.vpc.subnets?.management || defaultSubnetManagement;
925
1151
  console.log(`Subnet Management Mode: ${subnetManagement}`);
926
1152
 
927
1153
  const effectiveVpcId = vpcId || discoveredResources.defaultVpcId;
@@ -931,7 +1157,10 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
931
1157
 
932
1158
  if (subnetManagement === 'create') {
933
1159
  console.log('Creating new subnets...');
934
- const subnetVpcId = vpcManagement === 'create-new' ? { Ref: 'FriggVPC' } : effectiveVpcId;
1160
+ const subnetVpcId =
1161
+ vpcManagement === 'create-new'
1162
+ ? { Ref: 'FriggVPC' }
1163
+ : effectiveVpcId;
935
1164
  let subnet1Cidr;
936
1165
  let subnet2Cidr;
937
1166
  let publicSubnetCidr;
@@ -954,7 +1183,10 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
954
1183
  CidrBlock: subnet1Cidr,
955
1184
  AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
956
1185
  Tags: [
957
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-1' },
1186
+ {
1187
+ Key: 'Name',
1188
+ Value: '${self:service}-${self:provider.stage}-private-1',
1189
+ },
958
1190
  { Key: 'Type', Value: 'Private' },
959
1191
  { Key: 'ManagedBy', Value: 'Frigg' },
960
1192
  ],
@@ -968,7 +1200,10 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
968
1200
  CidrBlock: subnet2Cidr,
969
1201
  AvailabilityZone: { 'Fn::Select': [1, { 'Fn::GetAZs': '' }] },
970
1202
  Tags: [
971
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-2' },
1203
+ {
1204
+ Key: 'Name',
1205
+ Value: '${self:service}-${self:provider.stage}-private-2',
1206
+ },
972
1207
  { Key: 'Type', Value: 'Private' },
973
1208
  { Key: 'ManagedBy', Value: 'Frigg' },
974
1209
  ],
@@ -983,23 +1218,38 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
983
1218
  MapPublicIpOnLaunch: true,
984
1219
  AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
985
1220
  Tags: [
986
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-public' },
1221
+ {
1222
+ Key: 'Name',
1223
+ Value: '${self:service}-${self:provider.stage}-public',
1224
+ },
987
1225
  { Key: 'Type', Value: 'Public' },
988
1226
  { Key: 'ManagedBy', Value: 'Frigg' },
989
1227
  ],
990
1228
  },
991
1229
  };
992
1230
 
993
- vpcConfig.subnetIds = [{ Ref: 'FriggPrivateSubnet1' }, { Ref: 'FriggPrivateSubnet2' }];
1231
+ vpcConfig.subnetIds = [
1232
+ { Ref: 'FriggPrivateSubnet1' },
1233
+ { Ref: 'FriggPrivateSubnet2' },
1234
+ ];
994
1235
 
995
- if (!AppDefinition.vpc.natGateway || AppDefinition.vpc.natGateway.management === 'discover') {
996
- if (vpcManagement === 'create-new' || !discoveredResources.internetGatewayId) {
1236
+ if (
1237
+ !AppDefinition.vpc.natGateway ||
1238
+ AppDefinition.vpc.natGateway.management === 'discover'
1239
+ ) {
1240
+ if (
1241
+ vpcManagement === 'create-new' ||
1242
+ !discoveredResources.internetGatewayId
1243
+ ) {
997
1244
  if (!definition.resources.Resources.FriggInternetGateway) {
998
1245
  definition.resources.Resources.FriggInternetGateway = {
999
1246
  Type: 'AWS::EC2::InternetGateway',
1000
1247
  Properties: {
1001
1248
  Tags: [
1002
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-igw' },
1249
+ {
1250
+ Key: 'Name',
1251
+ Value: '${self:service}-${self:provider.stage}-igw',
1252
+ },
1003
1253
  { Key: 'ManagedBy', Value: 'Frigg' },
1004
1254
  ],
1005
1255
  },
@@ -1020,7 +1270,10 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1020
1270
  Properties: {
1021
1271
  VpcId: subnetVpcId,
1022
1272
  Tags: [
1023
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-public-rt' },
1273
+ {
1274
+ Key: 'Name',
1275
+ Value: '${self:service}-${self:provider.stage}-public-rt',
1276
+ },
1024
1277
  { Key: 'ManagedBy', Value: 'Frigg' },
1025
1278
  ],
1026
1279
  },
@@ -1028,51 +1281,65 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1028
1281
 
1029
1282
  definition.resources.Resources.FriggPublicRoute = {
1030
1283
  Type: 'AWS::EC2::Route',
1031
- DependsOn: vpcManagement === 'create-new' ? 'FriggIGWAttachment' : undefined,
1284
+ DependsOn:
1285
+ vpcManagement === 'create-new'
1286
+ ? 'FriggIGWAttachment'
1287
+ : undefined,
1032
1288
  Properties: {
1033
1289
  RouteTableId: { Ref: 'FriggPublicRouteTable' },
1034
1290
  DestinationCidrBlock: '0.0.0.0/0',
1035
- GatewayId: discoveredResources.internetGatewayId || { Ref: 'FriggInternetGateway' },
1291
+ GatewayId: discoveredResources.internetGatewayId || {
1292
+ Ref: 'FriggInternetGateway',
1293
+ },
1036
1294
  },
1037
1295
  };
1038
1296
 
1039
- definition.resources.Resources.FriggPublicSubnetRouteTableAssociation = {
1040
- Type: 'AWS::EC2::SubnetRouteTableAssociation',
1041
- Properties: {
1042
- SubnetId: { Ref: 'FriggPublicSubnet' },
1043
- RouteTableId: { Ref: 'FriggPublicRouteTable' },
1044
- },
1045
- };
1297
+ definition.resources.Resources.FriggPublicSubnetRouteTableAssociation =
1298
+ {
1299
+ Type: 'AWS::EC2::SubnetRouteTableAssociation',
1300
+ Properties: {
1301
+ SubnetId: { Ref: 'FriggPublicSubnet' },
1302
+ RouteTableId: { Ref: 'FriggPublicRouteTable' },
1303
+ },
1304
+ };
1046
1305
 
1047
1306
  definition.resources.Resources.FriggLambdaRouteTable = {
1048
1307
  Type: 'AWS::EC2::RouteTable',
1049
1308
  Properties: {
1050
1309
  VpcId: subnetVpcId,
1051
1310
  Tags: [
1052
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-lambda-rt' },
1311
+ {
1312
+ Key: 'Name',
1313
+ Value: '${self:service}-${self:provider.stage}-lambda-rt',
1314
+ },
1053
1315
  { Key: 'ManagedBy', Value: 'Frigg' },
1054
1316
  ],
1055
1317
  },
1056
1318
  };
1057
1319
 
1058
- definition.resources.Resources.FriggPrivateSubnet1RouteTableAssociation = {
1059
- Type: 'AWS::EC2::SubnetRouteTableAssociation',
1060
- Properties: {
1061
- SubnetId: { Ref: 'FriggPrivateSubnet1' },
1062
- RouteTableId: { Ref: 'FriggLambdaRouteTable' },
1063
- },
1064
- };
1320
+ definition.resources.Resources.FriggPrivateSubnet1RouteTableAssociation =
1321
+ {
1322
+ Type: 'AWS::EC2::SubnetRouteTableAssociation',
1323
+ Properties: {
1324
+ SubnetId: { Ref: 'FriggPrivateSubnet1' },
1325
+ RouteTableId: { Ref: 'FriggLambdaRouteTable' },
1326
+ },
1327
+ };
1065
1328
 
1066
- definition.resources.Resources.FriggPrivateSubnet2RouteTableAssociation = {
1067
- Type: 'AWS::EC2::SubnetRouteTableAssociation',
1068
- Properties: {
1069
- SubnetId: { Ref: 'FriggPrivateSubnet2' },
1070
- RouteTableId: { Ref: 'FriggLambdaRouteTable' },
1071
- },
1072
- };
1329
+ definition.resources.Resources.FriggPrivateSubnet2RouteTableAssociation =
1330
+ {
1331
+ Type: 'AWS::EC2::SubnetRouteTableAssociation',
1332
+ Properties: {
1333
+ SubnetId: { Ref: 'FriggPrivateSubnet2' },
1334
+ RouteTableId: { Ref: 'FriggLambdaRouteTable' },
1335
+ },
1336
+ };
1073
1337
  }
1074
1338
  } else if (subnetManagement === 'use-existing') {
1075
- if (!AppDefinition.vpc.subnets?.ids || AppDefinition.vpc.subnets.ids.length < 2) {
1339
+ if (
1340
+ !AppDefinition.vpc.subnets?.ids ||
1341
+ AppDefinition.vpc.subnets.ids.length < 2
1342
+ ) {
1076
1343
  throw new Error(
1077
1344
  'Subnet management is "use-existing" but less than 2 subnet IDs provided. Provide at least 2 subnet IDs in vpc.subnets.ids.'
1078
1345
  );
@@ -1082,13 +1349,19 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1082
1349
  vpcConfig.subnetIds =
1083
1350
  AppDefinition.vpc.subnets?.ids?.length > 0
1084
1351
  ? AppDefinition.vpc.subnets.ids
1085
- : discoveredResources.privateSubnetId1 && discoveredResources.privateSubnetId2
1086
- ? [discoveredResources.privateSubnetId1, discoveredResources.privateSubnetId2]
1352
+ : discoveredResources.privateSubnetId1 &&
1353
+ discoveredResources.privateSubnetId2
1354
+ ? [
1355
+ discoveredResources.privateSubnetId1,
1356
+ discoveredResources.privateSubnetId2,
1357
+ ]
1087
1358
  : [];
1088
1359
 
1089
1360
  if (vpcConfig.subnetIds.length < 2) {
1090
1361
  if (AppDefinition.vpc.selfHeal) {
1091
- console.log('No subnets found but self-heal enabled - creating minimal subnet setup');
1362
+ console.log(
1363
+ 'No subnets found but self-heal enabled - creating minimal subnet setup'
1364
+ );
1092
1365
  subnetManagement = 'create';
1093
1366
  discoveredResources.createSubnets = true;
1094
1367
  } else {
@@ -1100,19 +1373,22 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1100
1373
  }
1101
1374
 
1102
1375
  if (subnetManagement === 'create' && discoveredResources.createSubnets) {
1103
- definition.resources.Resources.FriggLambdaRouteTable =
1104
- definition.resources.Resources.FriggLambdaRouteTable || {
1105
- Type: 'AWS::EC2::RouteTable',
1106
- Properties: {
1107
- VpcId: effectiveVpcId,
1108
- Tags: [
1109
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-lambda-rt' },
1110
- { Key: 'ManagedBy', Value: 'Frigg' },
1111
- { Key: 'Environment', Value: '${self:provider.stage}' },
1112
- { Key: 'Service', Value: '${self:service}' },
1113
- ],
1114
- },
1115
- };
1376
+ definition.resources.Resources.FriggLambdaRouteTable = definition
1377
+ .resources.Resources.FriggLambdaRouteTable || {
1378
+ Type: 'AWS::EC2::RouteTable',
1379
+ Properties: {
1380
+ VpcId: effectiveVpcId,
1381
+ Tags: [
1382
+ {
1383
+ Key: 'Name',
1384
+ Value: '${self:service}-${self:provider.stage}-lambda-rt',
1385
+ },
1386
+ { Key: 'ManagedBy', Value: 'Frigg' },
1387
+ { Key: 'Environment', Value: '${self:provider.stage}' },
1388
+ { Key: 'Service', Value: '${self:service}' },
1389
+ ],
1390
+ },
1391
+ };
1116
1392
  }
1117
1393
 
1118
1394
  if (
@@ -1121,7 +1397,8 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1121
1397
  ) {
1122
1398
  definition.provider.vpc = vpcConfig;
1123
1399
 
1124
- const natGatewayManagement = AppDefinition.vpc.natGateway?.management || 'discover';
1400
+ const natGatewayManagement =
1401
+ AppDefinition.vpc.natGateway?.management || 'discover';
1125
1402
  let needsNewNatGateway =
1126
1403
  natGatewayManagement === 'createAndManage' ||
1127
1404
  discoveredResources.needsNewNatGateway === true;
@@ -1132,7 +1409,9 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1132
1409
  let useExistingEip = false;
1133
1410
 
1134
1411
  if (needsNewNatGateway) {
1135
- console.log('Create mode: Creating dedicated EIP, public subnet, and NAT Gateway...');
1412
+ console.log(
1413
+ 'Create mode: Creating dedicated EIP, public subnet, and NAT Gateway...'
1414
+ );
1136
1415
 
1137
1416
  if (
1138
1417
  discoveredResources.existingNatGatewayId &&
@@ -1140,12 +1419,18 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1140
1419
  ) {
1141
1420
  console.log('Found existing Frigg-managed NAT Gateway and EIP');
1142
1421
  if (!discoveredResources.natGatewayInPrivateSubnet) {
1143
- console.log('✅ Existing NAT Gateway is in PUBLIC subnet, will reuse it');
1422
+ console.log(
1423
+ '✅ Existing NAT Gateway is in PUBLIC subnet, will reuse it'
1424
+ );
1144
1425
  reuseExistingNatGateway = true;
1145
1426
  } else {
1146
- console.log('❌ NAT Gateway is in PRIVATE subnet - MUST create new one in PUBLIC subnet');
1427
+ console.log(
1428
+ '❌ NAT Gateway is in PRIVATE subnet - MUST create new one in PUBLIC subnet'
1429
+ );
1147
1430
  if (AppDefinition.vpc.selfHeal) {
1148
- console.log('Self-heal enabled: Creating new NAT Gateway in PUBLIC subnet');
1431
+ console.log(
1432
+ 'Self-heal enabled: Creating new NAT Gateway in PUBLIC subnet'
1433
+ );
1149
1434
  reuseExistingNatGateway = false;
1150
1435
  useExistingEip = false;
1151
1436
  discoveredResources.needsCleanup = true;
@@ -1159,12 +1444,16 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1159
1444
  discoveredResources.existingElasticIpAllocationId &&
1160
1445
  !discoveredResources.existingNatGatewayId
1161
1446
  ) {
1162
- console.log('Found orphaned EIP, will reuse it for new NAT Gateway in PUBLIC subnet');
1447
+ console.log(
1448
+ 'Found orphaned EIP, will reuse it for new NAT Gateway in PUBLIC subnet'
1449
+ );
1163
1450
  useExistingEip = true;
1164
1451
  }
1165
1452
 
1166
1453
  if (reuseExistingNatGateway) {
1167
- console.log('Reusing existing NAT Gateway - skipping resource creation');
1454
+ console.log(
1455
+ 'Reusing existing NAT Gateway - skipping resource creation'
1456
+ );
1168
1457
  } else {
1169
1458
  if (!useExistingEip) {
1170
1459
  definition.resources.Resources.FriggNATGatewayEIP = {
@@ -1174,10 +1463,16 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1174
1463
  Properties: {
1175
1464
  Domain: 'vpc',
1176
1465
  Tags: [
1177
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-eip' },
1466
+ {
1467
+ Key: 'Name',
1468
+ Value: '${self:service}-${self:provider.stage}-nat-eip',
1469
+ },
1178
1470
  { Key: 'ManagedBy', Value: 'Frigg' },
1179
1471
  { Key: 'Service', Value: '${self:service}' },
1180
- { Key: 'Stage', Value: '${self:provider.stage}' },
1472
+ {
1473
+ Key: 'Stage',
1474
+ Value: '${self:provider.stage}',
1475
+ },
1181
1476
  ],
1182
1477
  },
1183
1478
  };
@@ -1185,25 +1480,34 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1185
1480
 
1186
1481
  if (!discoveredResources.publicSubnetId) {
1187
1482
  if (discoveredResources.internetGatewayId) {
1188
- console.log('Reusing existing Internet Gateway for NAT Gateway');
1483
+ console.log(
1484
+ 'Reusing existing Internet Gateway for NAT Gateway'
1485
+ );
1189
1486
  } else {
1190
1487
  definition.resources.Resources.FriggInternetGateway =
1191
- definition.resources.Resources.FriggInternetGateway || {
1488
+ definition.resources.Resources
1489
+ .FriggInternetGateway || {
1192
1490
  Type: 'AWS::EC2::InternetGateway',
1193
1491
  Properties: {
1194
1492
  Tags: [
1195
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-igw' },
1493
+ {
1494
+ Key: 'Name',
1495
+ Value: '${self:service}-${self:provider.stage}-igw',
1496
+ },
1196
1497
  { Key: 'ManagedBy', Value: 'Frigg' },
1197
1498
  ],
1198
1499
  },
1199
1500
  };
1200
1501
 
1201
1502
  definition.resources.Resources.FriggIGWAttachment =
1202
- definition.resources.Resources.FriggIGWAttachment || {
1503
+ definition.resources.Resources
1504
+ .FriggIGWAttachment || {
1203
1505
  Type: 'AWS::EC2::VPCGatewayAttachment',
1204
1506
  Properties: {
1205
1507
  VpcId: discoveredResources.defaultVpcId,
1206
- InternetGatewayId: { Ref: 'FriggInternetGateway' },
1508
+ InternetGatewayId: {
1509
+ Ref: 'FriggInternetGateway',
1510
+ },
1207
1511
  },
1208
1512
  };
1209
1513
  }
@@ -1213,11 +1517,17 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1213
1517
  Properties: {
1214
1518
  VpcId: discoveredResources.defaultVpcId,
1215
1519
  CidrBlock:
1216
- AppDefinition.vpc.natGateway?.publicSubnetCidr || '172.31.250.0/24',
1217
- AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
1520
+ AppDefinition.vpc.natGateway
1521
+ ?.publicSubnetCidr || '172.31.250.0/24',
1522
+ AvailabilityZone: {
1523
+ 'Fn::Select': [0, { 'Fn::GetAZs': '' }],
1524
+ },
1218
1525
  MapPublicIpOnLaunch: true,
1219
1526
  Tags: [
1220
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-public-subnet' },
1527
+ {
1528
+ Key: 'Name',
1529
+ Value: '${self:service}-${self:provider.stage}-public-subnet',
1530
+ },
1221
1531
  { Key: 'Type', Value: 'Public' },
1222
1532
  ],
1223
1533
  },
@@ -1228,28 +1538,37 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1228
1538
  Properties: {
1229
1539
  VpcId: discoveredResources.defaultVpcId,
1230
1540
  Tags: [
1231
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-public-rt' },
1541
+ {
1542
+ Key: 'Name',
1543
+ Value: '${self:service}-${self:provider.stage}-public-rt',
1544
+ },
1232
1545
  ],
1233
1546
  },
1234
1547
  };
1235
1548
 
1236
1549
  definition.resources.Resources.FriggPublicRoute = {
1237
1550
  Type: 'AWS::EC2::Route',
1238
- DependsOn: discoveredResources.internetGatewayId ? [] : 'FriggIGWAttachment',
1551
+ DependsOn: discoveredResources.internetGatewayId
1552
+ ? []
1553
+ : 'FriggIGWAttachment',
1239
1554
  Properties: {
1240
1555
  RouteTableId: { Ref: 'FriggPublicRouteTable' },
1241
1556
  DestinationCidrBlock: '0.0.0.0/0',
1242
- GatewayId: discoveredResources.internetGatewayId || { Ref: 'FriggInternetGateway' },
1557
+ GatewayId:
1558
+ discoveredResources.internetGatewayId || {
1559
+ Ref: 'FriggInternetGateway',
1560
+ },
1243
1561
  },
1244
1562
  };
1245
1563
 
1246
- definition.resources.Resources.FriggPublicSubnetRouteTableAssociation = {
1247
- Type: 'AWS::EC2::SubnetRouteTableAssociation',
1248
- Properties: {
1249
- SubnetId: { Ref: 'FriggPublicSubnet' },
1250
- RouteTableId: { Ref: 'FriggPublicRouteTable' },
1251
- },
1252
- };
1564
+ definition.resources.Resources.FriggPublicSubnetRouteTableAssociation =
1565
+ {
1566
+ Type: 'AWS::EC2::SubnetRouteTableAssociation',
1567
+ Properties: {
1568
+ SubnetId: { Ref: 'FriggPublicSubnet' },
1569
+ RouteTableId: { Ref: 'FriggPublicRouteTable' },
1570
+ },
1571
+ };
1253
1572
  }
1254
1573
 
1255
1574
  definition.resources.Resources.FriggNATGateway = {
@@ -1259,11 +1578,20 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1259
1578
  Properties: {
1260
1579
  AllocationId: useExistingEip
1261
1580
  ? discoveredResources.existingElasticIpAllocationId
1262
- : { 'Fn::GetAtt': ['FriggNATGatewayEIP', 'AllocationId'] },
1263
- SubnetId:
1264
- discoveredResources.publicSubnetId || { Ref: 'FriggPublicSubnet' },
1581
+ : {
1582
+ 'Fn::GetAtt': [
1583
+ 'FriggNATGatewayEIP',
1584
+ 'AllocationId',
1585
+ ],
1586
+ },
1587
+ SubnetId: discoveredResources.publicSubnetId || {
1588
+ Ref: 'FriggPublicSubnet',
1589
+ },
1265
1590
  Tags: [
1266
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-gateway' },
1591
+ {
1592
+ Key: 'Name',
1593
+ Value: '${self:service}-${self:provider.stage}-nat-gateway',
1594
+ },
1267
1595
  { Key: 'ManagedBy', Value: 'Frigg' },
1268
1596
  { Key: 'Service', Value: '${self:service}' },
1269
1597
  { Key: 'Stage', Value: '${self:provider.stage}' },
@@ -1275,9 +1603,15 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1275
1603
  natGatewayManagement === 'discover' ||
1276
1604
  natGatewayManagement === 'useExisting'
1277
1605
  ) {
1278
- if (natGatewayManagement === 'useExisting' && AppDefinition.vpc.natGateway?.id) {
1279
- console.log(`Using explicitly provided NAT Gateway: ${AppDefinition.vpc.natGateway.id}`);
1280
- discoveredResources.existingNatGatewayId = AppDefinition.vpc.natGateway.id;
1606
+ if (
1607
+ natGatewayManagement === 'useExisting' &&
1608
+ AppDefinition.vpc.natGateway?.id
1609
+ ) {
1610
+ console.log(
1611
+ `Using explicitly provided NAT Gateway: ${AppDefinition.vpc.natGateway.id}`
1612
+ );
1613
+ discoveredResources.existingNatGatewayId =
1614
+ AppDefinition.vpc.natGateway.id;
1281
1615
  }
1282
1616
 
1283
1617
  if (discoveredResources.existingNatGatewayId) {
@@ -1287,14 +1621,20 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1287
1621
  );
1288
1622
 
1289
1623
  if (discoveredResources.natGatewayInPrivateSubnet) {
1290
- console.log('❌ CRITICAL: NAT Gateway is in PRIVATE subnet - Internet connectivity will NOT work!');
1624
+ console.log(
1625
+ '❌ CRITICAL: NAT Gateway is in PRIVATE subnet - Internet connectivity will NOT work!'
1626
+ );
1291
1627
 
1292
1628
  if (AppDefinition.vpc.selfHeal === true) {
1293
- console.log('Self-heal enabled: Will create new NAT Gateway in PUBLIC subnet');
1629
+ console.log(
1630
+ 'Self-heal enabled: Will create new NAT Gateway in PUBLIC subnet'
1631
+ );
1294
1632
  needsNewNatGateway = true;
1295
1633
  discoveredResources.existingNatGatewayId = null;
1296
1634
  if (!discoveredResources.publicSubnetId) {
1297
- console.log('No public subnet found - will create one for NAT Gateway');
1635
+ console.log(
1636
+ 'No public subnet found - will create one for NAT Gateway'
1637
+ );
1298
1638
  discoveredResources.createPublicSubnet = true;
1299
1639
  }
1300
1640
  } else {
@@ -1303,52 +1643,73 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1303
1643
  );
1304
1644
  }
1305
1645
  } else {
1306
- console.log(`Using discovered NAT Gateway for routing: ${discoveredResources.existingNatGatewayId}`);
1646
+ console.log(
1647
+ `Using discovered NAT Gateway for routing: ${discoveredResources.existingNatGatewayId}`
1648
+ );
1307
1649
  }
1308
- } else if (!needsNewNatGateway && AppDefinition.vpc.natGateway?.id) {
1309
- console.log(`Using explicitly provided NAT Gateway: ${AppDefinition.vpc.natGateway.id}`);
1310
- discoveredResources.existingNatGatewayId = AppDefinition.vpc.natGateway.id;
1650
+ } else if (
1651
+ !needsNewNatGateway &&
1652
+ AppDefinition.vpc.natGateway?.id
1653
+ ) {
1654
+ console.log(
1655
+ `Using explicitly provided NAT Gateway: ${AppDefinition.vpc.natGateway.id}`
1656
+ );
1657
+ discoveredResources.existingNatGatewayId =
1658
+ AppDefinition.vpc.natGateway.id;
1311
1659
  }
1312
1660
  }
1313
1661
 
1314
- definition.resources.Resources.FriggLambdaRouteTable =
1315
- definition.resources.Resources.FriggLambdaRouteTable || {
1316
- Type: 'AWS::EC2::RouteTable',
1317
- Properties: {
1318
- VpcId: discoveredResources.defaultVpcId || vpcId,
1319
- Tags: [
1320
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-lambda-rt' },
1321
- { Key: 'ManagedBy', Value: 'Frigg' },
1322
- { Key: 'Environment', Value: '${self:provider.stage}' },
1323
- { Key: 'Service', Value: '${self:service}' },
1324
- ],
1325
- },
1326
- };
1662
+ definition.resources.Resources.FriggLambdaRouteTable = definition
1663
+ .resources.Resources.FriggLambdaRouteTable || {
1664
+ Type: 'AWS::EC2::RouteTable',
1665
+ Properties: {
1666
+ VpcId: discoveredResources.defaultVpcId || vpcId,
1667
+ Tags: [
1668
+ {
1669
+ Key: 'Name',
1670
+ Value: '${self:service}-${self:provider.stage}-lambda-rt',
1671
+ },
1672
+ { Key: 'ManagedBy', Value: 'Frigg' },
1673
+ { Key: 'Environment', Value: '${self:provider.stage}' },
1674
+ { Key: 'Service', Value: '${self:service}' },
1675
+ ],
1676
+ },
1677
+ };
1327
1678
 
1328
1679
  const routeTableId = { Ref: 'FriggLambdaRouteTable' };
1329
1680
  let natGatewayIdForRoute;
1330
1681
 
1331
1682
  if (reuseExistingNatGateway) {
1332
1683
  natGatewayIdForRoute = discoveredResources.existingNatGatewayId;
1333
- console.log(`Using discovered NAT Gateway for routing: ${natGatewayIdForRoute}`);
1684
+ console.log(
1685
+ `Using discovered NAT Gateway for routing: ${natGatewayIdForRoute}`
1686
+ );
1334
1687
  } else if (needsNewNatGateway && !reuseExistingNatGateway) {
1335
1688
  natGatewayIdForRoute = { Ref: 'FriggNATGateway' };
1336
1689
  console.log('Using newly created NAT Gateway for routing');
1337
1690
  } else if (discoveredResources.existingNatGatewayId) {
1338
1691
  natGatewayIdForRoute = discoveredResources.existingNatGatewayId;
1339
- console.log(`Using discovered NAT Gateway for routing: ${natGatewayIdForRoute}`);
1692
+ console.log(
1693
+ `Using discovered NAT Gateway for routing: ${natGatewayIdForRoute}`
1694
+ );
1340
1695
  } else if (AppDefinition.vpc.natGateway?.id) {
1341
1696
  natGatewayIdForRoute = AppDefinition.vpc.natGateway.id;
1342
- console.log(`Using explicitly provided NAT Gateway for routing: ${natGatewayIdForRoute}`);
1697
+ console.log(
1698
+ `Using explicitly provided NAT Gateway for routing: ${natGatewayIdForRoute}`
1699
+ );
1343
1700
  } else if (AppDefinition.vpc.selfHeal === true) {
1344
1701
  natGatewayIdForRoute = null;
1345
- console.log('No NAT Gateway available - skipping NAT route creation');
1702
+ console.log(
1703
+ 'No NAT Gateway available - skipping NAT route creation'
1704
+ );
1346
1705
  } else {
1347
1706
  throw new Error('No existing NAT Gateway found in discovery mode');
1348
1707
  }
1349
1708
 
1350
1709
  if (natGatewayIdForRoute) {
1351
- console.log(`Configuring NAT route: 0.0.0.0/0 → ${natGatewayIdForRoute}`);
1710
+ console.log(
1711
+ `Configuring NAT route: 0.0.0.0/0 → ${natGatewayIdForRoute}`
1712
+ );
1352
1713
  definition.resources.Resources.FriggNATRoute = {
1353
1714
  Type: 'AWS::EC2::Route',
1354
1715
  DependsOn: 'FriggLambdaRouteTable',
@@ -1359,7 +1720,9 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1359
1720
  },
1360
1721
  };
1361
1722
  } else {
1362
- console.warn('⚠️ No NAT Gateway configured - Lambda functions will not have internet access');
1723
+ console.warn(
1724
+ '⚠️ No NAT Gateway configured - Lambda functions will not have internet access'
1725
+ );
1363
1726
  }
1364
1727
 
1365
1728
  if (typeof vpcConfig.subnetIds[0] === 'string') {
@@ -1384,25 +1747,37 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1384
1747
  };
1385
1748
  }
1386
1749
 
1387
- if (typeof vpcConfig.subnetIds[0] === 'object' && vpcConfig.subnetIds[0].Ref) {
1750
+ if (
1751
+ typeof vpcConfig.subnetIds[0] === 'object' &&
1752
+ vpcConfig.subnetIds[0].Ref
1753
+ ) {
1388
1754
  definition.resources.Resources.FriggNewSubnet1RouteAssociation = {
1389
1755
  Type: 'AWS::EC2::SubnetRouteTableAssociation',
1390
1756
  Properties: {
1391
1757
  SubnetId: vpcConfig.subnetIds[0],
1392
1758
  RouteTableId: routeTableId,
1393
1759
  },
1394
- DependsOn: ['FriggLambdaRouteTable', vpcConfig.subnetIds[0].Ref],
1760
+ DependsOn: [
1761
+ 'FriggLambdaRouteTable',
1762
+ vpcConfig.subnetIds[0].Ref,
1763
+ ],
1395
1764
  };
1396
1765
  }
1397
1766
 
1398
- if (typeof vpcConfig.subnetIds[1] === 'object' && vpcConfig.subnetIds[1].Ref) {
1767
+ if (
1768
+ typeof vpcConfig.subnetIds[1] === 'object' &&
1769
+ vpcConfig.subnetIds[1].Ref
1770
+ ) {
1399
1771
  definition.resources.Resources.FriggNewSubnet2RouteAssociation = {
1400
1772
  Type: 'AWS::EC2::SubnetRouteTableAssociation',
1401
1773
  Properties: {
1402
1774
  SubnetId: vpcConfig.subnetIds[1],
1403
1775
  RouteTableId: routeTableId,
1404
1776
  },
1405
- DependsOn: ['FriggLambdaRouteTable', vpcConfig.subnetIds[1].Ref],
1777
+ DependsOn: [
1778
+ 'FriggLambdaRouteTable',
1779
+ vpcConfig.subnetIds[1].Ref,
1780
+ ],
1406
1781
  };
1407
1782
  }
1408
1783
 
@@ -1421,7 +1796,8 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1421
1796
  Type: 'AWS::EC2::VPCEndpoint',
1422
1797
  Properties: {
1423
1798
  VpcId: discoveredResources.defaultVpcId,
1424
- ServiceName: 'com.amazonaws.${self:provider.region}.dynamodb',
1799
+ ServiceName:
1800
+ 'com.amazonaws.${self:provider.region}.dynamodb',
1425
1801
  VpcEndpointType: 'Gateway',
1426
1802
  RouteTableIds: [routeTableId],
1427
1803
  },
@@ -1438,7 +1814,10 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1438
1814
  if (!definition.resources.Resources.VPCEndpointSecurityGroup) {
1439
1815
  const vpcEndpointIngressRules = [];
1440
1816
 
1441
- if (vpcConfig.securityGroupIds && vpcConfig.securityGroupIds.length > 0) {
1817
+ if (
1818
+ vpcConfig.securityGroupIds &&
1819
+ vpcConfig.securityGroupIds.length > 0
1820
+ ) {
1442
1821
  for (const sg of vpcConfig.securityGroupIds) {
1443
1822
  if (typeof sg === 'string') {
1444
1823
  vpcEndpointIngressRules.push({
@@ -1486,13 +1865,20 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1486
1865
  definition.resources.Resources.VPCEndpointSecurityGroup = {
1487
1866
  Type: 'AWS::EC2::SecurityGroup',
1488
1867
  Properties: {
1489
- GroupDescription: 'Security group for VPC endpoints - allows HTTPS from Lambda functions',
1868
+ GroupDescription:
1869
+ 'Security group for VPC endpoints - allows HTTPS from Lambda functions',
1490
1870
  VpcId: discoveredResources.defaultVpcId,
1491
1871
  SecurityGroupIngress: vpcEndpointIngressRules,
1492
1872
  Tags: [
1493
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-vpc-endpoints-sg' },
1873
+ {
1874
+ Key: 'Name',
1875
+ Value: '${self:service}-${self:provider.stage}-vpc-endpoints-sg',
1876
+ },
1494
1877
  { Key: 'ManagedBy', Value: 'Frigg' },
1495
- { Key: 'Purpose', Value: 'Allow Lambda functions to access VPC endpoints' },
1878
+ {
1879
+ Key: 'Purpose',
1880
+ Value: 'Allow Lambda functions to access VPC endpoints',
1881
+ },
1496
1882
  ],
1497
1883
  },
1498
1884
  };
@@ -1515,7 +1901,8 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1515
1901
  Type: 'AWS::EC2::VPCEndpoint',
1516
1902
  Properties: {
1517
1903
  VpcId: discoveredResources.defaultVpcId,
1518
- ServiceName: 'com.amazonaws.${self:provider.region}.secretsmanager',
1904
+ ServiceName:
1905
+ 'com.amazonaws.${self:provider.region}.secretsmanager',
1519
1906
  VpcEndpointType: 'Interface',
1520
1907
  SubnetIds: vpcConfig.subnetIds,
1521
1908
  SecurityGroupIds: [{ Ref: 'VPCEndpointSecurityGroup' }],
@@ -1538,19 +1925,31 @@ const configureSsm = (definition, AppDefinition) => {
1538
1925
 
1539
1926
  definition.provider.iamRoleStatements.push({
1540
1927
  Effect: 'Allow',
1541
- Action: ['ssm:GetParameter', 'ssm:GetParameters', 'ssm:GetParametersByPath'],
1542
- Resource: ['arn:aws:ssm:${self:provider.region}:*:parameter/${self:service}/${self:provider.stage}/*'],
1928
+ Action: [
1929
+ 'ssm:GetParameter',
1930
+ 'ssm:GetParameters',
1931
+ 'ssm:GetParametersByPath',
1932
+ ],
1933
+ Resource: [
1934
+ 'arn:aws:ssm:${self:provider.region}:*:parameter/${self:service}/${self:provider.stage}/*',
1935
+ ],
1543
1936
  });
1544
1937
 
1545
- definition.provider.environment.SSM_PARAMETER_PREFIX = '/${self:service}/${self:provider.stage}';
1938
+ definition.provider.environment.SSM_PARAMETER_PREFIX =
1939
+ '/${self:service}/${self:provider.stage}';
1546
1940
  };
1547
1941
 
1548
1942
  const attachIntegrations = (definition, AppDefinition) => {
1549
- if (!Array.isArray(AppDefinition.integrations) || AppDefinition.integrations.length === 0) {
1943
+ if (
1944
+ !Array.isArray(AppDefinition.integrations) ||
1945
+ AppDefinition.integrations.length === 0
1946
+ ) {
1550
1947
  return;
1551
1948
  }
1552
1949
 
1553
- console.log(`Processing ${AppDefinition.integrations.length} integrations...`);
1950
+ console.log(
1951
+ `Processing ${AppDefinition.integrations.length} integrations...`
1952
+ );
1554
1953
 
1555
1954
  for (const integration of AppDefinition.integrations) {
1556
1955
  if (!integration?.Definition?.name) {
@@ -1558,7 +1957,9 @@ const attachIntegrations = (definition, AppDefinition) => {
1558
1957
  }
1559
1958
 
1560
1959
  const integrationName = integration.Definition.name;
1561
- const queueReference = `${integrationName.charAt(0).toUpperCase() + integrationName.slice(1)}Queue`;
1960
+ const queueReference = `${
1961
+ integrationName.charAt(0).toUpperCase() + integrationName.slice(1)
1962
+ }Queue`;
1562
1963
  const queueName = `\${self:service}--\${self:provider.stage}-${queueReference}`;
1563
1964
 
1564
1965
  definition.functions[integrationName] = {
@@ -1581,7 +1982,9 @@ const attachIntegrations = (definition, AppDefinition) => {
1581
1982
  VisibilityTimeout: 1800,
1582
1983
  RedrivePolicy: {
1583
1984
  maxReceiveCount: 1,
1584
- deadLetterTargetArn: { 'Fn::GetAtt': ['InternalErrorQueue', 'Arn'] },
1985
+ deadLetterTargetArn: {
1986
+ 'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
1987
+ },
1585
1988
  },
1586
1989
  },
1587
1990
  };
@@ -1603,7 +2006,9 @@ const attachIntegrations = (definition, AppDefinition) => {
1603
2006
 
1604
2007
  definition.provider.environment = {
1605
2008
  ...definition.provider.environment,
1606
- [`${integrationName.toUpperCase()}_QUEUE_URL`]: { Ref: queueReference },
2009
+ [`${integrationName.toUpperCase()}_QUEUE_URL`]: {
2010
+ Ref: queueReference,
2011
+ },
1607
2012
  };
1608
2013
 
1609
2014
  definition.custom[queueReference] = queueName;
@@ -1616,7 +2021,8 @@ const configureWebsockets = (definition, AppDefinition) => {
1616
2021
  }
1617
2022
 
1618
2023
  definition.functions.defaultWebsocket = {
1619
- handler: 'node_modules/@friggframework/core/handlers/routers/websocket.handler',
2024
+ handler:
2025
+ 'node_modules/@friggframework/core/handlers/routers/websocket.handler',
1620
2026
  events: [
1621
2027
  { websocket: { route: '$connect' } },
1622
2028
  { websocket: { route: '$default' } },
@@ -1630,11 +2036,33 @@ const composeServerlessDefinition = async (AppDefinition) => {
1630
2036
 
1631
2037
  const discoveredResources = await gatherDiscoveredResources(AppDefinition);
1632
2038
  const appEnvironmentVars = getAppEnvironmentVars(AppDefinition);
1633
- const definition = createBaseDefinition(AppDefinition, appEnvironmentVars, discoveredResources);
2039
+ const definition = createBaseDefinition(
2040
+ AppDefinition,
2041
+ appEnvironmentVars,
2042
+ discoveredResources
2043
+ );
2044
+
2045
+ // Check if we're in local build mode (AWS discovery was skipped)
2046
+ const isLocalBuild = !shouldRunDiscovery(AppDefinition);
2047
+
2048
+ if (isLocalBuild) {
2049
+ console.log(
2050
+ '🏠 Local build mode detected - skipping AWS-dependent configurations'
2051
+ );
2052
+ }
2053
+
2054
+ // Apply configurations (skip AWS-dependent ones in local build mode)
2055
+ if (!isLocalBuild) {
2056
+ applyKmsConfiguration(definition, AppDefinition, discoveredResources);
2057
+ configureVpc(definition, AppDefinition, discoveredResources);
2058
+ configurePostgres(definition, AppDefinition, discoveredResources);
2059
+ configureSsm(definition, AppDefinition);
2060
+ } else {
2061
+ console.log(
2062
+ ' ⏭️ Skipping: KMS, VPC, PostgreSQL, SSM configurations'
2063
+ );
2064
+ }
1634
2065
 
1635
- applyKmsConfiguration(definition, AppDefinition, discoveredResources);
1636
- configureVpc(definition, AppDefinition, discoveredResources);
1637
- configureSsm(definition, AppDefinition);
1638
2066
  attachIntegrations(definition, AppDefinition);
1639
2067
  configureWebsockets(definition, AppDefinition);
1640
2068