diff --git a/.gitignore b/.gitignore index 46ae420..6ac105e 100644 --- a/.gitignore +++ b/.gitignore @@ -58,4 +58,9 @@ pids # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json -config.dev \ No newline at end of file +config.dev +cdk.out +backend-cdk-new.out +web-cdk.out +backend-cdk.out + diff --git a/Dockerfile b/Dockerfile index 4be2071..b1f3b5a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,28 @@ -FROM node:20-alpine +FROM --platform=linux/amd64 node:20-alpine + +# curl for health checks +RUN apk add --no-cache curl WORKDIR /app + COPY package*.json ./ -RUN npm install -RUN npm install -g @nestjs/cli +RUN npm install --production --ignore-scripts COPY . . RUN npm run build -EXPOSE 4000 +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nestjs -u 1001 -CMD ["npm", "run", "start"] +RUN chown -R nestjs:nodejs /app +USER nestjs + +EXPOSE 3000 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3000/health || exit 1 + +CMD ["npm", "run", "start:prod"] diff --git a/cdk.context.json b/cdk.context.json new file mode 100644 index 0000000..2f75a86 --- /dev/null +++ b/cdk.context.json @@ -0,0 +1,16 @@ +{ + "availability-zones:account=426265406140:region=us-east-2": [ + "us-east-2a", + "us-east-2b", + "us-east-2c" + ], + "availability-zones:account=482311766496:region=us-east-2": [ + "us-east-2a", + "us-east-2b", + "us-east-2c" + ], + "hosted-zone:account=482311766496:domainName=syncrow.me:region=us-east-2": { + "Id": "/hostedzone/Z02085662NLJECF4DGJV3", + "Name": "syncrow.me." + } +} diff --git a/cdk.json b/cdk.json new file mode 100644 index 0000000..907507f --- /dev/null +++ b/cdk.json @@ -0,0 +1,58 @@ +{ + "app": "npx ts-node --prefer-ts-exts infrastructure/app.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-iam:standardizedServicePrincipals": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableLogging": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, + "@aws-cdk/aws-kms:aliasNameRef": true, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForSourceAction": true + } +} diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..a777919 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) +REGION=${AWS_DEFAULT_REGION:-us-east-2} + +echo "Deploying to account: $ACCOUNT_ID in region: $REGION" + +aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com + +docker build --platform=linux/amd64 -t syncrow-backend . +docker tag syncrow-backend:latest $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/syncrow-backend:latest +docker push $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/syncrow-backend:latest + +npx cdk deploy SyncrowBackendStack --require-approval never + +aws ecs update-service --cluster syncrow-backend-cluster --service $(aws ecs list-services --cluster syncrow-backend-cluster --query 'serviceArns[0]' --output text | cut -d'/' -f3) --force-new-deployment diff --git a/infrastructure/app.ts b/infrastructure/app.ts new file mode 100644 index 0000000..a5ee666 --- /dev/null +++ b/infrastructure/app.ts @@ -0,0 +1,15 @@ +#!/usr/bin/env node +import 'source-map-support/register'; +import * as cdk from 'aws-cdk-lib'; +import { BackendStack } from './stack'; + +const app = new cdk.App(); + +new BackendStack(app, 'SyncrowBackendStack', { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_DEFAULT_REGION, + }, + databaseName: 'syncrow', + certificateArn: app.node.tryGetContext('certificateArn'), +}); diff --git a/infrastructure/stack.ts b/infrastructure/stack.ts new file mode 100644 index 0000000..ab35fee --- /dev/null +++ b/infrastructure/stack.ts @@ -0,0 +1,330 @@ +import * as cdk from 'aws-cdk-lib'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as ecsPatterns from 'aws-cdk-lib/aws-ecs-patterns'; +import * as rds from 'aws-cdk-lib/aws-rds'; +import * as ecr from 'aws-cdk-lib/aws-ecr'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2'; +import * as acm from 'aws-cdk-lib/aws-certificatemanager'; +import * as route53 from 'aws-cdk-lib/aws-route53'; +import { Construct } from 'constructs'; +import * as dotenv from 'dotenv'; + +export interface BackendStackProps extends cdk.StackProps { + vpcId?: string; + databaseName?: string; + certificateArn?: string; +} + +export class BackendStack extends cdk.Stack { + public readonly apiUrl: string; + public readonly databaseEndpoint: string; + public readonly vpc: ec2.IVpc; + + constructor(scope: Construct, id: string, props?: BackendStackProps) { + super(scope, id, props); + + // Load environment variables from .env file + dotenv.config({ path: '.env' }); + + // VPC - either use existing or create new + this.vpc = props?.vpcId + ? ec2.Vpc.fromLookup(this, 'ExistingVpc', { vpcId: props.vpcId }) + : new ec2.Vpc(this, 'SyncrowVpc', { + maxAzs: 2, + natGateways: 1, + subnetConfiguration: [ + { + cidrMask: 24, + name: 'public', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'private', + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], + }); + + // Security Groups + const dbSecurityGroup = new ec2.SecurityGroup(this, 'DatabaseSecurityGroup', { + vpc: this.vpc, + description: 'Security group for RDS PostgreSQL', + allowAllOutbound: false, + }); + + const ecsSecurityGroup = new ec2.SecurityGroup(this, 'EcsSecurityGroup', { + vpc: this.vpc, + description: 'Security group for ECS Fargate service', + allowAllOutbound: true, + }); + + const albSecurityGroup = new ec2.SecurityGroup(this, 'AlbSecurityGroup', { + vpc: this.vpc, + description: 'Security group for Application Load Balancer', + allowAllOutbound: true, + }); + + // Allow ALB to connect to ECS + ecsSecurityGroup.addIngressRule( + albSecurityGroup, + ec2.Port.tcp(3000), + 'Allow ALB to connect to ECS service' + ); + + // Allow ECS to connect to RDS + dbSecurityGroup.addIngressRule( + ecsSecurityGroup, + ec2.Port.tcp(5432), + 'Allow ECS to connect to PostgreSQL' + ); + + // Allow HTTP/HTTPS traffic to ALB + albSecurityGroup.addIngressRule( + ec2.Peer.anyIpv4(), + ec2.Port.tcp(80), + 'Allow HTTP traffic' + ); + albSecurityGroup.addIngressRule( + ec2.Peer.anyIpv4(), + ec2.Port.tcp(443), + 'Allow HTTPS traffic' + ); + + // RDS Aurora Serverless v2 PostgreSQL + const dbCluster = new rds.DatabaseCluster(this, 'SyncrowDatabase', { + engine: rds.DatabaseClusterEngine.auroraPostgres({ + version: rds.AuroraPostgresEngineVersion.VER_15_4, + }), + vpc: this.vpc, + securityGroups: [dbSecurityGroup], + serverlessV2MinCapacity: 0.5, + serverlessV2MaxCapacity: 4, + writer: rds.ClusterInstance.serverlessV2('writer'), + defaultDatabaseName: props?.databaseName || 'syncrow', + credentials: rds.Credentials.fromGeneratedSecret('syncrowadmin', { + secretName: 'syncrow-db-credentials', + }), + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + // ECR Repository for Docker images + const ecrRepository = new ecr.Repository(this, 'SyncrowBackendRepo', { + repositoryName: 'syncrow-backend', + removalPolicy: cdk.RemovalPolicy.DESTROY, + emptyOnDelete: true, + }); + + // ECS Cluster + const cluster = new ecs.Cluster(this, 'SyncrowCluster', { + vpc: this.vpc, + clusterName: 'syncrow-backend-cluster', + }); + + // CloudWatch Log Group + const logGroup = new logs.LogGroup(this, 'SyncrowBackendLogs', { + logGroupName: '/ecs/syncrow-backend', + retention: logs.RetentionDays.ONE_WEEK, + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + // Use existing wildcard certificate or create new one + const apiCertificate = props?.certificateArn + ? acm.Certificate.fromCertificateArn(this, 'ApiCertificate', props.certificateArn) + : new acm.Certificate(this, 'ApiCertificate', { + domainName: 'api.syncrow.me', + validation: acm.CertificateValidation.fromDns(), + }); + + // ECS Fargate Service with Application Load Balancer + const fargateService = new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'SyncrowBackendService', { + cluster, + memoryLimitMiB: 1024, + cpu: 512, + desiredCount: 1, + domainName: 'api.syncrow.me', + domainZone: route53.HostedZone.fromLookup(this, 'SyncrowZone', { + domainName: 'syncrow.me', + }), + certificate: apiCertificate, + protocol: elbv2.ApplicationProtocol.HTTPS, + redirectHTTP: true, + taskImageOptions: { + image: ecs.ContainerImage.fromEcrRepository(ecrRepository, 'latest'), + containerPort: 3000, + environment: { + // App settings + NODE_ENV: process.env.NODE_ENV || 'production', + PORT: process.env.PORT || '3000', + BASE_URL: process.env.BASE_URL || '', + + // Database connection (CDK provides these automatically) + AZURE_POSTGRESQL_HOST: dbCluster.clusterEndpoint.hostname, + AZURE_POSTGRESQL_PORT: '5432', + AZURE_POSTGRESQL_DATABASE: props?.databaseName || 'syncrow', + AZURE_POSTGRESQL_USER: 'syncrowadmin', + AZURE_POSTGRESQL_SSL: process.env.AZURE_POSTGRESQL_SSL || 'false', + AZURE_POSTGRESQL_SYNC: process.env.AZURE_POSTGRESQL_SYNC || 'false', + + // JWT Configuration - CRITICAL: These must be set + JWT_SECRET: process.env.JWT_SECRET || 'syncrow-jwt-secret-key-2025-production-environment-very-secure-random-string', + JWT_SECRET_REFRESH: process.env.JWT_SECRET_REFRESH || 'syncrow-refresh-secret-key-2025-production-environment-different-secure-string', + JWT_EXPIRE_TIME: process.env.JWT_EXPIRE_TIME || '1h', + JWT_EXPIRE_TIME_REFRESH: process.env.JWT_EXPIRE_TIME_REFRESH || '7d', + + // Firebase Configuration + FIREBASE_API_KEY: process.env.FIREBASE_API_KEY || '', + FIREBASE_AUTH_DOMAIN: process.env.FIREBASE_AUTH_DOMAIN || '', + FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID || '', + FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET || '', + FIREBASE_MESSAGING_SENDER_ID: process.env.FIREBASE_MESSAGING_SENDER_ID || '', + FIREBASE_APP_ID: process.env.FIREBASE_APP_ID || '', + FIREBASE_MEASUREMENT_ID: process.env.FIREBASE_MEASUREMENT_ID || '', + FIREBASE_DATABASE_URL: process.env.FIREBASE_DATABASE_URL || '', + + // Tuya IoT Configuration + TUYA_EU_URL: process.env.TUYA_EU_URL || 'https://openapi.tuyaeu.com', + TUYA_ACCESS_ID: process.env.TUYA_ACCESS_ID || '', + TUYA_ACCESS_KEY: process.env.TUYA_ACCESS_KEY || '', + TRUN_ON_TUYA_SOCKET: process.env.TRUN_ON_TUYA_SOCKET || '', + + // Email Configuration + SMTP_HOST: process.env.SMTP_HOST || '', + SMTP_PORT: process.env.SMTP_PORT || '587', + SMTP_SECURE: process.env.SMTP_SECURE || 'true', + SMTP_USER: process.env.SMTP_USER || '', + SMTP_PASSWORD: process.env.SMTP_PASSWORD || '', + + // Mailtrap Configuration + MAILTRAP_API_TOKEN: process.env.MAILTRAP_API_TOKEN || '', + MAILTRAP_INVITATION_TEMPLATE_UUID: process.env.MAILTRAP_INVITATION_TEMPLATE_UUID || '', + MAILTRAP_EDIT_USER_TEMPLATE_UUID: process.env.MAILTRAP_EDIT_USER_TEMPLATE_UUID || '', + MAILTRAP_DISABLE_TEMPLATE_UUID: process.env.MAILTRAP_DISABLE_TEMPLATE_UUID || '', + MAILTRAP_ENABLE_TEMPLATE_UUID: process.env.MAILTRAP_ENABLE_TEMPLATE_UUID || '', + MAILTRAP_DELETE_USER_TEMPLATE_UUID: process.env.MAILTRAP_DELETE_USER_TEMPLATE_UUID || '', + + // OneSignal Push Notifications + ONESIGNAL_APP_ID: process.env.ONESIGNAL_APP_ID || '', + ONESIGNAL_API_KEY: process.env.ONESIGNAL_API_KEY || '', + + // Admin Configuration + SUPER_ADMIN_EMAIL: process.env.SUPER_ADMIN_EMAIL || 'admin@yourdomain.com', + SUPER_ADMIN_PASSWORD: process.env.SUPER_ADMIN_PASSWORD || 'YourSecureAdminPassword123!', + + // Google OAuth + GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID || '', + GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET || '', + + // Other Configuration + OTP_LIMITER: process.env.OTP_LIMITER || '5', + SECRET_KEY: process.env.SECRET_KEY || 'another-random-secret-key-for-general-encryption', + ACCESS_KEY: process.env.ACCESS_KEY || '', + DB_SYNC: process.env.DB_SYNC || 'false', + + // Redis (if used) + AZURE_REDIS_CONNECTIONSTRING: process.env.AZURE_REDIS_CONNECTIONSTRING || '', + + // Docker Registry (for deployment) + DOCKER_REGISTRY_SERVER_URL: process.env.DOCKER_REGISTRY_SERVER_URL || '', + DOCKER_REGISTRY_SERVER_USERNAME: process.env.DOCKER_REGISTRY_SERVER_USERNAME || '', + DOCKER_REGISTRY_SERVER_PASSWORD: process.env.DOCKER_REGISTRY_SERVER_PASSWORD || '', + + // Doppler (if used for secrets management) + DOPPLER_PROJECT: process.env.DOPPLER_PROJECT || '', + DOPPLER_CONFIG: process.env.DOPPLER_CONFIG || '', + DOPPLER_ENVIRONMENT: process.env.DOPPLER_ENVIRONMENT || '', + + // Azure specific + WEBSITES_ENABLE_APP_SERVICE_STORAGE: process.env.WEBSITES_ENABLE_APP_SERVICE_STORAGE || 'false', + }, + secrets: { + AZURE_POSTGRESQL_PASSWORD: ecs.Secret.fromSecretsManager( + dbCluster.secret!, + 'password' + ), + }, + logDriver: ecs.LogDrivers.awsLogs({ + streamPrefix: 'syncrow-backend', + logGroup, + }), + }, + publicLoadBalancer: true, + securityGroups: [ecsSecurityGroup], + }); + + // Add security group to load balancer after creation + fargateService.loadBalancer.addSecurityGroup(albSecurityGroup); + + // Configure health check + fargateService.targetGroup.configureHealthCheck({ + path: '/health', + healthyHttpCodes: '200', + interval: cdk.Duration.seconds(30), + timeout: cdk.Duration.seconds(5), + healthyThresholdCount: 2, + unhealthyThresholdCount: 3, + }); + + // Auto Scaling + const scalableTarget = fargateService.service.autoScaleTaskCount({ + minCapacity: 1, + maxCapacity: 10, + }); + + scalableTarget.scaleOnCpuUtilization('CpuScaling', { + targetUtilizationPercent: 70, + scaleInCooldown: cdk.Duration.minutes(5), + scaleOutCooldown: cdk.Duration.minutes(2), + }); + + scalableTarget.scaleOnMemoryUtilization('MemoryScaling', { + targetUtilizationPercent: 80, + scaleInCooldown: cdk.Duration.minutes(5), + scaleOutCooldown: cdk.Duration.minutes(2), + }); + + // For now, let's update the web app to use HTTPS URL and handle the certificate warning + // In production, you'll add a proper SSL certificate for api.syncrow.ae + + // Grant ECS task access to RDS credentials + if (dbCluster.secret) { + dbCluster.secret.grantRead(fargateService.taskDefinition.taskRole); + } + + this.apiUrl = 'https://api.syncrow.me'; + this.databaseEndpoint = dbCluster.clusterEndpoint.hostname; + + // Outputs + new cdk.CfnOutput(this, 'ApiUrl', { + value: this.apiUrl, + description: 'Application Load Balancer URL', + exportName: `${this.stackName}-ApiUrl`, + }); + + new cdk.CfnOutput(this, 'DatabaseEndpoint', { + value: this.databaseEndpoint, + description: 'RDS Cluster Endpoint', + exportName: `${this.stackName}-DatabaseEndpoint`, + }); + + new cdk.CfnOutput(this, 'EcrRepositoryUri', { + value: ecrRepository.repositoryUri, + description: 'ECR Repository URI', + exportName: `${this.stackName}-EcrRepositoryUri`, + }); + + new cdk.CfnOutput(this, 'ClusterName', { + value: cluster.clusterName, + description: 'ECS Cluster Name', + exportName: `${this.stackName}-ClusterName`, + }); + + new cdk.CfnOutput(this, 'ServiceName', { + value: fargateService.service.serviceName, + description: 'ECS Service Name', + exportName: `${this.stackName}-ServiceName`, + }); + } +} diff --git a/libs/common/src/firebase/devices-status/services/devices-status.service.ts b/libs/common/src/firebase/devices-status/services/devices-status.service.ts index 4f11f89..440ff21 100644 --- a/libs/common/src/firebase/devices-status/services/devices-status.service.ts +++ b/libs/common/src/firebase/devices-status/services/devices-status.service.ts @@ -48,7 +48,12 @@ export class DeviceStatusFirebaseService { }); // Initialize firebaseDb using firebaseDataBase function - this.firebaseDb = firebaseDataBase(this.configService); + try { + this.firebaseDb = firebaseDataBase(this.configService); + } catch (error) { + console.warn('Firebase initialization failed, continuing without Firebase:', error.message); + this.firebaseDb = null; + } this.isDevEnv = this.configService.get('NODE_ENV') === 'development'; } @@ -170,6 +175,14 @@ export class DeviceStatusFirebaseService { async createDeviceStatusFirebase( addDeviceStatusDto: AddDeviceStatusDto, ): Promise { + // Check if Firebase is available + if (!this.firebaseDb) { + console.warn('Firebase not available, skipping Firebase operations'); + // Still process the database logs but skip Firebase operations + await this.processDeviceStatusLogs(addDeviceStatusDto); + return { message: 'Device status processed without Firebase' }; + } + const dataRef = ref( this.firebaseDb, `device-status/${addDeviceStatusDto.deviceUuid}`, @@ -339,4 +352,127 @@ export class DeviceStatusFirebaseService { const snapshot: DataSnapshot = await get(dataRef); return snapshot.val(); } + + private async processDeviceStatusLogs(addDeviceStatusDto: AddDeviceStatusDto): Promise { + if (this.isDevEnv) { + // Save logs to your repository + const newLogs = addDeviceStatusDto.log.properties.map((property) => { + return this.deviceStatusLogRepository.create({ + deviceId: addDeviceStatusDto.deviceUuid, + deviceTuyaId: addDeviceStatusDto.deviceTuyaUuid, + productId: addDeviceStatusDto.log.productId, + log: addDeviceStatusDto.log, + code: property.code, + value: property.value, + eventId: addDeviceStatusDto.log.dataId, + eventTime: new Date(property.time).toISOString(), + }); + }); + await this.deviceStatusLogRepository.save(newLogs); + + if (addDeviceStatusDto.productType === ProductType.PC) { + const energyCodes = new Set([ + PowerClampEnergyEnum.ENERGY_CONSUMED, + PowerClampEnergyEnum.ENERGY_CONSUMED_A, + PowerClampEnergyEnum.ENERGY_CONSUMED_B, + PowerClampEnergyEnum.ENERGY_CONSUMED_C, + ]); + + const energyStatus = addDeviceStatusDto?.log?.properties?.find( + (status) => energyCodes.has(status.code), + ); + + if (energyStatus) { + await this.powerClampService.updateEnergyConsumedHistoricalData( + addDeviceStatusDto.deviceUuid, + ); + } + } + + if ( + addDeviceStatusDto.productType === ProductType.CPS || + addDeviceStatusDto.productType === ProductType.WPS + ) { + const occupancyCodes = new Set([PresenceSensorEnum.PRESENCE_STATE]); + + const occupancyStatus = addDeviceStatusDto?.log?.properties?.find( + (status) => occupancyCodes.has(status.code), + ); + + if (occupancyStatus) { + await this.occupancyService.updateOccupancySensorHistoricalData( + addDeviceStatusDto.deviceUuid, + ); + await this.occupancyService.updateOccupancySensorHistoricalDurationData( + addDeviceStatusDto.deviceUuid, + ); + } + } + if (addDeviceStatusDto.productType === ProductType.AQI) { + await this.aqiDataService.updateAQISensorHistoricalData( + addDeviceStatusDto.deviceUuid, + ); + } + } else { + // Save logs to your repository + const newLogs = addDeviceStatusDto?.status.map((property) => { + return this.deviceStatusLogRepository.create({ + deviceId: addDeviceStatusDto.deviceUuid, + deviceTuyaId: addDeviceStatusDto.deviceTuyaUuid, + productId: addDeviceStatusDto.log.productKey, + log: addDeviceStatusDto.log, + code: property.code, + value: property.value, + eventId: addDeviceStatusDto.log.dataId, + eventTime: new Date(property.t).toISOString(), + }); + }); + await this.deviceStatusLogRepository.save(newLogs); + + if (addDeviceStatusDto.productType === ProductType.PC) { + const energyCodes = new Set([ + PowerClampEnergyEnum.ENERGY_CONSUMED, + PowerClampEnergyEnum.ENERGY_CONSUMED_A, + PowerClampEnergyEnum.ENERGY_CONSUMED_B, + PowerClampEnergyEnum.ENERGY_CONSUMED_C, + ]); + + const energyStatus = addDeviceStatusDto?.status?.find((status) => { + return energyCodes.has(status.code as PowerClampEnergyEnum); + }); + + if (energyStatus) { + await this.powerClampService.updateEnergyConsumedHistoricalData( + addDeviceStatusDto.deviceUuid, + ); + } + } + + if ( + addDeviceStatusDto.productType === ProductType.CPS || + addDeviceStatusDto.productType === ProductType.WPS + ) { + const occupancyCodes = new Set([PresenceSensorEnum.PRESENCE_STATE]); + + const occupancyStatus = addDeviceStatusDto?.status?.find((status) => { + return occupancyCodes.has(status.code as PresenceSensorEnum); + }); + + if (occupancyStatus) { + await this.occupancyService.updateOccupancySensorHistoricalData( + addDeviceStatusDto.deviceUuid, + ); + await this.occupancyService.updateOccupancySensorHistoricalDurationData( + addDeviceStatusDto.deviceUuid, + ); + } + } + + if (addDeviceStatusDto.productType === ProductType.AQI) { + await this.aqiDataService.updateAQISensorHistoricalData( + addDeviceStatusDto.deviceUuid, + ); + } + } + } } diff --git a/libs/common/src/firebase/firebase.config.ts b/libs/common/src/firebase/firebase.config.ts index e34b0e3..b8d3cc7 100644 --- a/libs/common/src/firebase/firebase.config.ts +++ b/libs/common/src/firebase/firebase.config.ts @@ -3,21 +3,32 @@ import { getDatabase } from 'firebase/database'; import { ConfigService } from '@nestjs/config'; export const initializeFirebaseApp = (configService: ConfigService) => { - const firebaseConfig = { - apiKey: configService.get('FIREBASE_API_KEY'), - authDomain: configService.get('FIREBASE_AUTH_DOMAIN'), - projectId: configService.get('FIREBASE_PROJECT_ID'), - storageBucket: configService.get('FIREBASE_STORAGE_BUCKET'), - messagingSenderId: configService.get( - 'FIREBASE_MESSAGING_SENDER_ID', - ), - appId: configService.get('FIREBASE_APP_ID'), - measurementId: configService.get('FIREBASE_MEASUREMENT_ID'), - databaseURL: configService.get('FIREBASE_DATABASE_URL'), - }; + try { + const firebaseConfig = { + apiKey: configService.get('FIREBASE_API_KEY'), + authDomain: configService.get('FIREBASE_AUTH_DOMAIN'), + projectId: configService.get('FIREBASE_PROJECT_ID'), + storageBucket: configService.get('FIREBASE_STORAGE_BUCKET'), + messagingSenderId: configService.get( + 'FIREBASE_MESSAGING_SENDER_ID', + ), + appId: configService.get('FIREBASE_APP_ID'), + measurementId: configService.get('FIREBASE_MEASUREMENT_ID'), + databaseURL: configService.get('FIREBASE_DATABASE_URL'), + }; - const app = initializeApp(firebaseConfig); - return getDatabase(app); + // Check if required Firebase config is available + if (!firebaseConfig.projectId || firebaseConfig.projectId === 'placeholder-project') { + console.warn('Firebase configuration not available, Firebase features will be disabled'); + return null; + } + + const app = initializeApp(firebaseConfig); + return getDatabase(app); + } catch (error) { + console.warn('Firebase initialization failed, Firebase features will be disabled:', error.message); + return null; + } }; export const firebaseDataBase = (configService: ConfigService) => diff --git a/package-lock.json b/package-lock.json index eaf972a..ec4bbcd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,13 +24,16 @@ "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.3.8", "@tuya/tuya-connector-nodejs": "^2.1.2", + "@types/aws-lambda": "^8.10.150", "argon2": "^0.40.1", + "aws-serverless-express": "^3.4.0", "axios": "^1.7.7", "bcryptjs": "^2.4.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "crypto-js": "^4.2.0", "csv-parser": "^3.2.0", + "dotenv": "^17.0.0", "express-rate-limit": "^7.1.5", "firebase": "^10.12.5", "google-auth-library": "^9.14.1", @@ -40,11 +43,13 @@ "nest-winston": "^1.10.2", "nodemailer": "^6.9.10", "onesignal-node": "^3.4.0", + "passport": "^0.7.0", "passport-jwt": "^4.0.1", "pg": "^8.11.3", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "typeorm": "^0.3.20", + "webpack": "^5.99.9", "winston": "^3.17.0", "ws": "^8.17.0" }, @@ -61,7 +66,9 @@ "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", + "aws-cdk-lib": "^2.202.0", "concurrently": "^8.2.2", + "constructs": "^10.4.2", "eslint": "^8.42.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-import": "^2.31.0", @@ -75,6 +82,10 @@ "ts-node": "^10.9.1", "tsconfig-paths": "^4.2.0", "typescript": "^5.1.3" + }, + "engines": { + "node": "20.x", + "npm": "10.x" } }, "node_modules/@ampproject/remapping": { @@ -231,6 +242,59 @@ "node": ">=0.12.0" } }, + "node_modules/@aws-cdk/asset-awscli-v1": { + "version": "2.2.240", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.240.tgz", + "integrity": "sha512-Ry5yvGVf8s7j1Gf1aBFs0mBnWzRkkRtgSVpRGkDWXvZoPbRODAH33S1mAxkETNb+dNnTPGE2Gvws0XbhpJ6RzA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.0.tgz", + "integrity": "sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@aws-cdk/cloud-assembly-schema": { + "version": "44.8.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-44.8.0.tgz", + "integrity": "sha512-Bxyj0VH8phE1uHJ6LiG3/UC/HYK91EBZnXSOzwtLsMJ0ZPuaQCYDRVAAfjDCSsEOwAk56/Waks8b5pXHpgz/xw==", + "bundleDependencies": [ + "jsonschema", + "semver" + ], + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jsonschema": "~1.4.1", + "semver": "^7.7.2" + }, + "engines": { + "node": ">= 18.0.0" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { + "version": "1.4.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { + "version": "7.7.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -760,6 +824,19 @@ "dev": true, "license": "MIT" }, + "node_modules/@codegenie/serverless-express": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@codegenie/serverless-express/-/serverless-express-3.4.1.tgz", + "integrity": "sha512-PQ3v/wDflxx168B4TwuxbbKjfmvLkyRBdvHRFS8s48hDS0Wnukm+5Dp+HiLvqwXOU7PP2+FyrK47WX4WL15Rrw==", + "license": "Apache-2.0", + "dependencies": { + "binary-case": "^1.0.0", + "type-is": "^1.6.16" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -775,7 +852,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -788,7 +865,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -2147,7 +2224,6 @@ "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -2162,7 +2238,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2172,7 +2247,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2182,7 +2256,6 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -2193,14 +2266,12 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "devOptional": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2421,6 +2492,18 @@ "rxjs": "^7.1.0" } }, + "node_modules/@nestjs/config/node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/@nestjs/core": { "version": "10.4.15", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.4.15.tgz", @@ -2952,28 +3035,28 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tuya/tuya-connector-nodejs": { @@ -2995,6 +3078,12 @@ "follow-redirects": "^1.14.0" } }, + "node_modules/@types/aws-lambda": { + "version": "8.10.150", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.150.tgz", + "integrity": "sha512-AX+AbjH/rH5ezX1fbK8onC/a+HyQHo7QGmvoxAE42n22OsciAxvZoZNEr22tbXs8WfP1nIsBjKDpgPm3HjOZbA==", + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3086,7 +3175,6 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "*", @@ -3097,7 +3185,6 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, "license": "MIT", "dependencies": { "@types/eslint": "*", @@ -3108,7 +3195,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, "license": "MIT" }, "node_modules/@types/express": { @@ -3196,7 +3282,6 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, "license": "MIT" }, "node_modules/@types/json5": { @@ -3557,11 +3642,24 @@ "dev": true, "license": "ISC" }, + "node_modules/@vendia/serverless-express": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@vendia/serverless-express/-/serverless-express-3.4.1.tgz", + "integrity": "sha512-4dJJvr9vQlq9iUClpfm5iFL+neoSctUI6Zkh9F4wjk/tpcM7QVD6niJi4ptiIzyzJCWoN97ACQCXyE0O8MznLQ==", + "license": "Apache-2.0", + "dependencies": { + "@codegenie/serverless-express": "^3.4.1", + "binary-case": "^1.0.0", + "type-is": "^1.6.16" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", @@ -3572,28 +3670,24 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", @@ -3605,14 +3699,12 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3625,7 +3717,6 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "dev": true, "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" @@ -3635,7 +3726,6 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" @@ -3645,14 +3735,12 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3669,7 +3757,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3683,7 +3770,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3696,7 +3782,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3711,7 +3796,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3722,14 +3806,12 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, "license": "Apache-2.0" }, "node_modules/accepts": { @@ -3749,7 +3831,6 @@ "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "devOptional": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3772,7 +3853,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -3794,7 +3875,6 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -3811,7 +3891,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -3829,7 +3908,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" @@ -3962,7 +4040,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/argon2": { @@ -4191,6 +4269,405 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/aws-cdk-lib": { + "version": "2.202.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.202.0.tgz", + "integrity": "sha512-JDycQoE8AxUAeCFXFoCx6FGvR78e6W9zYxPgmfW/uPPbntyNCXXBqwyAYo17RGS/lr0RO3zqD/oCBZSNU2e/Yg==", + "bundleDependencies": [ + "@balena/dockerignore", + "case", + "fs-extra", + "ignore", + "jsonschema", + "minimatch", + "punycode", + "semver", + "table", + "yaml", + "mime-types" + ], + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-cdk/asset-awscli-v1": "2.2.240", + "@aws-cdk/asset-node-proxy-agent-v6": "^2.1.0", + "@aws-cdk/cloud-assembly-schema": "^44.2.0", + "@balena/dockerignore": "^1.0.2", + "case": "1.6.3", + "fs-extra": "^11.3.0", + "ignore": "^5.3.2", + "jsonschema": "^1.5.0", + "mime-types": "^2.1.35", + "minimatch": "^3.1.2", + "punycode": "^2.3.1", + "semver": "^7.7.2", + "table": "^6.9.0", + "yaml": "1.10.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "constructs": "^10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/aws-cdk-lib/node_modules/ajv": { + "version": "8.17.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/aws-cdk-lib/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aws-cdk-lib/node_modules/astral-regex": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/aws-cdk-lib/node_modules/case": { + "version": "1.6.3", + "dev": true, + "inBundle": true, + "license": "(MIT OR GPL-3.0-or-later)", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/fast-uri": { + "version": "3.0.6", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/aws-cdk-lib/node_modules/fs-extra": { + "version": "11.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/aws-cdk-lib/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/aws-cdk-lib/node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/aws-cdk-lib/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/jsonfile": { + "version": "6.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/jsonschema": { + "version": "1.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/aws-cdk-lib/node_modules/lodash.truncate": { + "version": "4.4.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/aws-cdk-lib/node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/aws-cdk-lib/node_modules/require-from-string": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/semver": { + "version": "7.7.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aws-cdk-lib/node_modules/slice-ansi": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/aws-cdk-lib/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/table": { + "version": "6.9.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/universalify": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/aws-serverless-express": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/aws-serverless-express/-/aws-serverless-express-3.4.0.tgz", + "integrity": "sha512-YG9ZjAOI9OpwqDDWzkRc3kKJYJuR7gTMjLa3kAWopO17myoprxskCUyCEee+RKe34tcR4UNrVtgAwW5yDe74bw==", + "license": "Apache-2.0", + "dependencies": { + "@vendia/serverless-express": "^3.4.0", + "binary-case": "^1.0.0", + "type-is": "^1.6.16" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -4411,6 +4888,12 @@ "node": "*" } }, + "node_modules/binary-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/binary-case/-/binary-case-1.1.4.tgz", + "integrity": "sha512-9Kq8m6NZTAgy05Ryuh7U3Qc4/ujLQU1AZ5vMw4cr3igTdi5itZC6kCNrRr2X8NzPiDn2oUIFTfa71DKMnue/Zg==", + "license": "Apache-2.0" + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -4588,7 +5071,6 @@ "version": "4.24.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4769,7 +5251,6 @@ "version": "1.0.30001700", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz", "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4863,7 +5344,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0" @@ -5301,6 +5781,13 @@ "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==", "license": "MIT" }, + "node_modules/constructs": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.4.2.tgz", + "integrity": "sha512-wsNxBlAott2qg8Zv87q3eYZYgheb9lchtBfjHzzLHtXbttwSrHPs1NNQbBrmbb1YZvYg2+Vh0Dor76w4mFxJkA==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -5423,7 +5910,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -5707,7 +6194,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -5750,9 +6237,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.0.0.tgz", + "integrity": "sha512-A0BJ5lrpJVSfnMMXjmeO0xUnoxqsBHWCoqqTnGwGYVdnctqXXUEhJOO7LxmgxJon9tEZFGpe0xPRX0h2v3AANQ==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -5835,7 +6322,6 @@ "version": "1.5.101", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.101.tgz", "integrity": "sha512-L0ISiQrP/56Acgu4/i/kfPwWSgrzYZUnQrC0+QPFuhqlLP1Ir7qzPPDVS9BcKIyWTRU8+o6CC8dKw38tSWhYIA==", - "dev": true, "license": "ISC" }, "node_modules/emittery": { @@ -5876,7 +6362,6 @@ "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -5984,7 +6469,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", - "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { @@ -6491,7 +6975,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -6504,7 +6987,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -6533,7 +7015,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.x" @@ -7417,7 +7898,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true, "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/minimatch": { @@ -7531,7 +8011,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/graphemer": { @@ -9383,7 +9862,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, "license": "MIT" }, "node_modules/json-schema": { @@ -9396,7 +9874,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { @@ -9591,7 +10068,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.11.5" @@ -9810,7 +10286,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/makeerror": { @@ -9867,7 +10343,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -10110,7 +10585,6 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, "license": "MIT" }, "node_modules/nest-winston": { @@ -10194,7 +10668,6 @@ "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "dev": true, "license": "MIT" }, "node_modules/nodemailer": { @@ -10606,7 +11079,6 @@ "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", "license": "MIT", - "peer": true, "dependencies": { "passport-strategy": "1.x.x", "pause": "0.0.1", @@ -10715,8 +11187,7 @@ "node_modules/pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==", - "peer": true + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, "node_modules/performance-now": { "version": "2.1.0", @@ -10817,7 +11288,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -11179,7 +11649,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" @@ -11463,7 +11932,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11892,7 +12360,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" @@ -12145,7 +12612,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -12156,7 +12622,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -12560,7 +13025,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12570,7 +13034,6 @@ "version": "5.39.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -12589,7 +13052,6 @@ "version": "5.3.11", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz", "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -12624,7 +13086,6 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -12639,7 +13100,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", - "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -12659,7 +13119,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -12675,7 +13134,6 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, "license": "MIT" }, "node_modules/test-exclude": { @@ -12947,7 +13405,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -13314,6 +13772,18 @@ "ieee754": "^1.2.1" } }, + "node_modules/typeorm/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/typeorm/node_modules/mkdirp": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", @@ -13346,7 +13816,7 @@ "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -13425,7 +13895,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -13493,7 +13962,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -13563,7 +14032,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", - "dev": true, "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -13590,15 +14058,14 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.98.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", - "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", - "dev": true, + "version": "5.99.9", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz", + "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", @@ -13615,7 +14082,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^4.3.0", + "schema-utils": "^4.3.2", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", @@ -13651,7 +14118,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -13661,9 +14127,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -13676,20 +14140,16 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=4.0" } }, "node_modules/webpack/node_modules/schema-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", - "dev": true, + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -14080,7 +14540,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/package.json b/package.json index b42b055..ad00d63 100644 --- a/package.json +++ b/package.json @@ -6,19 +6,24 @@ "private": true, "license": "UNLICENSED", "scripts": { - "build": "npm run test && npx nest build", + "build": "npx nest build", + "build:lambda": "npx nest build && cp package*.json dist/", "format": "prettier --write \"apps/**/*.ts\" \"libs/**/*.ts\"", - "start": "npm run test && node dist/main", - "start:dev": "npm run test && npx nest start --watch", + "start": "node dist/main", + "start:dev": "npx nest start --watch", "dev": "npx nest start --watch", - "start:debug": "npm run test && npx nest start --debug --watch", - "start:prod": "npm run test && node dist/main", + "start:debug": "npx nest start --debug --watch", + "start:prod": "node dist/main", + "start:lambda": "node dist/lambda", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "test": "jest --config jest.config.js", "test:watch": "jest --watch --config jest.config.js", "test:cov": "jest --coverage --config jest.config.js", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", - "test:e2e": "jest --config ./apps/backend/test/jest-e2e.json" + "test:e2e": "jest --config ./apps/backend/test/jest-e2e.json", + "deploy": "./deploy.sh", + "infra:deploy": "cdk deploy SyncrowBackendStack", + "infra:destroy": "cdk destroy SyncrowBackendStack" }, "dependencies": { "@fast-csv/format": "^5.0.2", @@ -36,13 +41,16 @@ "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.3.8", "@tuya/tuya-connector-nodejs": "^2.1.2", + "@types/aws-lambda": "^8.10.150", "argon2": "^0.40.1", + "aws-serverless-express": "^3.4.0", "axios": "^1.7.7", "bcryptjs": "^2.4.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "crypto-js": "^4.2.0", "csv-parser": "^3.2.0", + "dotenv": "^17.0.0", "express-rate-limit": "^7.1.5", "firebase": "^10.12.5", "google-auth-library": "^9.14.1", @@ -52,11 +60,13 @@ "nest-winston": "^1.10.2", "nodemailer": "^6.9.10", "onesignal-node": "^3.4.0", + "passport": "^0.7.0", "passport-jwt": "^4.0.1", "pg": "^8.11.3", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "typeorm": "^0.3.20", + "webpack": "^5.99.9", "winston": "^3.17.0", "ws": "^8.17.0" }, @@ -73,7 +83,9 @@ "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", + "aws-cdk-lib": "^2.202.0", "concurrently": "^8.2.2", + "constructs": "^10.4.2", "eslint": "^8.42.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-import": "^2.31.0", diff --git a/src/main.ts b/src/main.ts index d337a66..7ec46e1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -57,7 +57,8 @@ async function bootstrap() { logger.error('Seeding failed!', error.stack || error); } - logger.log('Starting auth at port ...', process.env.PORT || 4000); - await app.listen(process.env.PORT || 4000); + const port = process.env.PORT || 3000; + logger.log(`Starting application on port ${port}...`); + await app.listen(port, '0.0.0.0'); } bootstrap();