Merge branch 'dev' into alpha

This commit is contained in:
Stephanos A.
2026-05-22 18:19:36 +03:00
committed by GitHub
19 changed files with 9102 additions and 1042 deletions

7
.dockerignore Normal file
View File

@@ -0,0 +1,7 @@
**/node_modules
**/dist
**/.github
**/.vscode
**/.git
**/.env
.env

96
.github/workflows/deploy.yaml vendored Normal file
View File

@@ -0,0 +1,96 @@
name: Automatic Deployment
on:
push:
branches:
- dev
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
environment:
name: 🌍 Setup Environment
runs-on: [self-hosted]
outputs:
target: ${{ steps.dev.outputs.target || steps.staging.outputs.target }}
steps:
- name: Verify NPM Token
env:
# We map the secret here to check its existence
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
if [ -z "$NPM_TOKEN" ]; then
echo "::error::The NPM_TOKEN secret is missing or empty. Please add it to your GitHub Secrets."
exit 1
fi
echo "NPM_TOKEN is present, proceeding with build..."
- name: 🛠️ Set Development Environment
id: dev
if: ${{github.ref_name == 'dev'}}
run: |
echo "target=dev" >> $GITHUB_OUTPUT
- name: 🚀 Set Staging Environment
id: staging
if: ${{github.ref_name == 'staging'}}
run: |
echo "target=staging" >> $GITHUB_OUTPUT
build-base-image:
name: 🏗️ Build Base Image
runs-on: [self-hosted, dev]
needs: [environment]
steps:
- name: 🔍 Checkout
uses: actions/checkout@v4
- name: 🐳 Build Docker Image
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
# Create the multi-line file
cat <<EOF > .npmrc_temp
@tria-plc:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
always-auth=true
EOF
# Build using the file
docker build --secret id=npmrc,src=.npmrc_temp -t edr-${{needs.environment.outputs.target}} .
docker build --secret id=npmrc,src=.npmrc_temp --target passenger-migration -t edr-passenger-migration-${{needs.environment.outputs.target}} .
# Shred/Remove the sensitive file
rm .npmrc_temp
deploy-service:
name: ${{ matrix.display_name }}
runs-on: [self-hosted, dev]
needs: [build-base-image, environment]
strategy:
fail-fast: false
matrix:
include:
- service: freight-api
env_file: .env.freight-api
display_name: 🚚 Deploy Freight API Service
- service: passenger-api
env_file: .env.passenger-api
display_name: 🧑‍🦲 Deploy Passenger API Service
steps:
- name: 🔍 Checkout
uses: actions/checkout@v4
- name: 📋 Copy ${{ matrix.service }} Environment
run: cp ~/environment/edr/${{needs.environment.outputs.target}}/${{ matrix.env_file }} .env
- name: 🧪 Run Passenger API migrations
if: ${{ matrix.service == 'passenger-api' }}
run: |
docker run --rm --env-file .env edr-passenger-migration-${{needs.environment.outputs.target}}
- name: 🚀 Start ${{ matrix.service }} Service
run: docker compose --project-name="edr-${{needs.environment.outputs.target}}" up -d --force-recreate ${{ matrix.service }} --build

1
.gitignore vendored
View File

@@ -22,3 +22,4 @@ coverage/
.DS_Store
.idea/
.vscode/
.npmrc

84
Dockerfile Normal file
View File

