From e6c34c234512abeb71e96ef98db8f6c6e2381281 Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 10:09:49 -0400 Subject: [PATCH 01/17] Start with event emitters --- packages/backend/package-lock.json | 20 ++++++++++++++++++++ packages/backend/package.json | 1 + packages/backend/src/app.module.ts | 2 ++ 3 files changed, 23 insertions(+) diff --git a/packages/backend/package-lock.json b/packages/backend/package-lock.json index 786dfea..4956fa1 100644 --- a/packages/backend/package-lock.json +++ b/packages/backend/package-lock.json @@ -14,6 +14,7 @@ "@nestjs/common": "^11.0.1", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.0.1", + "@nestjs/event-emitter": "^3.0.1", "@nestjs/platform-express": "^11.0.1", "@nestjs/swagger": "^11.1.0", "@prisma/client": "^6.5.0", @@ -3732,6 +3733,19 @@ } } }, + "node_modules/@nestjs/event-emitter": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nestjs/event-emitter/-/event-emitter-3.0.1.tgz", + "integrity": "sha512-0Ln/x+7xkU6AJFOcQI9tIhUMXVF7D5itiaQGOyJbXtlAfAIt8gzDdJm+Im7cFzKoWkiW5nCXCPh6GSvdQd/3Dw==", + "license": "MIT", + "dependencies": { + "eventemitter2": "6.4.9" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "@nestjs/core": "^10.0.0 || ^11.0.0" + } + }, "node_modules/@nestjs/mapped-types": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", @@ -8086,6 +8100,12 @@ "node": ">= 0.6" } }, + "node_modules/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", + "license": "MIT" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", diff --git a/packages/backend/package.json b/packages/backend/package.json index e465f47..1297f58 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -26,6 +26,7 @@ "@nestjs/common": "^11.0.1", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.0.1", + "@nestjs/event-emitter": "^3.0.1", "@nestjs/platform-express": "^11.0.1", "@nestjs/swagger": "^11.1.0", "@prisma/client": "^6.5.0", diff --git a/packages/backend/src/app.module.ts b/packages/backend/src/app.module.ts index fe92c0b..3f0d7fd 100644 --- a/packages/backend/src/app.module.ts +++ b/packages/backend/src/app.module.ts @@ -11,6 +11,7 @@ import { S3Module } from './s3/s3.module'; import { UsersModule } from './users/users.module'; import { StudymappingModule } from './studymapping/studymapping.module'; import configuration from './config/configuration'; +import { EventEmitterModule } from '@nestjs/event-emitter'; @Module({ imports: [ @@ -18,6 +19,7 @@ import configuration from './config/configuration'; load: [configuration], isGlobal: true }), + EventEmitterModule.forRoot(), CasdoorModule, PrismaModule, TasksModule, From 0fb9f5cc2037002aa06932b8245dd3b170f431ed Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 10:22:06 -0400 Subject: [PATCH 02/17] Add download request schema --- .../20250611142155_download_request/migration.sql | 9 +++++++++ packages/backend/prisma/schema.prisma | 14 ++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 packages/backend/prisma/migrations/20250611142155_download_request/migration.sql diff --git a/packages/backend/prisma/migrations/20250611142155_download_request/migration.sql b/packages/backend/prisma/migrations/20250611142155_download_request/migration.sql new file mode 100644 index 0000000..62ac1ff --- /dev/null +++ b/packages/backend/prisma/migrations/20250611142155_download_request/migration.sql @@ -0,0 +1,9 @@ +-- CreateTable +CREATE TABLE `DownloadRequest` ( + `id` VARCHAR(191) NOT NULL, + `status` ENUM('STARTING', 'IN_PROGRESS', 'COMPLETE', 'FAILED') NOT NULL, + `location` VARCHAR(191) NOT NULL, + `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/packages/backend/prisma/schema.prisma b/packages/backend/prisma/schema.prisma index a850ee8..53d76a7 100644 --- a/packages/backend/prisma/schema.prisma +++ b/packages/backend/prisma/schema.prisma @@ -57,3 +57,17 @@ model StudyMapping { studyId String region String } + +enum DownloadStatus { + STARTING + IN_PROGRESS + COMPLETE + FAILED +} + +model DownloadRequest { + id String @id @default(uuid()) + status DownloadStatus + location String + createdAt DateTime @default(now()) +} From ebf8c35fdde782c5cc9f4142ebba1f9d09f5b927 Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 10:22:55 -0400 Subject: [PATCH 03/17] Generate template downloads module --- packages/backend/src/app.module.ts | 4 ++- .../downloads/downloads.controller.spec.ts | 20 +++++++++++ .../src/downloads/downloads.controller.ts | 34 +++++++++++++++++++ .../backend/src/downloads/downloads.module.ts | 9 +++++ .../src/downloads/downloads.service.spec.ts | 18 ++++++++++ .../src/downloads/downloads.service.ts | 26 ++++++++++++++ .../src/downloads/dto/create-download.dto.ts | 1 + .../src/downloads/dto/update-download.dto.ts | 4 +++ .../src/downloads/entities/download.entity.ts | 1 + 9 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 packages/backend/src/downloads/downloads.controller.spec.ts create mode 100644 packages/backend/src/downloads/downloads.controller.ts create mode 100644 packages/backend/src/downloads/downloads.module.ts create mode 100644 packages/backend/src/downloads/downloads.service.spec.ts create mode 100644 packages/backend/src/downloads/downloads.service.ts create mode 100644 packages/backend/src/downloads/dto/create-download.dto.ts create mode 100644 packages/backend/src/downloads/dto/update-download.dto.ts create mode 100644 packages/backend/src/downloads/entities/download.entity.ts diff --git a/packages/backend/src/app.module.ts b/packages/backend/src/app.module.ts index 3f0d7fd..6c9e2af 100644 --- a/packages/backend/src/app.module.ts +++ b/packages/backend/src/app.module.ts @@ -12,6 +12,7 @@ import { UsersModule } from './users/users.module'; import { StudymappingModule } from './studymapping/studymapping.module'; import configuration from './config/configuration'; import { EventEmitterModule } from '@nestjs/event-emitter'; +import { DownloadsModule } from './downloads/downloads.module'; @Module({ imports: [ @@ -27,7 +28,8 @@ import { EventEmitterModule } from '@nestjs/event-emitter'; TaskCompletionsModule, S3Module, UsersModule, - StudymappingModule + StudymappingModule, + DownloadsModule ], controllers: [AppController], providers: [AppService] diff --git a/packages/backend/src/downloads/downloads.controller.spec.ts b/packages/backend/src/downloads/downloads.controller.spec.ts new file mode 100644 index 0000000..28b46cf --- /dev/null +++ b/packages/backend/src/downloads/downloads.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { DownloadsController } from './downloads.controller'; +import { DownloadsService } from './downloads.service'; + +describe('DownloadsController', () => { + let controller: DownloadsController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [DownloadsController], + providers: [DownloadsService], + }).compile(); + + controller = module.get(DownloadsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/packages/backend/src/downloads/downloads.controller.ts b/packages/backend/src/downloads/downloads.controller.ts new file mode 100644 index 0000000..2ff9dfd --- /dev/null +++ b/packages/backend/src/downloads/downloads.controller.ts @@ -0,0 +1,34 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { DownloadsService } from './downloads.service'; +import { CreateDownloadDto } from './dto/create-download.dto'; +import { UpdateDownloadDto } from './dto/update-download.dto'; + +@Controller('downloads') +export class DownloadsController { + constructor(private readonly downloadsService: DownloadsService) {} + + @Post() + create(@Body() createDownloadDto: CreateDownloadDto) { + return this.downloadsService.create(createDownloadDto); + } + + @Get() + findAll() { + return this.downloadsService.findAll(); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.downloadsService.findOne(+id); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() updateDownloadDto: UpdateDownloadDto) { + return this.downloadsService.update(+id, updateDownloadDto); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.downloadsService.remove(+id); + } +} diff --git a/packages/backend/src/downloads/downloads.module.ts b/packages/backend/src/downloads/downloads.module.ts new file mode 100644 index 0000000..4810929 --- /dev/null +++ b/packages/backend/src/downloads/downloads.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { DownloadsService } from './downloads.service'; +import { DownloadsController } from './downloads.controller'; + +@Module({ + controllers: [DownloadsController], + providers: [DownloadsService], +}) +export class DownloadsModule {} diff --git a/packages/backend/src/downloads/downloads.service.spec.ts b/packages/backend/src/downloads/downloads.service.spec.ts new file mode 100644 index 0000000..12fc296 --- /dev/null +++ b/packages/backend/src/downloads/downloads.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { DownloadsService } from './downloads.service'; + +describe('DownloadsService', () => { + let service: DownloadsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [DownloadsService], + }).compile(); + + service = module.get(DownloadsService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts new file mode 100644 index 0000000..0fe7a8a --- /dev/null +++ b/packages/backend/src/downloads/downloads.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@nestjs/common'; +import { CreateDownloadDto } from './dto/create-download.dto'; +import { UpdateDownloadDto } from './dto/update-download.dto'; + +@Injectable() +export class DownloadsService { + create(createDownloadDto: CreateDownloadDto) { + return 'This action adds a new download'; + } + + findAll() { + return `This action returns all downloads`; + } + + findOne(id: number) { + return `This action returns a #${id} download`; + } + + update(id: number, updateDownloadDto: UpdateDownloadDto) { + return `This action updates a #${id} download`; + } + + remove(id: number) { + return `This action removes a #${id} download`; + } +} diff --git a/packages/backend/src/downloads/dto/create-download.dto.ts b/packages/backend/src/downloads/dto/create-download.dto.ts new file mode 100644 index 0000000..72f682e --- /dev/null +++ b/packages/backend/src/downloads/dto/create-download.dto.ts @@ -0,0 +1 @@ +export class CreateDownloadDto {} diff --git a/packages/backend/src/downloads/dto/update-download.dto.ts b/packages/backend/src/downloads/dto/update-download.dto.ts new file mode 100644 index 0000000..cb1dd25 --- /dev/null +++ b/packages/backend/src/downloads/dto/update-download.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateDownloadDto } from './create-download.dto'; + +export class UpdateDownloadDto extends PartialType(CreateDownloadDto) {} diff --git a/packages/backend/src/downloads/entities/download.entity.ts b/packages/backend/src/downloads/entities/download.entity.ts new file mode 100644 index 0000000..060ead4 --- /dev/null +++ b/packages/backend/src/downloads/entities/download.entity.ts @@ -0,0 +1 @@ +export class Download {} From c2632465cc02fa702226027e428f749212aa0e0f Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 11:11:31 -0400 Subject: [PATCH 04/17] Add in prisma calls for CRUD over download requests --- packages/backend/src/config/configuration.ts | 3 +- .../src/downloads/downloads.controller.ts | 46 +++++++++------ .../backend/src/downloads/downloads.module.ts | 3 + .../src/downloads/downloads.service.ts | 56 +++++++++++++++---- .../src/downloads/dto/create-download.dto.ts | 1 - .../src/downloads/dto/update-download.dto.ts | 4 -- .../src/downloads/entities/download.entity.ts | 17 +++++- 7 files changed, 95 insertions(+), 35 deletions(-) delete mode 100644 packages/backend/src/downloads/dto/create-download.dto.ts delete mode 100644 packages/backend/src/downloads/dto/update-download.dto.ts diff --git a/packages/backend/src/config/configuration.ts b/packages/backend/src/config/configuration.ts index 5f04fab..a5504da 100644 --- a/packages/backend/src/config/configuration.ts +++ b/packages/backend/src/config/configuration.ts @@ -18,7 +18,8 @@ export default () => ({ secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, region: process.env.S3_REGION || 'us-east-1', bucket: process.env.S3_BUCKET, - signedExpiration: process.env.S3_SIGNED_EXPIRATION || 5 * 60 + signedExpiration: process.env.S3_SIGNED_EXPIRATION || 5 * 60, + downloadZipsFolder: process.env.S3_DOWNLOAD_FOLDER || 'downloads' }, meta: { taskIteration: process.env.TASK_ITERATION || 'Sum25' diff --git a/packages/backend/src/downloads/downloads.controller.ts b/packages/backend/src/downloads/downloads.controller.ts index 2ff9dfd..762e2d4 100644 --- a/packages/backend/src/downloads/downloads.controller.ts +++ b/packages/backend/src/downloads/downloads.controller.ts @@ -1,34 +1,48 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { Controller, Get, Post, Param, Delete, UseGuards, Query, Response, NotFoundException } from '@nestjs/common'; import { DownloadsService } from './downloads.service'; -import { CreateDownloadDto } from './dto/create-download.dto'; -import { UpdateDownloadDto } from './dto/update-download.dto'; +import { DownloadEntity } from './entities/download.entity'; +import { ApiResponse, ApiBearerAuth } from '@nestjs/swagger'; +import { CasdoorGuard } from '../casdoor/casdoor.guard'; +import { AdminGuard } from '../casdoor/admin.guard'; +import { PaginationDTO, makeContentRange } from 'src/pagination/pagination.dto'; +import { Response as Res } from 'express'; @Controller('downloads') +@ApiBearerAuth() +@UseGuards(CasdoorGuard, AdminGuard) export class DownloadsController { constructor(private readonly downloadsService: DownloadsService) {} @Post() - create(@Body() createDownloadDto: CreateDownloadDto) { - return this.downloadsService.create(createDownloadDto); + @ApiResponse({ type: DownloadEntity }) + async create(): Promise { + return this.downloadsService.create(); } @Get() - findAll() { - return this.downloadsService.findAll(); - } + @ApiResponse({ type: [DownloadEntity] }) + async findAll(@Query() pagination: PaginationDTO, @Response() res: Res): Promise { + const result = await this.downloadsService.findAll(pagination); - @Get(':id') - findOne(@Param('id') id: string) { - return this.downloadsService.findOne(+id); + // Determine content-range header + const total = await this.downloadsService.count(); + res.setHeader('Content-Range', makeContentRange('tasks', pagination, total)); + + return res.json(result); } - @Patch(':id') - update(@Param('id') id: string, @Body() updateDownloadDto: UpdateDownloadDto) { - return this.downloadsService.update(+id, updateDownloadDto); + @Get(':id') + @ApiResponse({ type: DownloadEntity }) + async findOne(@Param('id') id: string): Promise { + const found = await this.downloadsService.findOne(id); + if (!found) { + throw new NotFoundException(`Task with id ${id} not found`); + } + return found; } @Delete(':id') - remove(@Param('id') id: string) { - return this.downloadsService.remove(+id); + remove(@Param('id') id: string): Promise { + return this.downloadsService.remove(id); } } diff --git a/packages/backend/src/downloads/downloads.module.ts b/packages/backend/src/downloads/downloads.module.ts index 4810929..272ac04 100644 --- a/packages/backend/src/downloads/downloads.module.ts +++ b/packages/backend/src/downloads/downloads.module.ts @@ -1,8 +1,11 @@ import { Module } from '@nestjs/common'; import { DownloadsService } from './downloads.service'; import { DownloadsController } from './downloads.controller'; +import { PrismaModule } from '../prisma/prisma.module'; +import { CasdoorModule } from '../casdoor/casdoor.module'; @Module({ + imports: [PrismaModule, CasdoorModule], controllers: [DownloadsController], providers: [DownloadsService], }) diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts index 0fe7a8a..30aca59 100644 --- a/packages/backend/src/downloads/downloads.service.ts +++ b/packages/backend/src/downloads/downloads.service.ts @@ -1,26 +1,58 @@ import { Injectable } from '@nestjs/common'; -import { CreateDownloadDto } from './dto/create-download.dto'; -import { UpdateDownloadDto } from './dto/update-download.dto'; +import { ConfigService } from '@nestjs/config'; +import { DownloadRequest, DownloadStatus } from '@prisma/client'; +import { PaginationDTO } from 'src/pagination/pagination.dto'; +import { PrismaService } from 'src/prisma/prisma.service'; @Injectable() export class DownloadsService { - create(createDownloadDto: CreateDownloadDto) { - return 'This action adds a new download'; + private readonly downloadLocation: string; + + constructor( + private readonly prismaService: PrismaService, + configService: ConfigService + ) { + this.downloadLocation = configService.getOrThrow('s3.downloadZipsFolder'); + } + + async create(): Promise { + const createdAt = new Date(); + return this.prismaService.downloadRequest.create({ + data: { + createdAt, + status: DownloadStatus.STARTING, + location: this.getLocationString(createdAt) + } + }) + } + + findAll(pagination: PaginationDTO): Promise { + return this.prismaService.downloadRequest.findMany({ + where: pagination.filter, + take: pagination.range ? pagination.range.end - pagination.range.start : undefined, + skip: pagination.range ? pagination.range.start : undefined, + orderBy: pagination.sort ? { [pagination.sort.field]: pagination.sort.direction } : undefined + }); } - findAll() { - return `This action returns all downloads`; + async findOne(id: string): Promise { + return this.prismaService.downloadRequest.findUnique({ + where: { id } + }); } - findOne(id: number) { - return `This action returns a #${id} download`; + async remove(id: string): Promise { + // TODO: Remove the ZIP in the bucket + await this.prismaService.downloadRequest.delete({ + where: { id } + }); } - update(id: number, updateDownloadDto: UpdateDownloadDto) { - return `This action updates a #${id} download`; + async count(): Promise { + return this.prismaService.downloadRequest.count(); } - remove(id: number) { - return `This action removes a #${id} download`; + private getLocationString(date: Date): string { + return `${this.downloadLocation}/download_${date.getFullYear()}_${date.toISOString()}.zip` } } diff --git a/packages/backend/src/downloads/dto/create-download.dto.ts b/packages/backend/src/downloads/dto/create-download.dto.ts deleted file mode 100644 index 72f682e..0000000 --- a/packages/backend/src/downloads/dto/create-download.dto.ts +++ /dev/null @@ -1 +0,0 @@ -export class CreateDownloadDto {} diff --git a/packages/backend/src/downloads/dto/update-download.dto.ts b/packages/backend/src/downloads/dto/update-download.dto.ts deleted file mode 100644 index cb1dd25..0000000 --- a/packages/backend/src/downloads/dto/update-download.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PartialType } from '@nestjs/mapped-types'; -import { CreateDownloadDto } from './create-download.dto'; - -export class UpdateDownloadDto extends PartialType(CreateDownloadDto) {} diff --git a/packages/backend/src/downloads/entities/download.entity.ts b/packages/backend/src/downloads/entities/download.entity.ts index 060ead4..259f1db 100644 --- a/packages/backend/src/downloads/entities/download.entity.ts +++ b/packages/backend/src/downloads/entities/download.entity.ts @@ -1 +1,16 @@ -export class Download {} +import { ApiProperty } from '@nestjs/swagger'; +import { DownloadRequest, DownloadStatus } from '@prisma/client'; + +export class DownloadEntity implements DownloadRequest { + @ApiProperty({ description: 'Unique ID of the download' }) + id: string; + + @ApiProperty({ description: 'The status of the download', enum: DownloadStatus }) + status: DownloadStatus; + + @ApiProperty({ description: 'Where the download is located in the download bucket' }) + location: string; + + @ApiProperty({ description: 'When the download request was made' }) + createdAt: Date; +} From 91e0eb87a3d40c93aaf9ea920df5fced03c2e5af Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 11:16:27 -0400 Subject: [PATCH 05/17] Start adding in downloads to admin page --- packages/admin/src/App.tsx | 2 ++ .../downloads/DownloadsLists.component.tsx | 13 +++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 packages/admin/src/components/downloads/DownloadsLists.component.tsx diff --git a/packages/admin/src/App.tsx b/packages/admin/src/App.tsx index 66829be..e5b45d5 100644 --- a/packages/admin/src/App.tsx +++ b/packages/admin/src/App.tsx @@ -8,6 +8,7 @@ import { SetsList } from './components/sets/SetsList.component'; import { StudyMappingList } from './components/studymapping/StudyMappingList.component'; import { BrowserRouter } from 'react-router-dom'; import { authProvider, JWT_TOKEN_KEY } from './auth'; +import { DownloadsList } from './components/downloads/DownloadsLists.component'; function App() { const httpClient = (url: string, options: fetchUtils.Options = {}) => { @@ -29,6 +30,7 @@ function App() { + diff --git a/packages/admin/src/components/downloads/DownloadsLists.component.tsx b/packages/admin/src/components/downloads/DownloadsLists.component.tsx new file mode 100644 index 0000000..a62988c --- /dev/null +++ b/packages/admin/src/components/downloads/DownloadsLists.component.tsx @@ -0,0 +1,13 @@ +import { Datagrid, List, TextField } from 'react-admin'; +import { FC } from 'react'; + +export const DownloadsList: FC = () => { + + return( + + + + + + ); +}; From bf9d002fa157bbea4b58f2f92e87c6c169b637da Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 11:21:35 -0400 Subject: [PATCH 06/17] Working ability to trigger a download request --- packages/admin/src/client/sdk.gen.ts | 80 +++++++++++- packages/admin/src/client/types.gen.ts | 115 ++++++++++++++++++ .../downloads/DownloadsLists.component.tsx | 31 ++++- 3 files changed, 219 insertions(+), 7 deletions(-) diff --git a/packages/admin/src/client/sdk.gen.ts b/packages/admin/src/client/sdk.gen.ts index 7a718c1..4dbebd0 100644 --- a/packages/admin/src/client/sdk.gen.ts +++ b/packages/admin/src/client/sdk.gen.ts @@ -1,7 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts import { type Options as ClientOptions, type TDataShape, type Client, formDataBodySerializer } from '@hey-api/client-fetch'; -import type { AppControllerGetHelloData, CasdoorControllerHandleRedirectData, CasdoorControllerHandleSigninData, TasksControllerFindAllData, TasksControllerFindAllResponse, TasksControllerCreateData, TasksControllerCreateResponse, TasksControllerRemoveData, TasksControllerFindOneData, TasksControllerFindOneResponse, TasksControllerUpdateData, TasksControllerUpdateResponse, TasksControllerGetActiveTasksData, TasksControllerGetActiveTasksResponse, TaskSetControllerFindAllData, TaskSetControllerFindAllResponse, TaskSetControllerCreateData, TaskSetControllerCreateResponse, TaskSetControllerRemoveData, TaskSetControllerFindOneData, TaskSetControllerFindOneResponse, TaskSetControllerUpdateData, TaskSetControllerUpdateResponse, TaskSetControllerSetActiveData, TaskSetControllerSetActiveResponse, TaskCompletionsControllerRemoveData, TaskCompletionsControllerFindAllData, TaskCompletionsControllerFindAllResponse, TaskCompletionsControllerUpdateData, TaskCompletionsControllerUpdateResponse, TaskCompletionsControllerCreateData, TaskCompletionsControllerCreateResponse, TaskCompletionsControllerFindOneData, TaskCompletionsControllerFindOneResponse, TaskCompletionsControllerFindOrCreateByUserTaskData, TaskCompletionsControllerFindOrCreateByUserTaskResponse, TaskCompletionsControllerFindOrCreateByTaskData, TaskCompletionsControllerFindOrCreateByTaskResponse, TaskCompletionsControllerGetNextIncompleteData, TaskCompletionsControllerGetNextIncompleteResponse, TaskCompletionsControllerGetVideoUploadUrlData, TaskCompletionsControllerGetVideoUploadUrlResponse, TaskCompletionsControllerGetVideoDownloadUrlData, TaskCompletionsControllerGetVideoDownloadUrlResponse, TaskCompletionsControllerDeleteVideoData, UsersControllerFindAllData, UsersControllerFindOneData, StudymappingControllerFindAllData, StudymappingControllerFindAllResponse, StudymappingControllerWebhookData, StudymappingControllerUploadCsvData } from './types.gen'; +import type { AppControllerGetHelloData, CasdoorControllerHandleRedirectData, CasdoorControllerHandleSigninData, TasksControllerFindAllData, TasksControllerFindAllResponse, TasksControllerCreateData, TasksControllerCreateResponse, TasksControllerRemoveData, TasksControllerFindOneData, TasksControllerFindOneResponse, TasksControllerUpdateData, TasksControllerUpdateResponse, TasksControllerGetActiveTasksData, TasksControllerGetActiveTasksResponse, TaskSetControllerFindAllData, TaskSetControllerFindAllResponse, TaskSetControllerCreateData, TaskSetControllerCreateResponse, TaskSetControllerRemoveData, TaskSetControllerFindOneData, TaskSetControllerFindOneResponse, TaskSetControllerUpdateData, TaskSetControllerUpdateResponse, TaskSetControllerSetActiveData, TaskSetControllerSetActiveResponse, TaskCompletionsControllerRemoveData, TaskCompletionsControllerFindAllData, TaskCompletionsControllerFindAllResponse, TaskCompletionsControllerUpdateData, TaskCompletionsControllerUpdateResponse, TaskCompletionsControllerCreateData, TaskCompletionsControllerCreateResponse, TaskCompletionsControllerFindOneData, TaskCompletionsControllerFindOneResponse, TaskCompletionsControllerFindOrCreateByUserTaskData, TaskCompletionsControllerFindOrCreateByUserTaskResponse, TaskCompletionsControllerFindOrCreateByTaskData, TaskCompletionsControllerFindOrCreateByTaskResponse, TaskCompletionsControllerGetNextIncompleteData, TaskCompletionsControllerGetNextIncompleteResponse, TaskCompletionsControllerGetVideoUploadUrlData, TaskCompletionsControllerGetVideoUploadUrlResponse, TaskCompletionsControllerGetVideoDownloadUrlData, TaskCompletionsControllerGetVideoDownloadUrlResponse, TaskCompletionsControllerDeleteVideoData, UsersControllerFindAllData, UsersControllerFindOneData, UsersControllerIsTrainingCompleteData, UsersControllerIsTrainingCompleteResponse, UsersControllerMarkTrainingCompleteData, StudymappingControllerFindAllData, StudymappingControllerFindAllResponse, StudymappingControllerWebhookData, StudymappingControllerUploadCsvData, DownloadsControllerFindAllData, DownloadsControllerFindAllResponse, DownloadsControllerCreateData, DownloadsControllerCreateResponse, DownloadsControllerRemoveData, DownloadsControllerFindOneData, DownloadsControllerFindOneResponse } from './types.gen'; import { client as _heyApiClient } from './client.gen'; export type Options = ClientOptions & { @@ -406,6 +406,32 @@ export const usersControllerFindOne = (opt }); }; +export const usersControllerIsTrainingComplete = (options: Options) => { + return (options.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/users/training-complete/{id}', + ...options + }); +}; + +export const usersControllerMarkTrainingComplete = (options: Options) => { + return (options.client ?? _heyApiClient).put({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/users/training-complete/{id}', + ...options + }); +}; + export const studymappingControllerFindAll = (options?: Options) => { return (options?.client ?? _heyApiClient).get({ security: [ @@ -452,4 +478,56 @@ export const studymappingControllerUploadCsv = (options?: Options) => { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/downloads', + ...options + }); +}; + +export const downloadsControllerCreate = (options?: Options) => { + return (options?.client ?? _heyApiClient).post({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/downloads', + ...options + }); +}; + +export const downloadsControllerRemove = (options: Options) => { + return (options.client ?? _heyApiClient).delete({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/downloads/{id}', + ...options + }); +}; + +export const downloadsControllerFindOne = (options: Options) => { + return (options.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/downloads/{id}', + ...options + }); }; \ No newline at end of file diff --git a/packages/admin/src/client/types.gen.ts b/packages/admin/src/client/types.gen.ts index 26714e1..ab12749 100644 --- a/packages/admin/src/client/types.gen.ts +++ b/packages/admin/src/client/types.gen.ts @@ -49,6 +49,12 @@ export type CreateTaskDto = { * User provided ID for the task */ descriptor: string; + /** + * Optional content image + */ + contentImage: { + [key: string]: unknown; + }; }; export type TaskEntity = { @@ -106,6 +112,10 @@ export type TaskEntity = { * User provided ID for the task */ descriptor: string; + /** + * Optional content image + */ + contentImage: string | null; }; export type UpdateTaskDto = { @@ -214,6 +224,10 @@ export type UpdateTaskCompletionDto = { userId?: string; }; +export type HasComplete = { + complete: boolean; +}; + export type WebhookPayload = { [key: string]: unknown; }; @@ -237,6 +251,25 @@ export type StudyMappingEntity = { region: string; }; +export type DownloadEntity = { + /** + * Unique ID of the download + */ + id: string; + /** + * The status of the download + */ + status: 'STARTING' | 'IN_PROGRESS' | 'COMPLETE' | 'FAILED'; + /** + * Where the download is located in the download bucket + */ + location: string; + /** + * When the download request was made + */ + createdAt: string; +}; + export type AppControllerGetHelloData = { body?: never; path?: never; @@ -650,6 +683,34 @@ export type UsersControllerFindOneResponses = { 200: unknown; }; +export type UsersControllerIsTrainingCompleteData = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/users/training-complete/{id}'; +}; + +export type UsersControllerIsTrainingCompleteResponses = { + default: HasComplete; +}; + +export type UsersControllerIsTrainingCompleteResponse = UsersControllerIsTrainingCompleteResponses[keyof UsersControllerIsTrainingCompleteResponses]; + +export type UsersControllerMarkTrainingCompleteData = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/users/training-complete/{id}'; +}; + +export type UsersControllerMarkTrainingCompleteResponses = { + 200: unknown; +}; + export type StudymappingControllerFindAllData = { body?: never; path?: never; @@ -687,6 +748,60 @@ export type StudymappingControllerUploadCsvResponses = { 201: unknown; }; +export type DownloadsControllerFindAllData = { + body?: never; + path?: never; + query?: never; + url: '/downloads'; +}; + +export type DownloadsControllerFindAllResponses = { + default: Array; +}; + +export type DownloadsControllerFindAllResponse = DownloadsControllerFindAllResponses[keyof DownloadsControllerFindAllResponses]; + +export type DownloadsControllerCreateData = { + body?: never; + path?: never; + query?: never; + url: '/downloads'; +}; + +export type DownloadsControllerCreateResponses = { + default: DownloadEntity; +}; + +export type DownloadsControllerCreateResponse = DownloadsControllerCreateResponses[keyof DownloadsControllerCreateResponses]; + +export type DownloadsControllerRemoveData = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/downloads/{id}'; +}; + +export type DownloadsControllerRemoveResponses = { + 200: unknown; +}; + +export type DownloadsControllerFindOneData = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/downloads/{id}'; +}; + +export type DownloadsControllerFindOneResponses = { + default: DownloadEntity; +}; + +export type DownloadsControllerFindOneResponse = DownloadsControllerFindOneResponses[keyof DownloadsControllerFindOneResponses]; + export type ClientOptions = { baseUrl: string; }; \ No newline at end of file diff --git a/packages/admin/src/components/downloads/DownloadsLists.component.tsx b/packages/admin/src/components/downloads/DownloadsLists.component.tsx index a62988c..feeb395 100644 --- a/packages/admin/src/components/downloads/DownloadsLists.component.tsx +++ b/packages/admin/src/components/downloads/DownloadsLists.component.tsx @@ -1,13 +1,32 @@ -import { Datagrid, List, TextField } from 'react-admin'; +import { Button, Datagrid, List, TextField, useRefresh } from 'react-admin'; import { FC } from 'react'; +import { Stack } from '@mui/material'; +import { downloadsControllerCreate } from '../../client'; export const DownloadsList: FC = () => { + const refresh = useRefresh(); + + const handleDownloadRequest = async () => { + const downloadResponse = await downloadsControllerCreate(); + + if (downloadResponse.error || !downloadResponse.data) { + console.error(downloadResponse.error); + alert('Failed to make a download request') + return; + } + + alert('Download in progress'); + refresh(); + }; return( - - - - - + + + + + + + + ); }; From f1963f8451a497812269526d3c410fd2c7885762 Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 11:22:59 -0400 Subject: [PATCH 07/17] Fill in additional columns --- .../src/components/downloads/DownloadsLists.component.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/admin/src/components/downloads/DownloadsLists.component.tsx b/packages/admin/src/components/downloads/DownloadsLists.component.tsx index feeb395..622b945 100644 --- a/packages/admin/src/components/downloads/DownloadsLists.component.tsx +++ b/packages/admin/src/components/downloads/DownloadsLists.component.tsx @@ -1,4 +1,4 @@ -import { Button, Datagrid, List, TextField, useRefresh } from 'react-admin'; +import { Button, Datagrid, DateField, List, TextField, useRefresh } from 'react-admin'; import { FC } from 'react'; import { Stack } from '@mui/material'; import { downloadsControllerCreate } from '../../client'; @@ -24,7 +24,9 @@ export const DownloadsList: FC = () => { + + From 66bc7045cd95107ef36afea493ffffee30e21ce2 Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 11:38:32 -0400 Subject: [PATCH 08/17] Start working on the download logic --- .../src/downloads/downloads.service.ts | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts index 30aca59..a9812d3 100644 --- a/packages/backend/src/downloads/downloads.service.ts +++ b/packages/backend/src/downloads/downloads.service.ts @@ -1,8 +1,9 @@ import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; +import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; import { DownloadRequest, DownloadStatus } from '@prisma/client'; -import { PaginationDTO } from 'src/pagination/pagination.dto'; -import { PrismaService } from 'src/prisma/prisma.service'; +import { PaginationDTO } from '../pagination/pagination.dto'; +import { PrismaService } from '../prisma/prisma.service'; @Injectable() export class DownloadsService { @@ -10,20 +11,27 @@ export class DownloadsService { constructor( private readonly prismaService: PrismaService, - configService: ConfigService + configService: ConfigService, + private readonly eventEmitter: EventEmitter2 ) { this.downloadLocation = configService.getOrThrow('s3.downloadZipsFolder'); } async create(): Promise { + // Make the request const createdAt = new Date(); - return this.prismaService.downloadRequest.create({ + const request = this.prismaService.downloadRequest.create({ data: { createdAt, status: DownloadStatus.STARTING, location: this.getLocationString(createdAt) } - }) + }); + + // Trigger the download progress + this.eventEmitter.emit('download.created', request); + + return request; } findAll(pagination: PaginationDTO): Promise { @@ -55,4 +63,8 @@ export class DownloadsService { private getLocationString(date: Date): string { return `${this.downloadLocation}/download_${date.getFullYear()}_${date.toISOString()}.zip` } + + @OnEvent('download.created') + async handleDownload(payload: DownloadRequest): Promise { + } } From 963fc7433eb290f49c04c270ec80ace8fca1895c Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 12:25:30 -0400 Subject: [PATCH 09/17] Working ability to get target objects to download --- .../backend/src/downloads/downloads.module.ts | 6 +- .../src/downloads/downloads.service.ts | 24 +++++-- packages/backend/src/downloads/events.ts | 4 ++ packages/backend/src/downloads/zip.service.ts | 69 +++++++++++++++++++ 4 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 packages/backend/src/downloads/events.ts create mode 100644 packages/backend/src/downloads/zip.service.ts diff --git a/packages/backend/src/downloads/downloads.module.ts b/packages/backend/src/downloads/downloads.module.ts index 272ac04..860f858 100644 --- a/packages/backend/src/downloads/downloads.module.ts +++ b/packages/backend/src/downloads/downloads.module.ts @@ -3,10 +3,12 @@ import { DownloadsService } from './downloads.service'; import { DownloadsController } from './downloads.controller'; import { PrismaModule } from '../prisma/prisma.module'; import { CasdoorModule } from '../casdoor/casdoor.module'; +import { S3Module } from '../s3/s3.module'; +import { Zipper } from './zip.service'; @Module({ - imports: [PrismaModule, CasdoorModule], + imports: [PrismaModule, CasdoorModule, S3Module], controllers: [DownloadsController], - providers: [DownloadsService], + providers: [DownloadsService, Zipper], }) export class DownloadsModule {} diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts index a9812d3..57b523e 100644 --- a/packages/backend/src/downloads/downloads.service.ts +++ b/packages/backend/src/downloads/downloads.service.ts @@ -1,9 +1,10 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; import { DownloadRequest, DownloadStatus } from '@prisma/client'; import { PaginationDTO } from '../pagination/pagination.dto'; import { PrismaService } from '../prisma/prisma.service'; +import * as events from './events'; @Injectable() export class DownloadsService { @@ -12,7 +13,7 @@ export class DownloadsService { constructor( private readonly prismaService: PrismaService, configService: ConfigService, - private readonly eventEmitter: EventEmitter2 + private readonly eventEmitter: EventEmitter2, ) { this.downloadLocation = configService.getOrThrow('s3.downloadZipsFolder'); } @@ -29,7 +30,7 @@ export class DownloadsService { }); // Trigger the download progress - this.eventEmitter.emit('download.created', request); + this.eventEmitter.emit(events.DOWNLOAD_REQUEST_CREATED, request); return request; } @@ -64,7 +65,20 @@ export class DownloadsService { return `${this.downloadLocation}/download_${date.getFullYear()}_${date.toISOString()}.zip` } - @OnEvent('download.created') - async handleDownload(payload: DownloadRequest): Promise { + @OnEvent(events.DOWNLOAD_SUCCESS) + async markSuccess(payload: DownloadRequest) { + await this.prismaService.downloadRequest.update({ + where: { id: payload.id }, + data: { status: DownloadStatus.COMPLETE } + }); } + + @OnEvent(events.DOWNLOAD_REQUEST_FAILED) + async markFailed(payload: DownloadRequest) { + await this.prismaService.downloadRequest.update({ + where: { id: payload.id }, + data: { status: DownloadStatus.FAILED } + }); + } + } diff --git a/packages/backend/src/downloads/events.ts b/packages/backend/src/downloads/events.ts new file mode 100644 index 0000000..2be1880 --- /dev/null +++ b/packages/backend/src/downloads/events.ts @@ -0,0 +1,4 @@ + +export const DOWNLOAD_REQUEST_CREATED = 'download.created'; +export const DOWNLOAD_REQUEST_FAILED = 'download.failed'; +export const DOWNLOAD_SUCCESS = 'download.success'; diff --git a/packages/backend/src/downloads/zip.service.ts b/packages/backend/src/downloads/zip.service.ts new file mode 100644 index 0000000..f730e3d --- /dev/null +++ b/packages/backend/src/downloads/zip.service.ts @@ -0,0 +1,69 @@ +import { Injectable, Inject } from '@nestjs/common'; +import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; +import * as events from './events'; +import { S3_PROVIDER } from 'src/s3/s3.provider'; +import { paginateListObjectsV2, S3Client } from '@aws-sdk/client-s3'; +import { ConfigService } from '@nestjs/config'; +import { DownloadRequest } from '@prisma/client'; + +@Injectable() +export class Zipper { + private readonly bucket: string; + private readonly downloadsFolder: string; + + constructor( + @Inject(S3_PROVIDER) private readonly s3: S3Client, + configService: ConfigService, + private readonly eventEmitter: EventEmitter2 + ) { + this.bucket = configService.getOrThrow('s3.bucket'); + this.downloadsFolder = configService.getOrThrow('s3.downloadZipsFolder'); + } + + @OnEvent(events.DOWNLOAD_REQUEST_CREATED) + async handleDownload(payload: DownloadRequest) { + try { + await this.download(); + } catch(e) { + console.error(e); + this.eventEmitter.emit(events.DOWNLOAD_REQUEST_FAILED, payload); + } + } + + private async download() { + const objects = await this.generateListOfFiles(); + console.log(objects); + } + + private async generateListOfFiles(): Promise { + const paginator = paginateListObjectsV2( + { client: this.s3, pageSize: 100 }, + { Bucket: this.bucket } + ); + + const objects: string[] = []; + + for await (const page of paginator) { + if (!page.Contents) { + continue; + } + for (const object of page.Contents) { + // Get the key + const key = object.Key; + if (!key) { + continue; + } + + // Make sure it doesn't start with the download prefix + if (key.startsWith(this.downloadsFolder)) { + continue; + } + + // Otherwise add it to the list of objects + objects.push(key); + } + } + + return objects; + } +} From a4d5633d2f2ea9e7610731b0c076b3fd9faff226 Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 16:02:10 -0400 Subject: [PATCH 10/17] Working ability to zip videos --- packages/backend/package-lock.json | 613 ++++++++++++++++-- packages/backend/package.json | 6 +- packages/backend/src/downloads/zip.service.ts | 46 +- 3 files changed, 604 insertions(+), 61 deletions(-) diff --git a/packages/backend/package-lock.json b/packages/backend/package-lock.json index 4956fa1..4652395 100644 --- a/packages/backend/package-lock.json +++ b/packages/backend/package-lock.json @@ -18,12 +18,14 @@ "@nestjs/platform-express": "^11.0.1", "@nestjs/swagger": "^11.1.0", "@prisma/client": "^6.5.0", + "archiver": "^7.0.1", "casdoor-nodejs-sdk": "^1.27.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "csv-parser": "^3.2.0", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "tmp": "^0.2.3" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", @@ -33,11 +35,13 @@ "@nestjs/testing": "^11.0.1", "@swc/cli": "^0.6.0", "@swc/core": "^1.10.7", + "@types/archiver": "^6.0.3", "@types/express": "^5.0.0", "@types/jest": "^29.5.14", "@types/multer": "^1.4.12", "@types/node": "^22.10.7", "@types/supertest": "^6.0.2", + "@types/tmp": "^0.2.6", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-prettier": "^5.2.2", @@ -2607,7 +2611,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -2625,7 +2628,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -2638,14 +2640,12 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -2663,7 +2663,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -4023,6 +4022,16 @@ "@noble/hashes": "^1.1.5" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@pkgr/core": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.0.tgz", @@ -5252,6 +5261,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/archiver": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.3.tgz", + "integrity": "sha512-a6wUll6k3zX6qs5KlxIggs1P1JcYJaTCx2gnlr+f0S1yd2DoaEwoIK10HmBaLnZwWneBz+JBm0dwcZu0zECBcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/readdir-glob": "*" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -5496,6 +5515,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/readdir-glob": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.5.tgz", + "integrity": "sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -5550,6 +5579,13 @@ "@types/superagent": "^8.1.0" } }, + "node_modules/@types/tmp": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.6.tgz", + "integrity": "sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/validator": { "version": "13.12.3", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.3.tgz", @@ -6112,6 +6148,18 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -6260,7 +6308,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -6273,7 +6320,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -6349,6 +6395,230 @@ ], "license": "MIT" }, + "node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/archiver-utils/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/archiver-utils/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/archiver/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/archiver/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/archiver/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -6380,7 +6650,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, "license": "MIT" }, "node_modules/asynckit": { @@ -6404,7 +6673,6 @@ "version": "1.6.7", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", - "dev": true, "license": "Apache-2.0" }, "node_modules/babel-jest": { @@ -6537,14 +6805,12 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/bare-events": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", - "dev": true, "license": "Apache-2.0", "optional": true }, @@ -6552,7 +6818,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -7183,7 +7448,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -7196,7 +7460,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/combined-stream": { @@ -7248,6 +7511,71 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/compress-commons/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/compress-commons/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -7379,6 +7707,80 @@ } } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/crc32-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/crc32-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -7412,7 +7814,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -7649,7 +8050,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, "license": "MIT" }, "node_modules/ecdsa-sig-formatter": { @@ -7707,7 +8107,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/encodeurl": { @@ -8100,6 +8499,15 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter2": { "version": "6.4.9", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", @@ -8110,7 +8518,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" @@ -8306,6 +8713,19 @@ "node": ">=0.10.0" } }, + "node_modules/external-editor/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -8324,7 +8744,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -8697,7 +9116,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -9155,7 +9573,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": { @@ -9454,7 +9871,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9523,7 +9939,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9555,7 +9970,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -10510,6 +10924,18 @@ "node": ">=6" } }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -10916,7 +11342,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -11106,7 +11531,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11327,7 +11751,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { @@ -11395,7 +11818,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -11690,6 +12112,15 @@ } } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -11867,6 +12298,36 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -12252,7 +12713,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -12265,7 +12725,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12347,7 +12806,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -12481,7 +12939,6 @@ "version": "2.22.0", "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", - "dev": true, "license": "MIT", "dependencies": { "fast-fifo": "^1.3.2", @@ -12547,7 +13004,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -12563,7 +13019,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -12578,7 +13033,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12588,7 +13042,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -12601,7 +13054,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12611,7 +13063,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -12624,7 +13075,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -12641,7 +13091,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -12654,7 +13103,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12845,7 +13293,6 @@ "version": "3.1.7", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "dev": true, "license": "MIT", "dependencies": { "b4a": "^1.6.4", @@ -13061,7 +13508,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" @@ -13075,16 +13521,12 @@ "license": "MIT" }, "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, "engines": { - "node": ">=0.6.0" + "node": ">=14.14" } }, "node_modules/tmpl": { @@ -13843,7 +14285,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -13885,7 +14326,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -13903,7 +14343,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13913,7 +14352,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -14076,6 +14514,69 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zip-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/zip-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } } } } diff --git a/packages/backend/package.json b/packages/backend/package.json index 1297f58..3eb5a56 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -30,12 +30,14 @@ "@nestjs/platform-express": "^11.0.1", "@nestjs/swagger": "^11.1.0", "@prisma/client": "^6.5.0", + "archiver": "^7.0.1", "casdoor-nodejs-sdk": "^1.27.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "csv-parser": "^3.2.0", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "tmp": "^0.2.3" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", @@ -45,11 +47,13 @@ "@nestjs/testing": "^11.0.1", "@swc/cli": "^0.6.0", "@swc/core": "^1.10.7", + "@types/archiver": "^6.0.3", "@types/express": "^5.0.0", "@types/jest": "^29.5.14", "@types/multer": "^1.4.12", "@types/node": "^22.10.7", "@types/supertest": "^6.0.2", + "@types/tmp": "^0.2.6", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-prettier": "^5.2.2", diff --git a/packages/backend/src/downloads/zip.service.ts b/packages/backend/src/downloads/zip.service.ts index f730e3d..d761eab 100644 --- a/packages/backend/src/downloads/zip.service.ts +++ b/packages/backend/src/downloads/zip.service.ts @@ -1,10 +1,14 @@ import { Injectable, Inject } from '@nestjs/common'; import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; import * as events from './events'; -import { S3_PROVIDER } from 'src/s3/s3.provider'; -import { paginateListObjectsV2, S3Client } from '@aws-sdk/client-s3'; +import { S3_PROVIDER } from '../s3/s3.provider'; +import { paginateListObjectsV2, S3Client, GetObjectCommand } from '@aws-sdk/client-s3'; import { ConfigService } from '@nestjs/config'; import { DownloadRequest } from '@prisma/client'; +import * as archiver from 'archiver'; +import { createWriteStream } from 'fs'; +import { fileSync } from 'tmp'; +import { basename } from 'path'; @Injectable() export class Zipper { @@ -30,9 +34,43 @@ export class Zipper { } } - private async download() { + private async download(): Promise { + // Get the objects to zip const objects = await this.generateListOfFiles(); - console.log(objects); + + // Get a temporary file to store the zip + const tmpFile = fileSync(); + + // Make a file stream into the temp file + const fileStream = createWriteStream(tmpFile.name); + + // Make the streaming archive + const archive = archiver.create('zip'); + archive.pipe(fileStream); + archive.on('error', err => { + throw err; + }); + + // Loop over the objects + for (const key of objects) { + // Download the file + const command = new GetObjectCommand({ Bucket: this.bucket, Key: key }); + const response = await this.s3.send(command); + const file = response.Body; + if (!file) { + continue; + } + + // Make a buffer of the file + const buffer = Buffer.from(await file.transformToByteArray()); + + // Use only the base name in the zip + const entryName = basename(key); + + // Add the file to the archive + archive.append(buffer, { name: entryName }); + } + await archive.finalize(); } private async generateListOfFiles(): Promise { From e3899c05c5fd105e8c9f31babd8c3ad08a64873a Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Wed, 11 Jun 2025 16:32:31 -0400 Subject: [PATCH 11/17] Working on upload logic --- .../src/downloads/downloads.service.ts | 5 ++- packages/backend/src/downloads/zip.service.ts | 43 ++++++++++++++++--- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts index 57b523e..1dd4909 100644 --- a/packages/backend/src/downloads/downloads.service.ts +++ b/packages/backend/src/downloads/downloads.service.ts @@ -21,7 +21,7 @@ export class DownloadsService { async create(): Promise { // Make the request const createdAt = new Date(); - const request = this.prismaService.downloadRequest.create({ + const request = await this.prismaService.downloadRequest.create({ data: { createdAt, status: DownloadStatus.STARTING, @@ -62,7 +62,7 @@ export class DownloadsService { } private getLocationString(date: Date): string { - return `${this.downloadLocation}/download_${date.getFullYear()}_${date.toISOString()}.zip` + return `${this.downloadLocation}/download_${date.getFullYear()}.zip` } @OnEvent(events.DOWNLOAD_SUCCESS) @@ -75,6 +75,7 @@ export class DownloadsService { @OnEvent(events.DOWNLOAD_REQUEST_FAILED) async markFailed(payload: DownloadRequest) { + console.log(payload); await this.prismaService.downloadRequest.update({ where: { id: payload.id }, data: { status: DownloadStatus.FAILED } diff --git a/packages/backend/src/downloads/zip.service.ts b/packages/backend/src/downloads/zip.service.ts index d761eab..200ce89 100644 --- a/packages/backend/src/downloads/zip.service.ts +++ b/packages/backend/src/downloads/zip.service.ts @@ -2,13 +2,14 @@ import { Injectable, Inject } from '@nestjs/common'; import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; import * as events from './events'; import { S3_PROVIDER } from '../s3/s3.provider'; -import { paginateListObjectsV2, S3Client, GetObjectCommand } from '@aws-sdk/client-s3'; +import { paginateListObjectsV2, S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3'; import { ConfigService } from '@nestjs/config'; import { DownloadRequest } from '@prisma/client'; import * as archiver from 'archiver'; -import { createWriteStream } from 'fs'; -import { fileSync } from 'tmp'; +import { createReadStream, createWriteStream } from 'fs'; +import { FileResult, fileSync } from 'tmp'; import { basename } from 'path'; +import { stat } from 'fs/promises'; @Injectable() export class Zipper { @@ -27,14 +28,39 @@ export class Zipper { @OnEvent(events.DOWNLOAD_REQUEST_CREATED) async handleDownload(payload: DownloadRequest) { try { - await this.download(); + // Make the zip + const file = await this.download(); + + // Upload the zip + await this.uploadZip(payload, file) + + // Mark the download process as complete + this.eventEmitter.emit(events.DOWNLOAD_SUCCESS, payload); } catch(e) { console.error(e); this.eventEmitter.emit(events.DOWNLOAD_REQUEST_FAILED, payload); } } - private async download(): Promise { + private async uploadZip(downloadRequest: DownloadRequest, file: FileResult): Promise { + // Make the read stream + const stream = createReadStream(file.name); + + const fileInfo = await stat(file.name); + + // Make the put command + const putCmd = new PutObjectCommand({ + Bucket: this.bucket, + Key: downloadRequest.location, + Body: stream, + ContentType: 'application/zip', + ContentLength: fileInfo.size + }); + + await this.s3.send(putCmd); + } + + private async download(): Promise { // Get the objects to zip const objects = await this.generateListOfFiles(); @@ -70,7 +96,14 @@ export class Zipper { // Add the file to the archive archive.append(buffer, { name: entryName }); } + + // Wait for the archive process to finalize await archive.finalize(); + + fileStream.close(); + + // Return the location of the zipped file + return tmpFile; } private async generateListOfFiles(): Promise { From 493d836af424e4b3c57e22fba81be2df8c3b4a7e Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Thu, 12 Jun 2025 10:18:52 -0400 Subject: [PATCH 12/17] Working file upload --- .../src/downloads/downloads.service.ts | 2 +- packages/backend/src/downloads/zip.service.ts | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts index 1dd4909..e4fd464 100644 --- a/packages/backend/src/downloads/downloads.service.ts +++ b/packages/backend/src/downloads/downloads.service.ts @@ -62,7 +62,7 @@ export class DownloadsService { } private getLocationString(date: Date): string { - return `${this.downloadLocation}/download_${date.getFullYear()}.zip` + return `${this.downloadLocation}/download_${date.toISOString()}.zip` } @OnEvent(events.DOWNLOAD_SUCCESS) diff --git a/packages/backend/src/downloads/zip.service.ts b/packages/backend/src/downloads/zip.service.ts index 200ce89..54946f4 100644 --- a/packages/backend/src/downloads/zip.service.ts +++ b/packages/backend/src/downloads/zip.service.ts @@ -7,9 +7,8 @@ import { ConfigService } from '@nestjs/config'; import { DownloadRequest } from '@prisma/client'; import * as archiver from 'archiver'; import { createReadStream, createWriteStream } from 'fs'; -import { FileResult, fileSync } from 'tmp'; +import { FileResultNoFd, fileSync } from 'tmp'; import { basename } from 'path'; -import { stat } from 'fs/promises'; @Injectable() export class Zipper { @@ -42,11 +41,18 @@ export class Zipper { } } - private async uploadZip(downloadRequest: DownloadRequest, file: FileResult): Promise { + private async uploadZip(downloadRequest: DownloadRequest, file: FileResultNoFd): Promise { // Make the read stream const stream = createReadStream(file.name); - const fileInfo = await stat(file.name); + await new Promise((resolve, reject) => { + stream.on('ready', () => { + resolve('Success'); + }); + stream.on('error', () => { + reject(); + }) + }); // Make the put command const putCmd = new PutObjectCommand({ @@ -54,18 +60,17 @@ export class Zipper { Key: downloadRequest.location, Body: stream, ContentType: 'application/zip', - ContentLength: fileInfo.size }); await this.s3.send(putCmd); } - private async download(): Promise { + private async download(): Promise { // Get the objects to zip const objects = await this.generateListOfFiles(); // Get a temporary file to store the zip - const tmpFile = fileSync(); + const tmpFile = fileSync({ discardDescriptor: true }); // Make a file stream into the temp file const fileStream = createWriteStream(tmpFile.name); From 4088c3f2a4ded497fe5e2a7d60bf27b1e7978718 Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Thu, 12 Jun 2025 11:00:20 -0400 Subject: [PATCH 13/17] Multi-part upload --- packages/backend/package-lock.json | 1771 ++++++++++++----- packages/backend/package.json | 1 + .../src/downloads/downloads.service.ts | 4 +- packages/backend/src/downloads/zip.service.ts | 24 +- 4 files changed, 1279 insertions(+), 521 deletions(-) diff --git a/packages/backend/package-lock.json b/packages/backend/package-lock.json index 4652395..0e38133 100644 --- a/packages/backend/package-lock.json +++ b/packages/backend/package-lock.json @@ -10,6 +10,7 @@ "license": "UNLICENSED", "dependencies": { "@aws-sdk/client-s3": "^3.782.0", + "@aws-sdk/lib-storage": "^3.828.0", "@aws-sdk/s3-request-presigner": "^3.782.0", "@nestjs/common": "^11.0.1", "@nestjs/config": "^4.0.2", @@ -415,66 +416,159 @@ } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.782.0.tgz", - "integrity": "sha512-V6JR2JAGYQY7J8wk5un5n/ja2nfCUyyoRCF8Du8JL91NGI8i41Mdr/TzuOGwTgFl6RSXb/ge1K1jk30OH4MugQ==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.828.0.tgz", + "integrity": "sha512-TvFyrEfJkf9NN3cq5mXCgFv/sPaA8Rm5tEPgV5emuLedeGsORlWmVpdSKqfZ4lSoED1tMfNM6LY4uA9D8/RS5g==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-node": "3.782.0", - "@aws-sdk/middleware-bucket-endpoint": "3.775.0", - "@aws-sdk/middleware-expect-continue": "3.775.0", - "@aws-sdk/middleware-flexible-checksums": "3.775.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-location-constraint": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-sdk-s3": "3.775.0", - "@aws-sdk/middleware-ssec": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.782.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/signature-v4-multi-region": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.782.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.782.0", - "@aws-sdk/xml-builder": "3.775.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/eventstream-serde-browser": "^4.0.2", - "@smithy/eventstream-serde-config-resolver": "^4.1.0", - "@smithy/eventstream-serde-node": "^4.0.2", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-blob-browser": "^4.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/hash-stream-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/md5-js": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.826.0", + "@aws-sdk/credential-provider-node": "3.828.0", + "@aws-sdk/middleware-bucket-endpoint": "3.821.0", + "@aws-sdk/middleware-expect-continue": "3.821.0", + "@aws-sdk/middleware-flexible-checksums": "3.826.0", + "@aws-sdk/middleware-host-header": "3.821.0", + "@aws-sdk/middleware-location-constraint": "3.821.0", + "@aws-sdk/middleware-logger": "3.821.0", + "@aws-sdk/middleware-recursion-detection": "3.821.0", + "@aws-sdk/middleware-sdk-s3": "3.826.0", + "@aws-sdk/middleware-ssec": "3.821.0", + "@aws-sdk/middleware-user-agent": "3.828.0", + "@aws-sdk/region-config-resolver": "3.821.0", + "@aws-sdk/signature-v4-multi-region": "3.826.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/util-endpoints": "3.828.0", + "@aws-sdk/util-user-agent-browser": "3.821.0", + "@aws-sdk/util-user-agent-node": "3.828.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.5.3", + "@smithy/eventstream-serde-browser": "^4.0.4", + "@smithy/eventstream-serde-config-resolver": "^4.1.2", + "@smithy/eventstream-serde-node": "^4.0.4", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-blob-browser": "^4.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/hash-stream-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/md5-js": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.11", + "@smithy/middleware-retry": "^4.1.12", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-stream": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.0.19", + "@smithy/util-defaults-mode-node": "^4.0.19", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.5", + "@smithy/util-stream": "^4.2.2", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.3", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.826.0.tgz", + "integrity": "sha512-8F0qWaYKfvD/de1AKccXuigM+gb/IZSncCqxdnFWqd+TFzo9qI9Hh+TpUhWOMYSgxsMsYQ8ipmLzlD/lDhjrmA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.826.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/util-arn-parser": "3.804.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-stream": "^4.2.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.826.0.tgz", + "integrity": "sha512-3fEi/zy6tpMzomYosksGtu7jZqGFcdBXoL7YRsG7OEeQzBbOW9B+fVaQZ4jnsViSjzA/yKydLahMrfPnt+iaxg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.826.0", + "@aws-sdk/types": "3.821.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-arn-parser": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.804.0.tgz", + "integrity": "sha512-wmBJqn1DRXnZu3b4EkE6CWnoWMo1ZMvlfkqU5zPz67xx1GMaXlDCchFvKAXMjk4jn/L1O3tKnoFDNsoLV1kgNQ==", + "license": "Apache-2.0", + "dependencies": { "tslib": "^2.6.2" }, "engines": { @@ -482,47 +576,47 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.782.0.tgz", - "integrity": "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.828.0.tgz", + "integrity": "sha512-qxw8JcPTaFaBwTBUr4YmLajaMh3En65SuBWAKEtjctbITRRekzR7tvr/TkwoyVOh+XoAtkwOn+BQeQbX+/wgHw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.782.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.782.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.782.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.826.0", + "@aws-sdk/middleware-host-header": "3.821.0", + "@aws-sdk/middleware-logger": "3.821.0", + "@aws-sdk/middleware-recursion-detection": "3.821.0", + "@aws-sdk/middleware-user-agent": "3.828.0", + "@aws-sdk/region-config-resolver": "3.821.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/util-endpoints": "3.828.0", + "@aws-sdk/util-user-agent-browser": "3.821.0", + "@aws-sdk/util-user-agent-node": "3.828.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.5.3", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.11", + "@smithy/middleware-retry": "^4.1.12", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-defaults-mode-browser": "^4.0.19", + "@smithy/util-defaults-mode-node": "^4.0.19", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.5", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -530,6 +624,45 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/core": { "version": "3.775.0", "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz", @@ -553,15 +686,54 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz", - "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==", + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.826.0.tgz", + "integrity": "sha512-DK3pQY8+iKK3MGDdC3uOZQ2psU01obaKlTYhEwNu4VWzgwQL4Vi3sWj4xSWGEK41vqZxiRLq6fOq7ysRI+qEZA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.826.0", + "@aws-sdk/types": "3.821.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -569,20 +741,59 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz", - "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==", + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.826.0.tgz", + "integrity": "sha512-N+IVZBh+yx/9GbMZTKO/gErBi/FYZQtcFRItoLbY+6WU+0cSWyZYfkoeOxHmQV3iX9k65oljERIWUmL9x6OSQg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.826.0", + "@aws-sdk/types": "3.821.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-stream": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-stream": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -590,23 +801,62 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.782.0.tgz", - "integrity": "sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.828.0.tgz", + "integrity": "sha512-T3DJMo2/j7gCPpFg2+xEHWgua05t8WP89ye7PaZxA2Fc6CgScHkZsJZTri1QQIU2h+eOZ75EZWkeFLIPgN0kRQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.826.0", + "@aws-sdk/credential-provider-env": "3.826.0", + "@aws-sdk/credential-provider-http": "3.826.0", + "@aws-sdk/credential-provider-process": "3.826.0", + "@aws-sdk/credential-provider-sso": "3.828.0", + "@aws-sdk/credential-provider-web-identity": "3.828.0", + "@aws-sdk/nested-clients": "3.828.0", + "@aws-sdk/types": "3.821.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-env": "3.775.0", - "@aws-sdk/credential-provider-http": "3.775.0", - "@aws-sdk/credential-provider-process": "3.775.0", - "@aws-sdk/credential-provider-sso": "3.782.0", - "@aws-sdk/credential-provider-web-identity": "3.782.0", - "@aws-sdk/nested-clients": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -614,22 +864,35 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.782.0.tgz", - "integrity": "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.828.0.tgz", + "integrity": "sha512-9z3iPwVYOQYNzVZj8qycZaS/BOSKRXWA+QVNQlfEnQ4sA4sOcKR4kmV2h+rJcuBsSFfmOF62ZDxyIBGvvM4t/w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.826.0", + "@aws-sdk/credential-provider-http": "3.826.0", + "@aws-sdk/credential-provider-ini": "3.828.0", + "@aws-sdk/credential-provider-process": "3.826.0", + "@aws-sdk/credential-provider-sso": "3.828.0", + "@aws-sdk/credential-provider-web-identity": "3.828.0", + "@aws-sdk/types": "3.821.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.775.0", - "@aws-sdk/credential-provider-http": "3.775.0", - "@aws-sdk/credential-provider-ini": "3.782.0", - "@aws-sdk/credential-provider-process": "3.775.0", - "@aws-sdk/credential-provider-sso": "3.782.0", - "@aws-sdk/credential-provider-web-identity": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -637,16 +900,55 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz", - "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==", + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.826.0.tgz", + "integrity": "sha512-kURrc4amu3NLtw1yZw7EoLNEVhmOMRUTs+chaNcmS+ERm3yK0nKjaJzmKahmwlTQTSl3wJ8jjK7x962VPo+zWw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.826.0", + "@aws-sdk/types": "3.821.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -654,18 +956,57 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.782.0.tgz", - "integrity": "sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.828.0.tgz", + "integrity": "sha512-9CEAXzUDSzOjOCb3XfM15TZhTaM+l07kumZyx2z8NC6T2U4qbCJqn4h8mFlRvYrs6cBj2SN40sD3r5Wp0Cq2Kw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.828.0", + "@aws-sdk/core": "3.826.0", + "@aws-sdk/token-providers": "3.828.0", + "@aws-sdk/types": "3.821.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.782.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/token-providers": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -673,33 +1014,103 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.782.0.tgz", - "integrity": "sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.828.0.tgz", + "integrity": "sha512-MguDhGHlQBeK9CQ/P4NOY0whAJ4HJU4x+f1dphg3I1sGlccFqfB8Moor2vXNKu0Th2kvAwkn9pr7gGb/+NGR9g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/nested-clients": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.826.0", + "@aws-sdk/nested-clients": "3.828.0", + "@aws-sdk/types": "3.821.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/lib-storage": { + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.828.0.tgz", + "integrity": "sha512-nBJmRzveYtdqL0u76tv62JGtkUfvyyZhAKNHFlzO8lCO7lxa0muRTG/ptUSS0ruFHq1K2MXHnDtLX90xiErIsQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.11", + "@smithy/smithy-client": "^4.4.3", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.828.0" + } + }, + "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.775.0.tgz", - "integrity": "sha512-qogMIpVChDYr4xiUNC19/RDSw/sKoHkAhouS6Skxiy6s27HBhow1L3Z1qVYXuBmOZGSWPU0xiyZCvOyWrv9s+Q==", + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.821.0.tgz", + "integrity": "sha512-cebgeytKlWOgGczLo3BPvNY9XlzAzGZQANSysgJ2/8PSldmUpXRIF+GKPXDVhXeInWYHIfB8zZi3RqrPoXcNYQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-arn-parser": "3.723.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/util-arn-parser": "3.804.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "@smithy/util-config-provider": "^4.0.0", "tslib": "^2.6.2" }, @@ -707,15 +1118,53 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@aws-sdk/util-arn-parser": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.804.0.tgz", + "integrity": "sha512-wmBJqn1DRXnZu3b4EkE6CWnoWMo1ZMvlfkqU5zPz67xx1GMaXlDCchFvKAXMjk4jn/L1O3tKnoFDNsoLV1kgNQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.775.0.tgz", - "integrity": "sha512-Apd3owkIeUW5dnk3au9np2IdW2N0zc9NjTjHiH+Mx3zqwSrc+m+ANgJVgk9mnQjMzU/vb7VuxJ0eqdEbp5gYsg==", + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.821.0.tgz", + "integrity": "sha512-zAOoSZKe1njOrtynvK6ZORU57YGv5I7KP4+rwOvUN3ZhJbQ7QPf8gKtFUCYAPRMegaXCKF/ADPtDZBAmM+zZ9g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -723,22 +1172,22 @@ } }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.775.0.tgz", - "integrity": "sha512-OmHLfRIb7IIXsf9/X/pMOlcSV3gzW/MmtPSZTkrz5jCTKzWXd7eRoyOJqewjsaC6KMAxIpNU77FoAd16jOZ21A==", + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.826.0.tgz", + "integrity": "sha512-Fz9w8CFYPfSlHEB6feSsi06hdS+s+FB8k5pO4L7IV0tUa78mlhxF/VNlAJaVWYyOkZXl4HPH2K48aapACSQOXw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", + "@aws-sdk/core": "3.826.0", + "@aws-sdk/types": "3.821.0", "@smithy/is-array-buffer": "^4.0.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-stream": "^4.2.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-stream": "^4.2.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -746,15 +1195,67 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", - "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.821.0.tgz", + "integrity": "sha512-xSMR+sopSeWGx5/4pAGhhfMvGBHioVBbqGvDs6pG64xfNwM5vq5s5v6D04e2i+uSTj4qGa71dLUs5I0UzAK3sw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -762,13 +1263,26 @@ } }, "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.775.0.tgz", - "integrity": "sha512-8TMXEHZXZTFTckQLyBT5aEI8fX11HZcwZseRifvBKKpj0RZDk4F0EEYGxeNSPpUQ7n+PRWyfAEnnZNRdAj/1NQ==", + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.821.0.tgz", + "integrity": "sha512-sKrm80k0t3R0on8aA/WhWFoMaAl4yvdk+riotmMElLUpcMcRXAd1+600uFVrxJqZdbrKQ0mjX0PjT68DlkYXLg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -776,13 +1290,26 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", - "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.821.0.tgz", + "integrity": "sha512-0cvI0ipf2tGx7fXYEEN5fBeZDz2RnHyb9xftSgUsEq7NBxjV0yTZfLJw6Za5rjE6snC80dRN8+bTNR1tuG89zA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -790,14 +1317,27 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", - "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.821.0.tgz", + "integrity": "sha512-efmaifbhBoqKG3bAoEfDdcM8hn1psF+4qa7ykWuYmfmah59JBeqHLfz5W9m9JoTwoKPkFcVLWZxnyZzAnVBOIg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -830,97 +1370,201 @@ } }, "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.775.0.tgz", - "integrity": "sha512-Iw1RHD8vfAWWPzBBIKaojO4GAvQkHOYIpKdAfis/EUSUmSa79QsnXnRqsdcE0mCB0Ylj23yi+ah4/0wh9FsekA==", + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.821.0.tgz", + "integrity": "sha512-YYi1Hhr2AYiU/24cQc8HIB+SWbQo6FBkMYojVuz/zgrtkFmALxENGF/21OPg7f/QWd+eadZJRxCjmRwh5F2Cxg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.828.0.tgz", + "integrity": "sha512-nixvI/SETXRdmrVab4D9LvXT3lrXkwAWGWk2GVvQvzlqN1/M/RfClj+o37Sn4FqRkGH9o9g7Fqb1YqZ4mqDAtA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.826.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/util-endpoints": "3.828.0", + "@smithy/core": "^3.5.3", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.828.0.tgz", + "integrity": "sha512-xmeOILiR9LvfC8MctgeRXXN8nQTwbOvO4wHvgE8tDRsjnBpyyO0j50R4+viHXdMUGtgGkHEXRv8fFNBq54RgnA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.826.0", + "@aws-sdk/middleware-host-header": "3.821.0", + "@aws-sdk/middleware-logger": "3.821.0", + "@aws-sdk/middleware-recursion-detection": "3.821.0", + "@aws-sdk/middleware-user-agent": "3.828.0", + "@aws-sdk/region-config-resolver": "3.821.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/util-endpoints": "3.828.0", + "@aws-sdk/util-user-agent-browser": "3.821.0", + "@aws-sdk/util-user-agent-node": "3.828.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.5.3", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.11", + "@smithy/middleware-retry": "^4.1.12", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.19", + "@smithy/util-defaults-mode-node": "^4.0.19", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.5", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.782.0.tgz", - "integrity": "sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg==", + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.782.0", - "@smithy/core": "^3.2.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.782.0.tgz", - "integrity": "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA==", + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.821.0.tgz", + "integrity": "sha512-t8og+lRCIIy5nlId0bScNpCkif8sc0LhmtaKsbm0ZPm3sCa/WhCbSZibjbZ28FNjVCV+p0D9RYZx0VDDbtWyjw==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.782.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.782.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.782.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/types": "3.821.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz", - "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==", + "node_modules/@aws-sdk/region-config-resolver/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -964,16 +1608,56 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.782.0.tgz", - "integrity": "sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.828.0.tgz", + "integrity": "sha512-JdOjI/TxkfQpY/bWbdGMdCiePESXTbtl6MfnJxz35zZ3tfHvBnxAWCoYJirdmjzY/j/dFo5oEyS6mQuXAG9w2w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/nested-clients": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.826.0", + "@aws-sdk/nested-clients": "3.828.0", + "@aws-sdk/types": "3.821.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/core": { + "version": "3.826.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.826.0.tgz", + "integrity": "sha512-BGbQYzWj3ps+dblq33FY5tz/SsgJCcXX0zjQlSC07tYvU1jHTUvsefphyig+fY38xZ4wdKjbTop+KUmXUYrOXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.821.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.5.3", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -1006,14 +1690,27 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.782.0.tgz", - "integrity": "sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.828.0.tgz", + "integrity": "sha512-RvKch111SblqdkPzg3oCIdlGxlQs+k+P7Etory9FmxPHyPDvsP1j1c74PmgYqtzzMWmoXTjd+c9naUHh9xG8xg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", - "@smithy/util-endpoints": "^3.0.2", + "@aws-sdk/types": "3.821.0", + "@smithy/types": "^4.3.1", + "@smithy/util-endpoints": "^3.0.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -1048,27 +1745,40 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", - "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.821.0.tgz", + "integrity": "sha512-irWZHyM0Jr1xhC+38OuZ7JB6OXMLPZlj48thElpsO1ZSLRkLZx5+I7VV6k3sp2yZ7BYbKz/G2ojSv4wdm7XTLw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.821.0", + "@smithy/types": "^4.3.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, + "node_modules/@aws-sdk/util-user-agent-browser/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.782.0.tgz", - "integrity": "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA==", + "version": "3.828.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.828.0.tgz", + "integrity": "sha512-LdN6fTBzTlQmc8O8f1wiZN0qF3yBWVGis7NwpWK7FUEzP9bEZRxYfIkV9oV9zpt6iNRze1SedK3JQVB/udxBoA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/middleware-user-agent": "3.828.0", + "@aws-sdk/types": "3.821.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -1083,13 +1793,26 @@ } } }, + "node_modules/@aws-sdk/util-user-agent-node/node_modules/@aws-sdk/types": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", + "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.775.0.tgz", - "integrity": "sha512-b9NGO6FKJeLGYnV7Z1yvcP1TNU4dkD5jNsLWOF1/sygZoASaQhNOlaiJ/1OH331YQ1R1oWk38nBb0frsYkDsOQ==", + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.821.0.tgz", + "integrity": "sha512-DIIotRnefVL6DiaHtO6/21DhJ4JZnnIwdNbpwiAhdt/AVbttcE4yw925gsjur0OGv5BTYXQXU3YnANBYnZjuQA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4183,12 +4906,12 @@ } }, "node_modules/@smithy/abort-controller": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.2.tgz", - "integrity": "sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", + "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4221,15 +4944,15 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.0.tgz", - "integrity": "sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.4.tgz", + "integrity": "sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", + "@smithy/util-middleware": "^4.0.4", "tslib": "^2.6.2" }, "engines": { @@ -4237,17 +4960,18 @@ } }, "node_modules/@smithy/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.2.0.tgz", - "integrity": "sha512-k17bgQhVZ7YmUvA8at4af1TDpl0NDMBuBKJl8Yg0nrefwmValU+CnA5l/AriVdQNthU/33H3nK71HrLgqOPr1Q==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.5.3.tgz", + "integrity": "sha512-xa5byV9fEguZNofCclv6v9ra0FYh5FATQW/da7FQUVTic94DfrN/NvmKZjrMyzbpqfot9ZjBaO8U1UeTbmSLuA==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^4.0.3", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-stream": "^4.2.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-stream": "^4.2.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -4256,15 +4980,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.2.tgz", - "integrity": "sha512-32lVig6jCaWBHnY+OEQ6e6Vnt5vDHaLiydGrwYMW9tPqO688hPGTYRamYJ1EptxEC2rAwJrHWmPoKRBl4iTa8w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.6.tgz", + "integrity": "sha512-hKMWcANhUiNbCJouYkZ9V3+/Qf9pteR1dnwgdyzR09R4ODEYx8BbUysHwRSyex4rZ9zapddZhLFTnT4ZijR4pw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "tslib": "^2.6.2" }, "engines": { @@ -4272,13 +4996,13 @@ } }, "node_modules/@smithy/eventstream-codec": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.2.tgz", - "integrity": "sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.4.tgz", + "integrity": "sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "@smithy/util-hex-encoding": "^4.0.0", "tslib": "^2.6.2" }, @@ -4287,13 +5011,13 @@ } }, "node_modules/@smithy/eventstream-serde-browser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.2.tgz", - "integrity": "sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.4.tgz", + "integrity": "sha512-3fb/9SYaYqbpy/z/H3yIi0bYKyAa89y6xPmIqwr2vQiUT2St+avRt8UKwsWt9fEdEasc5d/V+QjrviRaX1JRFA==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/eventstream-serde-universal": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4301,12 +5025,12 @@ } }, "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.0.tgz", - "integrity": "sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.2.tgz", + "integrity": "sha512-JGtambizrWP50xHgbzZI04IWU7LdI0nh/wGbqH3sJesYToMi2j/DcoElqyOcqEIG/D4tNyxgRuaqBXWE3zOFhQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4314,13 +5038,13 @@ } }, "node_modules/@smithy/eventstream-serde-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.2.tgz", - "integrity": "sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.4.tgz", + "integrity": "sha512-RD6UwNZ5zISpOWPuhVgRz60GkSIp0dy1fuZmj4RYmqLVRtejFqQ16WmfYDdoSoAjlp1LX+FnZo+/hkdmyyGZ1w==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/eventstream-serde-universal": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4328,13 +5052,13 @@ } }, "node_modules/@smithy/eventstream-serde-universal": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.2.tgz", - "integrity": "sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.4.tgz", + "integrity": "sha512-UeJpOmLGhq1SLox79QWw/0n2PFX+oPRE1ZyRMxPIaFEfCqWaqpB7BU9C8kpPOGEhLF7AwEqfFbtwNxGy4ReENA==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-codec": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/eventstream-codec": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4342,14 +5066,14 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.2.tgz", - "integrity": "sha512-+9Dz8sakS9pe7f2cBocpJXdeVjMopUDLgZs1yWeu7h++WqSbjUYv/JAJwKwXw1HV6gq1jyWjxuyn24E2GhoEcQ==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.4.tgz", + "integrity": "sha512-AMtBR5pHppYMVD7z7G+OlHHAcgAN7v0kVKEpHuTO4Gb199Gowh0taYi9oDStFeUhetkeP55JLSVlTW1n9rFtUw==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.1.0", - "@smithy/querystring-builder": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/querystring-builder": "^4.0.4", + "@smithy/types": "^4.3.1", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" }, @@ -4358,14 +5082,14 @@ } }, "node_modules/@smithy/hash-blob-browser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.0.2.tgz", - "integrity": "sha512-3g188Z3DyhtzfBRxpZjU8R9PpOQuYsbNnyStc/ZVS+9nVX1f6XeNOa9IrAh35HwwIZg+XWk8bFVtNINVscBP+g==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.0.4.tgz", + "integrity": "sha512-WszRiACJiQV3QG6XMV44i5YWlkrlsM5Yxgz4jvsksuu7LDXA6wAtypfPajtNTadzpJy3KyJPoWehYpmZGKUFIQ==", "license": "Apache-2.0", "dependencies": { "@smithy/chunked-blob-reader": "^5.0.0", "@smithy/chunked-blob-reader-native": "^4.0.0", - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4373,12 +5097,12 @@ } }, "node_modules/@smithy/hash-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.2.tgz", - "integrity": "sha512-VnTpYPnRUE7yVhWozFdlxcYknv9UN7CeOqSrMH+V877v4oqtVYuoqhIhtSjmGPvYrYnAkaM61sLMKHvxL138yg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.4.tgz", + "integrity": "sha512-qnbTPUhCVnCgBp4z4BUJUhOEkVwxiEi1cyFM+Zj6o+aY8OFGxUQleKWq8ltgp3dujuhXojIvJWdoqpm6dVO3lQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" @@ -4388,12 +5112,12 @@ } }, "node_modules/@smithy/hash-stream-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.0.2.tgz", - "integrity": "sha512-POWDuTznzbIwlEXEvvXoPMS10y0WKXK790soe57tFRfvf4zBHyzE529HpZMqmDdwG9MfFflnyzndUQ8j78ZdSg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.0.4.tgz", + "integrity": "sha512-wHo0d8GXyVmpmMh/qOR0R7Y46/G1y6OR8U+bSTB4ppEzRxd1xVAQ9xOE9hOc0bSjhz0ujCPAbfNLkLrpa6cevg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -4402,12 +5126,12 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.2.tgz", - "integrity": "sha512-GatB4+2DTpgWPday+mnUkoumP54u/MDM/5u44KF9hIu8jF0uafZtQLcdfIKkIcUNuF/fBojpLEHZS/56JqPeXQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.4.tgz", + "integrity": "sha512-bNYMi7WKTJHu0gn26wg8OscncTt1t2b8KcsZxvOv56XA6cyXtOAAAaNP7+m45xfppXfOatXF3Sb1MNsLUgVLTw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4427,12 +5151,12 @@ } }, "node_modules/@smithy/md5-js": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.0.2.tgz", - "integrity": "sha512-Hc0R8EiuVunUewCse2syVgA2AfSRco3LyAv07B/zCOMa+jpXI9ll+Q21Nc6FAlYPcpNcAXqBzMhNs1CD/pP2bA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.0.4.tgz", + "integrity": "sha512-uGLBVqcOwrLvGh/v/jw423yWHq/ofUGK1W31M2TNspLQbUV1Va0F5kTxtirkoHawODAZcjXTSGi7JwbnPcDPJg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -4441,13 +5165,13 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.2.tgz", - "integrity": "sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.4.tgz", + "integrity": "sha512-F7gDyfI2BB1Kc+4M6rpuOLne5LOcEknH1n6UQB69qv+HucXBR1rkzXBnQTB2q46sFy1PM/zuSJOB532yc8bg3w==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4455,18 +5179,18 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.0.tgz", - "integrity": "sha512-xhLimgNCbCzsUppRTGXWkZywksuTThxaIB0HwbpsVLY5sceac4e1TZ/WKYqufQLaUy+gUSJGNdwD2jo3cXL0iA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.2.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-middleware": "^4.0.2", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.11.tgz", + "integrity": "sha512-zDogwtRLzKl58lVS8wPcARevFZNBOOqnmzWWxVe9XiaXU2CADFjvJ9XfNibgkOWs08sxLuSr81NrpY4mgp9OwQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.5.3", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", + "@smithy/util-middleware": "^4.0.4", "tslib": "^2.6.2" }, "engines": { @@ -4474,18 +5198,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.0.tgz", - "integrity": "sha512-2zAagd1s6hAaI/ap6SXi5T3dDwBOczOMCSkkYzktqN1+tzbk1GAsHNAdo/1uzxz3Ky02jvZQwbi/vmDA6z4Oyg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/service-error-classification": "^4.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.12.tgz", + "integrity": "sha512-wvIH70c4e91NtRxdaLZF+mbLZ/HcC6yg7ySKUiufL6ESp6zJUSnJucZ309AvG9nqCFHSRB5I6T3Ez1Q9wCh0Ww==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.1.3", + "@smithy/protocol-http": "^5.1.2", + "@smithy/service-error-classification": "^4.0.5", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.5", "tslib": "^2.6.2", "uuid": "^9.0.1" }, @@ -4494,12 +5218,13 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.3.tgz", - "integrity": "sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.8.tgz", + "integrity": "sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4507,12 +5232,12 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.2.tgz", - "integrity": "sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.4.tgz", + "integrity": "sha512-kagK5ggDrBUCCzI93ft6DjteNSfY8Ulr83UtySog/h09lTIOAJ/xUSObutanlPT0nhoHAkpmW9V5K8oPyLh+QA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4520,14 +5245,14 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.2.tgz", - "integrity": "sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.1.3.tgz", + "integrity": "sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4535,15 +5260,15 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.4.tgz", - "integrity": "sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", + "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/querystring-builder": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/abort-controller": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/querystring-builder": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4551,12 +5276,12 @@ } }, "node_modules/@smithy/property-provider": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.2.tgz", - "integrity": "sha512-wNRoQC1uISOuNc2s4hkOYwYllmiyrvVXWMtq+TysNRVQaHm4yoafYQyjN/goYZS+QbYlPIbb/QRjaUZMuzwQ7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.4.tgz", + "integrity": "sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4564,12 +5289,12 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.0.tgz", - "integrity": "sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.2.tgz", + "integrity": "sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4577,12 +5302,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.2.tgz", - "integrity": "sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.4.tgz", + "integrity": "sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" }, @@ -4591,12 +5316,12 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.2.tgz", - "integrity": "sha512-v6w8wnmZcVXjfVLjxw8qF7OwESD9wnpjp0Dqry/Pod0/5vcEA3qxCr+BhbOHlxS8O+29eLpT3aagxXGwIoEk7Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.4.tgz", + "integrity": "sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4604,24 +5329,24 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.2.tgz", - "integrity": "sha512-LA86xeFpTKn270Hbkixqs5n73S+LVM0/VZco8dqd+JT75Dyx3Lcw/MraL7ybjmz786+160K8rPOmhsq0SocoJQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.5.tgz", + "integrity": "sha512-LvcfhrnCBvCmTee81pRlh1F39yTS/+kYleVeLCwNtkY8wtGg8V/ca9rbZZvYIl8OjlMtL6KIjaiL/lgVqHD2nA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0" + "@smithy/types": "^4.3.1" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.2.tgz", - "integrity": "sha512-J9/gTWBGVuFZ01oVA6vdb4DAjf1XbDhK6sLsu3OS9qmLrS6KB5ygpeHiM3miIbj1qgSJ96GYszXFWv6ErJ8QEw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.4.tgz", + "integrity": "sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4629,16 +5354,16 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.2.tgz", - "integrity": "sha512-Mz+mc7okA73Lyz8zQKJNyr7lIcHLiPYp0+oiqiMNc/t7/Kf2BENs5d63pEj7oPqdjaum6g0Fc8wC78dY1TgtXw==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.1.2.tgz", + "integrity": "sha512-d3+U/VpX7a60seHziWnVZOHuEgJlclufjkS6zhXvxcJgkJq4UWdH5eOBLzHRMx6gXjsdT9h6lfpmLzbrdupHgQ==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.0.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", + "@smithy/util-middleware": "^4.0.4", "@smithy/util-uri-escape": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" @@ -4648,17 +5373,17 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.0.tgz", - "integrity": "sha512-Qs65/w30pWV7LSFAez9DKy0Koaoh3iHhpcpCCJ4waj/iqwsuSzJna2+vYwq46yBaqO5ZbP9TjUsATUNxrKeBdw==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.4.3.tgz", + "integrity": "sha512-xxzNYgA0HD6ETCe5QJubsxP0hQH3QK3kbpJz3QrosBCuIWyEXLR/CO5hFb2OeawEKUxMNhz3a1nuJNN2np2RMA==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.2.0", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "@smithy/util-stream": "^4.2.0", + "@smithy/core": "^3.5.3", + "@smithy/middleware-endpoint": "^4.1.11", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "@smithy/util-stream": "^4.2.2", "tslib": "^2.6.2" }, "engines": { @@ -4666,9 +5391,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", - "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", + "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -4678,13 +5403,13 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.2.tgz", - "integrity": "sha512-Bm8n3j2ScqnT+kJaClSVCMeiSenK6jVAzZCNewsYWuZtnBehEz4r2qP0riZySZVfzB+03XZHJeqfmJDkeeSLiQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.4.tgz", + "integrity": "sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/querystring-parser": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4755,14 +5480,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.8.tgz", - "integrity": "sha512-ZTypzBra+lI/LfTYZeop9UjoJhhGRTg3pxrNpfSTQLd3AJ37r2z4AXTKpq1rFXiiUIJsYyFgNJdjWRGP/cbBaQ==", + "version": "4.0.19", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.19.tgz", + "integrity": "sha512-mvLMh87xSmQrV5XqnUYEPoiFFeEGYeAKIDDKdhE2ahqitm8OHM3aSvhqL6rrK6wm1brIk90JhxDf5lf2hbrLbQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", "bowser": "^2.11.0", "tslib": "^2.6.2" }, @@ -4771,17 +5496,17 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.8.tgz", - "integrity": "sha512-Rgk0Jc/UDfRTzVthye/k2dDsz5Xxs9LZaKCNPgJTRyoyBoeiNCnHsYGOyu1PKN+sDyPnJzMOz22JbwxzBp9NNA==", + "version": "4.0.19", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.19.tgz", + "integrity": "sha512-8tYnx+LUfj6m+zkUUIrIQJxPM1xVxfRBvoGHua7R/i6qAxOMjqR6CpEpDwKoIs1o0+hOjGvkKE23CafKL0vJ9w==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^4.1.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/smithy-client": "^4.4.3", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4789,13 +5514,13 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.2.tgz", - "integrity": "sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.6.tgz", + "integrity": "sha512-YARl3tFL3WgPuLzljRUnrS2ngLiUtkwhQtj8PAL13XZSyUiNLQxwG3fBBq3QXFqGFUXepIN73pINp3y8c2nBmA==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4815,12 +5540,12 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.2.tgz", - "integrity": "sha512-6GDamTGLuBQVAEuQ4yDQ+ti/YINf/MEmIegrEeg7DdB/sld8BX1lqt9RRuIcABOhAGTA50bRbPzErez7SlDtDQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.4.tgz", + "integrity": "sha512-9MLKmkBmf4PRb0ONJikCbCwORACcil6gUWojwARCClT7RmLzF04hUR4WdRprIXal7XVyrddadYNfp2eF3nrvtQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4828,13 +5553,13 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.2.tgz", - "integrity": "sha512-Qryc+QG+7BCpvjloFLQrmlSd0RsVRHejRXd78jNO3+oREueCjwG1CCEH1vduw/ZkM1U9TztwIKVIi3+8MJScGg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.5.tgz", + "integrity": "sha512-V7MSjVDTlEt/plmOFBn1762Dyu5uqMrV2Pl2X0dYk4XvWfdWJNe9Bs5Bzb56wkCuiWjSfClVMGcsuKrGj7S/yg==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/service-error-classification": "^4.0.5", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4842,14 +5567,14 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.0.tgz", - "integrity": "sha512-Vj1TtwWnuWqdgQI6YTUF5hQ/0jmFiOYsc51CSMgj7QfyO+RF4EnT2HNjoviNlOOmgzgvf3f5yno+EiC4vrnaWQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.2.tgz", + "integrity": "sha512-aI+GLi7MJoVxg24/3J1ipwLoYzgkB4kUfogZfnslcYlynj3xsQ0e7vk4TnTro9hhsS5PvX1mwmkRqqHQjwcU7w==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/types": "^4.2.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/types": "^4.3.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", @@ -4886,13 +5611,13 @@ } }, "node_modules/@smithy/util-waiter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.3.tgz", - "integrity": "sha512-JtaY3FxmD+te+KSI2FJuEcfNC9T/DGGVf551babM7fAaXhjJUt7oSYurH1Devxd2+BOSUACCgt3buinx4UnmEA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.5.tgz", + "integrity": "sha512-4QvC49HTteI1gfemu0I1syWovJgPvGn7CVUoN9ZFkdvr/cCFkrEL7qNCdx/2eICqDWEGnnr68oMdSIPCLAriSQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/abort-controller": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -12927,6 +13652,30 @@ "node": ">= 0.8" } }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", diff --git a/packages/backend/package.json b/packages/backend/package.json index 3eb5a56..e4814f9 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.782.0", + "@aws-sdk/lib-storage": "^3.828.0", "@aws-sdk/s3-request-presigner": "^3.782.0", "@nestjs/common": "^11.0.1", "@nestjs/config": "^4.0.2", diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts index e4fd464..d47d76d 100644 --- a/packages/backend/src/downloads/downloads.service.ts +++ b/packages/backend/src/downloads/downloads.service.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; import { DownloadRequest, DownloadStatus } from '@prisma/client'; @@ -24,7 +24,7 @@ export class DownloadsService { const request = await this.prismaService.downloadRequest.create({ data: { createdAt, - status: DownloadStatus.STARTING, + status: DownloadStatus.IN_PROGRESS, location: this.getLocationString(createdAt) } }); diff --git a/packages/backend/src/downloads/zip.service.ts b/packages/backend/src/downloads/zip.service.ts index 54946f4..c50cbc2 100644 --- a/packages/backend/src/downloads/zip.service.ts +++ b/packages/backend/src/downloads/zip.service.ts @@ -9,6 +9,8 @@ import * as archiver from 'archiver'; import { createReadStream, createWriteStream } from 'fs'; import { FileResultNoFd, fileSync } from 'tmp'; import { basename } from 'path'; +import { Upload } from "@aws-sdk/lib-storage"; +import { unlink } from 'fs/promises'; @Injectable() export class Zipper { @@ -31,7 +33,7 @@ export class Zipper { const file = await this.download(); // Upload the zip - await this.uploadZip(payload, file) + await this.uploadZip(payload, file); // Mark the download process as complete this.eventEmitter.emit(events.DOWNLOAD_SUCCESS, payload); @@ -45,6 +47,7 @@ export class Zipper { // Make the read stream const stream = createReadStream(file.name); + // Need to wait for the stream to be ready await new Promise((resolve, reject) => { stream.on('ready', () => { resolve('Success'); @@ -54,15 +57,20 @@ export class Zipper { }) }); - // Make the put command - const putCmd = new PutObjectCommand({ - Bucket: this.bucket, - Key: downloadRequest.location, - Body: stream, - ContentType: 'application/zip', + // Make the upload + const upload = new Upload({ + client: new S3Client({}), + params: { + Bucket: this.bucket, + Key: downloadRequest.location, + Body: stream, + }, }); - await this.s3.send(putCmd); + await upload.done(); + + // Remove the zip + await unlink(file.name); } private async download(): Promise { From f462133d2736549924fedcfd0834a006e35c9858 Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Thu, 12 Jun 2025 11:06:08 -0400 Subject: [PATCH 14/17] Start on download button --- .../downloads/DownloadButton.component.tsx | 13 +++++++++++++ .../downloads/DownloadsLists.component.tsx | 7 ++++--- 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 packages/admin/src/components/downloads/DownloadButton.component.tsx diff --git a/packages/admin/src/components/downloads/DownloadButton.component.tsx b/packages/admin/src/components/downloads/DownloadButton.component.tsx new file mode 100644 index 0000000..896907c --- /dev/null +++ b/packages/admin/src/components/downloads/DownloadButton.component.tsx @@ -0,0 +1,13 @@ +import { Button } from 'react-admin'; +import { FC } from 'react'; +import { useRecordContext } from 'react-admin'; + +export const DownloadButton: FC<{ source: string }> = ({ source }) => { + const record = useRecordContext(); + + if (!record) { + return null; + } + + return +}; diff --git a/packages/admin/src/components/downloads/DownloadsLists.component.tsx b/packages/admin/src/components/downloads/DownloadsLists.component.tsx index 622b945..7c98f84 100644 --- a/packages/admin/src/components/downloads/DownloadsLists.component.tsx +++ b/packages/admin/src/components/downloads/DownloadsLists.component.tsx @@ -2,6 +2,7 @@ import { Button, Datagrid, DateField, List, TextField, useRefresh } from 'react- import { FC } from 'react'; import { Stack } from '@mui/material'; import { downloadsControllerCreate } from '../../client'; +import { DownloadButton } from './DownloadButton.component'; export const DownloadsList: FC = () => { const refresh = useRefresh(); @@ -22,11 +23,11 @@ export const DownloadsList: FC = () => { return( - + - - + + From 0dea35e5824a7080c927af784755f7c45c72a15f Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Thu, 12 Jun 2025 11:22:45 -0400 Subject: [PATCH 15/17] Working download of zip --- packages/admin/src/client/sdk.gen.ts | 15 ++++++++- packages/admin/src/client/types.gen.ts | 15 +++++++++ .../downloads/DownloadButton.component.tsx | 33 +++++++++++++++++-- .../src/downloads/downloads.controller.ts | 6 ++++ .../src/downloads/downloads.service.ts | 16 +++++++-- 5 files changed, 79 insertions(+), 6 deletions(-) diff --git a/packages/admin/src/client/sdk.gen.ts b/packages/admin/src/client/sdk.gen.ts index 4dbebd0..68dd40b 100644 --- a/packages/admin/src/client/sdk.gen.ts +++ b/packages/admin/src/client/sdk.gen.ts @@ -1,7 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts import { type Options as ClientOptions, type TDataShape, type Client, formDataBodySerializer } from '@hey-api/client-fetch'; -import type { AppControllerGetHelloData, CasdoorControllerHandleRedirectData, CasdoorControllerHandleSigninData, TasksControllerFindAllData, TasksControllerFindAllResponse, TasksControllerCreateData, TasksControllerCreateResponse, TasksControllerRemoveData, TasksControllerFindOneData, TasksControllerFindOneResponse, TasksControllerUpdateData, TasksControllerUpdateResponse, TasksControllerGetActiveTasksData, TasksControllerGetActiveTasksResponse, TaskSetControllerFindAllData, TaskSetControllerFindAllResponse, TaskSetControllerCreateData, TaskSetControllerCreateResponse, TaskSetControllerRemoveData, TaskSetControllerFindOneData, TaskSetControllerFindOneResponse, TaskSetControllerUpdateData, TaskSetControllerUpdateResponse, TaskSetControllerSetActiveData, TaskSetControllerSetActiveResponse, TaskCompletionsControllerRemoveData, TaskCompletionsControllerFindAllData, TaskCompletionsControllerFindAllResponse, TaskCompletionsControllerUpdateData, TaskCompletionsControllerUpdateResponse, TaskCompletionsControllerCreateData, TaskCompletionsControllerCreateResponse, TaskCompletionsControllerFindOneData, TaskCompletionsControllerFindOneResponse, TaskCompletionsControllerFindOrCreateByUserTaskData, TaskCompletionsControllerFindOrCreateByUserTaskResponse, TaskCompletionsControllerFindOrCreateByTaskData, TaskCompletionsControllerFindOrCreateByTaskResponse, TaskCompletionsControllerGetNextIncompleteData, TaskCompletionsControllerGetNextIncompleteResponse, TaskCompletionsControllerGetVideoUploadUrlData, TaskCompletionsControllerGetVideoUploadUrlResponse, TaskCompletionsControllerGetVideoDownloadUrlData, TaskCompletionsControllerGetVideoDownloadUrlResponse, TaskCompletionsControllerDeleteVideoData, UsersControllerFindAllData, UsersControllerFindOneData, UsersControllerIsTrainingCompleteData, UsersControllerIsTrainingCompleteResponse, UsersControllerMarkTrainingCompleteData, StudymappingControllerFindAllData, StudymappingControllerFindAllResponse, StudymappingControllerWebhookData, StudymappingControllerUploadCsvData, DownloadsControllerFindAllData, DownloadsControllerFindAllResponse, DownloadsControllerCreateData, DownloadsControllerCreateResponse, DownloadsControllerRemoveData, DownloadsControllerFindOneData, DownloadsControllerFindOneResponse } from './types.gen'; +import type { AppControllerGetHelloData, CasdoorControllerHandleRedirectData, CasdoorControllerHandleSigninData, TasksControllerFindAllData, TasksControllerFindAllResponse, TasksControllerCreateData, TasksControllerCreateResponse, TasksControllerRemoveData, TasksControllerFindOneData, TasksControllerFindOneResponse, TasksControllerUpdateData, TasksControllerUpdateResponse, TasksControllerGetActiveTasksData, TasksControllerGetActiveTasksResponse, TaskSetControllerFindAllData, TaskSetControllerFindAllResponse, TaskSetControllerCreateData, TaskSetControllerCreateResponse, TaskSetControllerRemoveData, TaskSetControllerFindOneData, TaskSetControllerFindOneResponse, TaskSetControllerUpdateData, TaskSetControllerUpdateResponse, TaskSetControllerSetActiveData, TaskSetControllerSetActiveResponse, TaskCompletionsControllerRemoveData, TaskCompletionsControllerFindAllData, TaskCompletionsControllerFindAllResponse, TaskCompletionsControllerUpdateData, TaskCompletionsControllerUpdateResponse, TaskCompletionsControllerCreateData, TaskCompletionsControllerCreateResponse, TaskCompletionsControllerFindOneData, TaskCompletionsControllerFindOneResponse, TaskCompletionsControllerFindOrCreateByUserTaskData, TaskCompletionsControllerFindOrCreateByUserTaskResponse, TaskCompletionsControllerFindOrCreateByTaskData, TaskCompletionsControllerFindOrCreateByTaskResponse, TaskCompletionsControllerGetNextIncompleteData, TaskCompletionsControllerGetNextIncompleteResponse, TaskCompletionsControllerGetVideoUploadUrlData, TaskCompletionsControllerGetVideoUploadUrlResponse, TaskCompletionsControllerGetVideoDownloadUrlData, TaskCompletionsControllerGetVideoDownloadUrlResponse, TaskCompletionsControllerDeleteVideoData, UsersControllerFindAllData, UsersControllerFindOneData, UsersControllerIsTrainingCompleteData, UsersControllerIsTrainingCompleteResponse, UsersControllerMarkTrainingCompleteData, StudymappingControllerFindAllData, StudymappingControllerFindAllResponse, StudymappingControllerWebhookData, StudymappingControllerUploadCsvData, DownloadsControllerFindAllData, DownloadsControllerFindAllResponse, DownloadsControllerCreateData, DownloadsControllerCreateResponse, DownloadsControllerRemoveData, DownloadsControllerFindOneData, DownloadsControllerFindOneResponse, DownloadsControllerGetDownloadUrlData, DownloadsControllerGetDownloadUrlResponse } from './types.gen'; import { client as _heyApiClient } from './client.gen'; export type Options = ClientOptions & { @@ -530,4 +530,17 @@ export const downloadsControllerFindOne = url: '/downloads/{id}', ...options }); +}; + +export const downloadsControllerGetDownloadUrl = (options: Options) => { + return (options.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/downloads/download/url', + ...options + }); }; \ No newline at end of file diff --git a/packages/admin/src/client/types.gen.ts b/packages/admin/src/client/types.gen.ts index ab12749..74003b6 100644 --- a/packages/admin/src/client/types.gen.ts +++ b/packages/admin/src/client/types.gen.ts @@ -802,6 +802,21 @@ export type DownloadsControllerFindOneResponses = { export type DownloadsControllerFindOneResponse = DownloadsControllerFindOneResponses[keyof DownloadsControllerFindOneResponses]; +export type DownloadsControllerGetDownloadUrlData = { + body?: never; + path?: never; + query: { + downloadLocation: string; + }; + url: '/downloads/download/url'; +}; + +export type DownloadsControllerGetDownloadUrlResponses = { + default: string; +}; + +export type DownloadsControllerGetDownloadUrlResponse = DownloadsControllerGetDownloadUrlResponses[keyof DownloadsControllerGetDownloadUrlResponses]; + export type ClientOptions = { baseUrl: string; }; \ No newline at end of file diff --git a/packages/admin/src/components/downloads/DownloadButton.component.tsx b/packages/admin/src/components/downloads/DownloadButton.component.tsx index 896907c..637f045 100644 --- a/packages/admin/src/components/downloads/DownloadButton.component.tsx +++ b/packages/admin/src/components/downloads/DownloadButton.component.tsx @@ -1,13 +1,40 @@ import { Button } from 'react-admin'; -import { FC } from 'react'; +import { FC, useEffect, useState } from 'react'; import { useRecordContext } from 'react-admin'; +import { downloadsControllerGetDownloadUrl } from '../../client'; export const DownloadButton: FC<{ source: string }> = ({ source }) => { const record = useRecordContext(); - if (!record) { return null; } - return + const [url, setUrl] = useState(null); + + const getDownloadURL = async () => { + const urlResponse = await downloadsControllerGetDownloadUrl({ + query: { downloadLocation: source } + }); + + if (urlResponse.error || !urlResponse.data) { + // TODO: Handle inability to get video URL + console.error(urlResponse.error); + return; + } + + setUrl(urlResponse.data); + } + + useEffect(() => { + getDownloadURL(); + }, []); + + const onDownload = (url: string) => { + const link = document.createElement("a"); + link.download = source.split('/')[1]; + link.href = url; + link.click(); + }; + + return url && }; diff --git a/packages/backend/src/downloads/downloads.controller.ts b/packages/backend/src/downloads/downloads.controller.ts index 762e2d4..2726095 100644 --- a/packages/backend/src/downloads/downloads.controller.ts +++ b/packages/backend/src/downloads/downloads.controller.ts @@ -45,4 +45,10 @@ export class DownloadsController { remove(@Param('id') id: string): Promise { return this.downloadsService.remove(id); } + + @Get('/download/url') + @ApiResponse({ type: String }) + async getDownloadURL(@Query('downloadLocation') downloadLocation: string): Promise { + return this.downloadsService.getDownloadURL(downloadLocation); + } } diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts index d47d76d..15d9a4a 100644 --- a/packages/backend/src/downloads/downloads.service.ts +++ b/packages/backend/src/downloads/downloads.service.ts @@ -1,21 +1,29 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; import { DownloadRequest, DownloadStatus } from '@prisma/client'; import { PaginationDTO } from '../pagination/pagination.dto'; import { PrismaService } from '../prisma/prisma.service'; import * as events from './events'; +import { S3_PROVIDER } from 'src/s3/s3.provider'; +import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3'; +import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; @Injectable() export class DownloadsService { private readonly downloadLocation: string; + private readonly bucket: string; + private readonly expiration: number; constructor( private readonly prismaService: PrismaService, configService: ConfigService, private readonly eventEmitter: EventEmitter2, + @Inject(S3_PROVIDER) private readonly s3: S3Client ) { this.downloadLocation = configService.getOrThrow('s3.downloadZipsFolder'); + this.bucket = configService.getOrThrow('s3.bucket'); + this.expiration = configService.getOrThrow('s3.signedExpiration'); } async create(): Promise { @@ -65,6 +73,11 @@ export class DownloadsService { return `${this.downloadLocation}/download_${date.toISOString()}.zip` } + async getDownloadURL(location: string): Promise { + const request = new GetObjectCommand({ Bucket: this.bucket, Key: location }); + return getSignedUrl(this.s3, request, { expiresIn: this.expiration }); + } + @OnEvent(events.DOWNLOAD_SUCCESS) async markSuccess(payload: DownloadRequest) { await this.prismaService.downloadRequest.update({ @@ -81,5 +94,4 @@ export class DownloadsService { data: { status: DownloadStatus.FAILED } }); } - } From dcabe937cfaf723c622e483d4d8655db2b0e53b8 Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Thu, 12 Jun 2025 11:23:00 -0400 Subject: [PATCH 16/17] Run prettier --- .../downloads/DownloadButton.component.tsx | 12 +++++++++--- .../downloads/DownloadsLists.component.tsx | 14 ++++++++------ .../src/downloads/downloads.controller.spec.ts | 2 +- .../backend/src/downloads/downloads.module.ts | 2 +- .../src/downloads/downloads.service.spec.ts | 2 +- .../backend/src/downloads/downloads.service.ts | 2 +- packages/backend/src/downloads/events.ts | 1 - packages/backend/src/downloads/zip.service.ts | 17 +++++++---------- 8 files changed, 28 insertions(+), 24 deletions(-) diff --git a/packages/admin/src/components/downloads/DownloadButton.component.tsx b/packages/admin/src/components/downloads/DownloadButton.component.tsx index 637f045..8e48927 100644 --- a/packages/admin/src/components/downloads/DownloadButton.component.tsx +++ b/packages/admin/src/components/downloads/DownloadButton.component.tsx @@ -23,18 +23,24 @@ export const DownloadButton: FC<{ source: string }> = ({ source }) => { } setUrl(urlResponse.data); - } + }; useEffect(() => { getDownloadURL(); }, []); const onDownload = (url: string) => { - const link = document.createElement("a"); + const link = document.createElement('a'); link.download = source.split('/')[1]; link.href = url; link.click(); }; - return url && + return ( + url && ( + + ) + ); }; diff --git a/packages/admin/src/components/downloads/DownloadsLists.component.tsx b/packages/admin/src/components/downloads/DownloadsLists.component.tsx index 7c98f84..2ee9229 100644 --- a/packages/admin/src/components/downloads/DownloadsLists.component.tsx +++ b/packages/admin/src/components/downloads/DownloadsLists.component.tsx @@ -12,7 +12,7 @@ export const DownloadsList: FC = () => { if (downloadResponse.error || !downloadResponse.data) { console.error(downloadResponse.error); - alert('Failed to make a download request') + alert('Failed to make a download request'); return; } @@ -20,14 +20,16 @@ export const DownloadsList: FC = () => { refresh(); }; - return( + return ( - + - - - + + + diff --git a/packages/backend/src/downloads/downloads.controller.spec.ts b/packages/backend/src/downloads/downloads.controller.spec.ts index 28b46cf..f179b77 100644 --- a/packages/backend/src/downloads/downloads.controller.spec.ts +++ b/packages/backend/src/downloads/downloads.controller.spec.ts @@ -8,7 +8,7 @@ describe('DownloadsController', () => { beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ controllers: [DownloadsController], - providers: [DownloadsService], + providers: [DownloadsService] }).compile(); controller = module.get(DownloadsController); diff --git a/packages/backend/src/downloads/downloads.module.ts b/packages/backend/src/downloads/downloads.module.ts index 860f858..bfc2db5 100644 --- a/packages/backend/src/downloads/downloads.module.ts +++ b/packages/backend/src/downloads/downloads.module.ts @@ -9,6 +9,6 @@ import { Zipper } from './zip.service'; @Module({ imports: [PrismaModule, CasdoorModule, S3Module], controllers: [DownloadsController], - providers: [DownloadsService, Zipper], + providers: [DownloadsService, Zipper] }) export class DownloadsModule {} diff --git a/packages/backend/src/downloads/downloads.service.spec.ts b/packages/backend/src/downloads/downloads.service.spec.ts index 12fc296..1cc6b23 100644 --- a/packages/backend/src/downloads/downloads.service.spec.ts +++ b/packages/backend/src/downloads/downloads.service.spec.ts @@ -6,7 +6,7 @@ describe('DownloadsService', () => { beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [DownloadsService], + providers: [DownloadsService] }).compile(); service = module.get(DownloadsService); diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts index 15d9a4a..60dcc73 100644 --- a/packages/backend/src/downloads/downloads.service.ts +++ b/packages/backend/src/downloads/downloads.service.ts @@ -70,7 +70,7 @@ export class DownloadsService { } private getLocationString(date: Date): string { - return `${this.downloadLocation}/download_${date.toISOString()}.zip` + return `${this.downloadLocation}/download_${date.toISOString()}.zip`; } async getDownloadURL(location: string): Promise { diff --git a/packages/backend/src/downloads/events.ts b/packages/backend/src/downloads/events.ts index 2be1880..0649631 100644 --- a/packages/backend/src/downloads/events.ts +++ b/packages/backend/src/downloads/events.ts @@ -1,4 +1,3 @@ - export const DOWNLOAD_REQUEST_CREATED = 'download.created'; export const DOWNLOAD_REQUEST_FAILED = 'download.failed'; export const DOWNLOAD_SUCCESS = 'download.success'; diff --git a/packages/backend/src/downloads/zip.service.ts b/packages/backend/src/downloads/zip.service.ts index c50cbc2..ced2d10 100644 --- a/packages/backend/src/downloads/zip.service.ts +++ b/packages/backend/src/downloads/zip.service.ts @@ -9,7 +9,7 @@ import * as archiver from 'archiver'; import { createReadStream, createWriteStream } from 'fs'; import { FileResultNoFd, fileSync } from 'tmp'; import { basename } from 'path'; -import { Upload } from "@aws-sdk/lib-storage"; +import { Upload } from '@aws-sdk/lib-storage'; import { unlink } from 'fs/promises'; @Injectable() @@ -37,7 +37,7 @@ export class Zipper { // Mark the download process as complete this.eventEmitter.emit(events.DOWNLOAD_SUCCESS, payload); - } catch(e) { + } catch (e) { console.error(e); this.eventEmitter.emit(events.DOWNLOAD_REQUEST_FAILED, payload); } @@ -54,7 +54,7 @@ export class Zipper { }); stream.on('error', () => { reject(); - }) + }); }); // Make the upload @@ -63,8 +63,8 @@ export class Zipper { params: { Bucket: this.bucket, Key: downloadRequest.location, - Body: stream, - }, + Body: stream + } }); await upload.done(); @@ -86,7 +86,7 @@ export class Zipper { // Make the streaming archive const archive = archiver.create('zip'); archive.pipe(fileStream); - archive.on('error', err => { + archive.on('error', (err) => { throw err; }); @@ -120,10 +120,7 @@ export class Zipper { } private async generateListOfFiles(): Promise { - const paginator = paginateListObjectsV2( - { client: this.s3, pageSize: 100 }, - { Bucket: this.bucket } - ); + const paginator = paginateListObjectsV2({ client: this.s3, pageSize: 100 }, { Bucket: this.bucket }); const objects: string[] = []; From 604413922689fad8bb84bda8da14bb7bb2e2cb70 Mon Sep 17 00:00:00 2001 From: Collin Bolles Date: Thu, 12 Jun 2025 11:28:07 -0400 Subject: [PATCH 17/17] Working ability to handle zip deletion --- .../downloads/DownloadButton.component.tsx | 4 ++-- .../backend/src/downloads/downloads.service.ts | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/admin/src/components/downloads/DownloadButton.component.tsx b/packages/admin/src/components/downloads/DownloadButton.component.tsx index 8e48927..eea9a43 100644 --- a/packages/admin/src/components/downloads/DownloadButton.component.tsx +++ b/packages/admin/src/components/downloads/DownloadButton.component.tsx @@ -13,7 +13,7 @@ export const DownloadButton: FC<{ source: string }> = ({ source }) => { const getDownloadURL = async () => { const urlResponse = await downloadsControllerGetDownloadUrl({ - query: { downloadLocation: source } + query: { downloadLocation: record[source] } }); if (urlResponse.error || !urlResponse.data) { @@ -31,7 +31,7 @@ export const DownloadButton: FC<{ source: string }> = ({ source }) => { const onDownload = (url: string) => { const link = document.createElement('a'); - link.download = source.split('/')[1]; + link.download = record[source].split('/')[1]; link.href = url; link.click(); }; diff --git a/packages/backend/src/downloads/downloads.service.ts b/packages/backend/src/downloads/downloads.service.ts index 60dcc73..9ca6140 100644 --- a/packages/backend/src/downloads/downloads.service.ts +++ b/packages/backend/src/downloads/downloads.service.ts @@ -6,7 +6,7 @@ import { PaginationDTO } from '../pagination/pagination.dto'; import { PrismaService } from '../prisma/prisma.service'; import * as events from './events'; import { S3_PROVIDER } from 'src/s3/s3.provider'; -import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3'; +import { S3Client, GetObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; @Injectable() @@ -59,7 +59,20 @@ export class DownloadsService { } async remove(id: string): Promise { - // TODO: Remove the ZIP in the bucket + // See if a download request with the ID even exists + const existing = await this.findOne(id); + if (!existing) { + return; + } + + // Delete the zip itself + const deleteCmd = new DeleteObjectCommand({ + Bucket: this.bucket, + Key: existing.location + }); + await this.s3.send(deleteCmd); + + // Delete the download request object await this.prismaService.downloadRequest.delete({ where: { id } });