From d8687edb9f41516a205f8d433a9fa08ee4b1a8fb Mon Sep 17 00:00:00 2001 From: paritosh18 Date: Sun, 30 Nov 2025 12:17:20 +0530 Subject: [PATCH] feat: add Prisma layer build scripts and configuration for Lambda deployment --- .gitignore | 4 + build-prisma-layer.ps1 | 46 +++++ build-prisma-layer.sh | 40 +++++ layers/prisma/nodejs/package-lock.json | 228 +++++++++++++++++++++++++ layers/prisma/nodejs/package.json | 10 ++ package.json | 4 +- prisma/schema.prisma | 6 +- serverless.yml | 16 ++ serverless/patterns/base.yml | 8 +- 9 files changed, 355 insertions(+), 7 deletions(-) create mode 100644 build-prisma-layer.ps1 create mode 100644 build-prisma-layer.sh create mode 100644 layers/prisma/nodejs/package-lock.json create mode 100644 layers/prisma/nodejs/package.json diff --git a/.gitignore b/.gitignore index 51ebff3..ddcbcd6 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,10 @@ lerna-debug.log* .temp undefined/ +# tsx cache/temp directories +**/tsx-*/ +**/temp/tsx-* + # Runtime data pids *.pid diff --git a/build-prisma-layer.ps1 b/build-prisma-layer.ps1 new file mode 100644 index 0000000..04dad3c --- /dev/null +++ b/build-prisma-layer.ps1 @@ -0,0 +1,46 @@ +# build-prisma-layer.ps1 +# Script to rebuild the Prisma layer for Lambda deployment +# Usage: .\build-prisma-layer.ps1 + +$ErrorActionPreference = "Stop" + +$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +$layerPath = Join-Path $projectRoot "layers\prisma\nodejs" +$nodeModulesPath = Join-Path $layerPath "node_modules" + +Write-Host "๐Ÿ”„ Building Prisma layer for Lambda..." -ForegroundColor Cyan + +# Step 1: Regenerate Prisma client +Write-Host "๐Ÿ“ฆ Regenerating Prisma client..." -ForegroundColor Yellow +Push-Location $projectRoot +npx prisma generate +Pop-Location + +# Step 2: Clean layer node_modules +Write-Host "๐Ÿงน Cleaning layer node_modules..." -ForegroundColor Yellow +if (Test-Path $nodeModulesPath) { + Remove-Item -Recurse -Force $nodeModulesPath +} + +# Step 3: Install layer dependencies +Write-Host "๐Ÿ“ฅ Installing layer dependencies..." -ForegroundColor Yellow +Push-Location $layerPath +npm install --production +Pop-Location + +# Step 4: Copy generated Prisma client to layer +Write-Host "๐Ÿ“‹ Copying generated Prisma client to layer..." -ForegroundColor Yellow +$sourcePrisma = Join-Path $projectRoot "node_modules\.prisma\client" +$destPrisma = Join-Path $nodeModulesPath ".prisma\client" + +New-Item -ItemType Directory -Force -Path (Split-Path $destPrisma) | Out-Null +Copy-Item -Path $sourcePrisma -Destination $destPrisma -Recurse -Force + +# Step 5: Calculate layer size +$layerSize = (Get-ChildItem -Path $layerPath -Recurse -File | Measure-Object -Property Length -Sum).Sum / 1MB +Write-Host "โœ… Layer built successfully!" -ForegroundColor Green +Write-Host "๐Ÿ“Š Layer size: $([math]::Round($layerSize, 2)) MB" -ForegroundColor Cyan + +# List contents +Write-Host "`n๐Ÿ“ Layer contents:" -ForegroundColor Cyan +Get-ChildItem $nodeModulesPath -Directory | ForEach-Object { Write-Host " - $($_.Name)" } diff --git a/build-prisma-layer.sh b/build-prisma-layer.sh new file mode 100644 index 0000000..8d873ce --- /dev/null +++ b/build-prisma-layer.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# build-prisma-layer.sh +# Script to rebuild the Prisma layer for Lambda deployment +# Usage: ./build-prisma-layer.sh + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LAYER_PATH="$SCRIPT_DIR/layers/prisma/nodejs" + +echo "๐Ÿ”„ Building Prisma layer for Lambda..." + +# Step 1: Regenerate Prisma client +echo "๐Ÿ“ฆ Regenerating Prisma client..." +cd "$SCRIPT_DIR" +npx prisma generate + +# Step 2: Clean layer node_modules +echo "๐Ÿงน Cleaning layer node_modules..." +rm -rf "$LAYER_PATH/node_modules" + +# Step 3: Install layer dependencies +echo "๐Ÿ“ฅ Installing layer dependencies..." +cd "$LAYER_PATH" +npm install --production + +# Step 4: Copy generated Prisma client to layer +echo "๐Ÿ“‹ Copying generated Prisma client to layer..." +mkdir -p "$LAYER_PATH/node_modules/.prisma" +cp -r "$SCRIPT_DIR/node_modules/.prisma/client" "$LAYER_PATH/node_modules/.prisma/client" + +# Step 5: Calculate layer size +LAYER_SIZE=$(du -sh "$LAYER_PATH" | cut -f1) +echo "โœ… Layer built successfully!" +echo "๐Ÿ“Š Layer size: $LAYER_SIZE" + +# List contents +echo "" +echo "๐Ÿ“ Layer contents:" +ls -d "$LAYER_PATH/node_modules"/*/ 2>/dev/null | xargs -n 1 basename | sed 's/^/ - /' diff --git a/layers/prisma/nodejs/package-lock.json b/layers/prisma/nodejs/package-lock.json new file mode 100644 index 0000000..389329f --- /dev/null +++ b/layers/prisma/nodejs/package-lock.json @@ -0,0 +1,228 @@ +{ + "name": "prisma-layer", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "prisma-layer", + "version": "1.0.0", + "dependencies": { + "@prisma/adapter-pg": "^7.0.1", + "@prisma/client": "^7.0.1", + "pg": "^8.13.0" + } + }, + "node_modules/@prisma/adapter-pg": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.0.1.tgz", + "integrity": "sha512-01GpPPhLMoDMF4ipgfZz0L87fla/TV/PBQcmHy+9vV1ml6gUoqF8dUIRNI5Yf2YKpOwzQg9sn8C7dYD1Yio9Ug==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/driver-adapter-utils": "7.0.1", + "pg": "^8.16.3", + "postgres-array": "3.0.4" + } + }, + "node_modules/@prisma/client": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.0.1.tgz", + "integrity": "sha512-O74T6xcfaGAq5gXwCAvfTLvI6fmC3and2g5yLRMkNjri1K8mSpEgclDNuUWs9xj5AwNEMQ88NeD3asI+sovm1g==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/client-runtime-utils": "7.0.1" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24.0" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/client-runtime-utils": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.0.1.tgz", + "integrity": "sha512-R26BVX9D/iw4toUmZKZf3jniM/9pMGHHdZN5LVP2L7HNiCQKNQQx/9LuMtjepbgRqSqQO3oHN0yzojHLnKTGEw==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/debug": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.0.1.tgz", + "integrity": "sha512-5+25XokVeAK2Z2C9W457AFw7Hk032Q3QI3G58KYKXPlpgxy+9FvV1+S1jqfJ2d4Nmq9LP/uACrM6OVhpJMSr8w==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/driver-adapter-utils": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.0.1.tgz", + "integrity": "sha512-sBbxm/yysHLLF2iMAB+qcX/nn3WFgsiC4DQNz0uM6BwGSIs8lIvgo0u8nR9nxe5gvFgKiIH8f4z2fgOEMeXc8w==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.0.1" + } + }, + "node_modules/pg": { + "version": "8.16.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", + "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.9.1", + "pg-pool": "^3.10.1", + "pg-protocol": "^1.10.3", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.2.7" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz", + "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz", + "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz", + "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz", + "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-types/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/postgres-array": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz", + "integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/layers/prisma/nodejs/package.json b/layers/prisma/nodejs/package.json new file mode 100644 index 0000000..47d0046 --- /dev/null +++ b/layers/prisma/nodejs/package.json @@ -0,0 +1,10 @@ +{ + "name": "prisma-layer", + "version": "1.0.0", + "description": "Lambda layer for Prisma 7 with pg driver adapter", + "dependencies": { + "@prisma/client": "^7.0.1", + "@prisma/adapter-pg": "^7.0.1", + "pg": "^8.13.0" + } +} diff --git a/package.json b/package.json index 12e888a..e921a89 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,9 @@ "prisma:migrate": "prisma migrate dev", "prisma:studio": "prisma studio", "prisma:seed": "ts-node prisma/seed.ts", - "seeder": "tsx prisma/seed.ts" + "seeder": "tsx prisma/seed.ts", + "build:layer": "powershell -ExecutionPolicy Bypass -File ./build-prisma-layer.ps1", + "build:layer:unix": "chmod +x ./build-prisma-layer.sh && ./build-prisma-layer.sh" }, "dependencies": { "@aws-crypto/crc32c": "^5.2.0", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4d713bf..bc20abd 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,7 +1,7 @@ generator client { - provider = "prisma-client-js" - binaryTargets = ["native", "rhel-openssl-3.0.x"] // Add Linux target - previewFeatures = ["multiSchema"] + provider = "prisma-client-js" + // No binaryTargets or previewFeatures needed - Prisma 7 uses JS-based driver adapters (no native engines) + // multiSchema and driverAdapters are now stable features } datasource db { diff --git a/serverless.yml b/serverless.yml index 2e24c30..1ffa9f6 100644 --- a/serverless.yml +++ b/serverless.yml @@ -6,6 +6,9 @@ provider: region: ap-south-1 versionFunctions: false memorySize: 512 + # Apply Prisma layer to all functions + layers: + - !Ref PrismaLambdaLayer apiGateway: binaryMediaTypes: - '*/*' @@ -61,13 +64,26 @@ custom: platform: node concurrency: 5 external: + # These are provided by the Prisma layer - '@prisma/client' + - '@prisma/adapter-pg' - '.prisma' + - 'pg' exclude: - 'aws-sdk' serverless-offline: reloadHandler: true +# Define layers +layers: + prisma: + path: layers/prisma + name: ${self:service}-prisma-layer-${sls:stage} + description: Prisma 7 client with pg driver adapter (no binary engines) + compatibleRuntimes: + - nodejs22.x + retain: false + package: individually: true patterns: diff --git a/serverless/patterns/base.yml b/serverless/patterns/base.yml index 1fce4e7..9d4722d 100644 --- a/serverless/patterns/base.yml +++ b/serverless/patterns/base.yml @@ -1,6 +1,8 @@ # Base packaging patterns shared across all functions +# Note: Prisma 7 uses driver adapters (no binary engines) - everything is in the layer pattern1: 'src/common/**' pattern2: 'common/**' -pattern3: 'node_modules/@prisma/client/**' -pattern4: 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' -pattern5: '!node_modules/.prisma/client/libquery_engine*' \ No newline at end of file +# Prisma packages are now provided by the layer, no need to include in function package +pattern3: '!node_modules/@prisma/**' +pattern4: '!node_modules/.prisma/**' +pattern5: '!node_modules/pg/**' \ No newline at end of file