@friggframework/devtools 2.0.0--canary.428.4968614.0 → 2.0.0--canary.428.2b9210c.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.
@@ -670,7 +670,7 @@ const createVPCInfrastructure = (AppDefinition) => {
670
670
  vpcResources.FriggVPCEndpointSecurityGroup = {
671
671
  Type: 'AWS::EC2::SecurityGroup',
672
672
  Properties: {
673
- GroupDescription: 'Security group for Frigg VPC Endpoints',
673
+ GroupDescription: 'Security group for Frigg VPC Endpoints - allows HTTPS from Lambda functions',
674
674
  VpcId: { Ref: 'FriggVPC' },
675
675
  SecurityGroupIngress: [
676
676
  {
@@ -680,7 +680,15 @@ const createVPCInfrastructure = (AppDefinition) => {
680
680
  SourceSecurityGroupId: {
681
681
  Ref: 'FriggLambdaSecurityGroup',
682
682
  },
683
- Description: 'HTTPS from Lambda',
683
+ Description: 'HTTPS from Lambda security group',
684
+ },
685
+ {
686
+ // Also allow from VPC CIDR as fallback
687
+ IpProtocol: 'tcp',
688
+ FromPort: 443,
689
+ ToPort: 443,
690
+ CidrIp: AppDefinition.vpc.cidrBlock || '10.0.0.0/16',
691
+ Description: 'HTTPS from VPC CIDR (fallback)',
684
692
  },
685
693
  ],
686
694
  Tags: [
@@ -704,6 +712,10 @@ const createVPCInfrastructure = (AppDefinition) => {
704
712
  Key: 'Type',
705
713
  Value: 'VPCEndpoint',
706
714
  },
715
+ {
716
+ Key: 'Purpose',
717
+ Value: 'Allow Lambda functions to access VPC endpoints',
718
+ },
707
719
  ],
708
720
  },
709
721
  };
@@ -1668,6 +1680,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
1668
1680
  if (!useExistingEip) {
1669
1681
  definition.resources.Resources.FriggNATGatewayEIP = {
1670
1682
  Type: 'AWS::EC2::EIP',
1683
+ DeletionPolicy: 'Retain', // Prevent accidental deletion
1684
+ UpdateReplacePolicy: 'Retain', // Prevent replacement during updates
1671
1685
  Properties: {
1672
1686
  Domain: 'vpc',
1673
1687
  Tags: [
@@ -1796,6 +1810,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
1796
1810
  // Create NAT Gateway only if not reusing existing one
1797
1811
  definition.resources.Resources.FriggNATGateway = {
1798
1812
  Type: 'AWS::EC2::NatGateway',
1813
+ DeletionPolicy: 'Retain', // Prevent accidental deletion
1814
+ UpdateReplacePolicy: 'Retain', // Prevent replacement during updates
1799
1815
  Properties: {
1800
1816
  AllocationId: useExistingEip ?
1801
1817
  discoveredResources.existingElasticIpAllocationId :
@@ -1892,11 +1908,15 @@ const composeServerlessDefinition = async (AppDefinition) => {
1892
1908
  }
1893
1909
  }
1894
1910
 
1895
- // Always add route table and routes (referencing the NAT, whether new or existing)
1896
- // IMPORTANT: Create a new route table to ensure clean routing configuration
1897
- // This avoids issues with stale routes pointing to deleted NAT Gateways
1911
+ // ALWAYS create the route table resource in CloudFormation for consistency
1912
+ // Use DeletionPolicy: Retain to prevent deletion when removed from template
1913
+ // This ensures CloudFormation maintains consistent state management
1914
+ console.log('Setting up route table for Lambda subnets');
1915
+
1898
1916
  definition.resources.Resources.FriggLambdaRouteTable = {
1899
1917
  Type: 'AWS::EC2::RouteTable',
1918
+ DeletionPolicy: 'Retain', // Critical: Prevents deletion when resource is removed
1919
+ UpdateReplacePolicy: 'Retain', // Prevents replacement during stack updates
1900
1920
  Properties: {
1901
1921
  VpcId: discoveredResources.defaultVpcId || {
1902
1922
  Ref: 'FriggVPC',
@@ -1910,10 +1930,21 @@ const composeServerlessDefinition = async (AppDefinition) => {
1910
1930
  Key: 'ManagedBy',
1911
1931
  Value: 'Frigg',
1912
1932
  },
1933
+ {
1934
+ Key: 'Environment',
1935
+ Value: '${self:provider.stage}',
1936
+ },
1937
+ {
1938
+ Key: 'Service',
1939
+ Value: '${self:service}',
1940
+ },
1913
1941
  ],
1914
1942
  },
1915
1943
  };
1916
1944
 
1945
+ // Always use CloudFormation reference for consistency
1946
+ const routeTableId = { Ref: 'FriggLambdaRouteTable' };
1947
+
1917
1948
  // Determine which NAT Gateway ID to use for routing
1918
1949
  let natGatewayIdForRoute;
1919
1950
 
@@ -1944,13 +1975,15 @@ const composeServerlessDefinition = async (AppDefinition) => {
1944
1975
  );
1945
1976
  }
1946
1977
 
1947
- // Only create NAT route if we have a NAT Gateway
1978
+ // ALWAYS create/update NAT route if we have a NAT Gateway
1979
+ // This ensures routes are always correct even if NAT Gateway changes
1948
1980
  if (natGatewayIdForRoute) {
1949
- console.log(`Creating NAT route: 0.0.0.0/0 → ${natGatewayIdForRoute}`);
1981
+ console.log(`Configuring NAT route: 0.0.0.0/0 → ${natGatewayIdForRoute}`);
1950
1982
  definition.resources.Resources.FriggNATRoute = {
1951
1983
  Type: 'AWS::EC2::Route',
1984
+ DependsOn: 'FriggLambdaRouteTable',
1952
1985
  Properties: {
1953
- RouteTableId: { Ref: 'FriggLambdaRouteTable' },
1986
+ RouteTableId: routeTableId,
1954
1987
  DestinationCidrBlock: '0.0.0.0/0',
1955
1988
  NatGatewayId: natGatewayIdForRoute,
1956
1989
  },
@@ -1967,13 +2000,15 @@ const composeServerlessDefinition = async (AppDefinition) => {
1967
2000
  // CloudFormation will automatically disassociate from old route table first
1968
2001
  }
1969
2002
 
2003
+ // ALWAYS create subnet associations to ensure correct routing
2004
+ // CloudFormation will handle existing associations gracefully
1970
2005
  // Only create associations for discovered subnets (not for Refs)
1971
2006
  if (typeof vpcConfig.subnetIds[0] === 'string') {
1972
2007
  definition.resources.Resources.FriggSubnet1RouteAssociation = {
1973
2008
  Type: 'AWS::EC2::SubnetRouteTableAssociation',
1974
2009
  Properties: {
1975
2010
  SubnetId: vpcConfig.subnetIds[0],
1976
- RouteTableId: { Ref: 'FriggLambdaRouteTable' },
2011
+ RouteTableId: routeTableId,
1977
2012
  },
1978
2013
  DependsOn: 'FriggLambdaRouteTable',
1979
2014
  };
@@ -1984,7 +2019,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
1984
2019
  Type: 'AWS::EC2::SubnetRouteTableAssociation',
1985
2020
  Properties: {
1986
2021
  SubnetId: vpcConfig.subnetIds[1],
1987
- RouteTableId: { Ref: 'FriggLambdaRouteTable' },
2022
+ RouteTableId: routeTableId,
1988
2023
  },
1989
2024
  DependsOn: 'FriggLambdaRouteTable',
1990
2025
  };
@@ -1996,7 +2031,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
1996
2031
  Type: 'AWS::EC2::SubnetRouteTableAssociation',
1997
2032
  Properties: {
1998
2033
  SubnetId: vpcConfig.subnetIds[0],
1999
- RouteTableId: { Ref: 'FriggLambdaRouteTable' },
2034
+ RouteTableId: routeTableId,
2000
2035
  },
2001
2036
  DependsOn: ['FriggLambdaRouteTable', vpcConfig.subnetIds[0].Ref],
2002
2037
  };
@@ -2007,13 +2042,14 @@ const composeServerlessDefinition = async (AppDefinition) => {
2007
2042
  Type: 'AWS::EC2::SubnetRouteTableAssociation',
2008
2043
  Properties: {
2009
2044
  SubnetId: vpcConfig.subnetIds[1],
2010
- RouteTableId: { Ref: 'FriggLambdaRouteTable' },
2045
+ RouteTableId: routeTableId,
2011
2046
  },
2012
2047
  DependsOn: ['FriggLambdaRouteTable', vpcConfig.subnetIds[1].Ref],
2013
2048
  };
2014
2049
  }
2015
2050
 
2016
- // Add VPC endpoints for AWS service optimization (optional but recommended)
2051
+ // Add VPC endpoints for AWS service optimization
2052
+ // ALWAYS create these to ensure Lambda functions have optimized access to AWS services
2017
2053
  if (AppDefinition.vpc.enableVPCEndpoints !== false) {
2018
2054
  definition.resources.Resources.VPCEndpointS3 = {
2019
2055
  Type: 'AWS::EC2::VPCEndpoint',
@@ -2022,7 +2058,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
2022
2058
  ServiceName:
2023
2059
  'com.amazonaws.${self:provider.region}.s3',
2024
2060
  VpcEndpointType: 'Gateway',
2025
- RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }],
2061
+ RouteTableIds: [routeTableId],
2026
2062
  },
2027
2063
  };
2028
2064
 
@@ -2033,15 +2069,15 @@ const composeServerlessDefinition = async (AppDefinition) => {
2033
2069
  ServiceName:
2034
2070
  'com.amazonaws.${self:provider.region}.dynamodb',
2035
2071
  VpcEndpointType: 'Gateway',
2036
- RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }],
2072
+ RouteTableIds: [routeTableId],
2037
2073
  },
2038
2074
  };
2075
+ }
2039
2076
 