@@ -0,0 +1,84 @@
FROM node:24.15.0 AS base
RUN corepack enable && corepack prepare pnpm@latest-11 --activate
WORKDIR /app
FROM base AS deps
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY apps/edr-freight-api/package.json ./apps/edr-freight-api/
COPY apps/edr-passenger-api/package.json ./apps/edr-passenger-api/
COPY apps/edr-freight-web/backoffice/package.json ./apps/edr-freight-web/backoffice/
COPY apps/edr-freight-web/portal/package.json ./apps/edr-freight-web/portal/
COPY apps/edr-passenger-web/backoffice/package.json ./apps/edr-passenger-web/backoffice/
COPY apps/edr-passenger-web/portal/package.json ./apps/edr-passenger-web/portal/
COPY packages/api-common/package.json packages/api-common/
COPY packages/config/eslint-config/package.json packages/config/eslint-config/
COPY packages/config/prettier-config/package.json packages/config/prettier-config/
COPY packages/config/tsconfig/package.json packages/config/tsconfig/
COPY packages/types/package.json packages/types/
COPY packages/ui-common/package.json packages/ui-common/
RUN --mount=type=cache,id=pnpm,target=/pnpm/store\
--mount=type=secret,id=npmrc,target=./.npmrc \
pnpm install --frozen-lockfile
FROM deps AS build
COPY . .
RUN pnpm run build
FROM base AS freight-api
# RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app/apps/edr-freight-api
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./../../node_modules
COPY --from=deps /app/apps/edr-freight-api/node_modules ./node_modules
COPY --from=build /app/apps/edr-freight-api/dist ./dist
COPY --from=build /app/apps/edr-freight-api/package.json ./package.json
COPY --from=build /app/packages ./../../packages
EXPOSE 3001
CMD ["node", "dist/main.js"]
FROM base AS passenger-api
RUN apt-get update -y && apt-get install -y openssl
# RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app/apps/edr-passenger-api
ENV NODE_ENV=production
# Use build-stage node_modules (not deps): `pnpm run build` runs `prisma generate`, which
# writes the real @prisma/client (enums, types). deps never runs generate, so @IsEnum(ServiceClass)
# and similar would see undefined at runtime if we copied deps only.
COPY --from=build /app/node_modules ./../../node_modules
COPY --from=build /app/apps/edr-passenger-api/node_modules ./node_modules
COPY --from=build /app/apps/edr-passenger-api/dist ./dist
COPY --from=build /app/apps/edr-passenger-api/package.json ./package.json
COPY --from=build /app/packages ./../../packages
EXPOSE 3001
CMD ["node", "dist/main.js"]
FROM build as passenger-migration
WORKDIR /app/apps/edr-passenger-api
CMD pnpm run prisma:migrate && pnpm run prisma:seed
FROM nginx:1.27-alpine AS freight-web-portal
COPY --from=build /app/apps/edr-freight-web/portal/dist /usr/share/nginx/html
EXPOSE 5173
CMD ["nginx", "-g", "daemon off;"]
FROM nginx:1.27-alpine AS freight-web-backoffice
COPY --from=build /app/apps/edr-freight-web/backoffice/dist /usr/share/nginx/html
EXPOSE 5173
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,26 +0,0 @@
FROM node:20-alpine AS base
RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app
FROM base AS deps
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY apps/edr-freight-api/package.json ./apps/edr-freight-api/
COPY packages ./packages
RUN pnpm install --frozen-lockfile --filter @edr/freight-api...
FROM deps AS build
COPY apps/edr-freight-api ./apps/edr-freight-api
RUN pnpm --filter @edr/freight-api build
FROM node:20-alpine AS runtime
RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app/apps/edr-freight-api
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./../../node_modules
COPY --from=deps /app/apps/edr-freight-api/node_modules ./node_modules
COPY --from=build /app/apps/edr-freight-api/dist ./dist
COPY --from=build /app/apps/edr-freight-api/package.json ./package.json
EXPOSE 3001
CMD ["node", "dist/main.js"]

View File

@@ -1,18 +0,0 @@
FROM node:20-alpine AS base
RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app
FROM base AS deps
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY apps/edr-freight-web/backoffice/package.json ./apps/edr-freight-web/backoffice/
COPY packages ./packages
RUN pnpm install --frozen-lockfile --filter @edr/freight-backoffice...
FROM deps AS build
COPY apps/edr-freight-web/backoffice ./apps/edr-freight-web/backoffice
RUN pnpm --filter @edr/freight-backoffice build
FROM nginx:1.27-alpine AS runtime
COPY --from=build /app/apps/edr-freight-web/backoffice/dist /usr/share/nginx/html
EXPOSE 5183
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,18 +0,0 @@
FROM node:20-alpine AS base
RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app
FROM base AS deps
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY apps/edr-freight-web/portal/package.json ./apps/edr-freight-web/portal/
COPY packages ./packages
RUN pnpm install --frozen-lockfile --filter @edr/freight-portal...
FROM deps AS build
COPY apps/edr-freight-web/portal ./apps/edr-freight-web/portal
RUN pnpm --filter @edr/freight-portal build
FROM nginx:1.27-alpine AS runtime
COPY --from=build /app/apps/edr-freight-web/portal/dist /usr/share/nginx/html
EXPOSE 5173
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,28 +0,0 @@
FROM node:20-alpine AS base
RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app
FROM base AS deps
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY apps/edr-passenger-api/package.json ./apps/edr-passenger-api/
COPY packages ./packages
RUN pnpm install --frozen-lockfile --filter @edr/passenger-api...
FROM deps AS build
COPY apps/edr-passenger-api ./apps/edr-passenger-api
RUN pnpm --filter @edr/passenger-api run prisma:generate
RUN pnpm --filter @edr/passenger-api build
FROM node:20-alpine AS runtime
RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app/apps/edr-passenger-api
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./../../node_modules
COPY --from=deps /app/apps/edr-passenger-api/node_modules ./node_modules
COPY --from=build /app/apps/edr-passenger-api/dist ./dist
COPY --from=build /app/apps/edr-passenger-api/package.json ./package.json
COPY --from=build /app/apps/edr-passenger-api/prisma ./prisma
EXPOSE 4000
CMD ["node", "dist/main.js"]

