@friggframework/devtools 2.0.0--canary.487.63ed8db.0 → 2.0.0--canary.490.7d57f02.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/infrastructure/domains/shared/cloudformation-discovery.js +122 -4
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +108 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.js +23 -0
- package/infrastructure/domains/shared/resource-discovery.js +17 -5
- package/package.json +7 -7
|
@@ -111,6 +111,74 @@ class CloudFormationDiscovery {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Extract external resource references from stack resource properties
|
|
116
|
+
*
|
|
117
|
+
* When VPC/subnets/NAT are external, they're referenced in routing resources' properties.
|
|
118
|
+
* We query EC2 to get the actual VPC ID, NAT Gateway ID, and subnet IDs from the route table.
|
|
119
|
+
*
|
|
120
|
+
* @private
|
|
121
|
+
* @param {string} stackName - Stack name
|
|
122
|
+
* @param {Array} resources - CloudFormation stack resources
|
|
123
|
+
* @param {Object} discovered - Object to populate with discovered resources
|
|
124
|
+
*/
|
|
125
|
+
async _extractExternalReferencesFromStackResources(stackName, resources, discovered) {
|
|
126
|
+
if (!this.provider || !this.provider.getEC2Client) {
|
|
127
|
+
console.log(' ℹ Skipping external reference extraction (EC2 client not available)');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
// If we found a route table in the stack, query EC2 for its details
|
|
133
|
+
// This gives us VPC ID, NAT Gateway ID, and subnet IDs
|
|
134
|
+
if (discovered.routeTableId) {
|
|
135
|
+
try {
|
|
136
|
+
console.log(` ℹ Querying route table ${discovered.routeTableId} for external references...`);
|
|
137
|
+
const { DescribeRouteTablesCommand } = require('@aws-sdk/client-ec2');
|
|
138
|
+
const ec2 = this.provider.getEC2Client();
|
|
139
|
+
const rtResponse = await ec2.send(new DescribeRouteTablesCommand({
|
|
140
|
+
RouteTableIds: [discovered.routeTableId]
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
if (rtResponse.RouteTables && rtResponse.RouteTables.length > 0) {
|
|
144
|
+
const routeTable = rtResponse.RouteTables[0];
|
|
145
|
+
|
|
146
|
+
// Extract VPC ID
|
|
147
|
+
if (routeTable.VpcId && !discovered.defaultVpcId) {
|
|
148
|
+
discovered.defaultVpcId = routeTable.VpcId;
|
|
149
|
+
console.log(` ✓ Extracted VPC ID from route table: ${routeTable.VpcId}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Extract NAT Gateway ID from routes
|
|
153
|
+
const natRoute = routeTable.Routes?.find(r => r.NatGatewayId);
|
|
154
|
+
if (natRoute && natRoute.NatGatewayId && !discovered.natGatewayId) {
|
|
155
|
+
discovered.natGatewayId = natRoute.NatGatewayId;
|
|
156
|
+
discovered.existingNatGatewayId = natRoute.NatGatewayId;
|
|
157
|
+
console.log(` ✓ Extracted NAT Gateway ID from routes: ${natRoute.NatGatewayId}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Extract subnet IDs from route table associations
|
|
161
|
+
const associations = routeTable.Associations || [];
|
|
162
|
+
const subnetAssociations = associations.filter(a => a.SubnetId);
|
|
163
|
+
|
|
164
|
+
if (subnetAssociations.length >= 1 && !discovered.privateSubnetId1) {
|
|
165
|
+
discovered.privateSubnetId1 = subnetAssociations[0].SubnetId;
|
|
166
|
+
console.log(` ✓ Extracted private subnet 1 from associations: ${subnetAssociations[0].SubnetId}`);
|
|
167
|
+
}
|
|
168
|
+
if (subnetAssociations.length >= 2 && !discovered.privateSubnetId2) {
|
|
169
|
+
discovered.privateSubnetId2 = subnetAssociations[1].SubnetId;
|
|
170
|
+
console.log(` ✓ Extracted private subnet 2 from associations: ${subnetAssociations[1].SubnetId}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.warn(` ⚠️ Could not query route table for external references: ${error.message}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.warn(` ⚠️ Error extracting external references: ${error.message}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
114
182
|
/**
|
|
115
183
|
* Extract discovered resources from CloudFormation stack resources
|
|
116
184
|
*
|
|
@@ -216,6 +284,27 @@ class CloudFormationDiscovery {
|
|
|
216
284
|
discovered.natGatewayId = PhysicalResourceId;
|
|
217
285
|
}
|
|
218
286
|
|
|
287
|
+
// Route Table (Lambda route table for external VPC pattern)
|
|
288
|
+
if (LogicalResourceId === 'FriggLambdaRouteTable' && ResourceType === 'AWS::EC2::RouteTable') {
|
|
289
|
+
discovered.routeTableId = PhysicalResourceId;
|
|
290
|
+
discovered.privateRouteTableId = PhysicalResourceId;
|
|
291
|
+
console.log(` ✓ Found route table in stack: ${PhysicalResourceId}`);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// NAT Route (proves NAT configuration exists)
|
|
295
|
+
if (LogicalResourceId === 'FriggNATRoute' && ResourceType === 'AWS::EC2::Route') {
|
|
296
|
+
discovered.natRoute = PhysicalResourceId;
|
|
297
|
+
console.log(` ✓ Found NAT route in stack`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Route Table Associations (links subnets to route table)
|
|
301
|
+
if (LogicalResourceId.includes('RouteAssociation') && ResourceType === 'AWS::EC2::SubnetRouteTableAssociation') {
|
|
302
|
+
if (!discovered.routeTableAssociations) {
|
|
303
|
+
discovered.routeTableAssociations = [];
|
|
304
|
+
}
|
|
305
|
+
discovered.routeTableAssociations.push(PhysicalResourceId);
|
|
306
|
+
}
|
|
307
|
+
|
|
219
308
|
// VPC - direct extraction (primary method)
|
|
220
309
|
if (LogicalResourceId === 'FriggVPC' && ResourceType === 'AWS::EC2::VPC') {
|
|
221
310
|
discovered.defaultVpcId = PhysicalResourceId;
|
|
@@ -278,24 +367,53 @@ class CloudFormationDiscovery {
|
|
|
278
367
|
discovered.vpcEndpointSecurityGroupId = PhysicalResourceId;
|
|
279
368
|
}
|
|
280
369
|
|
|
281
|
-
// VPC Endpoints
|
|
282
|
-
|
|
370
|
+
// VPC Endpoints - support both old and new naming conventions
|
|
371
|
+
// Initialize vpcEndpoints object for structured access
|
|
372
|
+
if (!discovered.vpcEndpoints) {
|
|
373
|
+
discovered.vpcEndpoints = {};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// S3 Endpoint (both naming patterns)
|
|
377
|
+
if ((LogicalResourceId === 'FriggS3VPCEndpoint' || LogicalResourceId === 'VPCEndpointS3') &&
|
|
378
|
+
ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
283
379
|
discovered.s3VpcEndpointId = PhysicalResourceId;
|
|
380
|
+
discovered.vpcEndpoints.s3 = PhysicalResourceId;
|
|
381
|
+
console.log(` ✓ Found S3 VPC endpoint in stack: ${PhysicalResourceId}`);
|
|
284
382
|
}
|
|
285
|
-
|
|
383
|
+
|
|
384
|
+
// DynamoDB Endpoint (both naming patterns)
|
|
385
|
+
if ((LogicalResourceId === 'FriggDynamoDBVPCEndpoint' || LogicalResourceId === 'VPCEndpointDynamoDB') &&
|
|
386
|
+
ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
286
387
|
discovered.dynamoDbVpcEndpointId = PhysicalResourceId;
|
|
388
|
+
discovered.vpcEndpoints.dynamodb = PhysicalResourceId;
|
|
389
|
+
console.log(` ✓ Found DynamoDB VPC endpoint in stack: ${PhysicalResourceId}`);
|
|
287
390
|
}
|
|
288
|
-
|
|
391
|
+
|
|
392
|
+
// KMS Endpoint (both naming patterns)
|
|
393
|
+
if ((LogicalResourceId === 'FriggKMSVPCEndpoint' || LogicalResourceId === 'VPCEndpointKMS') &&
|
|
394
|
+
ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
289
395
|
discovered.kmsVpcEndpointId = PhysicalResourceId;
|
|
396
|
+
discovered.vpcEndpoints.kms = PhysicalResourceId;
|
|
397
|
+
console.log(` ✓ Found KMS VPC endpoint in stack: ${PhysicalResourceId}`);
|
|
290
398
|
}
|
|
399
|
+
|
|
400
|
+
// Secrets Manager Endpoint
|
|
291
401
|
if (LogicalResourceId === 'FriggSecretsManagerVPCEndpoint' && ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
292
402
|
discovered.secretsManagerVpcEndpointId = PhysicalResourceId;
|
|
403
|
+
discovered.vpcEndpoints.secretsManager = PhysicalResourceId;
|
|
293
404
|
}
|
|
405
|
+
|
|
406
|
+
// SQS Endpoint
|
|
294
407
|
if (LogicalResourceId === 'FriggSQSVPCEndpoint' && ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
295
408
|
discovered.sqsVpcEndpointId = PhysicalResourceId;
|
|
409
|
+
discovered.vpcEndpoints.sqs = PhysicalResourceId;
|
|
296
410
|
}
|
|
297
411
|
}
|
|
298
412
|
|
|
413
|
+
// Extract VPC ID and other external references from routing resource properties
|
|
414
|
+
// This handles the pattern where VPC is external but routing is in the stack
|
|
415
|
+
await this._extractExternalReferencesFromStackResources(stackName, resources, discovered);
|
|
416
|
+
|
|
299
417
|
// If we have a VPC ID but no subnet IDs, query EC2 for Frigg-managed subnets
|
|
300
418
|
if (discovered.defaultVpcId && this.provider &&
|
|
301
419
|
!discovered.privateSubnetId1 && !discovered.publicSubnetId1) {
|
|
@@ -586,5 +586,113 @@ describe('CloudFormationDiscovery', () => {
|
|
|
586
586
|
expect(mockProvider.describeKmsKey).toHaveBeenCalledWith('alias/test-service-dev-frigg-kms');
|
|
587
587
|
});
|
|
588
588
|
});
|
|
589
|
+
|
|
590
|
+
describe('External VPC with routing infrastructure pattern', () => {
|
|
591
|
+
it('should discover routing resources when VPC is external', async () => {
|
|
592
|
+
// This tests the Frontify pattern: external VPC/subnets/KMS,
|
|
593
|
+
// but stack creates routing infrastructure (route table, NAT route, VPC endpoints)
|
|
594
|
+
const mockStack = {
|
|
595
|
+
StackName: 'create-frigg-app-production',
|
|
596
|
+
Outputs: [],
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
const mockResources = [
|
|
600
|
+
{
|
|
601
|
+
LogicalResourceId: 'FriggLambdaRouteTable',
|
|
602
|
+
PhysicalResourceId: 'rtb-0b83aca77ccde20a6',
|
|
603
|
+
ResourceType: 'AWS::EC2::RouteTable',
|
|
604
|
+
ResourceStatus: 'UPDATE_COMPLETE',
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
LogicalResourceId: 'FriggNATRoute',
|
|
608
|
+
PhysicalResourceId: 'rtb-0b83aca77ccde20a6|0.0.0.0/0',
|
|
609
|
+
ResourceType: 'AWS::EC2::Route',
|
|
610
|
+
ResourceStatus: 'UPDATE_COMPLETE',
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
LogicalResourceId: 'FriggSubnet1RouteAssociation',
|
|
614
|
+
PhysicalResourceId: 'rtbassoc-07245da0b447ca469',
|
|
615
|
+
ResourceType: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
616
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
LogicalResourceId: 'FriggSubnet2RouteAssociation',
|
|
620
|
+
PhysicalResourceId: 'rtbassoc-0806f9783c4ea181f',
|
|
621
|
+
ResourceType: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
622
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
LogicalResourceId: 'VPCEndpointS3',
|
|
626
|
+
PhysicalResourceId: 'vpce-0352ceac2124c14be',
|
|
627
|
+
ResourceType: 'AWS::EC2::VPCEndpoint',
|
|
628
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
LogicalResourceId: 'VPCEndpointDynamoDB',
|
|
632
|
+
PhysicalResourceId: 'vpce-0b06c4f631199ea68',
|
|
633
|
+
ResourceType: 'AWS::EC2::VPCEndpoint',
|
|
634
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
635
|
+
},
|
|
636
|
+
];
|
|
637
|
+
|
|
638
|
+
mockProvider.describeStack.mockResolvedValue(mockStack);
|
|
639
|
+
mockProvider.listStackResources.mockResolvedValue(mockResources);
|
|
640
|
+
|
|
641
|
+
const result = await cfDiscovery.discoverFromStack('create-frigg-app-production');
|
|
642
|
+
|
|
643
|
+
// Verify routing infrastructure was discovered
|
|
644
|
+
expect(result.routeTableId).toBe('rtb-0b83aca77ccde20a6');
|
|
645
|
+
expect(result.privateRouteTableId).toBe('rtb-0b83aca77ccde20a6');
|
|
646
|
+
expect(result.natRoute).toBe('rtb-0b83aca77ccde20a6|0.0.0.0/0');
|
|
647
|
+
expect(result.routeTableAssociations).toEqual([
|
|
648
|
+
'rtbassoc-07245da0b447ca469',
|
|
649
|
+
'rtbassoc-0806f9783c4ea181f',
|
|
650
|
+
]);
|
|
651
|
+
|
|
652
|
+
// Verify VPC endpoints were discovered (both naming conventions)
|
|
653
|
+
expect(result.vpcEndpoints).toBeDefined();
|
|
654
|
+
expect(result.vpcEndpoints.s3).toBe('vpce-0352ceac2124c14be');
|
|
655
|
+
expect(result.vpcEndpoints.dynamodb).toBe('vpce-0b06c4f631199ea68');
|
|
656
|
+
expect(result.s3VpcEndpointId).toBe('vpce-0352ceac2124c14be');
|
|
657
|
+
expect(result.dynamoDbVpcEndpointId).toBe('vpce-0b06c4f631199ea68');
|
|
658
|
+
|
|
659
|
+
// Verify NO VPC/KMS resources (they're external)
|
|
660
|
+
expect(result.defaultVpcId).toBeUndefined();
|
|
661
|
+
expect(result.defaultKmsKeyId).toBeUndefined();
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
it('should work with legacy VPC endpoint naming (FriggS3VPCEndpoint)', async () => {
|
|
665
|
+
const mockStack = {
|
|
666
|
+
StackName: 'test-stack',
|
|
667
|
+
Outputs: [],
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
const mockResources = [
|
|
671
|
+
{
|
|
672
|
+
LogicalResourceId: 'FriggS3VPCEndpoint',
|
|
673
|
+
PhysicalResourceId: 'vpce-legacy-s3',
|
|
674
|
+
ResourceType: 'AWS::EC2::VPCEndpoint',
|
|
675
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
LogicalResourceId: 'FriggDynamoDBVPCEndpoint',
|
|
679
|
+
PhysicalResourceId: 'vpce-legacy-ddb',
|
|
680
|
+
ResourceType: 'AWS::EC2::VPCEndpoint',
|
|
681
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
682
|
+
},
|
|
683
|
+
];
|
|
684
|
+
|
|
685
|
+
mockProvider.describeStack.mockResolvedValue(mockStack);
|
|
686
|
+
mockProvider.listStackResources.mockResolvedValue(mockResources);
|
|
687
|
+
|
|
688
|
+
const result = await cfDiscovery.discoverFromStack('test-stack');
|
|
689
|
+
|
|
690
|
+
// Both naming conventions should work
|
|
691
|
+
expect(result.vpcEndpoints.s3).toBe('vpce-legacy-s3');
|
|
692
|
+
expect(result.vpcEndpoints.dynamodb).toBe('vpce-legacy-ddb');
|
|
693
|
+
expect(result.s3VpcEndpointId).toBe('vpce-legacy-s3');
|
|
694
|
+
expect(result.dynamoDbVpcEndpointId).toBe('vpce-legacy-ddb');
|
|
695
|
+
});
|
|
696
|
+
});
|
|
589
697
|
});
|
|
590
698
|
|
|
@@ -536,6 +536,29 @@ class AWSProviderAdapter extends CloudProviderAdapter {
|
|
|
536
536
|
return [];
|
|
537
537
|
}
|
|
538
538
|
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Describe a specific stack resource to get its full details including properties
|
|
542
|
+
* @param {string} stackName - Stack name
|
|
543
|
+
* @param {string} logicalResourceId - Logical resource ID
|
|
544
|
+
* @returns {Promise<Object>} Resource details
|
|
545
|
+
*/
|
|
546
|
+
async describeStackResource(stackName, logicalResourceId) {
|
|
547
|
+
const cf = this.getCloudFormationClient();
|
|
548
|
+
|
|
549
|
+
try {
|
|
550
|
+
const { DescribeStackResourceCommand } = require('@aws-sdk/client-cloudformation');
|
|
551
|
+
const response = await cf.send(new DescribeStackResourceCommand({
|
|
552
|
+
StackName: stackName,
|
|
553
|
+
LogicalResourceId: logicalResourceId,
|
|
554
|
+
}));
|
|
555
|
+
|
|
556
|
+
return response.StackResourceDetail || null;
|
|
557
|
+
} catch (error) {
|
|
558
|
+
console.warn(`Failed to describe stack resource ${logicalResourceId}:`, error.message);
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
539
562
|
}
|
|
540
563
|
|
|
541
564
|
module.exports = {
|
|
@@ -95,11 +95,23 @@ async function gatherDiscoveredResources(appDefinition) {
|
|
|
95
95
|
const cfDiscovery = new CloudFormationDiscovery(provider, { serviceName, stage });
|
|
96
96
|
const stackResources = await cfDiscovery.discoverFromStack(stackName);
|
|
97
97
|
|
|
98
|
-
// Validate CF discovery results -
|
|
99
|
-
const hasVpcData = stackResources?.defaultVpcId;
|
|
100
|
-
const hasKmsData = stackResources?.defaultKmsKeyId;
|
|
101
|
-
const hasAuroraData = stackResources?.auroraClusterId;
|
|
102
|
-
|
|
98
|
+
// Validate CF discovery results - check for ANY useful infrastructure
|
|
99
|
+
const hasVpcData = stackResources?.defaultVpcId; // VPC resource in stack
|
|
100
|
+
const hasKmsData = stackResources?.defaultKmsKeyId; // KMS resource in stack
|
|
101
|
+
const hasAuroraData = stackResources?.auroraClusterId; // Aurora in stack
|
|
102
|
+
|
|
103
|
+
// Check for routing infrastructure (proves VPC config exists even with external VPC)
|
|
104
|
+
const hasRoutingInfra = stackResources?.routeTableId || // FriggLambdaRouteTable
|
|
105
|
+
stackResources?.natRoute || // FriggNATRoute
|
|
106
|
+
stackResources?.vpcEndpoints?.s3 || // VPC endpoints
|
|
107
|
+
stackResources?.vpcEndpoints?.dynamodb;
|
|
108
|
+
|
|
109
|
+
// Stack is useful if it has EITHER actual resources OR routing infrastructure
|
|
110
|
+
const hasSomeUsefulData = hasVpcData || hasKmsData || hasAuroraData || hasRoutingInfra;
|
|
111
|
+
|
|
112
|
+
if (hasRoutingInfra && !hasVpcData) {
|
|
113
|
+
console.log(' ✓ Found VPC routing infrastructure in stack (external VPC pattern)');
|
|
114
|
+
}
|
|
103
115
|
|
|
104
116
|
// Check if we're in isolated mode (each stage gets its own VPC/Aurora)
|
|
105
117
|
const isIsolatedMode = appDefinition.managementMode === 'managed' &&
|
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.
|
|
4
|
+
"version": "2.0.0--canary.490.7d57f02.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"frigg": "./frigg-cli/index.js"
|
|
7
7
|
},
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"@babel/eslint-parser": "^7.18.9",
|
|
17
17
|
"@babel/parser": "^7.25.3",
|
|
18
18
|
"@babel/traverse": "^7.25.3",
|
|
19
|
-
"@friggframework/core": "2.0.0--canary.
|
|
20
|
-
"@friggframework/schemas": "2.0.0--canary.
|
|
21
|
-
"@friggframework/test": "2.0.0--canary.
|
|
19
|
+
"@friggframework/core": "2.0.0--canary.490.7d57f02.0",
|
|
20
|
+
"@friggframework/schemas": "2.0.0--canary.490.7d57f02.0",
|
|
21
|
+
"@friggframework/test": "2.0.0--canary.490.7d57f02.0",
|
|
22
22
|
"@hapi/boom": "^10.0.1",
|
|
23
23
|
"@inquirer/prompts": "^5.3.8",
|
|
24
24
|
"axios": "^1.7.2",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"validate-npm-package-name": "^5.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@friggframework/eslint-config": "2.0.0--canary.
|
|
50
|
-
"@friggframework/prettier-config": "2.0.0--canary.
|
|
49
|
+
"@friggframework/eslint-config": "2.0.0--canary.490.7d57f02.0",
|
|
50
|
+
"@friggframework/prettier-config": "2.0.0--canary.490.7d57f02.0",
|
|
51
51
|
"aws-sdk-client-mock": "^4.1.0",
|
|
52
52
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
53
53
|
"jest": "^30.1.3",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"publishConfig": {
|
|
80
80
|
"access": "public"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "7d57f02625ea51ce9dadd5e1535aac1c4491b9da"
|
|
83
83
|
}
|