@friggframework/devtools 2.0.0--canary.454.e2a280d.0 → 2.0.0--canary.458.c150d9a.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,7 +1,6 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs');
3
3
  const { AWSDiscovery } = require('./aws-discovery');
4
- const { buildPrismaLayer } = require('./scripts/build-prisma-layer');
5
4
 
6
5
  const shouldRunDiscovery = (AppDefinition) => {
7
6
  console.log('⚙️ Checking FRIGG_SKIP_AWS_DISCOVERY:', process.env.FRIGG_SKIP_AWS_DISCOVERY);
@@ -13,8 +12,7 @@ const shouldRunDiscovery = (AppDefinition) => {
13
12
  return (
14
13
  AppDefinition.vpc?.enable === true ||
15
14
  AppDefinition.encryption?.fieldLevelEncryptionMethod === 'kms' ||
16
- AppDefinition.ssm?.enable === true ||
17
- AppDefinition.database?.postgres?.enable === true
15
+ AppDefinition.ssm?.enable === true
18
16
  );
19
17
  };
20
18
 
@@ -437,17 +435,10 @@ const gatherDiscoveredResources = async (AppDefinition) => {
437
435
  try {
438
436
  const region = process.env.AWS_REGION || 'us-east-1';
439
437
  const discovery = new AWSDiscovery(region);
440
- // Use Serverless Framework's stage resolution (opt:stage with 'dev' as default)
441
- // This matches how serverless.yml resolves ${opt:stage, "dev"}
442
- // IMPORTANT: Use SLS_STAGE (not STAGE) to match actual deployment stage
443
- const stage = process.env.SLS_STAGE || 'dev';
444
-
445
438
  const config = {
446
439
  vpc: AppDefinition.vpc || {},
447
440
  encryption: AppDefinition.encryption || {},
448
441
  ssm: AppDefinition.ssm || {},
449
- serviceName: AppDefinition.name || 'create-frigg-app',
450
- stage: stage,
451
442
  };
452
443
 
453
444
  const discoveredResources = await discovery.discoverResources(config);
@@ -498,22 +489,6 @@ const buildEnvironment = (appEnvironmentVars, discoveredResources) => {
498
489
  }
499
490
  }
500
491
 
501
- // Add Aurora discovery mappings
502
- if (discoveredResources.aurora) {
503
- if (discoveredResources.aurora.clusterIdentifier) {
504
- environment.AWS_DISCOVERY_AURORA_CLUSTER_ID = discoveredResources.aurora.clusterIdentifier;
505
- }
506
- if (discoveredResources.aurora.endpoint) {
507
- environment.AWS_DISCOVERY_AURORA_ENDPOINT = discoveredResources.aurora.endpoint;
508
- }
509
- if (discoveredResources.aurora.port) {
510
- environment.AWS_DISCOVERY_AURORA_PORT = discoveredResources.aurora.port.toString();
511
- }
512
- if (discoveredResources.aurora.secretArn) {
513
- environment.AWS_DISCOVERY_AURORA_SECRET_ARN = discoveredResources.aurora.secretArn;
514
- }
515
- }
516
-
517
492
  return environment;
518
493
  };
519
494
 
@@ -525,49 +500,11 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
525
500
  service: AppDefinition.name || 'create-frigg-app',
526
501
  package: {
527
502
  individually: true,
528
- patterns: [
529
- // AWS SDK exclusions (already in Lambda runtime)
530
- '!**/node_modules/aws-sdk/**',
531
- '!**/node_modules/@aws-sdk/**',
532
-
533
- // Prisma exclusions (provided via Lambda Layer)
534
- '!**/node_modules/@prisma/**',
535
- '!**/node_modules/.prisma/**',
536
- '!**/node_modules/@prisma-mongodb/**',
537
- '!**/node_modules/@prisma-postgresql/**',
538
- '!**/node_modules/prisma/**',
539
-
540
- // Exclude Prisma generated clients from @friggframework/core
541
- // These are 81MB and provided via Lambda Layer instead
542
- '!**/node_modules/@friggframework/core/generated/**',
543
-
544
- // Exclude development and test files
545
- '!**/test/**',
546
- '!**/tests/**',
547
- '!**/*.test.js',
548
- '!**/*.spec.js',
549
- '!**/*.map',
550
- '!**/jest.config.js',
551
- '!**/jest.unit.config.js',
552
- '!**/.eslintrc.json',
553
- '!**/.prettierrc',
554
- '!**/.prettierignore',
555
- '!**/.markdownlintignore',
556
- '!**/docker-compose.yml',
557
- '!**/package.json',
558
- '!**/README.md',
559
- '!**/*.md',
560
-
561
- // Exclude .DS_Store and other OS files
562
- '!**/.DS_Store',
563
- '!**/.git/**',
564
- '!**/.claude-flow/**',
565
- ],
503
+ exclude: ['!**/node_modules/aws-sdk/**', '!**/node_modules/@aws-sdk/**', '!package.json'],
566
504
  },
567
505
  useDotenv: true,
568
506
  provider: {
569
507
  name: AppDefinition.provider || 'aws',
570
- ...(process.env.AWS_PROFILE && { profile: process.env.AWS_PROFILE }),
571
508
  runtime: 'nodejs20.x',
572
509
  timeout: 30,
573
510
  region,
@@ -606,8 +543,7 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
606
543
  },
607
544
  },