View File

@@ -1,7 +1,9 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true,
"plugins": ["@nestjs/swagger"],
"tsConfigPath": "tsconfig.build.json",
"watchAssets": true

View File

@@ -4,7 +4,7 @@
"private": true,
"scripts": {
"dev": "nest start --watch",
"build": "nest build",
"build": "prisma generate && nest build",
"start": "node dist/main.js",
"start:prod": "node dist/main.js",
"lint": "eslint src",

View File

@@ -1,19 +1,18 @@
import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
import { ResponseTransformInterceptor } from './common/interceptors/response-transform.interceptor';
import { SessionActivityInterceptor } from './common/interceptors/session-activity.interceptor';
import "reflect-metadata";
import { NestFactory } from "@nestjs/core";
import { ValidationPipe } from "@nestjs/common";
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
import { AppModule } from "./app.module";
import { HttpExceptionFilter } from "./common/filters/http-exception.filter";
import { ResponseTransformInterceptor } from "./common/interceptors/response-transform.interceptor";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
origin: [
process.env.FRONTEND_URL ?? 'http://localhost:3000',
process.env.PORTAL_URL ?? 'http://localhost:3001',
process.env.FRONTEND_URL ?? "http://localhost:3000",
process.env.PORTAL_URL ?? "http://localhost:3001",
],
});
@@ -25,196 +24,43 @@ async function bootstrap() {
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
const config = new DocumentBuilder()
.setTitle('EDR Passenger API')
.setTitle("EDR Passenger API")
.setDescription(
`# Ethio-Djibouti Railway Passenger Booking API
## Overview
Enterprise-grade REST API for the Ethio-Djibouti Railway passenger booking and management platform. Built with NestJS, TypeScript, PostgreSQL, and Prisma ORM.
## Authentication
### Passenger Authentication (JWT-auth)
Used for passenger-facing endpoints. Obtain token via \`POST /auth/login\`.
**Usage:** Add header \`Authorization: Bearer <token>\`
### Back-office Authentication (IAM-auth)
Used for agent, fraud, and reporting endpoints. Requires corporate IAM token.
**Usage:** Add header \`Authorization: Bearer <iam-token>\`
## Key Features
### 🎫 Booking Lifecycle
- Search trips with real-time availability
- Create bookings with seat selection
- Modify bookings (seat changes, passenger updates)
- Cancel bookings with automatic refunds
- Multi-segment journey support
### 💳 Payment Integration
- **Telebirr** - Ethiopia's leading mobile money
- **CBE Birr** - Commercial Bank of Ethiopia
- **eBirr** - Electronic payment gateway
- **Card** - International card payments
- **Wallet** - Internal wallet system
### 🪑 Seat Management
- Real-time seat availability
- Seat holds (15-minute expiry)
- Auto-assign seats with contiguous algorithm
- Seat blocking for maintenance
- Coach-level seat maps
### 🎟️ Ticketing
- QR code and barcode generation
- PDF ticket generation
- Gate validation with audit logs
- Offline validation support
### 🏆 Loyalty Program
- 4 tiers: Bronze, Silver, Gold, Platinum
- Points accumulation on trips
- Reward redemption
- Tier-based benefits
### 💰 Wallet System
- Top-up via payment methods
- Pay with wallet balance
- Transaction ledger
- Refund to wallet
### 📍 Live Tracking
- Real-time trip status
- Location updates
- Delay notifications
- Station crowd signals
### 🔒 Fraud Detection
- Velocity checks (multiple bookings)
- High-value transaction monitoring
- Failed payment pattern detection
- Automatic user blocking
### 🌍 Internationalization
- Multi-language support (English, Amharic, French, Oromo)
- Locale-based responses
- Currency formatting
### 👨‍💼 Agent Operations
- Counter booking
- Shift management
- Commission tracking
- Cash reconciliation
## Rate Limiting
- Auth endpoints: 5 requests/minute
- General endpoints: 100 requests/minute
- Webhook endpoints: No limit
## Error Handling
All errors follow standard format:
\`\`\`json
{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request",
"timestamp": "2026-05-20T14:30:00.000Z",
"path": "/bookings"
}
\`\`\`
## Pagination
List endpoints support pagination:
- \`limit\`: Number of items (default: 20, max: 100)
- \`offset\`: Skip items (default: 0)
## Webhooks
Payment providers send notifications to:
- \`POST /payments/webhooks/telebirr\`
- \`POST /payments/webhooks/cbe-birr\`
- \`POST /payments/webhooks/ebirr\`
- \`POST /payments/webhooks/card\`
## Support
- **Email:** support@edr-platform.com
- **Documentation:** https://docs.edr-platform.com
- **Status Page:** https://status.edr-platform.com
`,
"Ethio-Djibouti Railway Passenger API — booking lifecycle, seat inventory, payment (Telebirr, CBE Birr, eBirr, Card, Wallet), loyalty, live tracking, and support.",
)
.setVersion('1.0.0')
.setVersion("1.0.0")
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
in: 'header',
description: 'JWT token for passenger authentication. Obtain via POST /auth/login'
},
'JWT-auth'
{ type: "http", scheme: "bearer", bearerFormat: "JWT", in: "header" },
"JWT-auth",
)
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
in: 'header',
description: 'Corporate IAM token for back-office operations (agents, fraud, reports)'
},
'IAM-auth'
)
.addTag('Auth', '🔐 Registration, login, OTP verification, password reset')
.addTag('Agents', '👨‍💼 Agent booking, shifts, commissions, reconciliation')
.addTag('Booking', '🎫 Booking lifecycle, modification, cancellation, refunds')
.addTag('Dashboard', '📊 Home dashboard aggregated data')
.addTag('Fleet', '🚂 Trains, physical coaches, seat auto-generation, coach-to-schedule assignments')
.addTag('Seat Classes', '🎨 Seat class management and configuration')
.addTag('Fraud Detection', '🔒 Fraud detection, risk scoring, user blocking')
.addTag('Live Tracking', '📍 Real-time trip status, location updates, crowd signals')
.addTag('Loyalty', '🏆 Points accumulation, tier management, rewards redemption')
.addTag('Notifications', '🔔 Push, email, SMS notifications, preferences')
.addTag('Passenger', '👤 Profiles, traveler profiles, saved routes, preferences')
.addTag('Payment', '💳 Payment intents, status queries, refunds')
.addTag('Payment Webhooks', '🔗 Payment provider callback endpoints')
.addTag('Promotions', '🎁 Promo codes, campaigns, discount validation')
.addTag('Reports', '📈 Revenue reports, occupancy analytics, agent sales')
.addTag('Routes', '🗺️ Reusable route templates with ordered stops — referenced by schedules')
.addTag('Schedule', '🗓️ Train schedules (created from routes), stop time management, fare rules')
.addTag('Search', '🔍 Trip search, availability, fare quotes')
.addTag('Seats', '🪑 Seat maps, holds, releases, blocking, auto-assign')
.addTag('Segment-based Seats', '🎯 Segment-based seat availability and booking')
.addTag('Stations', '🚉 Station directory, information, crowd signals')
.addTag('Support', '💬 FAQ management, live chat conversations')
.addTag('Tickets', '🎟️ QR/barcode generation, PDF tickets, gate validation')
.addTag('Wallet', '💰 Wallet balance, top-up, transaction ledger')
.addServer('http://localhost:4000', 'Local Development')
.addServer('https://api-staging.edr-platform.com', 'Staging Environment')
.addServer('https://api.edr-platform.com', 'Production')
.addTag("Auth", "Registration and login")
.addTag("Stations", "Station directory")
.addTag("Fleet", "Train services and coaches")
.addTag("Schedule", "Trips and fare rules")
.addTag("Search", "Trip search and fare quotes")
.addTag("Seats", "Seat maps and holds")
.addTag("Booking", "Booking lifecycle")
.addTag("Payment", "Payment intents and refunds")
.addTag("Tickets", "QR ticket generation and validation")
.addTag("Passenger", "Profiles, traveler profiles, saved routes")
.addTag("Notifications", "Push and email notifications")
.addTag("Loyalty", "Points, tiers, and rewards")
.addTag("Wallet", "Wallet balance and ledger")
.addTag("Promotions", "Promo codes and campaigns")
.addTag("Live Tracking", "Real-time trip status and crowd signals")
.addTag("Support", "FAQ and chat support")
.addTag("Dashboard", "Home dashboard aggregate")
//.addServer('http://localhost:4000', 'Development')
// .addServer("https://api.edr-platform.com", "Production")
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api-docs', app, document, {
customSiteTitle: 'EDR Passenger API Documentation',
customfavIcon: 'https://edr-platform.com/favicon.ico',
customCss: `
.swagger-ui .topbar { display: none }
.swagger-ui .info { margin: 20px 0 }
.swagger-ui .info .title { font-size: 36px; font-weight: bold }
.swagger-ui .scheme-container { background: #fafafa; padding: 15px; border-radius: 4px }
`,
SwaggerModule.setup("api-docs", app, document, {
customSiteTitle: "EDR Passenger API",
swaggerOptions: {
persistAuthorization: true,
docExpansion: 'none',
docExpansion: "none",
filter: true,
tagsSorter: 'alpha',
operationsSorter: 'alpha',
displayRequestDuration: true,
tryItOutEnabled: true,
syntaxHighlight: {
activate: true,
theme: 'monokai'
}
},
});