2040
- // Add KMS VPC endpoint if using KMS encryption
2041
- if (
2042
- AppDefinition.encryption?.fieldLevelEncryptionMethod ===
2043
- 'kms'
2044
- ) {
2077
+ // Add KMS VPC endpoint if using KMS encryption
2078
+ if (
2079
+ AppDefinition.encryption?.fieldLevelEncryptionMethod === 'kms'
2080
+ ) {
2045
2081
  // Validate we have VPC CIDR for security group configuration
2046
2082
  if (!discoveredResources.vpcCidr) {
2047
2083
  console.warn(
@@ -2054,28 +2090,80 @@ const composeServerlessDefinition = async (AppDefinition) => {
2054
2090
  !definition.resources.Resources
2055
2091
  .VPCEndpointSecurityGroup
2056
2092
  ) {
2093
+ // Build ingress rules based on what we have
2094
+ const vpcEndpointIngressRules = [];
2095
+
2096
+ // CRITICAL: Allow from Lambda's security group (preferred method)
2097
+ if (vpcConfig.securityGroupIds && vpcConfig.securityGroupIds.length > 0) {
2098
+ // If we have the Lambda security group, reference it directly
2099
+ const lambdaSgId = vpcConfig.securityGroupIds[0];
2100
+ if (typeof lambdaSgId === 'string') {
2101
+ // It's a discovered security group ID
2102
+ vpcEndpointIngressRules.push({
2103
+ IpProtocol: 'tcp',
2104
+ FromPort: 443,
2105
+ ToPort: 443,
2106
+ SourceSecurityGroupId: lambdaSgId,
2107
+ Description: 'HTTPS from Lambda security group',
2108
+ });
2109
+ } else if (lambdaSgId && lambdaSgId.Ref) {
2110
+ // It's a CloudFormation reference
2111
+ vpcEndpointIngressRules.push({
2112
+ IpProtocol: 'tcp',
2113
+ FromPort: 443,
2114
+ ToPort: 443,
2115
+ SourceSecurityGroupId: lambdaSgId,
2116
+ Description: 'HTTPS from Lambda security group',
2117
+ });
2118
+ }
2119
+ }
2120
+
2121
+ // Fallback: If we don't have Lambda SG, use VPC CIDR
2122
+ if (vpcEndpointIngressRules.length === 0 && discoveredResources.vpcCidr) {
2123
+ vpcEndpointIngressRules.push({
2124
+ IpProtocol: 'tcp',
2125
+ FromPort: 443,
2126
+ ToPort: 443,
2127
+ CidrIp: discoveredResources.vpcCidr,
2128
+ Description: 'HTTPS from VPC CIDR (fallback)',
2129
+ });
2130
+ }
2131
+
2132
+ // Last resort: Allow from common private IP ranges
2133
+ if (vpcEndpointIngressRules.length === 0) {
2134
+ console.warn(
2135
+ '⚠️ WARNING: No Lambda security group or VPC CIDR found. Using default private IP ranges.'
2136
+ );
2137
+ vpcEndpointIngressRules.push({
2138
+ IpProtocol: 'tcp',
2139
+ FromPort: 443,
2140
+ ToPort: 443,
2141
+ CidrIp: '172.31.0.0/16', // Default VPC CIDR
2142
+ Description: 'HTTPS from default VPC range',
2143
+ });
2144
+ }
2145
+
2057
2146
  definition.resources.Resources.VPCEndpointSecurityGroup =
2058
2147
  {
2059
2148
  Type: 'AWS::EC2::SecurityGroup',
2060
2149
  Properties: {
2061
2150
  GroupDescription:
2062
- 'Security group for VPC endpoints',
2151
+ 'Security group for VPC endpoints - allows HTTPS from Lambda functions',
2063
2152
  VpcId: discoveredResources.defaultVpcId,
2064
- SecurityGroupIngress: discoveredResources.vpcCidr
2065
- ? [
2066
- {
2067
- IpProtocol: 'tcp',
2068
- FromPort: 443,
2069
- ToPort: 443,
2070
- CidrIp: discoveredResources.vpcCidr, // Use discovered VPC CIDR
2071
- },
2072
- ]
2073
- : [], // Empty array if no VPC CIDR discovered
2153
+ SecurityGroupIngress: vpcEndpointIngressRules,
2074
2154
  Tags: [
2075
2155
  {
2076
2156
  Key: 'Name',
2077
2157
  Value: '${self:service}-${self:provider.stage}-vpc-endpoints-sg',
2078
2158
  },
2159
+ {
2160
+ Key: 'ManagedBy',
2161
+ Value: 'Frigg',
2162
+ },
2163
+ {
2164
+ Key: 'Purpose',
2165
+ Value: 'Allow Lambda functions to access VPC endpoints',
2166
+ },
2079
2167
  ],
2080
2168
  },
2081
2169
  };
@@ -2117,7 +2205,6 @@ const composeServerlessDefinition = async (AppDefinition) => {
2117
2205
  }
2118
2206
  }
2119
2207
  }
2120
- }
2121
2208
 
2122
2209
  // SSM Parameter Store Configuration based on App Definition
2123
2210
  if (AppDefinition.ssm?.enable === true) {
@@ -1,30 +1,43 @@
1
1
  const { composeServerlessDefinition } = require('./serverless-template');
2
2
 
3
+ // Helper to build discovery responses with overridable fields
4
+ const createDiscoveryResponse = (overrides = {}) => ({
5
+ defaultVpcId: 'vpc-123456',
6
+ vpcCidr: '172.31.0.0/16', // Provide VPC CIDR so security group fallbacks can be tested
7
+ defaultSecurityGroupId: 'sg-123456',
8
+ privateSubnetId1: 'subnet-123456',
9
+ privateSubnetId2: 'subnet-789012',
10
+ publicSubnetId: 'subnet-public',
11
+ defaultRouteTableId: 'rtb-123456',
12
+ defaultKmsKeyId:
13
+ 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012',
14
+ existingNatGatewayId: 'nat-default123',
15
+ ...overrides,
16
+ });
17
+
3
18
  // Mock AWS Discovery to prevent actual AWS calls
4
19
  jest.mock('./aws-discovery', () => {
5
20
  return {
6
- AWSDiscovery: jest.fn().mockImplementation(() => {
7
- return {
8
- discoverResources: jest.fn().mockResolvedValue({
9
- defaultVpcId: 'vpc-123456',
10
- vpcCidr: '172.31.0.0/16', // Add VPC CIDR for security group configuration
11
- defaultSecurityGroupId: 'sg-123456',
12
- privateSubnetId1: 'subnet-123456',
13
- privateSubnetId2: 'subnet-789012',
14
- publicSubnetId: 'subnet-public',
15
- defaultRouteTableId: 'rtb-123456',
16
- defaultKmsKeyId: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012',
17
- existingNatGatewayId: 'nat-default123' // Add default NAT Gateway for discover mode
18
- })
19
- };
20
- })
21
+ AWSDiscovery: jest.fn().mockImplementation(() => ({
22
+ discoverResources: jest
23
+ .fn()
24
+ .mockResolvedValue(createDiscoveryResponse()),
25
+ })),
21
26
  };
22
27
  });
23
28
 
29
+ const { AWSDiscovery } = require('./aws-discovery');
30
+
24
31
  describe('composeServerlessDefinition', () => {
25
32
  let mockIntegration;
26
33
 
27
34
  beforeEach(() => {
35
+ AWSDiscovery.mockImplementation(() => ({
36
+ discoverResources: jest
37
+ .fn()
38
+ .mockResolvedValue(createDiscoveryResponse()),
39
+ }));
40
+
28
41
  mockIntegration = {
29
42
  Definition: {
30
43
  name: 'testIntegration'
@@ -344,6 +357,137 @@ describe('composeServerlessDefinition', () => {
344
357
  expect(result.resources.Resources.VPCEndpointS3.Properties.VpcId).toBe('vpc-123456');
345
358
  });
346
359
 
360
+ it('should allow Lambda security group access for VPC endpoints when security group is discovered', async () => {
361
+ const appDefinition = {
362
+ vpc: {
363
+ enable: true,
364
+ management: 'discover'
365
+ },
366
+ encryption: { fieldLevelEncryptionMethod: 'kms' },
367
+ integrations: []
368
+ };
369
+
370
+ const result = await composeServerlessDefinition(appDefinition);
371
+ const endpointSg = result.resources.Resources.VPCEndpointSecurityGroup;
372
+
373
+ expect(endpointSg).toBeDefined();
374
+ expect(endpointSg.Properties.SecurityGroupIngress).toEqual([
375
+ {
376
+ IpProtocol: 'tcp',
377
+ FromPort: 443,
378
+ ToPort: 443,
379
+ SourceSecurityGroupId: 'sg-123456',
380
+ Description: 'HTTPS from Lambda security group'
381
+ }
382
+ ]);
383
+ });
384
+
385
+ it('should fall back to VPC CIDR when Lambda security group identifier cannot be resolved', async () => {
386
+ AWSDiscovery.mockImplementation(() => ({
387
+ discoverResources: jest
388
+ .fn()
389
+ .mockResolvedValue(createDiscoveryResponse()),
390
+ }));
391
+
392
+ const appDefinition = {
393
+ vpc: {
394
+ enable: true,
395
+ management: 'discover',
396
+ securityGroupIds: [
397
+ {
398
+ 'Fn::ImportValue': 'shared-lambda-security-group',
399
+ },
400
+ ],
401
+ },
402
+ encryption: { fieldLevelEncryptionMethod: 'kms' },
403
+ integrations: [],
404
+ };
405
+
406
+ const result = await composeServerlessDefinition(appDefinition);
407
+ const endpointSg = result.resources.Resources.VPCEndpointSecurityGroup;
408
+
409
+ expect(endpointSg).toBeDefined();
410
+ expect(endpointSg.Properties.SecurityGroupIngress).toEqual([
411
+ {
412
+ IpProtocol: 'tcp',
413
+ FromPort: 443,
414
+ ToPort: 443,
415
+ CidrIp: '172.31.0.0/16',
416
+ Description: 'HTTPS from VPC CIDR (fallback)',
417
+ },
418
+ ]);
419
+ });
420
+
421
+ it('should fall back to default private ranges when neither Lambda security group nor VPC CIDR is available', async () => {
422
+ AWSDiscovery.mockImplementation(() => ({
423
+ discoverResources: jest
424
+ .fn()
425
+ .mockResolvedValue(
426
+ createDiscoveryResponse({ vpcCidr: null })
427
+ ),
428
+ }));
429
+
430
+ const appDefinition = {
431
+ vpc: {
432
+ enable: true,
433
+ management: 'discover',
434
+ securityGroupIds: [
435
+ {
436
+ 'Fn::ImportValue': 'shared-lambda-security-group',
437
+ },
438
+ ],
439
+ },
440
+ encryption: { fieldLevelEncryptionMethod: 'kms' },
441
+ integrations: [],
442
+ };
443
+
444
+ const result = await composeServerlessDefinition(appDefinition);
445
+ const endpointSg = result.resources.Resources.VPCEndpointSecurityGroup;
446
+
447
+ expect(endpointSg).toBeDefined();
448
+ expect(endpointSg.Properties.SecurityGroupIngress).toEqual([
449
+ {
450
+ IpProtocol: 'tcp',
451
+ FromPort: 443,
452
+ ToPort: 443,
453
+ CidrIp: '172.31.0.0/16',
454
+ Description: 'HTTPS from default VPC range',
455
+ },
456
+ ]);
457
+ });
458
+
459
+ it('should reference the Lambda security group when creating a new VPC', async () => {
460
+ const appDefinition = {
461
+ vpc: {
462
+ enable: true,
463
+ management: 'create-new'
464
+ },
465
+ encryption: { fieldLevelEncryptionMethod: 'kms' },
466
+ integrations: []
467
+ };
468
+
469
+ const result = await composeServerlessDefinition(appDefinition);
470
+ const endpointSg = result.resources.Resources.FriggVPCEndpointSecurityGroup;
471
+
472
+ expect(endpointSg).toBeDefined();
473
+ expect(endpointSg.Properties.SecurityGroupIngress).toEqual([
474
+ {
475
+ IpProtocol: 'tcp',
476
+ FromPort: 443,
477
+ ToPort: 443,
478
+ SourceSecurityGroupId: { Ref: 'FriggLambdaSecurityGroup' },
479
+ Description: 'HTTPS from Lambda security group'
480
+ },
481
+ {
482
+ IpProtocol: 'tcp',
483
+ FromPort: 443,
484
+ ToPort: 443,
485
+ CidrIp: '10.0.0.0/16',
486
+ Description: 'HTTPS from VPC CIDR (fallback)'
487
+ }
488
+ ]);
489
+ });
490
+
347
491
  it('should not add VPC configuration when vpc.enable is false', async () => {
348
492
  const appDefinition = {
349
493
  vpc: { enable: false },
@@ -1326,4 +1470,4 @@ describe('composeServerlessDefinition', () => {
1326
1470
  await expect(composeServerlessDefinition(appDefinition)).rejects.toThrow('Invalid integration: missing Definition or name');
1327
1471
  });
1328
1472
  });
1329
- });
1473
+ });
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.428.4968614.0",
4
+ "version": "2.0.0--canary.428.2b9210c.0",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-ec2": "^3.835.0",
7
7
  "@aws-sdk/client-kms": "^3.835.0",
@@ -9,8 +9,8 @@
9
9
  "@babel/eslint-parser": "^7.18.9",
10
10
  "@babel/parser": "^7.25.3",
11
11
  "@babel/traverse": "^7.25.3",
12
- "@friggframework/schemas": "2.0.0--canary.428.4968614.0",
13
- "@friggframework/test": "2.0.0--canary.428.4968614.0",
12
+ "@friggframework/schemas": "2.0.0--canary.428.2b9210c.0",
13
+ "@friggframework/test": "2.0.0--canary.428.2b9210c.0",
14
14
  "@hapi/boom": "^10.0.1",
15
15
  "@inquirer/prompts": "^5.3.8",
16
16
  "axios": "^1.7.2",
@@ -32,8 +32,8 @@
32
32
  "serverless-http": "^2.7.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@friggframework/eslint-config": "2.0.0--canary.428.4968614.0",
36
- "@friggframework/prettier-config": "2.0.0--canary.428.4968614.0",
35
+ "@friggframework/eslint-config": "2.0.0--canary.428.2b9210c.0",
36
+ "@friggframework/prettier-config": "2.0.0--canary.428.2b9210c.0",
37
37
  "aws-sdk-client-mock": "^4.1.0",
38
38
  "aws-sdk-client-mock-jest": "^4.1.0",
39
39
  "jest": "^30.1.3",
@@ -68,5 +68,5 @@
68
68
  "publishConfig": {
69
69
  "access": "public"
70
70
  },
71
- "gitHead": "49686143bbd8303507c1824ef167465d1efeaa1e"
71
+ "gitHead": "2b9210c7401ddd6baacac247aff11e3f73fcb315"
72
72
  }