@friggframework/devtools 2.0.0--canary.461.5767fa4.0 → 2.0.0--canary.461.0a68e4c.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.
@@ -288,6 +288,7 @@ class MigrationBuilder extends InfrastructureBuilder {
288
288
  // Note: Serverless will merge this with provider.environment
289
289
  },
290
290
  events: [
291
+ { httpApi: { path: '/db-migrate/status', method: 'GET' } },
291
292
  { httpApi: { path: '/db-migrate', method: 'POST' } },
292
293
  { httpApi: { path: '/db-migrate/{processId}', method: 'GET' } },
293
294
  ],
@@ -164,6 +164,9 @@ describe('MigrationBuilder', () => {
164
164
  'node_modules/@friggframework/core/handlers/routers/db-migration.handler'
165
165
  );
166
166
  expect(result.functions.dbMigrationRouter.timeout).toBe(30);
167
+ expect(result.functions.dbMigrationRouter.events).toContainEqual({
168
+ httpApi: { path: '/db-migrate/status', method: 'GET' },
169
+ });
167
170
  expect(result.functions.dbMigrationRouter.events).toContainEqual({
168
171
  httpApi: { path: '/db-migrate', method: 'POST' },
169
172
  });
@@ -463,8 +463,8 @@ class VpcBuilder extends InfrastructureBuilder {
463
463
 
464
464
  const subnetVpcId = vpcManagement === 'create-new' ? { Ref: 'FriggVPC' } : result.vpcId;
465
465
 
466
- // Generate CIDRs
467
- const cidrs = this.generateSubnetCidrs(vpcManagement);
466
+ // Generate CIDRs - pass discovered resources to avoid conflicts
467
+ const cidrs = this.generateSubnetCidrs(vpcManagement, discoveredResources);
468
468
 
469
469
  // Private Subnet 1
470
470
  result.resources.FriggPrivateSubnet1 = {
@@ -597,8 +597,9 @@ class VpcBuilder extends InfrastructureBuilder {
597
597
 
598
598
  /**
599
599
  * Generate subnet CIDR blocks
600
+ * Finds available CIDRs that don't conflict with existing subnets
600
601
  */
601
- generateSubnetCidrs(vpcManagement) {
602
+ generateSubnetCidrs(vpcManagement, discoveredResources) {
602
603
  if (vpcManagement === 'create-new') {
603
604
  // Use CloudFormation Fn::Cidr for dynamic generation
604
605
  return {
@@ -608,13 +609,47 @@ class VpcBuilder extends InfrastructureBuilder {
608
609
  public2: { 'Fn::Select': [3, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }] },
609
610
  };
610
611
  } else {
611
- // Static CIDRs for existing VPC (default VPC range)
612
- return {
613
- private1: '172.31.240.0/24',
614
- private2: '172.31.241.0/24',
615
- public1: '172.31.250.0/24',
616
- public2: '172.31.251.0/24',
612
+ // Find available CIDRs for existing VPC by checking existing subnets
613
+ const existingCidrs = new Set();
614
+
615
+ // Collect all existing subnet CIDRs
616
+ if (discoveredResources?.subnets) {
617
+ for (const subnet of discoveredResources.subnets) {
618
+ if (subnet.CidrBlock) {
619
+ existingCidrs.add(subnet.CidrBlock);
620
+ }
621
+ }
622
+ }
623
+
624
+ console.log(` Found ${existingCidrs.size} existing subnet CIDRs in VPC`);
625
+
626
+ // Generate candidates in the default VPC range (172.31.0.0/16)
627
+ // Private subnets: 240-249, Public subnets: 250-255
628
+ const findAvailableCidr = (startOctet, endOctet) => {
629
+ for (let octet = startOctet; octet <= endOctet; octet++) {
630
+ const candidate = `172.31.${octet}.0/24`;
631
+ if (!existingCidrs.has(candidate)) {
632
+ existingCidrs.add(candidate); // Mark as used immediately
633
+ return candidate;
634
+ }
635
+ }
636
+ // Fallback if range exhausted
637
+ return `172.31.${startOctet}.0/24`;
617
638
  };
639
+
640
+ const privateRange = { start: 240, end: 249 };
641
+ const publicRange = { start: 250, end: 255 };
642
+
643
+ const cidrs = {
644
+ private1: findAvailableCidr(privateRange.start, privateRange.end),
645
+ private2: findAvailableCidr(privateRange.start, privateRange.end),
646
+ public1: findAvailableCidr(publicRange.start, publicRange.end),
647
+ public2: findAvailableCidr(publicRange.start, publicRange.end),
648
+ };
649
+
650
+ console.log(` Using available CIDRs: ${Object.values(cidrs).join(', ')}`);
651
+
652
+ return cidrs;
618
653
  }
619
654
  }
620
655
 
@@ -983,6 +983,93 @@ describe('VpcBuilder', () => {
983
983
  });
984
984
  });
985
985
 
986
+ describe('generateSubnetCidrs()', () => {
987
+ it('should use CloudFormation Fn::Cidr for create-new mode', () => {
988
+ const cidrs = vpcBuilder.generateSubnetCidrs('create-new', {});
989
+
990
+ expect(cidrs.private1).toEqual({
991
+ 'Fn::Select': [0, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
992
+ });
993
+ expect(cidrs.private2).toEqual({
994
+ 'Fn::Select': [1, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
995
+ });
996
+ expect(cidrs.public1).toEqual({
997
+ 'Fn::Select': [2, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
998
+ });
999
+ expect(cidrs.public2).toEqual({
1000
+ 'Fn::Select': [3, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
1001
+ });
1002
+ });
1003
+
1004
+ it('should use default static CIDRs when no existing subnets in VPC', () => {
1005
+ const discoveredResources = {
1006
+ subnets: []
1007
+ };
1008
+
1009
+ const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
1010
+
1011
+ expect(cidrs.private1).toBe('172.31.240.0/24');
1012
+ expect(cidrs.private2).toBe('172.31.241.0/24');
1013
+ expect(cidrs.public1).toBe('172.31.250.0/24');
1014
+ expect(cidrs.public2).toBe('172.31.251.0/24');
1015
+ });
1016
+
1017
+ it('should avoid CIDR conflicts with existing subnets', () => {
1018
+ const discoveredResources = {
1019
+ subnets: [
1020
+ { CidrBlock: '172.31.240.0/24' }, // Conflicts with default private1
1021
+ { CidrBlock: '172.31.241.0/24' }, // Conflicts with default private2
1022
+ { CidrBlock: '172.31.0.0/20' }, // Default VPC subnet
1023
+ { CidrBlock: '172.31.16.0/20' }, // Default VPC subnet
1024
+ ]
1025
+ };
1026
+
1027
+ const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
1028
+
1029
+ // Should skip 240 and 241 (already taken), use 242-243 for private, 250-251 for public
1030
+ expect(cidrs.private1).toBe('172.31.242.0/24');
1031
+ expect(cidrs.private2).toBe('172.31.243.0/24');
1032
+ expect(cidrs.public1).toBe('172.31.250.0/24'); // Public range starts at 250
1033
+ expect(cidrs.public2).toBe('172.31.251.0/24');
1034
+ });
1035
+
1036
+ it('should find first available CIDR blocks when some in range are taken', () => {
1037
+ const discoveredResources = {
1038
+ subnets: [
1039
+ { CidrBlock: '172.31.240.0/24' },
1040
+ { CidrBlock: '172.31.242.0/24' },
1041
+ { CidrBlock: '172.31.244.0/24' },
1042
+ ]
1043
+ };
1044
+
1045
+ const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
1046
+
1047
+ // Should use 241, 243 for private (filling gaps), 250, 251 for public
1048
+ expect(cidrs.private1).toBe('172.31.241.0/24');
1049
+ expect(cidrs.private2).toBe('172.31.243.0/24');
1050
+ expect(cidrs.public1).toBe('172.31.250.0/24'); // Public range starts at 250
1051
+ expect(cidrs.public2).toBe('172.31.251.0/24');
1052
+ });
1053
+
1054
+ it('should handle missing discoveredResources gracefully', () => {
1055
+ const cidrs = vpcBuilder.generateSubnetCidrs('discover', null);
1056
+
1057
+ // Should fallback to default CIDRs
1058
+ expect(cidrs.private1).toBe('172.31.240.0/24');
1059
+ expect(cidrs.private2).toBe('172.31.241.0/24');
1060
+ });
1061
+
1062
+ it('should handle discoveredResources without subnets array', () => {
1063
+ const discoveredResources = { vpcId: 'vpc-123' };
1064
+
1065
+ const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
1066
+
1067
+ // Should fallback to default CIDRs
1068
+ expect(cidrs.private1).toBe('172.31.240.0/24');
1069
+ expect(cidrs.private2).toBe('172.31.241.0/24');
1070
+ });
1071
+ });
1072
+
986
1073
  describe('Outputs', () => {
987
1074
  it.skip('should generate VPC ID output', async () => {
988
1075
  const appDefinition = {
@@ -94,17 +94,17 @@ async function gatherDiscoveredResources(appDefinition) {
94
94
  // But still discover KMS (encryption keys can be safely shared across stages)
95
95
  if (appDefinition.managementMode === 'managed' && appDefinition.vpcIsolation === 'isolated') {
96
96
  console.log(' ℹ Isolated mode: discovering KMS (shareable) but not VPC/Aurora (isolated)');
97
-
97
+
98
98
  // Still run KMS discovery - encryption keys are safe to share
99
99
  const kmsDiscovery = new KmsDiscovery(provider);
100
100
  const kmsResult = await kmsDiscovery.discover();
101
-
101
+
102
102
  if (kmsResult?.defaultKmsKeyId) {
103
103
  console.log(' ✓ Found shared KMS key (can be reused across stages)');
104
104
  console.log('✅ Cloud resource discovery completed successfully!');
105
105
  return kmsResult;
106
106
  }
107
-
107
+
108
108
  console.log(' ℹ No existing resources found - will create fresh infrastructure');
109
109
  console.log('✅ Cloud resource discovery completed successfully!');
110
110
  return {};
@@ -427,7 +427,7 @@ describe('Resource Discovery', () => {
427
427
  };
428
428
 
429
429
  process.env.SLS_STAGE = 'dev';
430
-
430
+
431
431
  // Mock KMS discovery returning a shared key
432
432
  mockKmsDiscovery.discover.mockResolvedValue({
433
433
  defaultKmsKeyId: 'shared-kms-key-123',
@@ -462,7 +462,7 @@ describe('Resource Discovery', () => {
462
462
  };
463
463
 
464
464
  process.env.SLS_STAGE = 'dev';
465
-
465
+
466
466
  // Mock KMS discovery finding nothing
467
467
  mockKmsDiscovery.discover.mockResolvedValue({});
468
468
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/devtools",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.461.5767fa4.0",
4
+ "version": "2.0.0--canary.461.0a68e4c.0",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-ec2": "^3.835.0",
7
7
  "@aws-sdk/client-kms": "^3.835.0",
@@ -11,8 +11,8 @@
11
11
  "@babel/eslint-parser": "^7.18.9",
12
12
  "@babel/parser": "^7.25.3",
13
13
  "@babel/traverse": "^7.25.3",
14
- "@friggframework/schemas": "2.0.0--canary.461.5767fa4.0",
15
- "@friggframework/test": "2.0.0--canary.461.5767fa4.0",
14
+ "@friggframework/schemas": "2.0.0--canary.461.0a68e4c.0",
15
+ "@friggframework/test": "2.0.0--canary.461.0a68e4c.0",
16
16
  "@hapi/boom": "^10.0.1",
17
17
  "@inquirer/prompts": "^5.3.8",
18
18
  "axios": "^1.7.2",
@@ -34,8 +34,8 @@
34
34
  "serverless-http": "^2.7.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@friggframework/eslint-config": "2.0.0--canary.461.5767fa4.0",
38
- "@friggframework/prettier-config": "2.0.0--canary.461.5767fa4.0",
37
+ "@friggframework/eslint-config": "2.0.0--canary.461.0a68e4c.0",
38
+ "@friggframework/prettier-config": "2.0.0--canary.461.0a68e4c.0",
39
39
  "aws-sdk-client-mock": "^4.1.0",
40
40
  "aws-sdk-client-mock-jest": "^4.1.0",
41
41
  "jest": "^30.1.3",
@@ -70,5 +70,5 @@
70
70
  "publishConfig": {
71
71
  "access": "public"
72
72
  },
73
- "gitHead": "5767fa41c5e27a098d51bf4edff785f87de1d6bf"
73
+ "gitHead": "0a68e4cd99db73582144693112740ff3786d8e93"
74
74
  }