View File

@@ -1,18 +0,0 @@
FROM node:20-alpine AS base
RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app
FROM base AS deps
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY apps/edr-passenger-web/backoffice/package.json ./apps/edr-passenger-web/backoffice/
COPY packages ./packages
RUN pnpm install --frozen-lockfile --filter @edr/passenger-backoffice...
FROM deps AS build
COPY apps/edr-passenger-web/backoffice ./apps/edr-passenger-web/backoffice
RUN pnpm --filter @edr/passenger-backoffice build
FROM nginx:1.27-alpine AS runtime
COPY --from=build /app/apps/edr-passenger-web/backoffice/dist /usr/share/nginx/html
EXPOSE 5184
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,18 +0,0 @@
FROM node:20-alpine AS base
RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
WORKDIR /app
FROM base AS deps
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY apps/edr-passenger-web/portal/package.json ./apps/edr-passenger-web/portal/
COPY packages ./packages
RUN pnpm install --frozen-lockfile --filter @edr/passenger-portal...
FROM deps AS build
COPY apps/edr-passenger-web/portal ./apps/edr-passenger-web/portal
RUN pnpm --filter @edr/passenger-portal build
FROM nginx:1.27-alpine AS runtime
COPY --from=build /app/apps/edr-passenger-web/portal/dist /usr/share/nginx/html
EXPOSE 5174
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -7,8 +7,8 @@ export default defineConfig({
port: 5184,
host: "0.0.0.0",
},
test: {
environment: "jsdom",
globals: true,
},
// test: {
// environment: "jsdom",
// globals: true,
// },
});