608
545
  plugins: [
609
- // Temporarily disabled Jetpack - it ignores package.patterns in dependency mode
610
- // 'serverless-jetpack',
546
+ 'serverless-jetpack',
611
547
  'serverless-dotenv-plugin',
612
548
  'serverless-offline-sqs',
613
549
  'serverless-offline',
@@ -628,15 +564,13 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
628
564
  secretAccessKey: 'root',
629
565
  skipCacheInvalidation: false,
630
566
  },
631
- // Jetpack config removed - testing with standard Serverless packaging
632
- // jetpack: {
633
- // base: '..',
634
- // },
567
+ jetpack: {
568
+ base: '..',
569
+ },
635
570
  },
636
571
  functions: {
637
572
  auth: {
638
573
  handler: 'node_modules/@friggframework/core/handlers/routers/auth.handler',
639
- layers: [{ Ref: 'PrismaLambdaLayer' }],
640
574
  events: [
641
575
  { httpApi: { path: '/api/integrations', method: 'ANY' } },
642
576
  { httpApi: { path: '/api/integrations/{proxy+}', method: 'ANY' } },
@@ -645,56 +579,15 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
645
579
  },
646
580
  user: {
647
581
  handler: 'node_modules/@friggframework/core/handlers/routers/user.handler',
648
- layers: [{ Ref: 'PrismaLambdaLayer' }],
649
582
  events: [{ httpApi: { path: '/user/{proxy+}', method: 'ANY' } }],
650
583
  },
651
584
  health: {
652
585
  handler: 'node_modules/@friggframework/core/handlers/routers/health.handler',
653
- layers: [{ Ref: 'PrismaLambdaLayer' }],
654
586
  events: [
655
587
  { httpApi: { path: '/health', method: 'GET' } },
656
588
  { httpApi: { path: '/health/{proxy+}', method: 'GET' } },
657
589
  ],
658
590
  },
659
- dbMigrate: {
660
- handler: 'node_modules/@friggframework/core/handlers/workers/db-migration.handler',
661
- layers: [{ Ref: 'PrismaLambdaLayer' }],
662
- timeout: 300, // 5 minutes for long-running migrations
663
- memorySize: 512, // Extra memory for Prisma CLI operations
664
- reservedConcurrency: 1, // Prevent concurrent migrations
665
- description: 'Runs database migrations via Prisma (invoke manually from CI/CD)',
666
- // No events - this function is invoked manually via AWS CLI
667
- maximumEventAge: 60, // Don't retry old migration requests (60 seconds)
668
- maximumRetryAttempts: 0, // Don't auto-retry failed migrations
669
- tags: {
670
- Purpose: 'DatabaseMigration',
671
- ManagedBy: 'Frigg',
672
- },
673
- // Environment variables for non-interactive Prisma CLI operation
674
- environment: {
675
- CI: '1', // Forces Prisma to non-interactive mode
676
- PRISMA_HIDE_UPDATE_MESSAGE: '1', // Suppress update messages
677
- PRISMA_MIGRATE_SKIP_SEED: '1', // Skip seeding during migrations
678
- },
679
- // Function-specific packaging: Include Prisma schemas (CLI from layer)
680
- package: {
681
- patterns: [
682
- // Include Prisma schemas from @friggframework/core
683
- // Note: Prisma CLI and clients come from Lambda Layer
684
- 'node_modules/@friggframework/core/prisma-mongodb/**',
685
- 'node_modules/@friggframework/core/prisma-postgresql/**',
686
- ],
687
- },
688
- },
689
- },
690
- layers: {
691
- prisma: {
692
- path: 'layers/prisma',
693
- name: '${self:service}-prisma-${sls:stage}',
694
- description: 'Prisma ORM clients for MongoDB and PostgreSQL with rhel-openssl-3.0.x binaries. Reduces function sizes by ~60% (120MB → 45MB). See LAMBDA-LAYER-PRISMA.md for details.',
695
- compatibleRuntimes: ['nodejs18.x', 'nodejs20.x'],
696
- retain: false, // Don't retain old layer versions
697
- },
698
591
  },
699
592
  resources: {
700
593
  Resources: {
@@ -773,21 +666,14 @@ const applyKmsConfiguration = (definition, AppDefinition, discoveredResources) =
773
666
 
774
667
  if (discoveredResources.defaultKmsKeyId) {
775
668
  console.log(`Using existing KMS key: ${discoveredResources.defaultKmsKeyId}`);
776
-
777
- // Only create alias if it doesn't already exist
778
- if (!discoveredResources.kmsAliasExists) {
779
- console.log('Creating KMS alias for discovered key...');
780
- definition.resources.Resources.FriggKMSKeyAlias = {
781
- Type: 'AWS::KMS::Alias',
782
- DeletionPolicy: 'Retain',
783
- Properties: {
784
- AliasName: 'alias/${self:service}-${self:provider.stage}-frigg-kms',
785
- TargetKeyId: discoveredResources.defaultKmsKeyId,
786
- },
787
- };
788
- } else {
789
- console.log('KMS alias already exists, skipping alias creation');
790
- }
669
+ definition.resources.Resources.FriggKMSKeyAlias = {
670
+ Type: 'AWS::KMS::Alias',
671
+ DeletionPolicy: 'Retain',
672
+ Properties: {
673
+ AliasName: 'alias/${self:service}-${self:provider.stage}-frigg-kms',
674
+ TargetKeyId: discoveredResources.defaultKmsKeyId,
675
+ },
676
+ };
791
677
 
792
678
  definition.provider.iamRoleStatements.push({
793
679
  Effect: 'Allow',
@@ -798,7 +684,7 @@ const applyKmsConfiguration = (definition, AppDefinition, discoveredResources) =
798
684
  if (AppDefinition.encryption?.createResourceIfNoneFound !== true) {
799
685
  throw new Error(
800
686
  'KMS field-level encryption is enabled but no KMS key was found. ' +
801
- 'Either provide an existing KMS key or set encryption.createResourceIfNoneFound to true to create a new key.'
687
+ 'Either provide an existing KMS key or set encryption.createResourceIfNoneFound to true to create a new key.'
802
688
  );
803
689
  }
804
690
 
@@ -1197,8 +1083,8 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1197
1083
  AppDefinition.vpc.subnets?.ids?.length > 0
1198
1084
  ? AppDefinition.vpc.subnets.ids
1199
1085
  : discoveredResources.privateSubnetId1 && discoveredResources.privateSubnetId2
1200
- ? [discoveredResources.privateSubnetId1, discoveredResources.privateSubnetId2]
1201
- : [];
1086
+ ? [discoveredResources.privateSubnetId1, discoveredResources.privateSubnetId2]
1087
+ : [];
1202
1088
 
1203
1089
  if (vpcConfig.subnetIds.length < 2) {
1204
1090
  if (AppDefinition.vpc.selfHeal) {
@@ -1624,9 +1510,7 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1624
1510
  },
1625
1511
  };
1626
1512
 
1627
- // Create Secrets Manager VPC Endpoint if explicitly enabled OR if Aurora is enabled
1628
- // (Aurora requires Secrets Manager access for credential retrieval)
1629
- if (AppDefinition.secretsManager?.enable === true || AppDefinition.database?.postgres?.enable === true) {
1513
+ if (AppDefinition.secretsManager?.enable === true) {
1630
1514
  definition.resources.Resources.VPCEndpointSecretsManager = {
1631
1515
  Type: 'AWS::EC2::VPCEndpoint',
1632
1516
  Properties: {
@@ -1643,283 +1527,6 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1643
1527
  }
1644
1528
  };
1645
1529
 
1646
- const createAuroraInfrastructure = (definition, AppDefinition, discoveredResources) => {
1647
- const dbConfig = AppDefinition.database.postgres;
1648
-
1649
- console.log('🔧 Creating Aurora Serverless v2 infrastructure...');
1650
-
1651
- // 1. DB Subnet Group (using Lambda private subnets)
1652
- definition.resources.Resources.FriggDBSubnetGroup = {
1653
- Type: 'AWS::RDS::DBSubnetGroup',
1654
- Properties: {
1655
- DBSubnetGroupDescription: 'Subnet group for Frigg Aurora cluster',
1656
- SubnetIds: [
1657
- discoveredResources.privateSubnetId1,
1658
- discoveredResources.privateSubnetId2
1659
- ],
1660
- Tags: [
1661
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-db-subnet-group' },
1662
- { Key: 'ManagedBy', Value: 'Frigg' },
1663
- { Key: 'Service', Value: '${self:service}' },
1664
- { Key: 'Stage', Value: '${self:provider.stage}' },
1665
- ]
1666
- }
1667
- };
1668
-
1669
- // 2. Security Group (allow Lambda SG to access 5432)
1670
- // In create-new VPC mode, Lambda uses FriggLambdaSecurityGroup
1671
- // In other modes, use discovered default security group
1672
- const lambdaSecurityGroupId = AppDefinition.vpc?.management === 'create-new'
1673
- ? { Ref: 'FriggLambdaSecurityGroup' }
1674
- : discoveredResources.defaultSecurityGroupId;
1675
-
1676
- definition.resources.Resources.FriggAuroraSecurityGroup = {
1677
- Type: 'AWS::EC2::SecurityGroup',
1678
- Properties: {
1679
- GroupDescription: 'Security group for Frigg Aurora PostgreSQL',
1680
- VpcId: discoveredResources.defaultVpcId,
1681
- SecurityGroupIngress: [
1682
- {
1683
- IpProtocol: 'tcp',
1684
- FromPort: 5432,
1685
- ToPort: 5432,
1686
- SourceSecurityGroupId: lambdaSecurityGroupId,
1687
- Description: 'PostgreSQL access from Lambda functions'
1688
- }
1689
- ],
1690
- Tags: [
1691
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-aurora-sg' },
1692
- { Key: 'ManagedBy', Value: 'Frigg' },
1693
- { Key: 'Service', Value: '${self:service}' },
1694
- { Key: 'Stage', Value: '${self:provider.stage}' },
1695
- ]
1696
- }
1697
- };
1698
-
1699
- // 3. Secrets Manager Secret (database credentials)
1700
- definition.resources.Resources.FriggDatabaseSecret = {
1701
- Type: 'AWS::SecretsManager::Secret',
1702
- Properties: {
1703
- Name: '${self:service}-${self:provider.stage}-aurora-credentials',
1704
- Description: 'Aurora PostgreSQL credentials for Frigg application',
1705
- GenerateSecretString: {
1706
- SecretStringTemplate: JSON.stringify({
1707
- username: dbConfig.masterUsername || 'frigg_admin'
1708
- }),
1709
- GenerateStringKey: 'password',
1710
- PasswordLength: 32,
1711
- ExcludeCharacters: '"@/\\'
1712
- },
1713
- Tags: [
1714
- { Key: 'ManagedBy', Value: 'Frigg' },
1715
- { Key: 'Service', Value: '${self:service}' },
1716
- { Key: 'Stage', Value: '${self:provider.stage}' },
1717
- ]
1718
- }
1719
- };
1720
-
1721
- // 4. Aurora Serverless v2 Cluster
1722
- definition.resources.Resources.FriggAuroraCluster = {
1723
- Type: 'AWS::RDS::DBCluster',
1724
- DeletionPolicy: 'Snapshot',
1725
- UpdateReplacePolicy: 'Snapshot',
1726
- Properties: {
1727
- Engine: 'aurora-postgresql',
1728
- EngineVersion: dbConfig.engineVersion || '15.3',
1729
- EngineMode: 'provisioned', // Required for Serverless v2
1730
- DatabaseName: dbConfig.databaseName || 'frigg_db',
1731
- MasterUsername: { 'Fn::Sub': '{{resolve:secretsmanager:${FriggDatabaseSecret}:SecretString:username}}' },
1732
- MasterUserPassword: { 'Fn::Sub': '{{resolve:secretsmanager:${FriggDatabaseSecret}:SecretString:password}}' },
1733
- DBSubnetGroupName: { Ref: 'FriggDBSubnetGroup' },
1734
- VpcSecurityGroupIds: [{ Ref: 'FriggAuroraSecurityGroup' }],
1735
- ServerlessV2ScalingConfiguration: {
1736
- MinCapacity: dbConfig.scaling?.minCapacity || 0.5,
1737
- MaxCapacity: dbConfig.scaling?.maxCapacity || 1.0
1738
- },
1739
- BackupRetentionPeriod: dbConfig.backupRetentionDays || 7,
1740
- PreferredBackupWindow: dbConfig.preferredBackupWindow || '03:00-04:00',
1741
- DeletionProtection: dbConfig.deletionProtection !== false,
1742
- EnableCloudwatchLogsExports: ['postgresql'],
1743
- Tags: [
1744
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-aurora-cluster' },
1745
- { Key: 'ManagedBy', Value: 'Frigg' },
1746
- { Key: 'Service', Value: '${self:service}' },
1747
- { Key: 'Stage', Value: '${self:provider.stage}' },
1748
- ]
1749
- }
1750
- };
1751
-
1752
- // 5. Aurora Serverless v2 Instance
1753
- definition.resources.Resources.FriggAuroraInstance = {
1754
- Type: 'AWS::RDS::DBInstance',
1755
- Properties: {
1756
- Engine: 'aurora-postgresql',
1757
- DBInstanceClass: 'db.serverless',
1758
- DBClusterIdentifier: { Ref: 'FriggAuroraCluster' },
1759
- PubliclyAccessible: false,
1760
- EnablePerformanceInsights: dbConfig.enablePerformanceInsights || false,
1761
- Tags: [
1762
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-aurora-instance' },
1763
- { Key: 'ManagedBy', Value: 'Frigg' },
1764
- { Key: 'Service', Value: '${self:service}' },
1765
- { Key: 'Stage', Value: '${self:provider.stage}' },
1766
- ]
1767
- }
1768
- };
1769
-
1770
- // 6. Secret Attachment (links cluster to secret)
1771
- definition.resources.Resources.FriggSecretAttachment = {
1772
- Type: 'AWS::SecretsManager::SecretTargetAttachment',
1773
- Properties: {
1774
- SecretId: { Ref: 'FriggDatabaseSecret' },
1775
- TargetId: { Ref: 'FriggAuroraCluster' },
1776
- TargetType: 'AWS::RDS::DBCluster'
1777
- }
1778
- };
1779
-
1780
- // 7. Add IAM permissions for Secrets Manager
1781
- definition.provider.iamRoleStatements.push({
1782
- Effect: 'Allow',
1783
- Action: [
1784
- 'secretsmanager:GetSecretValue',
1785
- 'secretsmanager:DescribeSecret'
1786
- ],
1787
- Resource: { Ref: 'FriggDatabaseSecret' }
1788
- });
1789
-
1790
- // 8. Set DATABASE_URL environment variable
1791
- definition.provider.environment.DATABASE_URL = {
1792
- 'Fn::Sub': [
1793
- 'postgresql://${Username}:${Password}@${Endpoint}:${Port}/${DatabaseName}',
1794
- {
1795
- Username: { 'Fn::Sub': '{{resolve:secretsmanager:${FriggDatabaseSecret}:SecretString:username}}' },
1796
- Password: { 'Fn::Sub': '{{resolve:secretsmanager:${FriggDatabaseSecret}:SecretString:password}}' },
1797
- Endpoint: { 'Fn::GetAtt': ['FriggAuroraCluster', 'Endpoint'] },
1798
- Port: { 'Fn::GetAtt': ['FriggAuroraCluster', 'Port'] },
1799
- DatabaseName: dbConfig.databaseName || 'frigg_db'
1800
- }
1801
- ]
1802
- };
1803
-
1804
- // 9. Set DB_TYPE for Prisma client selection
1805
- definition.provider.environment.DB_TYPE = 'postgresql';
1806
-
1807
- console.log('✅ Aurora infrastructure resources created');
1808
- };
1809
-
1810
- const useExistingAurora = (definition, AppDefinition, discoveredResources) => {
1811
- const dbConfig = AppDefinition.database.postgres;
1812
-
1813
- console.log(`🔗 Using existing Aurora cluster: ${discoveredResources.aurora.clusterIdentifier}`);
1814
-
1815
- // Add IAM permissions for Secrets Manager if secret exists
1816
- if (discoveredResources.aurora.secretArn) {
1817
- definition.provider.iamRoleStatements.push({
1818
- Effect: 'Allow',
1819
- Action: [
1820
- 'secretsmanager:GetSecretValue',
1821
- 'secretsmanager:DescribeSecret'
1822
- ],
1823
- Resource: discoveredResources.aurora.secretArn
1824
- });
1825
-
1826
- // Set DATABASE_URL from discovered secret
1827
- definition.provider.environment.DATABASE_URL = {
1828
- 'Fn::Sub': [
1829
- 'postgresql://${Username}:${Password}@${Endpoint}:${Port}/${DatabaseName}',
1830
- {
1831
- Username: { 'Fn::Sub': `{{resolve:secretsmanager:${discoveredResources.aurora.secretArn}:SecretString:username}}` },
1832
- Password: { 'Fn::Sub': `{{resolve:secretsmanager:${discoveredResources.aurora.secretArn}:SecretString:password}}` },
1833
- Endpoint: discoveredResources.aurora.endpoint,
1834
- Port: discoveredResources.aurora.port,
1835
- DatabaseName: dbConfig.databaseName || 'frigg_db'
1836
- }
1837
- ]
1838
- };
1839
- } else if (dbConfig.secretArn) {
1840
- // Use user-provided secret ARN
1841
- definition.provider.iamRoleStatements.push({
1842
- Effect: 'Allow',
1843
- Action: [
1844
- 'secretsmanager:GetSecretValue',
1845
- 'secretsmanager:DescribeSecret'
1846
- ],
1847
- Resource: dbConfig.secretArn
1848
- });
1849
-
1850
- definition.provider.environment.DATABASE_URL = {
1851
- 'Fn::Sub': [
1852
- 'postgresql://${Username}:${Password}@${Endpoint}:${Port}/${DatabaseName}',
1853
- {
1854
- Username: { 'Fn::Sub': `{{resolve:secretsmanager:${dbConfig.secretArn}:SecretString:username}}` },
1855
- Password: { 'Fn::Sub': `{{resolve:secretsmanager:${dbConfig.secretArn}:SecretString:password}}` },
1856
- Endpoint: discoveredResources.aurora.endpoint,
1857
- Port: discoveredResources.aurora.port,
1858
- DatabaseName: dbConfig.databaseName || 'frigg_db'
1859
- }
1860
- ]
1861
- };
1862
- } else {
1863
- throw new Error('No database secret found. Provide secretArn in database.postgres configuration or ensure Secrets Manager secret exists.');
1864
- }
1865
-
1866
- // Set DB_TYPE for Prisma client selection
1867
- definition.provider.environment.DB_TYPE = 'postgresql';
1868
-
1869
- console.log('✅ Existing Aurora cluster configured');
1870
- };
1871
-
1872
- const useDiscoveredAurora = (definition, AppDefinition, discoveredResources) => {
1873
- console.log(`🔍 Using discovered Aurora cluster: ${discoveredResources.aurora.clusterIdentifier}`);
1874
- useExistingAurora(definition, AppDefinition, discoveredResources);
1875
- };
1876
-
1877
- const configurePostgres = (definition, AppDefinition, discoveredResources) => {
1878
- if (!AppDefinition.database?.postgres?.enable) {
1879
- return;
1880
- }
1881
-
1882
- // Validate VPC is enabled (required for Aurora deployment)
1883
- if (!AppDefinition.vpc?.enable) {
1884
- throw new Error(
1885
- 'Aurora PostgreSQL requires VPC deployment. ' +
1886
- 'Set vpc.enable to true in your app definition.'
1887
- );
1888
- }
1889
-
1890
- // Validate private subnets exist (Aurora requires at least 2 subnets in different AZs)
1891
- // Skip validation if VPC management is 'create-new' (subnets will be created)
1892
- const vpcManagement = AppDefinition.vpc?.management || 'discover';
1893
- if (vpcManagement !== 'create-new' && (!discoveredResources.privateSubnetId1 || !discoveredResources.privateSubnetId2)) {
1894
- throw new Error(
1895
- 'Aurora PostgreSQL requires at least 2 private subnets in different availability zones. ' +
1896
- 'No private subnets were discovered in your VPC. ' +
1897
- 'Please create private subnets or use VPC management mode "create-new".'
1898
- );
1899
- }
1900
-
1901
- const dbConfig = AppDefinition.database.postgres;
1902
- const management = dbConfig.management || 'discover';
1903
-
1904
- console.log(`\n🐘 PostgreSQL Management Mode: ${management}`);
1905
-
1906
- if (management === 'create-new' || discoveredResources.aurora?.needsCreation) {
1907
- createAuroraInfrastructure(definition, AppDefinition, discoveredResources);
1908
- } else if (management === 'use-existing') {
1909
- if (!discoveredResources.aurora?.clusterIdentifier && !dbConfig.clusterIdentifier) {
1910
- throw new Error('PostgreSQL management is set to "use-existing" but no clusterIdentifier was found or provided');
1911
- }
1912
- useExistingAurora(definition, AppDefinition, discoveredResources);
1913
- } else {
1914
- // discover mode
1915
- if (discoveredResources.aurora?.clusterIdentifier) {
1916
- useDiscoveredAurora(definition, AppDefinition, discoveredResources);
1917
- } else {
1918
- throw new Error('No Aurora cluster found in discovery mode. Set management to "create-new" or provide clusterIdentifier with "use-existing".');
1919
- }
1920
- }
1921
- };
1922
-
1923
1530
  const configureSsm = (definition, AppDefinition) => {
1924
1531
  if (AppDefinition.ssm?.enable !== true) {
1925
1532
  return;
@@ -2018,61 +1625,16 @@ const configureWebsockets = (definition, AppDefinition) => {
2018
1625
  };
2019
1626
  };
2020
1627
 
2021
- /**
2022
- * Ensure Prisma Lambda Layer exists
2023
- * Automatically builds the layer if it doesn't exist in the project root
2024
- */
2025
- async function ensurePrismaLayerExists() {
2026
- const projectRoot = process.cwd();
2027
- const layerPath = path.join(projectRoot, 'layers/prisma');
2028
-
2029
- // Check if layer already exists
2030
- if (fs.existsSync(layerPath)) {
2031
- console.log('✓ Prisma Lambda Layer already exists at', layerPath);
2032
- return;
2033
- }
2034
-
2035
- // Layer doesn't exist - build it automatically
2036
- console.log('📦 Prisma Lambda Layer not found - building automatically...');
2037
- console.log(' This may take a minute on first deployment.\n');
2038
-
2039
- try {
2040
- await buildPrismaLayer();
2041
- console.log('✓ Prisma Lambda Layer built successfully\n');
2042
- } catch (error) {
2043
- console.error('✗ Failed to build Prisma Lambda Layer:', error.message);
2044
- console.error(' You may need to run: npm install @friggframework/core\n');
2045
- throw error;
2046
- }
2047
- }
2048
-
2049
1628
  const composeServerlessDefinition = async (AppDefinition) => {
2050
1629
  console.log('composeServerlessDefinition', AppDefinition);
2051
1630
 
2052
- // Ensure Prisma layer exists before generating serverless config
2053
- await ensurePrismaLayerExists();
2054
-
2055
1631
  const discoveredResources = await gatherDiscoveredResources(AppDefinition);
2056
1632
  const appEnvironmentVars = getAppEnvironmentVars(AppDefinition);
2057
1633
  const definition = createBaseDefinition(AppDefinition, appEnvironmentVars, discoveredResources);
2058
1634
 
2059
- // Check if we're in local build mode (AWS discovery was skipped)
2060
- const isLocalBuild = !shouldRunDiscovery(AppDefinition);
2061
-
2062
- if (isLocalBuild) {
2063
- console.log('🏠 Local build mode detected - skipping AWS-dependent configurations');
2064
- }
2065
-
2066
- // Apply configurations (skip AWS-dependent ones in local build mode)
2067
- if (!isLocalBuild) {
2068
- applyKmsConfiguration(definition, AppDefinition, discoveredResources);
2069
- configureVpc(definition, AppDefinition, discoveredResources);
2070
- configurePostgres(definition, AppDefinition, discoveredResources);
2071
- configureSsm(definition, AppDefinition);
2072
- } else {
2073
- console.log(' ⏭️ Skipping: KMS, VPC, PostgreSQL, SSM configurations');
2074
- }
2075
-
1635
+ applyKmsConfiguration(definition, AppDefinition, discoveredResources);
1636
+ configureVpc(definition, AppDefinition, discoveredResources);
1637
+ configureSsm(definition, AppDefinition);
2076
1638
  attachIntegrations(definition, AppDefinition);
2077
1639
  configureWebsockets(definition, AppDefinition);
2078
1640