@friggframework/devtools 2.0.0--canary.490.6e556a4.0 → 2.0.0--canary.490.df708d7.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.
@@ -300,9 +300,23 @@ class VpcResourceResolver extends BaseResourceResolver {
300
300
  const encryptionMethod = appDefinition.encryption?.fieldLevelEncryptionMethod;
301
301
  const needsKms = encryptionMethod === 'kms';
302
302
 
303
+ // DynamoDB endpoint only needed if using DynamoDB (not MongoDB or PostgreSQL)
304
+ // Currently framework only supports MongoDB (via Prisma) and PostgreSQL (via Aurora)
305
+ // DynamoDB support is not implemented, so endpoint is not needed
306
+ const usesDynamoDB = appDefinition.database?.dynamodb?.enable === true;
307
+
308
+ // Special case: If DynamoDB endpoint exists in stack but not needed, preserve it
309
+ // to avoid deletion (user may have enabled it previously)
310
+ const dynamoDbInStack = this.isInStack('FriggDynamoDBVPCEndpoint', discovery);
311
+ const shouldPreserveDynamoDB = !usesDynamoDB && dynamoDbInStack;
312
+
303
313
  const endpoints = {
304
314
  s3: this._resolveEndpoint('FriggS3VPCEndpoint', 's3', userIntent, appDefinition, discovery),
305
- dynamodb: this._resolveEndpoint('FriggDynamoDBVPCEndpoint', 'dynamodb', userIntent, appDefinition, discovery),
315
+ dynamodb: usesDynamoDB
316
+ ? this._resolveEndpoint('FriggDynamoDBVPCEndpoint', 'dynamodb', userIntent, appDefinition, discovery)
317
+ : shouldPreserveDynamoDB
318
+ ? this._resolveEndpoint('FriggDynamoDBVPCEndpoint', 'dynamodb', userIntent, appDefinition, discovery)
319
+ : { ownership: null, reason: 'DynamoDB endpoint not needed (application uses MongoDB/PostgreSQL, not DynamoDB)' },
306
320
  kms: needsKms
307
321
  ? this._resolveEndpoint('FriggKMSVPCEndpoint', 'kms', userIntent, appDefinition, discovery)
308
322
  : { ownership: null, reason: 'KMS endpoint not needed (encryption method is not KMS)' },
@@ -340,13 +354,27 @@ class VpcResourceResolver extends BaseResourceResolver {
340
354
  );
341
355
  }
342
356
 
343
- // Auto-decide
344
- return this.resolveResourceOwnership(
357
+ // Auto-decide - check if in stack first for more informative logging
358
+ const inStack = this.isInStack(logicalId, discovery);
359
+ const stackResource = inStack ? this.findInStack(logicalId, discovery) : null;
360
+
361
+ const decision = this.resolveResourceOwnership(
345
362
  'auto',
346
363
  logicalId,
347
364
  'AWS::EC2::VPCEndpoint',
348
365
  discovery
349
366
  );
367
+
368
+ // Override reason with more detailed explanation
369
+ if (decision.ownership === 'stack' && decision.physicalId) {
370
+ decision.reason = `Found in CloudFormation stack (must keep in template to avoid deletion)`;
371
+ } else if (decision.ownership === 'stack' && !decision.physicalId) {
372
+ decision.reason = `No existing ${endpointType} endpoint found - will create in stack`;
373
+ } else if (decision.ownership === 'external') {
374
+ decision.reason = `Found external ${endpointType} endpoint via discovery`;
375
+ }
376
+
377
+ return decision;
350
378
  }
351
379
 
352
380
  /**
@@ -300,6 +300,82 @@ describe('VpcResourceResolver', () => {
300
300
  });
301
301
 
302
302
  describe('resolveVpcEndpoints', () => {
303
+ it('should skip DynamoDB endpoint when application uses MongoDB', () => {
304
+ const appDefinition = {
305
+ vpc: { ownership: { vpcEndpoints: 'auto' } },
306
+ database: { mongoDB: { enable: true } }, // Using MongoDB, not DynamoDB
307
+ encryption: { fieldLevelEncryptionMethod: 'kms' }
308
+ };
309
+ const discovery = {
310
+ stackManaged: [],
311
+ external: [],
312
+ fromCloudFormation: false
313
+ };
314
+
315
+ const decisions = resolver.resolveVpcEndpoints(appDefinition, discovery);
316
+
317
+ expect(decisions.s3.ownership).toBe('stack'); // S3 always needed
318
+ expect(decisions.dynamodb.ownership).toBeNull(); // DynamoDB NOT needed
319
+ expect(decisions.dynamodb.reason).toContain('MongoDB/PostgreSQL');
320
+ expect(decisions.kms.ownership).toBe('stack'); // KMS needed (encryption enabled)
321
+ expect(decisions.secretsManager.ownership).toBe('stack'); // SM always needed
322
+ expect(decisions.sqs.ownership).toBe('stack'); // SQS always needed
323
+ });
324
+
325
+ it('should skip DynamoDB endpoint when application uses PostgreSQL', () => {
326
+ const appDefinition = {
327
+ vpc: { ownership: { vpcEndpoints: 'auto' } },
328
+ database: { postgres: { enable: true } }, // Using PostgreSQL, not DynamoDB
329
+ };
330
+ const discovery = {
331
+ stackManaged: [],
332
+ external: [],
333
+ fromCloudFormation: false
334
+ };
335
+
336
+ const decisions = resolver.resolveVpcEndpoints(appDefinition, discovery);
337
+
338
+ expect(decisions.dynamodb.ownership).toBeNull();
339
+ expect(decisions.dynamodb.reason).toContain('MongoDB/PostgreSQL');
340
+ });
341
+
342
+ it('should create DynamoDB endpoint when explicitly enabled', () => {
343
+ const appDefinition = {
344
+ vpc: { ownership: { vpcEndpoints: 'auto' } },
345
+ database: { dynamodb: { enable: true } }, // Explicitly using DynamoDB
346
+ };
347
+ const discovery = {
348
+ stackManaged: [],
349
+ external: [],
350
+ fromCloudFormation: false
351
+ };
352
+
353
+ const decisions = resolver.resolveVpcEndpoints(appDefinition, discovery);
354
+
355
+ expect(decisions.dynamodb.ownership).toBe('stack'); // DynamoDB needed
356
+ });
357
+
358
+ it('should preserve DynamoDB endpoint if exists in stack even when not needed', () => {
359
+ const appDefinition = {
360
+ vpc: { ownership: { vpcEndpoints: 'auto' } },
361
+ database: { mongoDB: { enable: true } }, // Using MongoDB (DynamoDB not needed)
362
+ };
363
+ const discovery = {
364
+ stackManaged: [
365
+ { logicalId: 'FriggDynamoDBVPCEndpoint', physicalId: 'vpce-ddb-legacy', resourceType: 'AWS::EC2::VPCEndpoint' }
366
+ ],
367
+ external: [],
368
+ fromCloudFormation: true
369
+ };
370
+
371
+ const decisions = resolver.resolveVpcEndpoints(appDefinition, discovery);
372
+
373
+ // Should preserve (not delete) even though not actively needed
374
+ expect(decisions.dynamodb.ownership).toBe('stack');
375
+ expect(decisions.dynamodb.physicalId).toBe('vpce-ddb-legacy');
376
+ });
377
+
378
+
303
379
  it('should return null decisions when endpoints disabled', () => {
304
380
  const appDefinition = {
305
381
  vpc: {
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.490.6e556a4.0",
4
+ "version": "2.0.0--canary.490.df708d7.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.490.6e556a4.0",
20
- "@friggframework/schemas": "2.0.0--canary.490.6e556a4.0",
21
- "@friggframework/test": "2.0.0--canary.490.6e556a4.0",
19
+ "@friggframework/core": "2.0.0--canary.490.df708d7.0",
20
+ "@friggframework/schemas": "2.0.0--canary.490.df708d7.0",
21
+ "@friggframework/test": "2.0.0--canary.490.df708d7.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.490.6e556a4.0",
50
- "@friggframework/prettier-config": "2.0.0--canary.490.6e556a4.0",
49
+ "@friggframework/eslint-config": "2.0.0--canary.490.df708d7.0",
50
+ "@friggframework/prettier-config": "2.0.0--canary.490.df708d7.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": "6e556a4ddd243fe9163916341b1d70c31dd86ca0"
82
+ "gitHead": "df708d7b3a84f180a3edc5267375f9210e6a585a"
83
83
  }