View File

@@ -7,8 +7,8 @@ export default defineConfig({
port: 5174,
host: "0.0.0.0",
},
test: {
environment: "jsdom",
globals: true,
},
// test: {
// environment: "jsdom",
// globals: true,
// },
});

21
docker-compose.yaml Normal file
View File

@@ -0,0 +1,21 @@
services:
freight-api:
build:
context: .
dockerfile: ./Dockerfile
target: freight-api
env_file:
- .env
ports:
- ${PORT}:${PORT}
restart: unless-stopped
passenger-api:
build:
context: .
dockerfile: ./Dockerfile
target: passenger-api
env_file:
- .env
ports:
- ${PORT}:${PORT}
restart: unless-stopped

View File

@@ -42,7 +42,7 @@
"prettier --write"
]
},
"packageManager": "pnpm@9.12.0",
"packageManager": "pnpm@11.1.1+sha512.d1fdf5f73c617b64fa1a56a81c3c8dfe0e966e33a6010aa256b517ae77be21d93e05affc0de1a83b0e4f29d569f68b446ae8f068cd7247c0bb3df0fb4d7bdf9a",
"engines": {
"node": ">=20"
}

9537
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,21 @@
packages:
- "apps/edr-freight-api"
- "apps/edr-freight-web/*"
- "apps/edr-passenger-api"
- "apps/edr-passenger-web/*"
- "packages/*"
- "packages/config/*"
allowBuilds:
'@nestjs/core': true
'@prisma/client': true
'@prisma/engines': true
'@scarf/scarf': true
argon2: true
bcrypt: true
core-js: true
es5-ext: true
esbuild: true
highlight.js: true
prisma: true
tesseract.js: true
uglifyjs-webpack-plugin: true