@friggframework/devtools 2.0.0--canary.398.53eac55.0 → 2.0.0--canary.397.878fefa.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.
@@ -1,26 +1,7 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs');
3
- const { AWSDiscovery } = require('./aws-discovery');
4
3
 
5
- /**
6
- * Check if AWS discovery should run based on AppDefinition
7
- * @param {Object} AppDefinition - Application definition
8
- * @returns {boolean} True if discovery should run
9
- */
10
- const shouldRunDiscovery = (AppDefinition) => {
11
- return AppDefinition.vpc?.enable === true ||
12
- AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption === true ||
13
- AppDefinition.ssm?.enable === true;
14
- };
15
-
16
- /**
17
- * Find the actual path to node_modules directory
18
- * Tries multiple methods to locate node_modules:
19
- * 1. Traversing up from current directory
20
- * 2. Using npm root command
21
- * 3. Looking for package.json and adjacent node_modules
22
- * @returns {string} Path to node_modules directory
23
- */
4
+ // Function to find the actual path to node_modules
24
5
  const findNodeModulesPath = () => {
25
6
  try {
26
7
  // Method 1: Try to find node_modules by traversing up from current directory
@@ -94,12 +75,7 @@ const findNodeModulesPath = () => {
94
75
  }
95
76
  };
96
77
 
97
- /**
98
- * Modify handler paths to point to the correct node_modules location
99
- * Only modifies paths when running in offline mode
100
- * @param {Object} functions - Serverless functions configuration object
101
- * @returns {Object} Modified functions object with updated handler paths
102
- */
78
+ // Function to modify handler paths to point to the correct node_modules
103
79
  const modifyHandlerPaths = (functions) => {
104
80
  // Check if we're running in offline mode
105
81
  const isOffline = process.argv.includes('offline');
@@ -118,8 +94,7 @@ const modifyHandlerPaths = (functions) => {
118
94
  const functionDef = modifiedFunctions[functionName];
119
95
  if (functionDef?.handler?.includes('node_modules/')) {
120
96
  // Replace node_modules/ with the actual path to node_modules/
121
- const relativePath = path.relative(process.cwd(), nodeModulesPath);
122
- functionDef.handler = functionDef.handler.replace('node_modules/', `${relativePath}/`);
97
+ functionDef.handler = functionDef.handler.replace('node_modules/', '../node_modules/');
123
98
  console.log(`Updated handler for ${functionName}: ${functionDef.handler}`);
124
99
  }
125
100
  }
@@ -127,367 +102,7 @@ const modifyHandlerPaths = (functions) => {
127
102
  return modifiedFunctions;
128
103
  };
129
104
 
130
- /**
131
- * Create VPC infrastructure resources for CloudFormation
132
- * Creates VPC, subnets, NAT gateway, route tables, and security groups
133
- * @param {Object} AppDefinition - Application definition object
134
- * @param {Object} AppDefinition.vpc - VPC configuration
135
- * @param {string} [AppDefinition.vpc.cidrBlock='10.0.0.0/16'] - CIDR block for VPC
136
- * @returns {Object} CloudFormation resources for VPC infrastructure
137
- */
138
- const createVPCInfrastructure = (AppDefinition) => {
139
- const vpcResources = {
140
- // VPC
141
- FriggVPC: {
142
- Type: 'AWS::EC2::VPC',
143
- Properties: {
144
- CidrBlock: AppDefinition.vpc.cidrBlock || '10.0.0.0/16',
145
- EnableDnsHostnames: true,
146
- EnableDnsSupport: true,
147
- Tags: [
148
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-vpc' }
149
- ]
150
- }
151
- },
152
-
153
- // Internet Gateway
154
- FriggInternetGateway: {
155
- Type: 'AWS::EC2::InternetGateway',
156
- Properties: {
157
- Tags: [
158
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-igw' }
159
- ]
160
- }
161
- },
162
-
163
- // Attach Internet Gateway to VPC
164
- FriggVPCGatewayAttachment: {
165
- Type: 'AWS::EC2::VPCGatewayAttachment',
166
- Properties: {
167
- VpcId: { Ref: 'FriggVPC' },
168
- InternetGatewayId: { Ref: 'FriggInternetGateway' }
169
- }
170
- },
171
-
172
- // Public Subnet for NAT Gateway
173
- FriggPublicSubnet: {
174
- Type: 'AWS::EC2::Subnet',
175
- Properties: {
176
- VpcId: { Ref: 'FriggVPC' },
177
- CidrBlock: '10.0.1.0/24',
178
- AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
179
- MapPublicIpOnLaunch: true,
180
- Tags: [
181
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-public-subnet' }
182
- ]
183
- }
184
- },
185
-
186
- // Private Subnet 1 for Lambda
187
- FriggPrivateSubnet1: {
188
- Type: 'AWS::EC2::Subnet',
189
- Properties: {
190
- VpcId: { Ref: 'FriggVPC' },
191
- CidrBlock: '10.0.2.0/24',
192
- AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
193
- Tags: [
194
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-subnet-1' }
195
- ]
196
- }
197
- },
198
-
199
- // Private Subnet 2 for Lambda (different AZ for redundancy)
200
- FriggPrivateSubnet2: {
201
- Type: 'AWS::EC2::Subnet',
202
- Properties: {
203
- VpcId: { Ref: 'FriggVPC' },
204
- CidrBlock: '10.0.3.0/24',
205
- AvailabilityZone: { 'Fn::Select': [1, { 'Fn::GetAZs': '' }] },
206
- Tags: [
207
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-subnet-2' }
208
- ]
209
- }
210
- },
211
-
212
- // Elastic IP for NAT Gateway
213
- FriggNATGatewayEIP: {
214
- Type: 'AWS::EC2::EIP',
215
- Properties: {
216
- Domain: 'vpc',
217
- Tags: [
218
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-eip' }
219
- ]
220
- },
221
- DependsOn: 'FriggVPCGatewayAttachment'
222
- },
223
-
224
- // NAT Gateway for private subnet internet access
225
- FriggNATGateway: {
226
- Type: 'AWS::EC2::NatGateway',
227
- Properties: {
228
- AllocationId: { 'Fn::GetAtt': ['FriggNATGatewayEIP', 'AllocationId'] },
229
- SubnetId: { Ref: 'FriggPublicSubnet' },
230
- Tags: [
231
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-gateway' }
232
- ]
233
- }
234
- },
235
-
236
- // Public Route Table
237
- FriggPublicRouteTable: {
238
- Type: 'AWS::EC2::RouteTable',
239
- Properties: {
240
- VpcId: { Ref: 'FriggVPC' },
241
- Tags: [
242
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-public-rt' }
243
- ]
244
- }
245
- },
246
-
247
- // Public Route to Internet Gateway
248
- FriggPublicRoute: {
249
- Type: 'AWS::EC2::Route',
250
- Properties: {
251
- RouteTableId: { Ref: 'FriggPublicRouteTable' },
252
- DestinationCidrBlock: '0.0.0.0/0',
253
- GatewayId: { Ref: 'FriggInternetGateway' }
254
- },
255
- DependsOn: 'FriggVPCGatewayAttachment'
256
- },
257
-
258
- // Associate Public Subnet with Public Route Table
259
- FriggPublicSubnetRouteTableAssociation: {
260
- Type: 'AWS::EC2::SubnetRouteTableAssociation',
261
- Properties: {
262
- SubnetId: { Ref: 'FriggPublicSubnet' },
263
- RouteTableId: { Ref: 'FriggPublicRouteTable' }
264
- }
265
- },
266
-
267
- // Private Route Table
268
- FriggPrivateRouteTable: {
269
- Type: 'AWS::EC2::RouteTable',
270
- Properties: {
271
- VpcId: { Ref: 'FriggVPC' },
272
- Tags: [
273
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-rt' }
274
- ]
275
- }
276
- },
277
-
278
- // Private Route to NAT Gateway
279
- FriggPrivateRoute: {
280
- Type: 'AWS::EC2::Route',
281
- Properties: {
282
- RouteTableId: { Ref: 'FriggPrivateRouteTable' },
283
- DestinationCidrBlock: '0.0.0.0/0',
284
- NatGatewayId: { Ref: 'FriggNATGateway' }
285
- }
286
- },
287
-
288
- // Associate Private Subnet 1 with Private Route Table
289
- FriggPrivateSubnet1RouteTableAssociation: {
290
- Type: 'AWS::EC2::SubnetRouteTableAssociation',
291
- Properties: {
292
- SubnetId: { Ref: 'FriggPrivateSubnet1' },
293
- RouteTableId: { Ref: 'FriggPrivateRouteTable' }
294
- }
295
- },
296
-
297
- // Associate Private Subnet 2 with Private Route Table
298
- FriggPrivateSubnet2RouteTableAssociation: {
299
- Type: 'AWS::EC2::SubnetRouteTableAssociation',
300
- Properties: {
301
- SubnetId: { Ref: 'FriggPrivateSubnet2' },
302
- RouteTableId: { Ref: 'FriggPrivateRouteTable' }
303
- }
304
- },
305
-
306
- // Security Group for Lambda functions
307
- FriggLambdaSecurityGroup: {
308
- Type: 'AWS::EC2::SecurityGroup',
309
- Properties: {
310
- GroupDescription: 'Security group for Frigg Lambda functions',
311
- VpcId: { Ref: 'FriggVPC' },
312
- SecurityGroupEgress: [
313
- {
314
- IpProtocol: 'tcp',
315
- FromPort: 443,
316
- ToPort: 443,
317
- CidrIp: '0.0.0.0/0',
318
- Description: 'HTTPS outbound'
319
- },
320
- {
321
- IpProtocol: 'tcp',
322
- FromPort: 80,
323
- ToPort: 80,
324
- CidrIp: '0.0.0.0/0',
325
- Description: 'HTTP outbound'
326
- },
327
- {
328
- IpProtocol: 'tcp',
329
- FromPort: 53,
330
- ToPort: 53,
331
- CidrIp: '0.0.0.0/0',
332
- Description: 'DNS TCP'
333
- },
334
- {
335
- IpProtocol: 'udp',
336
- FromPort: 53,
337
- ToPort: 53,
338
- CidrIp: '0.0.0.0/0',
339
- Description: 'DNS UDP'
340
- }
341
- ],
342
- Tags: [
343
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-lambda-sg' }
344
- ]
345
- }
346
- }
347
- };
348
-
349
- // Add VPC Endpoints for cost optimization
350
- if (AppDefinition.vpc.enableVPCEndpoints !== false) {
351
- // S3 Gateway Endpoint (free)
352
- vpcResources.FriggS3VPCEndpoint = {
353
- Type: 'AWS::EC2::VPCEndpoint',
354
- Properties: {
355
- VpcId: { Ref: 'FriggVPC' },
356
- ServiceName: 'com.amazonaws.${self:provider.region}.s3',
357
- VpcEndpointType: 'Gateway',
358
- RouteTableIds: [
359
- { Ref: 'FriggPrivateRouteTable' }
360
- ]
361
- }
362
- };
363
-
364
- // DynamoDB Gateway Endpoint (free)
365
- vpcResources.FriggDynamoDBVPCEndpoint = {
366
- Type: 'AWS::EC2::VPCEndpoint',
367
- Properties: {
368
- VpcId: { Ref: 'FriggVPC' },
369
- ServiceName: 'com.amazonaws.${self:provider.region}.dynamodb',
370
- VpcEndpointType: 'Gateway',
371
- RouteTableIds: [
372
- { Ref: 'FriggPrivateRouteTable' }
373
- ]
374
- }
375
- };
376
-
377
- // KMS Interface Endpoint (paid, but useful if using KMS)
378
- if (AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption === true) {
379
- vpcResources.FriggKMSVPCEndpoint = {
380
- Type: 'AWS::EC2::VPCEndpoint',
381
- Properties: {
382
- VpcId: { Ref: 'FriggVPC' },
383
- ServiceName: 'com.amazonaws.${self:provider.region}.kms',
384
- VpcEndpointType: 'Interface',
385
- SubnetIds: [
386
- { Ref: 'FriggPrivateSubnet1' },
387
- { Ref: 'FriggPrivateSubnet2' }
388
- ],
389
- SecurityGroupIds: [
390
- { Ref: 'FriggVPCEndpointSecurityGroup' }
391
- ],
392
- PrivateDnsEnabled: true
393
- }
394
- };
395
- }
396
-
397
- // Secrets Manager Interface Endpoint (paid, but useful for secrets)
398
- vpcResources.FriggSecretsManagerVPCEndpoint = {
399
- Type: 'AWS::EC2::VPCEndpoint',
400
- Properties: {
401
- VpcId: { Ref: 'FriggVPC' },
402
- ServiceName: 'com.amazonaws.${self:provider.region}.secretsmanager',
403
- VpcEndpointType: 'Interface',
404
- SubnetIds: [
405
- { Ref: 'FriggPrivateSubnet1' },
406
- { Ref: 'FriggPrivateSubnet2' }
407
- ],
408
- SecurityGroupIds: [
409
- { Ref: 'FriggVPCEndpointSecurityGroup' }
410
- ],
411
- PrivateDnsEnabled: true
412
- }
413
- };
414
-
415
- // Security Group for VPC Endpoints
416
- vpcResources.FriggVPCEndpointSecurityGroup = {
417
- Type: 'AWS::EC2::SecurityGroup',
418
- Properties: {
419
- GroupDescription: 'Security group for Frigg VPC Endpoints',
420
- VpcId: { Ref: 'FriggVPC' },
421
- SecurityGroupIngress: [
422
- {
423
- IpProtocol: 'tcp',
424
- FromPort: 443,
425
- ToPort: 443,
426
- SourceSecurityGroupId: { Ref: 'FriggLambdaSecurityGroup' },
427
- Description: 'HTTPS from Lambda'
428
- }
429
- ],
430
- Tags: [
431
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-vpc-endpoint-sg' }
432
- ]
433
- }
434
- };
435
- }
436
-
437
- return vpcResources;
438
- };
439
-
440
- /**
441
- * Compose a complete serverless framework configuration from app definition
442
- * @param {Object} AppDefinition - Application definition object
443
- * @param {string} [AppDefinition.name] - Application name
444
- * @param {string} [AppDefinition.provider='aws'] - Cloud provider
445
- * @param {Array} AppDefinition.integrations - Array of integration definitions
446
- * @param {Object} [AppDefinition.vpc] - VPC configuration
447
- * @param {Object} [AppDefinition.encryption] - KMS encryption configuration
448
- * @param {Object} [AppDefinition.ssm] - SSM parameter store configuration
449
- * @param {Object} [AppDefinition.websockets] - WebSocket configuration
450
- * @param {boolean} [AppDefinition.websockets.enable=false] - Enable WebSocket support for live update streaming
451
- * @returns {Object} Complete serverless framework configuration
452
- */
453
- const composeServerlessDefinition = async (AppDefinition) => {
454
- // Store discovered resources
455
- let discoveredResources = {};
456
-
457
- // Run AWS discovery if needed
458
- if (shouldRunDiscovery(AppDefinition)) {
459
- console.log('🔍 Running AWS resource discovery for serverless template...');
460
- try {
461
- const region = process.env.AWS_REGION || 'us-east-1';
462
- const discovery = new AWSDiscovery(region);
463
-
464
- const config = {
465
- vpc: AppDefinition.vpc || {},
466
- encryption: AppDefinition.encryption || {},
467
- ssm: AppDefinition.ssm || {}
468
- };
469
-
470
- discoveredResources = await discovery.discoverResources(config);
471
-
472
- console.log('✅ AWS discovery completed successfully!');
473
- if (discoveredResources.defaultVpcId) {
474
- console.log(` VPC: ${discoveredResources.defaultVpcId}`);
475
- }
476
- if (discoveredResources.privateSubnetId1 && discoveredResources.privateSubnetId2) {
477
- console.log(` Subnets: ${discoveredResources.privateSubnetId1}, ${discoveredResources.privateSubnetId2}`);
478
- }
479
- if (discoveredResources.defaultSecurityGroupId) {
480
- console.log(` Security Group: ${discoveredResources.defaultSecurityGroupId}`);
481
- }
482
- if (discoveredResources.defaultKmsKeyId) {
483
- console.log(` KMS Key: ${discoveredResources.defaultKmsKeyId}`);
484
- }
485
- } catch (error) {
486
- console.error('❌ AWS discovery failed:', error.message);
487
- throw new Error(`AWS discovery failed: ${error.message}`);
488
- }
489
- }
490
-
105
+ const composeServerlessDefinition = (AppDefinition) => {
491
106
  const definition = {
492
107
  frameworkVersion: '>=3.17.0',
493
108
  service: AppDefinition.name || 'create-frigg-app',
@@ -505,14 +120,6 @@ const composeServerlessDefinition = async (AppDefinition) => {
505
120
  environment: {
506
121
  STAGE: '${opt:stage}',
507
122
  AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1,
508
- // Add discovered resources to environment if available
509
- ...(discoveredResources.defaultVpcId && { AWS_DISCOVERY_VPC_ID: discoveredResources.defaultVpcId }),
510
- ...(discoveredResources.defaultSecurityGroupId && { AWS_DISCOVERY_SECURITY_GROUP_ID: discoveredResources.defaultSecurityGroupId }),
511
- ...(discoveredResources.privateSubnetId1 && { AWS_DISCOVERY_SUBNET_ID_1: discoveredResources.privateSubnetId1 }),
512
- ...(discoveredResources.privateSubnetId2 && { AWS_DISCOVERY_SUBNET_ID_2: discoveredResources.privateSubnetId2 }),
513
- ...(discoveredResources.publicSubnetId && { AWS_DISCOVERY_PUBLIC_SUBNET_ID: discoveredResources.publicSubnetId }),
514
- ...(discoveredResources.defaultRouteTableId && { AWS_DISCOVERY_ROUTE_TABLE_ID: discoveredResources.defaultRouteTableId }),
515
- ...(discoveredResources.defaultKmsKeyId && { AWS_DISCOVERY_KMS_KEY_ID: discoveredResources.defaultKmsKeyId }),
516
123
  },
517
124
  iamRoleStatements: [
518
125
  {
@@ -573,6 +180,26 @@ const composeServerlessDefinition = async (AppDefinition) => {
573
180
  },
574
181
  },
575
182
  functions: {
183
+ defaultWebsocket: {
184
+ handler: 'node_modules/@friggframework/core/handlers/routers/websocket.handler',
185
+ events: [
186
+ {
187
+ websocket: {
188
+ route: '$connect',
189
+ },
190
+ },
191
+ {
192
+ websocket: {
193
+ route: '$default',
194
+ },
195
+ },
196
+ {
197
+ websocket: {
198
+ route: '$disconnect',
199
+ },
200
+ },
201
+ ],
202
+ },
576
203
  auth: {
577
204
  handler: 'node_modules/@friggframework/core/handlers/routers/auth.handler',
578
205
  events: [
@@ -618,7 +245,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
618
245
  Type: 'AWS::SQS::Queue',
619
246
  Properties: {
620
247
  QueueName:
621
- '${self:service}-internal-error-queue-${self:provider.stage}',
248
+ 'internal-error-queue-${self:provider.stage}',
622
249
  MessageRetentionPeriod: 300,
623
250
  },
624
251
  },
@@ -702,7 +329,6 @@ const composeServerlessDefinition = async (AppDefinition) => {
702
329
  },
703
330
  };
704
331
 
705
-
706
332
  // KMS Configuration based on App Definition
707
333
  if (AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption === true) {
708
334
  // Add KMS IAM permissions
@@ -721,183 +347,12 @@ const composeServerlessDefinition = async (AppDefinition) => {
721
347
  // Add serverless-kms-grants plugin
722
348
  definition.plugins.push('serverless-kms-grants');
723
349
 
724
- // Configure KMS grants with discovered default key
350
+ // Configure KMS grants with default key
725
351
  definition.custom.kmsGrants = {
726
- kmsKeyId: discoveredResources.defaultKmsKeyId || '${env:AWS_DISCOVERY_KMS_KEY_ID}'
352
+ kmsKeyId: '*'
727
353
  };
728
354
  }
729
355
 
730
- // VPC Configuration based on App Definition
731
- if (AppDefinition.vpc?.enable === true) {
732
- // Add VPC-related IAM permissions
733
- definition.provider.iamRoleStatements.push({
734
- Effect: 'Allow',
735
- Action: [
736
- 'ec2:CreateNetworkInterface',
737
- 'ec2:DescribeNetworkInterfaces',
738
- 'ec2:DeleteNetworkInterface',
739
- 'ec2:AttachNetworkInterface',
740
- 'ec2:DetachNetworkInterface'
741
- ],
742
- Resource: '*'
743
- });
744
-
745
- // Default approach: Use AWS Discovery to find existing VPC resources
746
- if (AppDefinition.vpc.createNew === true) {
747
- // Option 1: Create new VPC infrastructure (explicit opt-in)
748
- const vpcConfig = {};
749
-
750
- if (AppDefinition.vpc.securityGroupIds) {
751
- // User provided custom security groups
752
- vpcConfig.securityGroupIds = AppDefinition.vpc.securityGroupIds;
753
- } else {
754
- // Use auto-created security group
755
- vpcConfig.securityGroupIds = [{ Ref: 'FriggLambdaSecurityGroup' }];
756
- }
757
-
758
- if (AppDefinition.vpc.subnetIds) {
759
- // User provided custom subnets
760
- vpcConfig.subnetIds = AppDefinition.vpc.subnetIds;
761
- } else {
762
- // Use auto-created private subnets
763
- vpcConfig.subnetIds = [
764
- { Ref: 'FriggPrivateSubnet1' },
765
- { Ref: 'FriggPrivateSubnet2' }
766
- ];
767
- }
768
-
769
- // Set VPC config for Lambda functions
770
- definition.provider.vpc = vpcConfig;
771
-
772
- // Add VPC infrastructure resources to CloudFormation
773
- const vpcResources = createVPCInfrastructure(AppDefinition);
774
- Object.assign(definition.resources.Resources, vpcResources);
775
- } else {
776
- // Option 2: Use AWS Discovery (default behavior)
777
- // VPC configuration using discovered or explicitly provided resources
778
- const vpcConfig = {
779
- securityGroupIds: AppDefinition.vpc.securityGroupIds ||
780
- (discoveredResources.defaultSecurityGroupId ? [discoveredResources.defaultSecurityGroupId] : []),
781
- subnetIds: AppDefinition.vpc.subnetIds ||
782
- (discoveredResources.privateSubnetId1 && discoveredResources.privateSubnetId2 ?
783
- [discoveredResources.privateSubnetId1, discoveredResources.privateSubnetId2] :
784
- [])
785
- };
786
-
787
- // Set VPC config for Lambda functions only if we have valid subnet IDs
788
- if (vpcConfig.subnetIds.length >= 2 && vpcConfig.securityGroupIds.length > 0) {
789
- definition.provider.vpc = vpcConfig;
790
-
791
- // Always create NAT Gateway for Lambda internet access
792
- // Default VPCs don't have NAT gateways, so we need to create them
793
- definition.resources.Resources.FriggNATGatewayEIP = {
794
- Type: 'AWS::EC2::EIP',
795
- Properties: {
796
- Domain: 'vpc',
797
- Tags: [
798
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-eip' }
799
- ]
800
- }
801
- };
802
-
803
- definition.resources.Resources.FriggNATGateway = {
804
- Type: 'AWS::EC2::NatGateway',
805
- Properties: {
806
- AllocationId: { 'Fn::GetAtt': ['FriggNATGatewayEIP', 'AllocationId'] },
807
- SubnetId: discoveredResources.publicSubnetId || discoveredResources.privateSubnetId1, // Use first discovered subnet if no public subnet found
808
- Tags: [
809
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-gateway' }
810
- ]
811
- }
812
- };
813
-
814
- // Create route table for Lambda subnets to use NAT Gateway
815
- definition.resources.Resources.FriggLambdaRouteTable = {
816
- Type: 'AWS::EC2::RouteTable',
817
- Properties: {
818
- VpcId: discoveredResources.defaultVpcId || { Ref: 'FriggVPC' },
819
- Tags: [
820
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-lambda-rt' }
821
- ]
822
- }
823
- };
824
-
825
- definition.resources.Resources.FriggNATRoute = {
826
- Type: 'AWS::EC2::Route',
827
- Properties: {
828
- RouteTableId: { Ref: 'FriggLambdaRouteTable' },
829
- DestinationCidrBlock: '0.0.0.0/0',
830
- NatGatewayId: { Ref: 'FriggNATGateway' }
831
- }
832
- };
833
-
834
- // Associate Lambda subnets with NAT Gateway route table
835
- definition.resources.Resources.FriggSubnet1RouteAssociation = {
836
- Type: 'AWS::EC2::SubnetRouteTableAssociation',
837
- Properties: {
838
- SubnetId: vpcConfig.subnetIds[0],
839
- RouteTableId: { Ref: 'FriggLambdaRouteTable' }
840
- }
841
- };
842
-
843
- definition.resources.Resources.FriggSubnet2RouteAssociation = {
844
- Type: 'AWS::EC2::SubnetRouteTableAssociation',
845
- Properties: {
846
- SubnetId: vpcConfig.subnetIds[1],
847
- RouteTableId: { Ref: 'FriggLambdaRouteTable' }
848
- }
849
- };
850
-
851
- // Add VPC endpoints for AWS service optimization (optional but recommended)
852
- if (AppDefinition.vpc.enableVPCEndpoints !== false) {
853
- definition.resources.Resources.VPCEndpointS3 = {
854
- Type: 'AWS::EC2::VPCEndpoint',
855
- Properties: {
856
- VpcId: discoveredResources.defaultVpcId,
857
- ServiceName: 'com.amazonaws.${self:provider.region}.s3',
858
- VpcEndpointType: 'Gateway',
859
- RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
860
- }
861
- };
862
-
863
- definition.resources.Resources.VPCEndpointDynamoDB = {
864
- Type: 'AWS::EC2::VPCEndpoint',
865
- Properties: {
866
- VpcId: discoveredResources.defaultVpcId,
867
- ServiceName: 'com.amazonaws.${self:provider.region}.dynamodb',
868
- VpcEndpointType: 'Gateway',
869
- RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
870
- }
871
- };
872
- }
873
- }
874
- }
875
- }
876
-
877
- // SSM Parameter Store Configuration based on App Definition
878
- if (AppDefinition.ssm?.enable === true) {
879
- // Add AWS Parameters and Secrets Lambda Extension layer
880
- definition.provider.layers = [
881
- 'arn:aws:lambda:${self:provider.region}:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11'
882
- ];
883
-
884
- // Add SSM IAM permissions
885
- definition.provider.iamRoleStatements.push({
886
- Effect: 'Allow',
887
- Action: [
888
- 'ssm:GetParameter',
889
- 'ssm:GetParameters',
890
- 'ssm:GetParametersByPath'
891
- ],
892
- Resource: [
893
- 'arn:aws:ssm:${self:provider.region}:*:parameter/${self:service}/${self:provider.stage}/*'
894
- ]
895
- });
896
-
897
- // Add environment variable for SSM parameter prefix
898
- definition.provider.environment.SSM_PARAMETER_PREFIX = '/${self:service}/${self:provider.stage}';
899
- }
900
-
901
356
  // Add integration-specific functions and resources
902
357
  for (const integration of AppDefinition.integrations) {
903
358
  const integrationName = integration.Definition.name;
@@ -964,33 +419,6 @@ const composeServerlessDefinition = async (AppDefinition) => {
964
419
  definition.custom[queueReference] = queueName;
965
420
  }
966
421
 
967
- // Discovery has already run successfully at this point if needed
968
- // The discoveredResources object contains all the necessary AWS resources
969
-
970
- // Add websocket function if enabled
971
- if (AppDefinition.websockets?.enable === true) {
972
- definition.functions.defaultWebsocket = {
973
- handler: 'node_modules/@friggframework/core/handlers/routers/websocket.handler',
974
- events: [
975
- {
976
- websocket: {
977
- route: '$connect',
978
- },
979
- },
980
- {
981
- websocket: {
982
- route: '$default',
983
- },
984
- },
985
- {
986
- websocket: {
987
- route: '$disconnect',
988
- },
989
- },
990
- ],
991
- };
992
- }
993
-
994
422
  // Modify handler paths to point to the correct node_modules location
995
423
  definition.functions = modifyHandlerPaths(definition.functions);
996
424