@friggframework/devtools 2.0.0--canary.454.16de0f8.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,27 +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
- // Existing AWS SDK exclusions
530
- '!**/node_modules/aws-sdk/**',
531
- '!**/node_modules/@aws-sdk/**',
532
- '!package.json',
533
-
534
- // GLOBAL Prisma exclusions - all Prisma packages moved to Lambda Layer
535
- // This reduces each function from ~120MB to ~45MB (60% reduction)
536
- '!node_modules/@prisma/**',
537
- '!node_modules/.prisma/**',
538
- '!node_modules/@prisma-mongodb/**',
539
- '!node_modules/@prisma-postgresql/**',
540
- '!node_modules/prisma/**',
541
- // Prisma packages will be provided at runtime via Lambda Layer
542
- // See: LAMBDA-LAYER-PRISMA.md for complete documentation
543
- ],
503
+ exclude: ['!**/node_modules/aws-sdk/**', '!**/node_modules/@aws-sdk/**', '!package.json'],
544
504
  },
545
505
  useDotenv: true,
546
506
  provider: {
547
507
  name: AppDefinition.provider || 'aws',
548
- ...(process.env.AWS_PROFILE && { profile: process.env.AWS_PROFILE }),
549
508
  runtime: 'nodejs20.x',
550
509
  timeout: 30,
551
510
  region,
@@ -612,7 +571,6 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
612
571
  functions: {
613
572
  auth: {
614
573
  handler: 'node_modules/@friggframework/core/handlers/routers/auth.handler',
615
- layers: [{ Ref: 'PrismaLambdaLayer' }],
616
574
  events: [
617
575
  { httpApi: { path: '/api/integrations', method: 'ANY' } },
618
576
  { httpApi: { path: '/api/integrations/{proxy+}', method: 'ANY' } },
@@ -621,56 +579,15 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
621
579
  },
622
580
  user: {
623
581
  handler: 'node_modules/@friggframework/core/handlers/routers/user.handler',
624
- layers: [{ Ref: 'PrismaLambdaLayer' }],
625
582
  events: [{ httpApi: { path: '/user/{proxy+}', method: 'ANY' } }],
626
583
  },
627
584
  health: {
628
585
  handler: 'node_modules/@friggframework/core/handlers/routers/health.handler',
629
- layers: [{ Ref: 'PrismaLambdaLayer' }],
630
586
  events: [
631
587
  { httpApi: { path: '/health', method: 'GET' } },
632
588
  { httpApi: { path: '/health/{proxy+}', method: 'GET' } },
633
589
  ],
634
590
  },
635
- dbMigrate: {
636
- handler: 'node_modules/@friggframework/core/handlers/workers/db-migration.handler',
637
- layers: [{ Ref: 'PrismaLambdaLayer' }],
638
- timeout: 300, // 5 minutes for long-running migrations
639
- memorySize: 512, // Extra memory for Prisma CLI operations
640
- reservedConcurrency: 1, // Prevent concurrent migrations
641
- description: 'Runs database migrations via Prisma (invoke manually from CI/CD)',
642
- // No events - this function is invoked manually via AWS CLI
643
- maximumEventAge: 60, // Don't retry old migration requests (60 seconds)
644
- maximumRetryAttempts: 0, // Don't auto-retry failed migrations
645
- tags: {
646
- Purpose: 'DatabaseMigration',
647
- ManagedBy: 'Frigg',
648
- },
649
- // Environment variables for non-interactive Prisma CLI operation
650
- environment: {
651
- CI: '1', // Forces Prisma to non-interactive mode
652
- PRISMA_HIDE_UPDATE_MESSAGE: '1', // Suppress update messages
653
- PRISMA_MIGRATE_SKIP_SEED: '1', // Skip seeding during migrations
654
- },
655
- // Function-specific packaging: Include Prisma schemas (CLI from layer)
656
- package: {
657
- patterns: [
658
- // Include Prisma schemas from @friggframework/core
659
- // Note: Prisma CLI and clients come from Lambda Layer
660
- 'node_modules/@friggframework/core/prisma-mongodb/**',
661
- 'node_modules/@friggframework/core/prisma-postgresql/**',
662
- ],
663
- },
664
- },
665
- },
666
- layers: {
667
- prisma: {
668
- path: 'layers/prisma',
669
- name: '${self:service}-prisma-${sls:stage}',
670
- 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.',
671
- compatibleRuntimes: ['nodejs18.x', 'nodejs20.x'],
672
- retain: false, // Don't retain old layer versions
673
- },
674
591
  },
675
592
  resources: {
676
593
  Resources: {
@@ -749,21 +666,14 @@ const applyKmsConfiguration = (definition, AppDefinition, discoveredResources) =
749
666
 
750
667
  if (discoveredResources.defaultKmsKeyId) {
751
668
  console.log(`Using existing KMS key: ${discoveredResources.defaultKmsKeyId}`);
752
-
753
- // Only create alias if it doesn't already exist
754
- if (!discoveredResources.kmsAliasExists) {
755
- console.log('Creating KMS alias for discovered key...');
756
- definition.resources.Resources.FriggKMSKeyAlias = {
757
- Type: 'AWS::KMS::Alias',
758
- DeletionPolicy: 'Retain',
759
- Properties: {
760
- AliasName: 'alias/${self:service}-${self:provider.stage}-frigg-kms',
761
- TargetKeyId: discoveredResources.defaultKmsKeyId,
762
- },
763
- };
764
- } else {
765
- console.log('KMS alias already exists, skipping alias creation');
766
- }
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
+ };
767
677
 
768
678
  definition.provider.iamRoleStatements.push({
769
679
  Effect: 'Allow',
@@ -1600,9 +1510,7 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1600
1510
  },
1601
1511
  };
1602
1512
 
1603
- // Create Secrets Manager VPC Endpoint if explicitly enabled OR if Aurora is enabled
1604
- // (Aurora requires Secrets Manager access for credential retrieval)
1605
- if (AppDefinition.secretsManager?.enable === true || AppDefinition.database?.postgres?.enable === true) {
1513
+ if (AppDefinition.secretsManager?.enable === true) {
1606
1514
  definition.resources.Resources.VPCEndpointSecretsManager = {
1607
1515
  Type: 'AWS::EC2::VPCEndpoint',
1608
1516
  Properties: {
@@ -1619,283 +1527,6 @@ const configureVpc = (definition, AppDefinition, discoveredResources) => {
1619
1527
  }
1620
1528
  };
1621
1529
 
1622
- const createAuroraInfrastructure = (definition, AppDefinition, discoveredResources) => {
1623
- const dbConfig = AppDefinition.database.postgres;
1624
-
1625
- console.log('🔧 Creating Aurora Serverless v2 infrastructure...');
1626
-
1627
- // 1. DB Subnet Group (using Lambda private subnets)
1628
- definition.resources.Resources.FriggDBSubnetGroup = {
1629
- Type: 'AWS::RDS::DBSubnetGroup',
1630
- Properties: {
1631
- DBSubnetGroupDescription: 'Subnet group for Frigg Aurora cluster',
1632
- SubnetIds: [
1633
- discoveredResources.privateSubnetId1,
1634
- discoveredResources.privateSubnetId2
1635
- ],
1636
- Tags: [
1637
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-db-subnet-group' },
1638
- { Key: 'ManagedBy', Value: 'Frigg' },
1639
- { Key: 'Service', Value: '${self:service}' },
1640
- { Key: 'Stage', Value: '${self:provider.stage}' },
1641
- ]
1642
- }
1643
- };
1644
-
1645
- // 2. Security Group (allow Lambda SG to access 5432)
1646
- // In create-new VPC mode, Lambda uses FriggLambdaSecurityGroup
1647
- // In other modes, use discovered default security group
1648
- const lambdaSecurityGroupId = AppDefinition.vpc?.management === 'create-new'
1649
- ? { Ref: 'FriggLambdaSecurityGroup' }
1650
- : discoveredResources.defaultSecurityGroupId;
1651
-
1652
- definition.resources.Resources.FriggAuroraSecurityGroup = {
1653
- Type: 'AWS::EC2::SecurityGroup',
1654
- Properties: {
1655
- GroupDescription: 'Security group for Frigg Aurora PostgreSQL',
1656
- VpcId: discoveredResources.defaultVpcId,
1657
- SecurityGroupIngress: [
1658
- {
1659
- IpProtocol: 'tcp',
1660
- FromPort: 5432,
1661
- ToPort: 5432,
1662
- SourceSecurityGroupId: lambdaSecurityGroupId,
1663
- Description: 'PostgreSQL access from Lambda functions'
1664
- }
1665
- ],
1666
- Tags: [
1667
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-aurora-sg' },
1668
- { Key: 'ManagedBy', Value: 'Frigg' },
1669
- { Key: 'Service', Value: '${self:service}' },
1670
- { Key: 'Stage', Value: '${self:provider.stage}' },
1671
- ]
1672
- }
1673
- };
1674
-
1675
- // 3. Secrets Manager Secret (database credentials)
1676
- definition.resources.Resources.FriggDatabaseSecret = {
1677
- Type: 'AWS::SecretsManager::Secret',
1678
- Properties: {
1679
- Name: '${self:service}-${self:provider.stage}-aurora-credentials',
1680
- Description: 'Aurora PostgreSQL credentials for Frigg application',
1681
- GenerateSecretString: {
1682
- SecretStringTemplate: JSON.stringify({
1683
- username: dbConfig.masterUsername || 'frigg_admin'
1684
- }),
1685
- GenerateStringKey: 'password',
1686
- PasswordLength: 32,
1687
- ExcludeCharacters: '"@/\\'
1688
- },
1689
- Tags: [
1690
- { Key: 'ManagedBy', Value: 'Frigg' },
1691
- { Key: 'Service', Value: '${self:service}' },
1692
- { Key: 'Stage', Value: '${self:provider.stage}' },
1693
- ]
1694
- }
1695
- };
1696
-
1697
- // 4. Aurora Serverless v2 Cluster
1698
- definition.resources.Resources.FriggAuroraCluster = {
1699
- Type: 'AWS::RDS::DBCluster',
1700
- DeletionPolicy: 'Snapshot',
1701
- UpdateReplacePolicy: 'Snapshot',
1702
- Properties: {
1703
- Engine: 'aurora-postgresql',
1704
- EngineVersion: dbConfig.engineVersion || '15.3',
1705
- EngineMode: 'provisioned', // Required for Serverless v2
1706
- DatabaseName: dbConfig.databaseName || 'frigg_db',
1707
- MasterUsername: { 'Fn::Sub': '{{resolve:secretsmanager:${FriggDatabaseSecret}:SecretString:username}}' },
1708
- MasterUserPassword: { 'Fn::Sub': '{{resolve:secretsmanager:${FriggDatabaseSecret}:SecretString:password}}' },
1709
- DBSubnetGroupName: { Ref: 'FriggDBSubnetGroup' },
1710
- VpcSecurityGroupIds: [{ Ref: 'FriggAuroraSecurityGroup' }],
1711
- ServerlessV2ScalingConfiguration: {
1712
- MinCapacity: dbConfig.scaling?.minCapacity || 0.5,
1713
- MaxCapacity: dbConfig.scaling?.maxCapacity || 1.0
1714
- },
1715
- BackupRetentionPeriod: dbConfig.backupRetentionDays || 7,
1716
- PreferredBackupWindow: dbConfig.preferredBackupWindow || '03:00-04:00',
1717
- DeletionProtection: dbConfig.deletionProtection !== false,
1718
- EnableCloudwatchLogsExports: ['postgresql'],
1719
- Tags: [
1720
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-aurora-cluster' },
1721
- { Key: 'ManagedBy', Value: 'Frigg' },
1722
- { Key: 'Service', Value: '${self:service}' },
1723
- { Key: 'Stage', Value: '${self:provider.stage}' },
1724
- ]
1725
- }
1726
- };
1727
-
1728
- // 5. Aurora Serverless v2 Instance
1729
- definition.resources.Resources.FriggAuroraInstance = {
1730
- Type: 'AWS::RDS::DBInstance',
1731
- Properties: {
1732
- Engine: 'aurora-postgresql',
1733
- DBInstanceClass: 'db.serverless',
1734
- DBClusterIdentifier: { Ref: 'FriggAuroraCluster' },
1735
- PubliclyAccessible: false,
1736
- EnablePerformanceInsights: dbConfig.enablePerformanceInsights || false,
1737
- Tags: [
1738
- { Key: 'Name', Value: '${self:service}-${self:provider.stage}-aurora-instance' },
1739
- { Key: 'ManagedBy', Value: 'Frigg' },
1740
- { Key: 'Service', Value: '${self:service}' },
1741
- { Key: 'Stage', Value: '${self:provider.stage}' },
1742
- ]
1743
- }
1744
- };
1745
-
1746
- // 6. Secret Attachment (links cluster to secret)
1747
- definition.resources.Resources.FriggSecretAttachment = {
1748
- Type: 'AWS::SecretsManager::SecretTargetAttachment',
1749
- Properties: {
1750
- SecretId: { Ref: 'FriggDatabaseSecret' },
1751
- TargetId: { Ref: 'FriggAuroraCluster' },
1752
- TargetType: 'AWS::RDS::DBCluster'
1753
- }
1754
- };
1755
-
1756
- // 7. Add IAM permissions for Secrets Manager
1757
- definition.provider.iamRoleStatements.push({
1758
- Effect: 'Allow',
1759
- Action: [
1760
- 'secretsmanager:GetSecretValue',
1761
- 'secretsmanager:DescribeSecret'
1762
- ],
1763
- Resource: { Ref: 'FriggDatabaseSecret' }
1764
- });
1765
-
1766
- // 8. Set DATABASE_URL environment variable
1767
- definition.provider.environment.DATABASE_URL = {
1768
- 'Fn::Sub': [
1769
- 'postgresql://${Username}:${Password}@${Endpoint}:${Port}/${DatabaseName}',
1770
- {
1771
- Username: { 'Fn::Sub': '{{resolve:secretsmanager:${FriggDatabaseSecret}:SecretString:username}}' },
1772
- Password: { 'Fn::Sub': '{{resolve:secretsmanager:${FriggDatabaseSecret}:SecretString:password}}' },
1773
- Endpoint: { 'Fn::GetAtt': ['FriggAuroraCluster', 'Endpoint'] },
1774
- Port: { 'Fn::GetAtt': ['FriggAuroraCluster', 'Port'] },
1775
- DatabaseName: dbConfig.databaseName || 'frigg_db'
1776
- }
1777
- ]
1778
- };
1779
-
1780
- // 9. Set DB_TYPE for Prisma client selection
1781
- definition.provider.environment.DB_TYPE = 'postgresql';
1782
-
1783
- console.log('✅ Aurora infrastructure resources created');
1784
- };
1785
-
1786
- const useExistingAurora = (definition, AppDefinition, discoveredResources) => {
1787
- const dbConfig = AppDefinition.database.postgres;
1788
-
1789
- console.log(`🔗 Using existing Aurora cluster: ${discoveredResources.aurora.clusterIdentifier}`);
1790
-
1791
- // Add IAM permissions for Secrets Manager if secret exists
1792
- if (discoveredResources.aurora.secretArn) {
1793
- definition.provider.iamRoleStatements.push({
1794
- Effect: 'Allow',
1795
- Action: [
1796
- 'secretsmanager:GetSecretValue',
1797
- 'secretsmanager:DescribeSecret'
1798
- ],
1799
- Resource: discoveredResources.aurora.secretArn
1800
- });
1801
-
1802
- // Set DATABASE_URL from discovered secret
1803
- definition.provider.environment.DATABASE_URL = {
1804
- 'Fn::Sub': [
1805
- 'postgresql://${Username}:${Password}@${Endpoint}:${Port}/${DatabaseName}',
1806
- {
1807
- Username: { 'Fn::Sub': `{{resolve:secretsmanager:${discoveredResources.aurora.secretArn}:SecretString:username}}` },
1808
- Password: { 'Fn::Sub': `{{resolve:secretsmanager:${discoveredResources.aurora.secretArn}:SecretString:password}}` },
1809
- Endpoint: discoveredResources.aurora.endpoint,
1810
- Port: discoveredResources.aurora.port,
1811
- DatabaseName: dbConfig.databaseName || 'frigg_db'
1812
- }
1813
- ]
1814
- };
1815
- } else if (dbConfig.secretArn) {
1816
- // Use user-provided secret ARN
1817
- definition.provider.iamRoleStatements.push({
1818
- Effect: 'Allow',
1819
- Action: [
1820
- 'secretsmanager:GetSecretValue',
1821
- 'secretsmanager:DescribeSecret'
1822
- ],
1823
- Resource: dbConfig.secretArn
1824
- });
1825
-
1826
- definition.provider.environment.DATABASE_URL = {
1827
- 'Fn::Sub': [
1828
- 'postgresql://${Username}:${Password}@${Endpoint}:${Port}/${DatabaseName}',
1829
- {
1830
- Username: { 'Fn::Sub': `{{resolve:secretsmanager:${dbConfig.secretArn}:SecretString:username}}` },
1831
- Password: { 'Fn::Sub': `{{resolve:secretsmanager:${dbConfig.secretArn}:SecretString:password}}` },
1832
- Endpoint: discoveredResources.aurora.endpoint,
1833
- Port: discoveredResources.aurora.port,
1834
- DatabaseName: dbConfig.databaseName || 'frigg_db'
1835
- }
1836
- ]
1837
- };
1838
- } else {
1839
- throw new Error('No database secret found. Provide secretArn in database.postgres configuration or ensure Secrets Manager secret exists.');
1840
- }
1841
-
1842
- // Set DB_TYPE for Prisma client selection
1843
- definition.provider.environment.DB_TYPE = 'postgresql';
1844
-
1845
- console.log('✅ Existing Aurora cluster configured');
1846
- };
1847
-
1848
- const useDiscoveredAurora = (definition, AppDefinition, discoveredResources) => {
1849
- console.log(`🔍 Using discovered Aurora cluster: ${discoveredResources.aurora.clusterIdentifier}`);
1850
- useExistingAurora(definition, AppDefinition, discoveredResources);
1851
- };
1852
-
1853
- const configurePostgres = (definition, AppDefinition, discoveredResources) => {
1854
- if (!AppDefinition.database?.postgres?.enable) {
1855
- return;
1856
- }
1857
-
1858
- // Validate VPC is enabled (required for Aurora deployment)
1859
- if (!AppDefinition.vpc?.enable) {
1860
- throw new Error(
1861
- 'Aurora PostgreSQL requires VPC deployment. ' +
1862
- 'Set vpc.enable to true in your app definition.'
1863
- );
1864
- }
1865
-
1866
- // Validate private subnets exist (Aurora requires at least 2 subnets in different AZs)
1867
- // Skip validation if VPC management is 'create-new' (subnets will be created)
1868
- const vpcManagement = AppDefinition.vpc?.management || 'discover';
1869
- if (vpcManagement !== 'create-new' && (!discoveredResources.privateSubnetId1 || !discoveredResources.privateSubnetId2)) {
1870
- throw new Error(
1871
- 'Aurora PostgreSQL requires at least 2 private subnets in different availability zones. ' +
1872
- 'No private subnets were discovered in your VPC. ' +
1873
- 'Please create private subnets or use VPC management mode "create-new".'
1874
- );
1875
- }
1876
-
1877
- const dbConfig = AppDefinition.database.postgres;
1878
- const management = dbConfig.management || 'discover';
1879
-
1880
- console.log(`\n🐘 PostgreSQL Management Mode: ${management}`);
1881
-
1882
- if (management === 'create-new' || discoveredResources.aurora?.needsCreation) {
1883
- createAuroraInfrastructure(definition, AppDefinition, discoveredResources);
1884
- } else if (management === 'use-existing') {
1885
- if (!discoveredResources.aurora?.clusterIdentifier && !dbConfig.clusterIdentifier) {
1886
- throw new Error('PostgreSQL management is set to "use-existing" but no clusterIdentifier was found or provided');
1887
- }
1888
- useExistingAurora(definition, AppDefinition, discoveredResources);
1889
- } else {
1890
- // discover mode
1891
- if (discoveredResources.aurora?.clusterIdentifier) {
1892
- useDiscoveredAurora(definition, AppDefinition, discoveredResources);
1893
- } else {
1894
- throw new Error('No Aurora cluster found in discovery mode. Set management to "create-new" or provide clusterIdentifier with "use-existing".');
1895
- }
1896
- }
1897
- };
1898
-
1899
1530
  const configureSsm = (definition, AppDefinition) => {
1900
1531
  if (AppDefinition.ssm?.enable !== true) {
1901
1532
  return;
@@ -1994,47 +1625,15 @@ const configureWebsockets = (definition, AppDefinition) => {
1994
1625
  };
1995
1626
  };
1996
1627
 
1997
- /**
1998
- * Ensure Prisma Lambda Layer exists
1999
- * Automatically builds the layer if it doesn't exist in the project root
2000
- */
2001
- async function ensurePrismaLayerExists() {
2002
- const projectRoot = process.cwd();
2003
- const layerPath = path.join(projectRoot, 'layers/prisma');
2004
-
2005
- // Check if layer already exists
2006
- if (fs.existsSync(layerPath)) {
2007
- console.log('✓ Prisma Lambda Layer already exists at', layerPath);
2008
- return;
2009
- }
2010
-
2011
- // Layer doesn't exist - build it automatically
2012
- console.log('📦 Prisma Lambda Layer not found - building automatically...');
2013
- console.log(' This may take a minute on first deployment.\n');
2014
-
2015
- try {
2016
- await buildPrismaLayer();
2017
- console.log('✓ Prisma Lambda Layer built successfully\n');
2018
- } catch (error) {
2019
- console.error('✗ Failed to build Prisma Lambda Layer:', error.message);
2020
- console.error(' You may need to run: npm install @friggframework/core\n');
2021
- throw error;
2022
- }
2023
- }
2024
-
2025
1628
  const composeServerlessDefinition = async (AppDefinition) => {
2026
1629
  console.log('composeServerlessDefinition', AppDefinition);
2027
1630
 
2028
- // Ensure Prisma layer exists before generating serverless config
2029
- await ensurePrismaLayerExists();
2030
-
2031
1631
  const discoveredResources = await gatherDiscoveredResources(AppDefinition);
2032
1632
  const appEnvironmentVars = getAppEnvironmentVars(AppDefinition);
2033
1633
  const definition = createBaseDefinition(AppDefinition, appEnvironmentVars, discoveredResources);
2034
1634
 
2035
1635
  applyKmsConfiguration(definition, AppDefinition, discoveredResources);
2036
1636
  configureVpc(definition, AppDefinition, discoveredResources);
2037
- configurePostgres(definition, AppDefinition, discoveredResources);
2038
1637
  configureSsm(definition, AppDefinition);
2039
1638
  attachIntegrations(definition, AppDefinition);
2040
1639
  configureWebsockets(definition, AppDefinition);
@@ -1762,97 +1762,6 @@ describe('composeServerlessDefinition', () => {
1762
1762
  });
1763
1763
  });
1764
1764
 
1765
- describe('Database Migration Lambda', () => {
1766
- it('should include dbMigrate function in all deployments', async () => {
1767
- const appDefinition = {
1768
- name: 'test-app',
1769
- integrations: []
1770
- };
1771
-
1772
- const result = await composeServerlessDefinition(appDefinition);
1773
-
1774
- // Check dbMigrate function exists
1775
- expect(result.functions.dbMigrate).toBeDefined();
1776
- expect(result.functions.dbMigrate.handler).toBe(
1777
- 'node_modules/@friggframework/core/handlers/workers/db-migration.handler'
1778
- );
1779
- });
1780
-
1781
- it('should configure dbMigrate with correct settings', async () => {
1782
- const appDefinition = {
1783
- integrations: []
1784
- };
1785
-
1786
- const result = await composeServerlessDefinition(appDefinition);
1787
-
1788
- const dbMigrate = result.functions.dbMigrate;
1789
-
1790
- // Check timeout (5 minutes for long migrations)
1791
- expect(dbMigrate.timeout).toBe(300);
1792
-
1793
- // Check memory allocation (extra for Prisma CLI)
1794
- expect(dbMigrate.memorySize).toBe(512);
1795
-
1796
- // Check description
1797
- expect(dbMigrate.description).toContain('database migrations');
1798
- expect(dbMigrate.description).toContain('Prisma');
1799
- });
1800
-
1801
- it('should not have HTTP events (manual invocation only)', async () => {
1802
- const appDefinition = {
1803
- integrations: []
1804
- };
1805
-
1806
- const result = await composeServerlessDefinition(appDefinition);
1807
-
1808
- const dbMigrate = result.functions.dbMigrate;
1809
-
1810
- // Should have no events (manually invoked via AWS CLI)
1811
- expect(dbMigrate.events).toBeUndefined();
1812
- });
1813
-
1814
- it('should include dbMigrate even with VPC enabled', async () => {
1815
- const appDefinition = {
1816
- vpc: {
1817
- enable: true,
1818
- management: 'discover'
1819
- },
1820
- integrations: []
1821
- };
1822
-
1823
- const result = await composeServerlessDefinition(appDefinition);
1824
-
1825
- // dbMigrate should exist with VPC configuration
1826
- expect(result.functions.dbMigrate).toBeDefined();
1827
-
1828
- // Should have same VPC access as other functions
1829
- expect(result.provider.vpc).toBeDefined();
1830
- });
1831
-
1832
- it('should include dbMigrate with database configuration', async () => {
1833
- const appDefinition = {
1834
- vpc: {
1835
- enable: true,
1836
- management: 'discover'
1837
- },
1838
- database: {
1839
- postgres: {
1840
- enable: true,
1841
- management: 'discover'
1842
- }
1843
- },
1844
- integrations: []
1845
- };
1846
-
1847
- const result = await composeServerlessDefinition(appDefinition);
1848
-
1849
- // dbMigrate should exist alongside database configuration
1850
- expect(result.functions.dbMigrate).toBeDefined();
1851
- expect(result.provider.environment.DB_TYPE).toBe('postgresql');
1852
- expect(result.provider.environment.DATABASE_URL).toBeDefined();
1853
- });
1854
- });
1855
-
1856
1765
  describe('Edge Cases', () => {
1857
1766
  it('should handle empty app definition', async () => {
1858
1767
  const appDefinition = {};