diff --git a/Dockerfile.service b/Dockerfile.service index fbcf475..a39b782 100644 --- a/Dockerfile.service +++ b/Dockerfile.service @@ -24,6 +24,7 @@ COPY packages/services/inventory-service/package.json packages/services/inventor COPY packages/services/monitor-service/package.json packages/services/monitor-service/ COPY packages/services/comm-service/package.json packages/services/comm-service/ COPY packages/services/audit-service/package.json packages/services/audit-service/ +COPY packages/services/version-service/package.json packages/services/version-service/ # Install all dependencies (cached unless package.json changes) RUN pnpm install --frozen-lockfile @@ -60,6 +61,7 @@ COPY --from=builder /app/packages/services/inventory-service/package.json packag COPY --from=builder /app/packages/services/monitor-service/package.json packages/services/monitor-service/ COPY --from=builder /app/packages/services/comm-service/package.json packages/services/comm-service/ COPY --from=builder /app/packages/services/audit-service/package.json packages/services/audit-service/ +COPY --from=builder /app/packages/services/version-service/package.json packages/services/version-service/ # Install production dependencies only RUN pnpm install --frozen-lockfile --prod diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 1a69bc7..c174923 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -63,6 +63,8 @@ services: condition: service_healthy audit-service: condition: service_healthy + version-service: + condition: service_healthy healthcheck: test: ["CMD", "kong", "health"] interval: 10s @@ -311,6 +313,39 @@ services: networks: - it0-network + version-service: + build: + context: ../.. + dockerfile: Dockerfile.service + args: + SERVICE_NAME: version-service + SERVICE_PORT: 3009 + container_name: it0-version-service + restart: unless-stopped + ports: + - "13009:3009" + volumes: + - version_data:/data/versions + environment: + - DB_HOST=postgres + - DB_PORT=5432 + - DB_USERNAME=${POSTGRES_USER:-it0} + - DB_PASSWORD=${POSTGRES_PASSWORD:-it0_dev} + - DB_DATABASE=${POSTGRES_DB:-it0} + - VERSION_SERVICE_PORT=3009 + - DOWNLOAD_BASE_URL=https://it0api.szaiai.com/downloads/versions + healthcheck: + test: ["CMD-SHELL", "node -e \"require('http').get('http://localhost:3009/',r=>{process.exit(r.statusCode<500?0:1)}).on('error',()=>process.exit(1))\""] + interval: 30s + timeout: 5s + retries: 3 + start_period: 15s + depends_on: + postgres: + condition: service_healthy + networks: + - it0-network + # ===== LiveKit Infrastructure ===== # NOTE: livekit-server, voice-agent, voice-service use host networking # to eliminate docker-proxy overhead for real-time audio (WebRTC UDP). @@ -429,6 +464,7 @@ services: volumes: postgres_data: claude_tenants: + version_data: networks: it0-network: diff --git a/packages/gateway/config/kong.yml b/packages/gateway/config/kong.yml index 648f9b5..7556197 100644 --- a/packages/gateway/config/kong.yml +++ b/packages/gateway/config/kong.yml @@ -113,6 +113,14 @@ services: - /api/v1/audit strip_path: false + - name: version-service + url: http://version-service:3009 + routes: + - name: version-routes + paths: + - /api/v1/versions + strip_path: false + plugins: # ===== Global plugins (apply to ALL routes) ===== - name: cors @@ -121,6 +129,7 @@ plugins: - http://localhost:3000 - https://it0.szaiai.com - http://it0.szaiai.com + - https://update.szaiai.com methods: - GET - POST diff --git a/packages/services/version-service/package.json b/packages/services/version-service/package.json new file mode 100644 index 0000000..9ea3ddb --- /dev/null +++ b/packages/services/version-service/package.json @@ -0,0 +1,36 @@ +{ + "name": "@it0/version-service", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "nest build", + "dev": "nest start --watch", + "start": "node dist/main", + "test": "jest" + }, + "dependencies": { + "@nestjs/common": "^10.3.0", + "@nestjs/core": "^10.3.0", + "@nestjs/config": "^3.2.0", + "@nestjs/typeorm": "^10.0.0", + "@nestjs/platform-express": "^10.3.0", + "typeorm": "^0.3.20", + "pg": "^8.11.0", + "reflect-metadata": "^0.2.0", + "rxjs": "^7.8.0", + "multer": "^1.4.5-lts.1", + "app-info-parser": "^1.1.6", + "@it0/common": "workspace:*", + "@it0/database": "workspace:*" + }, + "devDependencies": { + "@nestjs/cli": "^10.3.0", + "@types/express": "^4.17.21", + "@types/multer": "^1.4.11", + "@types/jest": "^29.5.0", + "@types/node": "^20.11.0", + "jest": "^29.7.0", + "ts-jest": "^29.1.0", + "typescript": "^5.4.0" + } +} diff --git a/packages/services/version-service/src/application/dtos/create-version.dto.ts b/packages/services/version-service/src/application/dtos/create-version.dto.ts new file mode 100644 index 0000000..6b39a08 --- /dev/null +++ b/packages/services/version-service/src/application/dtos/create-version.dto.ts @@ -0,0 +1,14 @@ +import { Platform } from '../../domain/entities/app-version.entity'; + +export class CreateVersionDto { + platform!: Platform; + versionName!: string; + buildNumber!: string; + changelog?: string; + downloadUrl?: string; + fileSize?: number; + isForceUpdate?: boolean; + isEnabled?: boolean; + minOsVersion?: string; + releaseDate?: string; +} diff --git a/packages/services/version-service/src/application/dtos/update-version.dto.ts b/packages/services/version-service/src/application/dtos/update-version.dto.ts new file mode 100644 index 0000000..4d46186 --- /dev/null +++ b/packages/services/version-service/src/application/dtos/update-version.dto.ts @@ -0,0 +1,10 @@ +export class UpdateVersionDto { + versionName?: string; + buildNumber?: string; + changelog?: string; + downloadUrl?: string; + isForceUpdate?: boolean; + isEnabled?: boolean; + minOsVersion?: string; + releaseDate?: string; +} diff --git a/packages/services/version-service/src/domain/entities/app-version.entity.ts b/packages/services/version-service/src/domain/entities/app-version.entity.ts new file mode 100644 index 0000000..341da75 --- /dev/null +++ b/packages/services/version-service/src/domain/entities/app-version.entity.ts @@ -0,0 +1,54 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +export enum Platform { + ANDROID = 'ANDROID', + IOS = 'IOS', +} + +@Entity('app_versions') +export class AppVersion { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column({ type: 'enum', enum: Platform }) + platform!: Platform; + + @Column({ type: 'varchar', length: 30 }) + versionName!: string; + + @Column({ type: 'varchar', length: 20 }) + buildNumber!: string; + + @Column({ type: 'text', nullable: true }) + changelog?: string; + + @Column({ type: 'varchar', length: 500, nullable: true }) + downloadUrl?: string; + + @Column({ type: 'bigint', nullable: true }) + fileSize?: number; + + @Column({ type: 'boolean', default: false }) + isForceUpdate!: boolean; + + @Column({ type: 'boolean', default: true }) + isEnabled!: boolean; + + @Column({ type: 'varchar', length: 20, nullable: true }) + minOsVersion?: string; + + @Column({ type: 'timestamptz', nullable: true }) + releaseDate?: Date; + + @CreateDateColumn({ type: 'timestamptz' }) + createdAt!: Date; + + @UpdateDateColumn({ type: 'timestamptz' }) + updatedAt!: Date; +} diff --git a/packages/services/version-service/src/infrastructure/repositories/app-version.repository.ts b/packages/services/version-service/src/infrastructure/repositories/app-version.repository.ts new file mode 100644 index 0000000..b588ab3 --- /dev/null +++ b/packages/services/version-service/src/infrastructure/repositories/app-version.repository.ts @@ -0,0 +1,50 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { AppVersion, Platform } from '../../domain/entities/app-version.entity'; + +export interface VersionListFilter { + platform?: Platform; + includeDisabled?: boolean; +} + +@Injectable() +export class AppVersionRepository { + constructor( + @InjectRepository(AppVersion) + private readonly repo: Repository, + ) {} + + async findAll(filter?: VersionListFilter): Promise { + const qb = this.repo.createQueryBuilder('v'); + + if (filter?.platform) { + qb.andWhere('v.platform = :platform', { platform: filter.platform }); + } + + if (!filter?.includeDisabled) { + qb.andWhere('v.isEnabled = true'); + } + + qb.orderBy('v.createdAt', 'DESC'); + return qb.getMany(); + } + + async findById(id: string): Promise { + return this.repo.findOne({ where: { id } }); + } + + async create(data: Partial): Promise { + const entity = this.repo.create(data); + return this.repo.save(entity); + } + + async update(id: string, data: Partial): Promise { + await this.repo.update(id, data); + return this.findById(id); + } + + async delete(id: string): Promise { + await this.repo.delete(id); + } +} diff --git a/packages/services/version-service/src/interfaces/rest/controllers/version.controller.ts b/packages/services/version-service/src/interfaces/rest/controllers/version.controller.ts new file mode 100644 index 0000000..dac8fa0 --- /dev/null +++ b/packages/services/version-service/src/interfaces/rest/controllers/version.controller.ts @@ -0,0 +1,214 @@ +import { + Controller, + Get, + Post, + Put, + Delete, + Patch, + Param, + Query, + Body, + UploadedFile, + UseInterceptors, + NotFoundException, + Logger, +} from '@nestjs/common'; +import { FileInterceptor } from '@nestjs/platform-express'; +import { ConfigService } from '@nestjs/config'; +import { diskStorage } from 'multer'; +import * as fs from 'fs'; +import * as path from 'path'; +import { AppVersionRepository } from '../../../infrastructure/repositories/app-version.repository'; +import { Platform } from '../../../domain/entities/app-version.entity'; +import { CreateVersionDto } from '../../../application/dtos/create-version.dto'; +import { UpdateVersionDto } from '../../../application/dtos/update-version.dto'; + +const UPLOAD_DIR = '/data/versions'; + +@Controller('api/v1/versions') +export class VersionController { + private readonly logger = new Logger(VersionController.name); + private readonly downloadBaseUrl: string; + + constructor( + private readonly versionRepo: AppVersionRepository, + private readonly config: ConfigService, + ) { + this.downloadBaseUrl = this.config.get( + 'DOWNLOAD_BASE_URL', + 'https://it0api.szaiai.com/downloads/versions', + ); + // Ensure upload directories exist + for (const p of [Platform.ANDROID, Platform.IOS]) { + const dir = path.join(UPLOAD_DIR, p.toLowerCase()); + fs.mkdirSync(dir, { recursive: true }); + } + } + + @Get() + async list( + @Query('platform') platform?: string, + @Query('includeDisabled') includeDisabled?: string, + ) { + const filter: { platform?: Platform; includeDisabled?: boolean } = {}; + if (platform) { + filter.platform = platform.toUpperCase() as Platform; + } + if (includeDisabled === 'true') { + filter.includeDisabled = true; + } + return this.versionRepo.findAll(filter); + } + + @Get(':id') + async getById(@Param('id') id: string) { + const version = await this.versionRepo.findById(id); + if (!version) throw new NotFoundException('Version not found'); + return version; + } + + @Post() + async create(@Body() dto: CreateVersionDto) { + return this.versionRepo.create({ + ...dto, + releaseDate: dto.releaseDate ? new Date(dto.releaseDate) : undefined, + }); + } + + @Put(':id') + async update(@Param('id') id: string, @Body() dto: UpdateVersionDto) { + const existing = await this.versionRepo.findById(id); + if (!existing) throw new NotFoundException('Version not found'); + return this.versionRepo.update(id, { + ...dto, + releaseDate: dto.releaseDate ? new Date(dto.releaseDate) : undefined, + }); + } + + @Delete(':id') + async delete(@Param('id') id: string) { + const version = await this.versionRepo.findById(id); + if (!version) throw new NotFoundException('Version not found'); + + // Delete the associated file if it exists + if (version.downloadUrl) { + const platformDir = version.platform.toLowerCase(); + const filename = path.basename(new URL(version.downloadUrl).pathname); + const filePath = path.join(UPLOAD_DIR, platformDir, filename); + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + this.logger.log(`Deleted file: ${filePath}`); + } + } + + await this.versionRepo.delete(id); + return { deleted: true }; + } + + @Patch(':id/toggle') + async toggle(@Param('id') id: string, @Body('isEnabled') isEnabled: boolean) { + const existing = await this.versionRepo.findById(id); + if (!existing) throw new NotFoundException('Version not found'); + return this.versionRepo.update(id, { isEnabled }); + } + + @Post('upload') + @UseInterceptors( + FileInterceptor('file', { + storage: diskStorage({ + destination: (req, _file, cb) => { + const platform = (req.body.platform || 'ANDROID').toLowerCase(); + const dir = path.join(UPLOAD_DIR, platform); + fs.mkdirSync(dir, { recursive: true }); + cb(null, dir); + }, + filename: (_req, file, cb) => { + // Preserve original filename with timestamp prefix to avoid collisions + const timestamp = Date.now(); + const safeName = file.originalname.replace(/[^a-zA-Z0-9._-]/g, '_'); + cb(null, `${timestamp}_${safeName}`); + }, + }), + limits: { fileSize: 500 * 1024 * 1024 }, // 500 MB + }), + ) + async upload( + @UploadedFile() file: Express.Multer.File, + @Body('platform') platform: string, + @Body('versionName') versionName: string, + @Body('buildNumber') buildNumber: string, + @Body('changelog') changelog?: string, + @Body('isForceUpdate') isForceUpdate?: string, + @Body('minOsVersion') minOsVersion?: string, + @Body('releaseDate') releaseDate?: string, + ) { + const platformEnum = (platform || 'ANDROID').toUpperCase() as Platform; + const platformDir = platformEnum.toLowerCase(); + const downloadUrl = `${this.downloadBaseUrl}/${platformDir}/${file.filename}`; + + return this.versionRepo.create({ + platform: platformEnum, + versionName, + buildNumber, + changelog: changelog || undefined, + downloadUrl, + fileSize: file.size, + isForceUpdate: isForceUpdate === 'true', + isEnabled: true, + minOsVersion: minOsVersion || undefined, + releaseDate: releaseDate ? new Date(releaseDate) : undefined, + }); + } + + @Post('parse') + @UseInterceptors( + FileInterceptor('file', { + storage: diskStorage({ + destination: '/tmp', + filename: (_req, file, cb) => { + cb(null, `parse_${Date.now()}_${file.originalname}`); + }, + }), + limits: { fileSize: 500 * 1024 * 1024 }, + }), + ) + async parsePackage( + @UploadedFile() file: Express.Multer.File, + @Body('platform') platform: string, + ) { + try { + // Dynamic import for app-info-parser (CommonJS module) + const AppInfoParser = (await import('app-info-parser')).default; + const parser = new AppInfoParser(file.path); + const info = await parser.parse(); + + let result: { versionName?: string; versionCode?: string; minSdkVersion?: string } = {}; + + if (platform?.toUpperCase() === 'IOS') { + result = { + versionName: info.CFBundleShortVersionString, + versionCode: info.CFBundleVersion, + minSdkVersion: info.MinimumOSVersion, + }; + } else { + result = { + versionName: info.versionName, + versionCode: String(info.versionCode), + minSdkVersion: info.usesSdk?.minSdkVersion + ? String(info.usesSdk.minSdkVersion) + : undefined, + }; + } + + return result; + } catch (err) { + this.logger.warn(`Failed to parse package: ${(err as Error).message}`); + return { versionName: null, versionCode: null, minSdkVersion: null }; + } finally { + // Clean up temp file + if (fs.existsSync(file.path)) { + fs.unlinkSync(file.path); + } + } + } +} diff --git a/packages/services/version-service/src/main.ts b/packages/services/version-service/src/main.ts new file mode 100644 index 0000000..d98d8ea --- /dev/null +++ b/packages/services/version-service/src/main.ts @@ -0,0 +1,25 @@ +import { NestFactory } from '@nestjs/core'; +import { Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { VersionModule } from './version.module'; + +const logger = new Logger('VersionService'); + +process.on('unhandledRejection', (reason) => { + logger.error(`Unhandled Rejection: ${reason}`); +}); +process.on('uncaughtException', (error) => { + logger.error(`Uncaught Exception: ${error.message}`, error.stack); +}); + +async function bootstrap() { + const app = await NestFactory.create(VersionModule); + const config = app.get(ConfigService); + const port = config.get('VERSION_SERVICE_PORT', 3009); + await app.listen(port); + logger.log(`version-service running on port ${port}`); +} +bootstrap().catch((err) => { + logger.error(`Failed to start version-service: ${err.message}`, err.stack); + process.exit(1); +}); diff --git a/packages/services/version-service/src/version.module.ts b/packages/services/version-service/src/version.module.ts new file mode 100644 index 0000000..4a2bfcd --- /dev/null +++ b/packages/services/version-service/src/version.module.ts @@ -0,0 +1,30 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { AppVersion } from './domain/entities/app-version.entity'; +import { AppVersionRepository } from './infrastructure/repositories/app-version.repository'; +import { VersionController } from './interfaces/rest/controllers/version.controller'; + +@Module({ + imports: [ + ConfigModule.forRoot({ isGlobal: true }), + TypeOrmModule.forRootAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (config: ConfigService) => ({ + type: 'postgres' as const, + host: config.get('DB_HOST', 'localhost'), + port: config.get('DB_PORT', 5432), + username: config.get('DB_USERNAME', 'it0'), + password: config.get('DB_PASSWORD', 'it0_dev'), + database: config.get('DB_DATABASE', 'it0'), + entities: [AppVersion], + synchronize: true, + }), + }), + TypeOrmModule.forFeature([AppVersion]), + ], + controllers: [VersionController], + providers: [AppVersionRepository], +}) +export class VersionModule {} diff --git a/packages/services/version-service/tsconfig.json b/packages/services/version-service/tsconfig.json new file mode 100644 index 0000000..7899197 --- /dev/null +++ b/packages/services/version-service/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "baseUrl": ".", + "paths": { + "@it0/common": ["../../shared/common/src"], + "@it0/common/*": ["../../shared/common/src/*"], + "@it0/database": ["../../shared/database/src"], + "@it0/database/*": ["../../shared/database/src/*"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1c1b1be..2a832d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -589,6 +589,73 @@ importers: specifier: ^5.4.0 version: 5.9.3 + packages/services/version-service: + dependencies: + '@it0/common': + specifier: workspace:* + version: link:../../shared/common + '@it0/database': + specifier: workspace:* + version: link:../../shared/database + '@nestjs/common': + specifier: ^10.3.0 + version: 10.4.22(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/config': + specifier: ^3.2.0 + version: 3.3.0(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) + '@nestjs/core': + specifier: ^10.3.0 + version: 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22)(@nestjs/websockets@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^10.3.0 + version: 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22) + '@nestjs/typeorm': + specifier: ^10.0.0 + version: 10.0.2(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.28(ioredis@5.9.2)(pg@8.18.0)) + app-info-parser: + specifier: ^1.1.6 + version: 1.1.6 + multer: + specifier: ^1.4.5-lts.1 + version: 1.4.5-lts.2 + pg: + specifier: ^8.11.0 + version: 8.18.0 + reflect-metadata: + specifier: ^0.2.0 + version: 0.2.2 + rxjs: + specifier: ^7.8.0 + version: 7.8.2 + typeorm: + specifier: ^0.3.20 + version: 0.3.28(ioredis@5.9.2)(pg@8.18.0) + devDependencies: + '@nestjs/cli': + specifier: ^10.3.0 + version: 10.4.9 + '@types/express': + specifier: ^4.17.21 + version: 4.17.25 + '@types/jest': + specifier: ^29.5.0 + version: 29.5.14 + '@types/multer': + specifier: ^1.4.11 + version: 1.4.13 + '@types/node': + specifier: ^20.11.0 + version: 20.19.33 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.19.33) + ts-jest: + specifier: ^29.1.0 + version: 29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.33))(typescript@5.9.3) + typescript: + specifier: ^5.4.0 + version: 5.9.3 + packages/shared/common: dependencies: '@nestjs/common': @@ -1407,6 +1474,9 @@ packages: '@types/minimatch@5.1.2': resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + '@types/multer@1.4.13': + resolution: {integrity: sha512-bhhdtPw7JqCiEfC9Jimx5LqX9BDIPJEh2q/fQ4bqbBPtyEZYr3cvF22NwG0DmPZNYA0CAf2CnqDB4KIGGpJcaw==} + '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} @@ -1510,6 +1580,10 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@xmldom/xmldom@0.8.11': + resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} + engines: {node: '>=10.0.0'} + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -1600,6 +1674,10 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + app-info-parser@1.1.6: + resolution: {integrity: sha512-ZAFCM0bN88cbpsMoRhL/JfdX3b+nb5iBEXcu30xABvbaqtw6tXfHujDnuKSpNmA3P0uwpkIxTV/Wun5HfEch8A==} + hasBin: true + app-root-path@3.1.0: resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==} engines: {node: '>= 6.0.0'} @@ -1671,6 +1749,10 @@ packages: bcryptjs@2.4.3: resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} + big-integer@1.6.52: + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} + engines: {node: '>=0.6'} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -1682,6 +1764,10 @@ packages: resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + bplist-parser@0.2.0: + resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} + engines: {node: '>= 5.10.0'} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1704,6 +1790,9 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} @@ -1716,6 +1805,9 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + bufferpack@0.0.6: + resolution: {integrity: sha512-MTWvLHElqczrIVhge9qHtqgNigJFyh0+tCDId5yCbFAfuekHWIG+uAgvoHVflwrDPuY/e47JE1ki5qcM7w4uLg==} + bull@4.16.5: resolution: {integrity: sha512-lDsx2BzkKe7gkCYiT5Acj02DpTwDznl/VNN7Psn7M3USPG7Vs/BaClZJJTAG+ufAR9++N1/NiUTdaFBWDIl5TQ==} engines: {node: '>=12'} @@ -1724,6 +1816,10 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} + bytebuffer@5.0.1: + resolution: {integrity: sha512-IuzSdmADppkZ6DlpycMkm8l9zeEq16fWtLvunEwFiYciR/BHo4E8/xs5piFquG+Za8OWmMqHF8zuRviz2LHvRQ==} + engines: {node: '>=0.8'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -1755,6 +1851,9 @@ packages: caniuse-lite@1.0.30001769: resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} + cgbi-to-png@1.0.7: + resolution: {integrity: sha512-YR80kxTPuq9oRpZUdQmNEQWrmTKLINk1cfLVfyrV7Rfr9KLtLJdcockPKbreIr4JYAq+DhHBR7w+WA/tF5VDaQ==} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -1848,6 +1947,10 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + comment-json@4.2.5: resolution: {integrity: sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==} engines: {node: '>= 6'} @@ -1855,6 +1958,10 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + concat-stream@2.0.0: resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} engines: {'0': node >= 6.0} @@ -1900,6 +2007,9 @@ packages: typescript: optional: true + crc@3.8.0: + resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} + create-jest@29.7.0: resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2151,6 +2261,9 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -2431,12 +2544,18 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isomorphic-unzip@1.1.5: + resolution: {integrity: sha512-2McA51lWhmO3Kk438jxVcYeh6L+AOqVnl9XdX1yI7GlLA9RwEyTBgGem1rNuRIU2abAmOiv+IagThdUxASY4IA==} + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -2722,6 +2841,10 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + long@3.2.0: + resolution: {integrity: sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg==} + engines: {node: '>=0.6'} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -2824,6 +2947,11 @@ packages: msgpackr@1.11.8: resolution: {integrity: sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA==} + multer@1.4.5-lts.2: + resolution: {integrity: sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==} + engines: {node: '>= 6.0.0'} + deprecated: Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version. + multer@2.0.2: resolution: {integrity: sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==} engines: {node: '>= 10.16.0'} @@ -2996,6 +3124,9 @@ packages: pause@0.0.1: resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + pg-cloudflare@1.3.0: resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} @@ -3049,6 +3180,10 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + plist@3.1.0: + resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} + engines: {node: '>=10.4.0'} + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -3077,6 +3212,9 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -3116,6 +3254,9 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -3189,6 +3330,9 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -3324,6 +3468,18 @@ packages: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} + stream-to-buffer@0.1.0: + resolution: {integrity: sha512-Da4WoKaZyu3nf+bIdIifh7IPkFjARBnBK+pYqn0EUJqksjV9afojjaCCHUemH30Jmu7T2qcKvlZm2ykN38uzaw==} + engines: {node: '>= 0.8'} + + stream-to@0.2.2: + resolution: {integrity: sha512-Kg1BSDTwgGiVMtTCJNlo7kk/xzL33ZuZveEBRt6rXw+f1WLK/8kmz2NVCT/Qnv0JkV85JOHcLhD82mnXsR3kPw==} + engines: {node: '>= 0.10.0'} + + streamifier@0.1.1: + resolution: {integrity: sha512-zDgl+muIlWzXNsXeyUfOk9dChMjlpkq0DRsxujtYPgyJ676yQ8jEm6zzaaWHFDg5BNcLuif0eD2MTyJdZqXpdg==} + engines: {node: '>=0.10'} + streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -3340,6 +3496,9 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -3784,6 +3943,10 @@ packages: resolution: {integrity: sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==} engines: {node: '>=6.0'} + xmlbuilder@15.1.1: + resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} + engines: {node: '>=8.0'} + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -3803,6 +3966,9 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -4682,6 +4848,10 @@ snapshots: '@types/minimatch@5.1.2': {} + '@types/multer@1.4.13': + dependencies: + '@types/express': 4.17.25 + '@types/node-fetch@2.6.13': dependencies: '@types/node': 20.19.33 @@ -4836,6 +5006,8 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 + '@xmldom/xmldom@0.8.11': {} + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -4924,6 +5096,15 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + app-info-parser@1.1.6: + dependencies: + bplist-parser: 0.2.0 + bytebuffer: 5.0.1 + cgbi-to-png: 1.0.7 + commander: 7.2.0 + isomorphic-unzip: 1.1.5 + plist: 3.1.0 + app-root-path@3.1.0: {} append-field@1.0.0: {} @@ -5017,6 +5198,8 @@ snapshots: bcryptjs@2.4.3: {} + big-integer@1.6.52: {} + binary-extensions@2.3.0: {} bl@4.1.0: @@ -5042,6 +5225,10 @@ snapshots: transitivePeerDependencies: - supports-color + bplist-parser@0.2.0: + dependencies: + big-integer: 1.6.52 + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -5071,6 +5258,8 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-crc32@0.2.13: {} + buffer-equal-constant-time@1.0.1: {} buffer-from@1.1.2: {} @@ -5085,6 +5274,8 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + bufferpack@0.0.6: {} + bull@4.16.5: dependencies: cron-parser: 4.9.0 @@ -5101,6 +5292,10 @@ snapshots: dependencies: streamsearch: 1.1.0 + bytebuffer@5.0.1: + dependencies: + long: 3.2.0 + bytes@3.1.2: {} call-bind-apply-helpers@1.0.2: @@ -5128,6 +5323,13 @@ snapshots: caniuse-lite@1.0.30001769: {} + cgbi-to-png@1.0.7: + dependencies: + bufferpack: 0.0.6 + crc: 3.8.0 + stream-to-buffer: 0.1.0 + streamifier: 0.1.1 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -5209,6 +5411,8 @@ snapshots: commander@4.1.1: {} + commander@7.2.0: {} + comment-json@4.2.5: dependencies: array-timsort: 1.0.3 @@ -5219,6 +5423,13 @@ snapshots: concat-map@0.0.1: {} + concat-stream@1.6.2: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + typedarray: 0.0.6 + concat-stream@2.0.0: dependencies: buffer-from: 1.1.2 @@ -5261,6 +5472,10 @@ snapshots: optionalDependencies: typescript: 5.7.2 + crc@3.8.0: + dependencies: + buffer: 5.7.1 + create-jest@29.7.0(@types/node@20.19.33): dependencies: '@jest/types': 29.6.3 @@ -5513,6 +5728,10 @@ snapshots: dependencies: bser: 2.1.1 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + fflate@0.8.2: {} figures@3.2.0: @@ -5837,10 +6056,17 @@ snapshots: is-unicode-supported@0.1.0: {} + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} + isomorphic-unzip@1.1.5: + dependencies: + buffer: 5.7.1 + yauzl: 2.10.0 + istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@5.2.1: @@ -6326,6 +6552,8 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + long@3.2.0: {} + lru-cache@10.4.3: {} lru-cache@5.1.1: @@ -6415,6 +6643,16 @@ snapshots: optionalDependencies: msgpackr-extract: 3.0.3 + multer@1.4.5-lts.2: + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 1.6.2 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + multer@2.0.2: dependencies: append-field: 1.0.0 @@ -6563,6 +6801,8 @@ snapshots: pause@0.0.1: {} + pend@1.2.0: {} + pg-cloudflare@1.3.0: optional: true @@ -6610,6 +6850,12 @@ snapshots: dependencies: find-up: 4.1.0 + plist@3.1.0: + dependencies: + '@xmldom/xmldom': 0.8.11 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 + pluralize@8.0.0: {} possible-typed-array-names@1.1.0: {} @@ -6630,6 +6876,8 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + process-nextick-args@2.0.1: {} + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -6667,6 +6915,16 @@ snapshots: react-is@18.3.1: {} + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -6726,6 +6984,8 @@ snapshots: dependencies: tslib: 2.8.1 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safer-buffer@2.1.2: {} @@ -6897,6 +7157,14 @@ snapshots: statuses@2.0.2: {} + stream-to-buffer@0.1.0: + dependencies: + stream-to: 0.2.2 + + stream-to@0.2.2: {} + + streamifier@0.1.1: {} + streamsearch@1.1.0: {} string-length@4.0.2: @@ -6916,6 +7184,10 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.2 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -7286,6 +7558,8 @@ snapshots: xmlbuilder@13.0.2: {} + xmlbuilder@15.1.1: {} + xtend@4.0.2: {} y18n@5.0.8: {} @@ -7304,6 +7578,11 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + yocto-queue@0.1.0: {} zod@4.3.6: {}