From 522a0eec8a46fb33e77b38f44d55448b55e6f087 Mon Sep 17 00:00:00 2001 From: JakkrapartXD Date: Wed, 4 Mar 2026 17:19:58 +0700 Subject: [PATCH 01/10] refactor: update user identification to pass userId directly to services instead of JWT tokens. --- .../AdminCourseApprovalController.ts | 18 +- Backend/src/controllers/AuditController.ts | 30 --- Backend/src/controllers/AuthController.ts | 26 --- .../src/controllers/CategoriesController.ts | 11 +- .../src/controllers/CertificateController.ts | 13 +- .../ChaptersLessonInstructorController.ts | 66 ++---- .../CoursesInstructorController.ts | 108 +++------ .../controllers/CoursesStudentController.ts | 56 +---- Backend/src/controllers/LessonsController.ts | 20 +- .../RecommendedCoursesController.ts | 13 +- Backend/src/controllers/UserController.ts | 60 +---- .../controllers/announcementsController.ts | 30 +-- .../services/AdminCourseApproval.service.ts | 36 ++- .../src/services/ChaptersLesson.service.ts | 211 +++++++----------- .../src/services/CoursesInstructor.service.ts | 191 ++++++++-------- .../src/services/CoursesStudent.service.ts | 168 +++++++------- .../services/RecommendedCourses.service.ts | 60 +++-- Backend/src/services/announcements.service.ts | 64 +++--- Backend/src/services/auth.service.ts | 1 - Backend/src/services/categories.service.ts | 28 +-- Backend/src/services/certificate.service.ts | 34 ++- Backend/src/services/user.service.ts | 112 +++------- Backend/src/types/ChaptersLesson.typs.ts | 50 ++--- Backend/src/types/CoursesInstructor.types.ts | 39 ++-- Backend/src/types/CoursesStudent.types.ts | 22 +- Backend/src/types/announcements.types.ts | 36 +-- Backend/src/types/auth.types.ts | 1 - Backend/src/types/certificate.types.ts | 6 +- 28 files changed, 558 insertions(+), 952 deletions(-) diff --git a/Backend/src/controllers/AdminCourseApprovalController.ts b/Backend/src/controllers/AdminCourseApprovalController.ts index f10b99ca..46cc1028 100644 --- a/Backend/src/controllers/AdminCourseApprovalController.ts +++ b/Backend/src/controllers/AdminCourseApprovalController.ts @@ -24,9 +24,7 @@ export class AdminCourseApprovalController { @Response('401', 'Unauthorized') @Response('403', 'Forbidden - Admin only') public async listPendingCourses(@Request() request: any): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await AdminCourseApprovalService.listPendingCourses(token); + return await AdminCourseApprovalService.listPendingCourses(request.user.id); } /** @@ -41,9 +39,7 @@ export class AdminCourseApprovalController { @Response('403', 'Forbidden - Admin only') @Response('404', 'Course not found') public async getCourseDetail(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await AdminCourseApprovalService.getCourseDetail(token, courseId); + return await AdminCourseApprovalService.getCourseDetail(request.user.id, courseId); } /** @@ -62,10 +58,7 @@ export class AdminCourseApprovalController { @Request() request: any, @Path() courseId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - - return await AdminCourseApprovalService.approveCourse(token, courseId, undefined); + return await AdminCourseApprovalService.approveCourse(request.user.id, courseId, undefined); } /** @@ -85,13 +78,10 @@ export class AdminCourseApprovalController { @Path() courseId: number, @Body() body: RejectCourseBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - // Validate body const { error } = RejectCourseValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); - return await AdminCourseApprovalService.rejectCourse(token, courseId, body.comment); + return await AdminCourseApprovalService.rejectCourse(request.user.id, courseId, body.comment); } } diff --git a/Backend/src/controllers/AuditController.ts b/Backend/src/controllers/AuditController.ts index a78c8d5a..6f715061 100644 --- a/Backend/src/controllers/AuditController.ts +++ b/Backend/src/controllers/AuditController.ts @@ -40,11 +40,6 @@ export class AuditController { @Query() page?: number, @Query() limit?: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await auditService.getLogs({ userId, action, @@ -72,11 +67,6 @@ export class AuditController { @Request() request: any, @Path() logId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - const log = await auditService.getLogById(logId); if (!log) { throw new ValidationError('Audit log not found'); @@ -94,11 +84,6 @@ export class AuditController { @Response('401', 'Unauthorized') @Response('403', 'Forbidden - Admin only') public async getAuditStats(@Request() request: any): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await auditService.getStats(); } @@ -118,11 +103,6 @@ export class AuditController { @Path() entityType: string, @Path() entityId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await auditService.getEntityHistory(entityType, entityId); } @@ -142,11 +122,6 @@ export class AuditController { @Path() userId: number, @Query() limit?: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await auditService.getUserActivity(userId, limit || 50); } @@ -164,11 +139,6 @@ export class AuditController { @Request() request: any, @Query() days: number = 90 ): Promise<{ deleted: number; message: string }> { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - if (days < 6) { throw new ValidationError('Cannot delete logs newer than 6 days'); } diff --git a/Backend/src/controllers/AuthController.ts b/Backend/src/controllers/AuthController.ts index 96cb0673..b3c8e280 100644 --- a/Backend/src/controllers/AuthController.ts +++ b/Backend/src/controllers/AuthController.ts @@ -33,32 +33,6 @@ export class AuthController { data: { token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', - user: { - id: 1, - username: 'admin', - email: 'admin@elearning.local', - email_verified_at: new Date('2024-01-01T00:00:00Z'), - updated_at: new Date('2024-01-01T00:00:00Z'), - created_at: new Date('2024-01-01T00:00:00Z'), - role: { - code: 'ADMIN', - name: { - th: 'ผู้ดูแลระบบ', - en: 'Administrator' - } - }, - profile: { - prefix: { - th: 'นาย', - en: 'Mr.' - }, - first_name: 'Admin', - last_name: 'User', - phone: null, - avatar_url: null, - birth_date: null - } - } } }) public async login(@Body() body: LoginRequest): Promise { diff --git a/Backend/src/controllers/CategoriesController.ts b/Backend/src/controllers/CategoriesController.ts index 81fd8b86..fd4b0d20 100644 --- a/Backend/src/controllers/CategoriesController.ts +++ b/Backend/src/controllers/CategoriesController.ts @@ -27,13 +27,11 @@ export class CategoriesAdminController { @SuccessResponse('200', 'Category created successfully') @Response('401', 'Invalid or expired token') public async createCategory(@Request() request: any, @Body() body: createCategory): Promise { - const token = request.headers.authorization?.replace('Bearer ', '') || ''; - // Validate body const { error } = CreateCategoryValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); - return await this.categoryService.createCategory(token, body); + return await this.categoryService.createCategory(request.user.id, body); } @Put('{id}') @@ -41,13 +39,11 @@ export class CategoriesAdminController { @SuccessResponse('200', 'Category updated successfully') @Response('401', 'Invalid or expired token') public async updateCategory(@Request() request: any, @Body() body: updateCategory): Promise { - const token = request.headers.authorization?.replace('Bearer ', '') || ''; - // Validate body const { error } = UpdateCategoryValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); - return await this.categoryService.updateCategory(token, body.id, body); + return await this.categoryService.updateCategory(request.user.id, body.id, body); } @Delete('{id}') @@ -55,7 +51,6 @@ export class CategoriesAdminController { @SuccessResponse('200', 'Category deleted successfully') @Response('401', 'Invalid or expired token') public async deleteCategory(@Request() request: any, @Path() id: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', '') || ''; - return await this.categoryService.deleteCategory(token, id); + return await this.categoryService.deleteCategory(request.user.id, id); } } \ No newline at end of file diff --git a/Backend/src/controllers/CertificateController.ts b/Backend/src/controllers/CertificateController.ts index 13ec2075..a6e3f5bf 100644 --- a/Backend/src/controllers/CertificateController.ts +++ b/Backend/src/controllers/CertificateController.ts @@ -1,5 +1,4 @@ import { Get, Post, Route, Tags, SuccessResponse, Response, Security, Path, Request } from 'tsoa'; -import { ValidationError } from '../middleware/errorHandler'; import { CertificateService } from '../services/certificate.service'; import { GenerateCertificateResponse, @@ -21,9 +20,7 @@ export class CertificateController { @SuccessResponse('200', 'Certificates retrieved successfully') @Response('401', 'Invalid or expired token') public async listMyCertificates(@Request() request: any): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await this.certificateService.listMyCertificates({ token }); + return await this.certificateService.listMyCertificates({ userId: request.user.id }); } /** @@ -37,9 +34,7 @@ export class CertificateController { @Response('401', 'Invalid or expired token') @Response('404', 'Certificate not found') public async getCertificate(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await this.certificateService.getCertificate({ token, course_id: courseId }); + return await this.certificateService.getCertificate({ userId: request.user.id, course_id: courseId }); } /** @@ -54,8 +49,6 @@ export class CertificateController { @Response('401', 'Invalid or expired token') @Response('404', 'Enrollment not found') public async generateCertificate(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await this.certificateService.generateCertificate({ token, course_id: courseId }); + return await this.certificateService.generateCertificate({ userId: request.user.id, course_id: courseId }); } } diff --git a/Backend/src/controllers/ChaptersLessonInstructorController.ts b/Backend/src/controllers/ChaptersLessonInstructorController.ts index 7ba48f5c..213ae095 100644 --- a/Backend/src/controllers/ChaptersLessonInstructorController.ts +++ b/Backend/src/controllers/ChaptersLessonInstructorController.ts @@ -65,14 +65,11 @@ export class ChaptersLessonInstructorController { @Path() courseId: number, @Body() body: CreateChapterBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = CreateChapterValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.createChapter({ - token, + userId: request.user.id, course_id: courseId, title: body.title, description: body.description, @@ -96,14 +93,11 @@ export class ChaptersLessonInstructorController { @Path() chapterId: number, @Body() body: UpdateChapterBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = UpdateChapterValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.updateChapter({ - token, + userId: request.user.id, course_id: courseId, chapter_id: chapterId, ...body, @@ -125,9 +119,7 @@ export class ChaptersLessonInstructorController { @Path() courseId: number, @Path() chapterId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await chaptersLessonService.deleteChapter({ token, course_id: courseId, chapter_id: chapterId }); + return await chaptersLessonService.deleteChapter({ userId: request.user.id, course_id: courseId, chapter_id: chapterId }); } /** @@ -143,14 +135,11 @@ export class ChaptersLessonInstructorController { @Path() chapterId: number, @Body() body: ReorderChapterBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = ReorderChapterValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.reorderChapter({ - token, + userId: request.user.id, course_id: courseId, chapter_id: chapterId, sort_order: body.sort_order, @@ -174,9 +163,7 @@ export class ChaptersLessonInstructorController { @Path() chapterId: number, @Path() lessonId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await chaptersLessonService.getLesson({ token, course_id: courseId, chapter_id: chapterId, lesson_id: lessonId }); + return await chaptersLessonService.getLesson({ userId: request.user.id, course_id: courseId, chapter_id: chapterId, lesson_id: lessonId }); } /** @@ -192,14 +179,11 @@ export class ChaptersLessonInstructorController { @Path() chapterId: number, @Body() body: CreateLessonBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = CreateLessonValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.createLesson({ - token, + userId: request.user.id, course_id: courseId, chapter_id: chapterId, title: body.title, @@ -223,14 +207,11 @@ export class ChaptersLessonInstructorController { @Path() lessonId: number, @Body() body: UpdateLessonBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = UpdateLessonValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.updateLesson({ - token, + userId: request.user.id, course_id: courseId, chapter_id: chapterId, lesson_id: lessonId, @@ -258,9 +239,7 @@ export class ChaptersLessonInstructorController { @Path() chapterId: number, @Path() lessonId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await chaptersLessonService.deleteLesson({ token, course_id: courseId, chapter_id: chapterId, lesson_id: lessonId }); + return await chaptersLessonService.deleteLesson({ userId: request.user.id, course_id: courseId, chapter_id: chapterId, lesson_id: lessonId }); } /** @@ -276,14 +255,11 @@ export class ChaptersLessonInstructorController { @Path() chapterId: number, @Body() body: ReorderLessonsBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = ReorderLessonsValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.reorderLessons({ - token, + userId: request.user.id, course_id: courseId, chapter_id: chapterId, lesson_id: body.lesson_id, @@ -309,14 +285,11 @@ export class ChaptersLessonInstructorController { @Path() lessonId: number, @Body() body: AddQuestionBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = AddQuestionValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.addQuestion({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, ...body, @@ -338,14 +311,11 @@ export class ChaptersLessonInstructorController { @Path() questionId: number, @Body() body: UpdateQuestionBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = UpdateQuestionValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.updateQuestion({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, question_id: questionId, @@ -364,14 +334,11 @@ export class ChaptersLessonInstructorController { @Path() questionId: number, @Body() body: ReorderQuestionBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = ReorderQuestionValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.reorderQuestion({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, question_id: questionId, @@ -393,10 +360,8 @@ export class ChaptersLessonInstructorController { @Path() lessonId: number, @Path() questionId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.deleteQuestion({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, question_id: questionId, @@ -417,14 +382,11 @@ export class ChaptersLessonInstructorController { @Path() lessonId: number, @Body() body: UpdateQuizBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = UpdateQuizValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.updateQuiz({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, ...body, diff --git a/Backend/src/controllers/CoursesInstructorController.ts b/Backend/src/controllers/CoursesInstructorController.ts index 3657e928..4556281c 100644 --- a/Backend/src/controllers/CoursesInstructorController.ts +++ b/Backend/src/controllers/CoursesInstructorController.ts @@ -22,12 +22,10 @@ import { GetCourseApprovalHistoryResponse, setCourseDraftResponse, CloneCourseResponse, + GetAllMyStudentsResponse, } from '../types/CoursesInstructor.types'; import { CreateCourseValidator, UpdateCourseValidator, CloneCourseValidator } from "../validators/CoursesInstructor.validator"; -import jwt from 'jsonwebtoken'; -import { config } from '../config'; - @Route('api/instructors/courses') @Tags('CoursesInstructor') export class CoursesInstructorController { @@ -45,11 +43,7 @@ export class CoursesInstructorController { @Request() request: any, @Query() status?: 'DRAFT' | 'PENDING' | 'APPROVED' | 'REJECTED' | 'ARCHIVED' ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await CoursesInstructorService.listMyCourses({ token, status }); + return await CoursesInstructorService.listMyCourses({ userId: request.user.id, status }); } /** @@ -67,9 +61,23 @@ export class CoursesInstructorController { @Path() courseId: number, @Query() query: string ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await CoursesInstructorService.searchInstructors({ token, query, course_id: courseId }); + return await CoursesInstructorService.searchInstructors({ userId: request.user.id, query, course_id: courseId }); + } + + /** + * ดึงผู้เรียนทั้งหมดของ instructor ทุกคอร์ส + * Get all students enrolled in all of instructor's courses + * + * @returns รายการผู้เรียนแยกตามคอร์ส พร้อม total_enrolled และ total_completed ต่อคอร์ส + */ + @Get('my-students') + @Security('jwt', ['instructor']) + @SuccessResponse('200', 'Students retrieved successfully') + @Response('401', 'Unauthorized') + public async getMyAllStudents( + @Request() request: any + ): Promise { + return await CoursesInstructorService.getMyAllStudents(request.user.id); } /** @@ -83,11 +91,7 @@ export class CoursesInstructorController { @Response('401', 'Invalid or expired token') @Response('404', 'Course not found') public async getMyCourse(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await CoursesInstructorService.getmyCourse({ token, course_id: courseId }); + return await CoursesInstructorService.getmyCourse({ userId: request.user.id, course_id: courseId }); } /** @@ -101,13 +105,10 @@ export class CoursesInstructorController { @Response('401', 'Invalid or expired token') @Response('404', 'Course not found') public async updateCourse(@Request() request: any, @Path() courseId: number, @Body() body: UpdateMyCourse): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = UpdateCourseValidator.validate(body.data); if (error) throw new ValidationError(error.details[0].message); - return await CoursesInstructorService.updateCourse(token, courseId, body.data); + return await CoursesInstructorService.updateCourse(request.user.id, courseId, body.data); } /** @@ -126,10 +127,6 @@ export class CoursesInstructorController { @FormField() data: string, @UploadedFile() thumbnail?: Express.Multer.File ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; const parsed = JSON.parse(data); const { error, value } = CreateCourseValidator.validate(parsed); if (error) throw new ValidationError(error.details[0].message); @@ -137,7 +134,7 @@ export class CoursesInstructorController { // Validate thumbnail file type if provided if (thumbnail && !thumbnail.mimetype?.startsWith('image/')) throw new ValidationError('Only image files are allowed for thumbnail'); - return await CoursesInstructorService.createCourse(value, decoded.id, thumbnail); + return await CoursesInstructorService.createCourse(value, request.user.id, thumbnail); } /** @@ -156,11 +153,9 @@ export class CoursesInstructorController { @Path() courseId: number, @UploadedFile() file: Express.Multer.File ): Promise<{ code: number; message: string; data: { course_id: number; thumbnail_url: string } }> { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); if (!file.mimetype?.startsWith('image/')) throw new ValidationError('Only image files are allowed'); - return await CoursesInstructorService.uploadThumbnail(token, courseId, file); + return await CoursesInstructorService.uploadThumbnail(request.user.id, courseId, file); } /** @@ -174,9 +169,7 @@ export class CoursesInstructorController { @Response('401', 'Invalid or expired token') @Response('404', 'Course not found') public async deleteCourse(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided') - return await CoursesInstructorService.deleteCourse(token, courseId); + return await CoursesInstructorService.deleteCourse(request.user.id, courseId); } /** @@ -196,14 +189,11 @@ export class CoursesInstructorController { @Path() courseId: number, @Body() body: { title: { th: string; en: string } } ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - const { error } = CloneCourseValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); const result = await CoursesInstructorService.cloneCourse({ - token, + userId: request.user.id, course_id: courseId, title: body.title }); @@ -220,9 +210,7 @@ export class CoursesInstructorController { @Response('401', 'Invalid or expired token') @Response('404', 'Course not found') public async submitCourse(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided') - return await CoursesInstructorService.sendCourseForReview({ token, course_id: courseId }); + return await CoursesInstructorService.sendCourseForReview({ userId: request.user.id, course_id: courseId }); } /** @@ -236,9 +224,7 @@ export class CoursesInstructorController { @Response('401', 'Invalid or expired token') @Response('404', 'Course not found') public async setCourseDraft(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided') - return await CoursesInstructorService.setCourseDraft({ token, course_id: courseId }); + return await CoursesInstructorService.setCourseDraft({ userId: request.user.id, course_id: courseId }); } /** @@ -253,9 +239,7 @@ export class CoursesInstructorController { @Response('403', 'You are not an instructor of this course') @Response('404', 'Course not found') public async getCourseApprovals(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided') - return await CoursesInstructorService.getCourseApprovals(token, courseId); + return await CoursesInstructorService.getCourseApprovals(request.user.id, courseId); } /** @@ -269,9 +253,7 @@ export class CoursesInstructorController { @Response('401', 'Invalid or expired token') @Response('404', 'Instructors not found') public async listInstructorCourses(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided') - return await CoursesInstructorService.listInstructorsOfCourse({ token, course_id: courseId }); + return await CoursesInstructorService.listInstructorsOfCourse({ userId: request.user.id, course_id: courseId }); } /** @@ -286,9 +268,7 @@ export class CoursesInstructorController { @Response('401', 'Invalid or expired token') @Response('404', 'Instructor not found') public async addInstructor(@Request() request: any, @Path() courseId: number, @Path() emailOrUsername: string): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided') - return await CoursesInstructorService.addInstructorToCourse({ token, course_id: courseId, email_or_username: emailOrUsername }); + return await CoursesInstructorService.addInstructorToCourse({ userId: request.user.id, course_id: courseId, email_or_username: emailOrUsername }); } /** @@ -303,9 +283,7 @@ export class CoursesInstructorController { @Response('401', 'Invalid or expired token') @Response('404', 'Instructor not found') public async removeInstructor(@Request() request: any, @Path() courseId: number, @Path() userId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided') - return await CoursesInstructorService.removeInstructorFromCourse({ token, course_id: courseId, user_id: userId }); + return await CoursesInstructorService.removeInstructorFromCourse({ userId: request.user.id, course_id: courseId, user_id: userId }); } /** @@ -320,9 +298,7 @@ export class CoursesInstructorController { @Response('401', 'Invalid or expired token') @Response('404', 'Primary instructor not found') public async setPrimaryInstructor(@Request() request: any, @Path() courseId: number, @Path() userId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided') - return await CoursesInstructorService.setPrimaryInstructor({ token, course_id: courseId, user_id: userId }); + return await CoursesInstructorService.setPrimaryInstructor({ userId: request.user.id, course_id: courseId, user_id: userId }); } /** @@ -347,10 +323,8 @@ export class CoursesInstructorController { @Query() search?: string, @Query() status?: 'ENROLLED' | 'COMPLETED' ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await CoursesInstructorService.getEnrolledStudents({ - token, + userId: request.user.id, course_id: courseId, page, limit, @@ -376,10 +350,8 @@ export class CoursesInstructorController { @Path() courseId: number, @Path() studentId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await CoursesInstructorService.getEnrolledStudentDetail({ - token, + userId: request.user.id, course_id: courseId, student_id: studentId, }); @@ -410,10 +382,8 @@ export class CoursesInstructorController { @Query() search?: string, @Query() isPassed?: boolean ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await CoursesInstructorService.getQuizScores({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, page, @@ -442,10 +412,8 @@ export class CoursesInstructorController { @Path() lessonId: number, @Path() studentId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await CoursesInstructorService.getQuizAttemptDetail({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, student_id: studentId, @@ -467,8 +435,6 @@ export class CoursesInstructorController { @Request() request: any, @Path() courseId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await CoursesInstructorService.getCourseApprovalHistory(token, courseId); + return await CoursesInstructorService.getCourseApprovalHistory(request.user.id, courseId); } } \ No newline at end of file diff --git a/Backend/src/controllers/CoursesStudentController.ts b/Backend/src/controllers/CoursesStudentController.ts index 87a5a613..62e01636 100644 --- a/Backend/src/controllers/CoursesStudentController.ts +++ b/Backend/src/controllers/CoursesStudentController.ts @@ -36,11 +36,7 @@ export class CoursesStudentController { @Response('404', 'Course not found') @Response('409', 'Already enrolled in this course') public async enrollCourse(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.service.enrollCourse({ token, course_id: courseId }); + return await this.service.enrollCourse({ userId: request.user.id, course_id: courseId }); } /** @@ -60,11 +56,7 @@ export class CoursesStudentController { @Query() limit?: number, @Query() status?: EnrollmentStatus ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.service.GetEnrolledCourses({ token, page, limit, status }); + return await this.service.GetEnrolledCourses({ userId: request.user.id, page, limit, status }); } /** @@ -79,11 +71,7 @@ export class CoursesStudentController { @Response('403', 'Not enrolled in this course') @Response('404', 'Course not found') public async getCourseLearning(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.service.getCourseLearning({ token, course_id: courseId }); + return await this.service.getCourseLearning({ userId: request.user.id, course_id: courseId }); } /** @@ -103,11 +91,7 @@ export class CoursesStudentController { @Path() courseId: number, @Path() lessonId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.service.getlessonContent({ token, course_id: courseId, lesson_id: lessonId }); + return await this.service.getlessonContent({ userId: request.user.id, course_id: courseId, lesson_id: lessonId }); } /** @@ -126,11 +110,7 @@ export class CoursesStudentController { @Path() courseId: number, @Path() lessonId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.service.checkAccessLesson({ token, course_id: courseId, lesson_id: lessonId }); + return await this.service.checkAccessLesson({ userId: request.user.id, course_id: courseId, lesson_id: lessonId }); } /** @@ -149,14 +129,12 @@ export class CoursesStudentController { @Path() lessonId: number, @Body() body: SaveVideoProgressBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); const { error } = SaveVideoProgressValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await this.service.saveVideoProgress({ - token, + userId: request.user.id, lesson_id: lessonId, video_progress_seconds: body.video_progress_seconds, video_duration_seconds: body.video_duration_seconds, @@ -178,11 +156,7 @@ export class CoursesStudentController { @Request() request: any, @Path() lessonId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.service.getVideoProgress({ token, lesson_id: lessonId }); + return await this.service.getVideoProgress({ userId: request.user.id, lesson_id: lessonId }); } /** @@ -202,11 +176,7 @@ export class CoursesStudentController { @Path() courseId: number, @Path() lessonId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.service.completeLesson({ token, lesson_id: lessonId }); + return await this.service.completeLesson({ userId: request.user.id, lesson_id: lessonId }); } /** @@ -227,14 +197,12 @@ export class CoursesStudentController { @Path() lessonId: number, @Body() body: SubmitQuizBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); const { error } = SubmitQuizValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await this.service.submitQuiz({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, answers: body.answers, @@ -258,12 +226,8 @@ export class CoursesStudentController { @Path() courseId: number, @Path() lessonId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } return await this.service.getQuizAttempts({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, }); diff --git a/Backend/src/controllers/LessonsController.ts b/Backend/src/controllers/LessonsController.ts index 0323f4ab..33cc1cef 100644 --- a/Backend/src/controllers/LessonsController.ts +++ b/Backend/src/controllers/LessonsController.ts @@ -42,8 +42,6 @@ export class LessonsController { @Path() lessonId: number, @UploadedFile() video: Express.Multer.File ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); if (!video) { throw new ValidationError('Video file is required'); @@ -57,7 +55,7 @@ export class LessonsController { }; return await chaptersLessonService.uploadVideo({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, video: videoInfo, @@ -87,8 +85,6 @@ export class LessonsController { @Path() lessonId: number, @UploadedFile() video: Express.Multer.File ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); if (!video) { throw new ValidationError('Video file is required'); @@ -102,7 +98,7 @@ export class LessonsController { }; return await chaptersLessonService.updateVideo({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, video: videoInfo, @@ -132,8 +128,6 @@ export class LessonsController { @Path() lessonId: number, @UploadedFile() attachment: Express.Multer.File ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); if (!attachment) { throw new ValidationError('Attachment file is required'); @@ -147,7 +141,7 @@ export class LessonsController { }; return await chaptersLessonService.uploadAttachment({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, attachment: attachmentInfo, @@ -177,11 +171,9 @@ export class LessonsController { @Path() lessonId: number, @Path() attachmentId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.deleteAttachment({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, attachment_id: attachmentId, @@ -211,14 +203,12 @@ export class LessonsController { @Path() lessonId: number, @Body() body: SetYouTubeVideoBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); const { error } = SetYouTubeVideoValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await chaptersLessonService.setYouTubeVideo({ - token, + userId: request.user.id, course_id: courseId, lesson_id: lessonId, youtube_video_id: body.youtube_video_id, diff --git a/Backend/src/controllers/RecommendedCoursesController.ts b/Backend/src/controllers/RecommendedCoursesController.ts index 720bff7c..fa0b17c5 100644 --- a/Backend/src/controllers/RecommendedCoursesController.ts +++ b/Backend/src/controllers/RecommendedCoursesController.ts @@ -1,5 +1,4 @@ import { Get, Path, Put, Query, Request, Response, Route, Security, SuccessResponse, Tags } from 'tsoa'; -import { ValidationError } from '../middleware/errorHandler'; import { RecommendedCoursesService } from '../services/RecommendedCourses.service'; import { ListApprovedCoursesResponse, @@ -25,9 +24,7 @@ export class RecommendedCoursesController { @Query() search?: string, @Query() categoryId?: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await RecommendedCoursesService.listApprovedCourses(token, { search, categoryId }); + return await RecommendedCoursesService.listApprovedCourses(request.user.id, { search, categoryId }); } /** @@ -43,9 +40,7 @@ export class RecommendedCoursesController { @Response('403', 'Forbidden - Admin only') @Response('404', 'Course not found') public async getCourseById(@Request() request: any, @Path() courseId: number): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await RecommendedCoursesService.getCourseById(token, courseId); + return await RecommendedCoursesService.getCourseById(request.user.id, courseId); } /** @@ -65,8 +60,6 @@ export class RecommendedCoursesController { @Path() courseId: number, @Query() is_recommended: boolean ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await RecommendedCoursesService.toggleRecommended(token, courseId, is_recommended); + return await RecommendedCoursesService.toggleRecommended(request.user.id, courseId, is_recommended); } } diff --git a/Backend/src/controllers/UserController.ts b/Backend/src/controllers/UserController.ts index ccbe7c76..72b9a33a 100644 --- a/Backend/src/controllers/UserController.ts +++ b/Backend/src/controllers/UserController.ts @@ -1,12 +1,10 @@ -import { Get, Body, Post, Route, Tags, SuccessResponse, Response, Example, Controller, Security, Request, Put, UploadedFile } from 'tsoa'; +import { Get, Body, Post, Route, Tags, SuccessResponse, Response, Security, Request, Put, UploadedFile } from 'tsoa'; import { ValidationError } from '../middleware/errorHandler'; import { UserService } from '../services/user.service'; import { UserResponse, - ProfileResponse, ProfileUpdate, ProfileUpdateResponse, - ChangePasswordRequest, ChangePasswordResponse, updateAvatarResponse, SendVerifyEmailResponse, @@ -23,8 +21,6 @@ export class UserController { /** * Get current user profile - * @summary Retrieve authenticated user's profile information - * @param request Express request object with JWT token in Authorization header */ @Get('me') @SuccessResponse('200', 'User found') @@ -32,12 +28,7 @@ export class UserController { @Response('401', 'Invalid or expired token') @Security('jwt') public async getMe(@Request() request: any): Promise { - // Extract token from Authorization header - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.userService.getUserProfile(token); + return await this.userService.getUserProfile(request.user.id); } @Put('me') @@ -47,34 +38,20 @@ export class UserController { @Response('400', 'Validation error') public async updateProfile(@Request() request: any, @Body() body: ProfileUpdate): Promise { const { error } = profileUpdateSchema.validate(body); - if (error) { - throw new ValidationError(error.details[0].message); - } - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.userService.updateProfile(token, body); + if (error) throw new ValidationError(error.details[0].message); + return await this.userService.updateProfile(request.user.id, body); } @Get('roles') @Security('jwt') @SuccessResponse('200', 'Roles retrieved successfully') @Response('401', 'Invalid or expired token') - public async getRoles(@Request() request: any): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - return await this.userService.getRoles(token); + public async getRoles(): Promise { + return await this.userService.getRoles(); } /** * Change password - * @summary Change user password using old password - * @param request Express request object with JWT token in Authorization header - * @param body Old password and new password - * @returns Success message */ @Post('change-password') @Security('jwt') @@ -83,22 +60,12 @@ export class UserController { @Response('400', 'Validation error') public async changePassword(@Request() request: any, @Body() body: ChangePassword): Promise { const { error } = changePasswordSchema.validate(body); - if (error) { - throw new ValidationError(error.details[0].message); - } - - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) { - throw new ValidationError('No token provided'); - } - - return await this.userService.changePassword(token, body.oldPassword, body.newPassword); + if (error) throw new ValidationError(error.details[0].message); + return await this.userService.changePassword(request.user.id, body.oldPassword, body.newPassword); } /** * Upload user avatar picture - * @param request Express request object with JWT token in Authorization header - * @param file Avatar image file */ @Post('upload-avatar') @Security('jwt') @@ -109,9 +76,6 @@ export class UserController { @Request() request: any, @UploadedFile() file: Express.Multer.File ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - // Validate file type (images only) if (!file.mimetype?.startsWith('image/')) throw new ValidationError('Only image files are allowed'); @@ -119,13 +83,11 @@ export class UserController { const maxSize = 5 * 1024 * 1024; // 5MB if (file.size > maxSize) throw new ValidationError('File size must be less than 5MB'); - return await this.userService.uploadAvatarPicture(token, file); + return await this.userService.uploadAvatarPicture(request.user.id, file); } /** * Send verification email to user - * @summary Send email verification link to authenticated user's email - * @param request Express request object with JWT token in Authorization header */ @Post('send-verify-email') @Security('jwt') @@ -133,9 +95,7 @@ export class UserController { @Response('401', 'Invalid or expired token') @Response('400', 'Email already verified') public async sendVerifyEmail(@Request() request: any): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - return await this.userService.sendVerifyEmail(token); + return await this.userService.sendVerifyEmail(request.user.id); } /** diff --git a/Backend/src/controllers/announcementsController.ts b/Backend/src/controllers/announcementsController.ts index 8ac03c70..aa38ca54 100644 --- a/Backend/src/controllers/announcementsController.ts +++ b/Backend/src/controllers/announcementsController.ts @@ -37,10 +37,8 @@ export class AnnouncementsController { @Query() page?: number, @Query() limit?: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await announcementsService.listAnnouncement({ - token, + userId: request.user.id, course_id: courseId, page, limit, @@ -63,9 +61,6 @@ export class AnnouncementsController { @FormField() data: string, @UploadedFiles() files?: Express.Multer.File[] ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - // Parse JSON data field const parsed = JSON.parse(data) as CreateAnnouncementBody; @@ -74,7 +69,7 @@ export class AnnouncementsController { if (error) throw new ValidationError(error.details[0].message); return await announcementsService.createAnnouncement({ - token, + userId: request.user.id, course_id: courseId, title: parsed.title, content: parsed.content, @@ -103,15 +98,12 @@ export class AnnouncementsController { @Path() announcementId: number, @Body() body: UpdateAnnouncementBody ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); - // Validate body const { error } = UpdateAnnouncementValidator.validate(body); if (error) throw new ValidationError(error.details[0].message); return await announcementsService.updateAnnouncement({ - token, + userId: request.user.id, course_id: courseId, announcement_id: announcementId, title: body.title, @@ -139,10 +131,8 @@ export class AnnouncementsController { @Path() courseId: number, @Path() announcementId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await announcementsService.deleteAnnouncement({ - token, + userId: request.user.id, course_id: courseId, announcement_id: announcementId, }); @@ -166,10 +156,8 @@ export class AnnouncementsController { @Path() announcementId: number, @UploadedFile() file: Express.Multer.File ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await announcementsService.uploadAttachment({ - token, + userId: request.user.id, course_id: courseId, announcement_id: announcementId, file: file as any, @@ -195,10 +183,8 @@ export class AnnouncementsController { @Path() announcementId: number, @Path() attachmentId: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await announcementsService.deleteAttachment({ - token, + userId: request.user.id, course_id: courseId, announcement_id: announcementId, attachment_id: attachmentId, @@ -228,10 +214,8 @@ export class AnnouncementsStudentController { @Query() page?: number, @Query() limit?: number ): Promise { - const token = request.headers.authorization?.replace('Bearer ', ''); - if (!token) throw new ValidationError('No token provided'); return await announcementsService.listAnnouncement({ - token, + userId: request.user.id, course_id: courseId, page, limit, diff --git a/Backend/src/services/AdminCourseApproval.service.ts b/Backend/src/services/AdminCourseApproval.service.ts index 0596034c..808f2747 100644 --- a/Backend/src/services/AdminCourseApproval.service.ts +++ b/Backend/src/services/AdminCourseApproval.service.ts @@ -1,8 +1,6 @@ import { prisma } from '../config/database'; -import { config } from '../config'; import { logger } from '../config/logger'; -import { UnauthorizedError, ValidationError, ForbiddenError, NotFoundError } from '../middleware/errorHandler'; -import jwt from 'jsonwebtoken'; +import { ValidationError, NotFoundError } from '../middleware/errorHandler'; import { getPresignedUrl } from '../config/minio'; import { ListPendingCoursesResponse, @@ -18,7 +16,7 @@ export class AdminCourseApprovalService { /** * Get all pending courses for admin review */ - static async listPendingCourses(token: string): Promise { + static async listPendingCourses(userId: number): Promise { try { const courses = await prisma.course.findMany({ where: { status: 'PENDING' }, @@ -96,9 +94,8 @@ export class AdminCourseApprovalService { }; } catch (error) { logger.error('Failed to list pending courses', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId, action: AuditAction.ERROR, entityType: 'Course', entityId: 0, @@ -113,7 +110,7 @@ export class AdminCourseApprovalService { /** * Get course details for admin review */ - static async getCourseDetail(token: string, courseId: number): Promise { + static async getCourseDetail(userId: number, courseId: number): Promise { try { const course = await prisma.course.findUnique({ where: { id: courseId }, @@ -228,9 +225,8 @@ export class AdminCourseApprovalService { }; } catch (error) { logger.error('Failed to get course detail', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId, action: AuditAction.ERROR, entityType: 'Course', entityId: courseId, @@ -245,9 +241,8 @@ export class AdminCourseApprovalService { /** * Approve a course */ - static async approveCourse(token: string, courseId: number, comment?: string): Promise { + static async approveCourse(userId: number, courseId: number, comment?: string): Promise { try { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; const course = await prisma.course.findUnique({ where: { id: courseId } }); if (!course) { @@ -264,7 +259,7 @@ export class AdminCourseApprovalService { where: { id: courseId }, data: { status: 'APPROVED', - approved_by: decoded.id, + approved_by: userId, approved_at: new Date() } }), @@ -273,7 +268,7 @@ export class AdminCourseApprovalService { data: { course_id: courseId, submitted_by: course.created_by, - reviewed_by: decoded.id, + reviewed_by: userId, action: 'APPROVED', previous_status: course.status, new_status: 'APPROVED', @@ -284,7 +279,7 @@ export class AdminCourseApprovalService { // Audit log - APPROVE_COURSE await auditService.logSync({ - userId: decoded.id, + userId, action: AuditAction.APPROVE_COURSE, entityType: 'Course', entityId: courseId, @@ -299,9 +294,8 @@ export class AdminCourseApprovalService { }; } catch (error) { logger.error('Failed to approve course', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId, action: AuditAction.ERROR, entityType: 'Course', entityId: courseId, @@ -317,9 +311,8 @@ export class AdminCourseApprovalService { /** * Reject a course */ - static async rejectCourse(token: string, courseId: number, comment: string): Promise { + static async rejectCourse(userId: number, courseId: number, comment: string): Promise { try { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; const course = await prisma.course.findUnique({ where: { id: courseId } }); if (!course) { @@ -350,7 +343,7 @@ export class AdminCourseApprovalService { data: { course_id: courseId, submitted_by: course.created_by, - reviewed_by: decoded.id, + reviewed_by: userId, action: 'REJECTED', previous_status: course.status, new_status: 'REJECTED', @@ -361,7 +354,7 @@ export class AdminCourseApprovalService { // Audit log - REJECT_COURSE await auditService.logSync({ - userId: decoded.id, + userId, action: AuditAction.REJECT_COURSE, entityType: 'Course', entityId: courseId, @@ -376,9 +369,8 @@ export class AdminCourseApprovalService { }; } catch (error) { logger.error('Failed to reject course', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId, action: AuditAction.ERROR, entityType: 'Course', entityId: courseId, diff --git a/Backend/src/services/ChaptersLesson.service.ts b/Backend/src/services/ChaptersLesson.service.ts index 003670b1..63a68356 100644 --- a/Backend/src/services/ChaptersLesson.service.ts +++ b/Backend/src/services/ChaptersLesson.service.ts @@ -59,14 +59,11 @@ import { AuditAction } from '@prisma/client'; * ตรวจสอบสิทธิ์เข้าถึง Course (สำหรับทั้ง Instructor และ Student) * Returns: { hasAccess: boolean, role: 'INSTRUCTOR' | 'STUDENT' | null, userId: number } */ -async function validateCourseAccess(token: string, course_id: number): Promise<{ +async function validateCourseAccess(userId: number, course_id: number): Promise<{ hasAccess: boolean; role: 'INSTRUCTOR' | 'STUDENT' | null; userId: number; }> { - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; - const userId = decodedToken.id; - const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new UnauthorizedError('Invalid token'); @@ -98,9 +95,8 @@ async function validateCourseAccess(token: string, course_id: number): Promise<{ export class ChaptersLessonService { async listChapters(request: ChaptersRequest): Promise { try { - const { token, course_id } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const { userId, course_id } = request; + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new UnauthorizedError('Invalid token'); } @@ -117,14 +113,13 @@ export class ChaptersLessonService { async createChapter(request: CreateChapterInput): Promise { try { - const { token, course_id, title, description, sort_order } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, title, description, sort_order } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new UnauthorizedError('Invalid token'); } - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) { throw new ForbiddenError('You are not permitted to create chapter'); } @@ -132,7 +127,7 @@ export class ChaptersLessonService { // Audit log - CREATE Chapter auditService.log({ - userId: decodedToken.id, + userId: userId, action: AuditAction.CREATE, entityType: 'Chapter', entityId: chapter.id, @@ -142,9 +137,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Chapter created successfully', data: chapter as ChapterData }; } catch (error) { logger.error(`Error creating chapter: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Chapter', entityId: 0, @@ -159,14 +153,13 @@ export class ChaptersLessonService { async updateChapter(request: UpdateChapterInput): Promise { try { - const { token, course_id, chapter_id, title, description, sort_order } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, chapter_id, title, description, sort_order } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new UnauthorizedError('Invalid token'); } - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) { throw new ForbiddenError('You are not permitted to update chapter'); } @@ -174,9 +167,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Chapter updated successfully', data: chapter as ChapterData }; } catch (error) { logger.error(`Error updating chapter: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Chapter', entityId: request.chapter_id, @@ -191,14 +183,13 @@ export class ChaptersLessonService { async deleteChapter(request: DeleteChapterRequest): Promise { try { - const { token, course_id, chapter_id } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, chapter_id } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new UnauthorizedError('Invalid token'); } - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) { throw new ForbiddenError('You are not permitted to delete chapter'); } @@ -206,7 +197,7 @@ export class ChaptersLessonService { // Audit log - DELETE Chapter auditService.log({ - userId: decodedToken.id, + userId: userId, action: AuditAction.DELETE, entityType: 'Chapter', entityId: chapter_id, @@ -219,9 +210,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Chapter deleted successfully' }; } catch (error) { logger.error(`Error deleting chapter: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Chapter', entityId: request.chapter_id, @@ -236,14 +226,13 @@ export class ChaptersLessonService { async reorderChapter(request: ReorderChapterRequest): Promise { try { - const { token, course_id, chapter_id, sort_order: newSortOrder } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, chapter_id, sort_order: newSortOrder } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new UnauthorizedError('Invalid token'); } - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) { throw new ForbiddenError('You are not permitted to reorder chapter'); } @@ -313,9 +302,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Chapter reordered successfully', data: chapters as ChapterData[] }; } catch (error) { logger.error(`Error reordering chapter: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Chapter', entityId: request.chapter_id, @@ -335,14 +323,13 @@ export class ChaptersLessonService { */ async createLesson(request: CreateLessonInput): Promise { try { - const { token, course_id, chapter_id, title, content, type, sort_order } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, chapter_id, title, content, type, sort_order } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new UnauthorizedError('Invalid token'); } - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) { throw new ForbiddenError('You are not permitted to create lesson'); } @@ -354,7 +341,6 @@ export class ChaptersLessonService { // If QUIZ type, create empty Quiz shell if (type === 'QUIZ') { - const userId = decodedToken.id; await prisma.quiz.create({ data: { @@ -376,7 +362,7 @@ export class ChaptersLessonService { // Audit log - CREATE Lesson (QUIZ) auditService.log({ - userId: decodedToken.id, + userId: userId, action: AuditAction.CREATE, entityType: 'Lesson', entityId: lesson.id, @@ -388,7 +374,7 @@ export class ChaptersLessonService { // Audit log - CREATE Lesson auditService.log({ - userId: decodedToken.id, + userId: userId, action: AuditAction.CREATE, entityType: 'Lesson', entityId: lesson.id, @@ -398,9 +384,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Lesson created successfully', data: lesson as LessonData }; } catch (error) { logger.error(`Error creating lesson: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Lesson', entityId: 0, @@ -419,10 +404,10 @@ export class ChaptersLessonService { */ async getLesson(request: GetLessonRequest): Promise { try { - const { token, course_id, lesson_id } = request; + const { userId, course_id, lesson_id } = request; // Check access for both instructor and enrolled student - const access = await validateCourseAccess(token, course_id); + const access = await validateCourseAccess(userId, course_id); if (!access.hasAccess) { throw new ForbiddenError('You do not have access to this course'); } @@ -549,9 +534,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Lesson fetched successfully', data: lessonData as LessonData }; } catch (error) { logger.error(`Error fetching lesson: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Lesson', entityId: request.lesson_id, @@ -566,14 +550,13 @@ export class ChaptersLessonService { async updateLesson(request: UpdateLessonRequest): Promise { try { - const { token, course_id, lesson_id, data } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, data } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new UnauthorizedError('Invalid token'); } - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) { throw new ForbiddenError('You are not permitted to update lesson'); } @@ -581,9 +564,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Lesson updated successfully', data: lesson as LessonData }; } catch (error) { logger.error(`Error updating lesson: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Lesson', entityId: request.lesson_id, @@ -602,14 +584,13 @@ export class ChaptersLessonService { */ async reorderLessons(request: ReorderLessonsRequest): Promise { try { - const { token, course_id, chapter_id, lesson_id, sort_order: newSortOrder } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, chapter_id, lesson_id, sort_order: newSortOrder } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to reorder lessons'); // Verify chapter exists and belongs to the course @@ -682,9 +663,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Lessons reordered successfully', data: lessons as LessonData[] }; } catch (error) { logger.error(`Error reordering lessons: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Lesson', entityId: request.lesson_id, @@ -704,14 +684,13 @@ export class ChaptersLessonService { */ async deleteLesson(request: DeleteLessonRequest): Promise { try { - const { token, course_id, lesson_id } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to delete this lesson'); // Fetch lesson with all related data @@ -751,7 +730,7 @@ export class ChaptersLessonService { // Audit log - DELETE Lesson auditService.log({ - userId: decodedToken.id, + userId: userId, action: AuditAction.DELETE, entityType: 'Lesson', entityId: lesson_id, @@ -764,9 +743,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Lesson deleted successfully' }; } catch (error) { logger.error(`Error deleting lesson: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Lesson', entityId: request.lesson_id, @@ -789,14 +767,13 @@ export class ChaptersLessonService { */ async uploadVideo(request: UploadVideoInput): Promise { try { - const { token, course_id, lesson_id, video } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, video } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists and is VIDEO type @@ -833,7 +810,7 @@ export class ChaptersLessonService { // Audit log - UPLOAD_FILE (Video) auditService.log({ - userId: decodedToken.id, + userId: userId, action: AuditAction.UPLOAD_FILE, entityType: 'Lesson', entityId: lesson_id, @@ -853,9 +830,8 @@ export class ChaptersLessonService { }; } catch (error) { logger.error(`Error uploading video: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Lesson', entityId: request.lesson_id, @@ -874,14 +850,13 @@ export class ChaptersLessonService { */ async updateVideo(request: UpdateVideoInput): Promise { try { - const { token, course_id, lesson_id, video } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, video } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists and is VIDEO type @@ -946,9 +921,8 @@ export class ChaptersLessonService { }; } catch (error) { logger.error(`Error updating video: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Lesson', entityId: request.lesson_id, @@ -967,14 +941,13 @@ export class ChaptersLessonService { */ async setYouTubeVideo(request: SetYouTubeVideoInput): Promise { try { - const { token, course_id, lesson_id, youtube_video_id, video_title } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, youtube_video_id, video_title } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists and is VIDEO type @@ -1038,9 +1011,8 @@ export class ChaptersLessonService { }; } catch (error) { logger.error(`Error setting YouTube video: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Lesson', entityId: request.lesson_id, @@ -1059,14 +1031,13 @@ export class ChaptersLessonService { */ async uploadAttachment(request: UploadAttachmentInput): Promise { try { - const { token, course_id, lesson_id, attachment } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, attachment } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists @@ -1101,7 +1072,7 @@ export class ChaptersLessonService { // Audit log - UPLOAD_FILE (Attachment) auditService.log({ - userId: decodedToken.id, + userId: userId, action: AuditAction.UPLOAD_FILE, entityType: 'LessonAttachment', entityId: newAttachment.id, @@ -1125,9 +1096,8 @@ export class ChaptersLessonService { }; } catch (error) { logger.error(`Error uploading attachment: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'LessonAttachment', entityId: request.lesson_id, @@ -1146,14 +1116,13 @@ export class ChaptersLessonService { */ async deleteAttachment(request: DeleteAttachmentInput): Promise { try { - const { token, course_id, lesson_id, attachment_id } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, attachment_id } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists @@ -1184,7 +1153,7 @@ export class ChaptersLessonService { // Audit log - DELETE_FILE (Attachment) auditService.log({ - userId: decodedToken.id, + userId: userId, action: AuditAction.DELETE_FILE, entityType: 'LessonAttachment', entityId: attachment_id, @@ -1194,9 +1163,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Attachment deleted successfully' }; } catch (error) { logger.error(`Error deleting attachment: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'LessonAttachment', entityId: request.attachment_id, @@ -1216,14 +1184,13 @@ export class ChaptersLessonService { */ async addQuestion(request: AddQuestionInput): Promise { try { - const { token, course_id, lesson_id, question, explanation, question_type, sort_order, choices } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, question, explanation, question_type, sort_order, choices } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists and is QUIZ type @@ -1281,9 +1248,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Question added successfully', data: completeQuestion as QuizQuestionData }; } catch (error) { logger.error(`Error adding question: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Question', entityId: 0, @@ -1303,14 +1269,13 @@ export class ChaptersLessonService { */ async updateQuestion(request: UpdateQuestionInput): Promise { try { - const { token, course_id, lesson_id, question_id, question, explanation, question_type, sort_order, choices } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, question_id, question, explanation, question_type, sort_order, choices } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists and is QUIZ type @@ -1367,9 +1332,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Question updated successfully', data: completeQuestion as QuizQuestionData }; } catch (error) { logger.error(`Error updating question: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Question', entityId: request.question_id, @@ -1384,14 +1348,13 @@ export class ChaptersLessonService { async reorderQuestion(request: ReorderQuestionInput): Promise { try { - const { token, course_id, lesson_id, question_id, sort_order } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, question_id, sort_order } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists and is QUIZ type @@ -1471,9 +1434,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Question reordered successfully', data: questions as QuizQuestionData[] }; } catch (error) { logger.error(`Error reordering question: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Question', entityId: request.question_id, @@ -1493,14 +1455,13 @@ export class ChaptersLessonService { */ async deleteQuestion(request: DeleteQuestionInput): Promise { try { - const { token, course_id, lesson_id, question_id } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, question_id } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists and is QUIZ type @@ -1530,9 +1491,8 @@ export class ChaptersLessonService { return { code: 200, message: 'Question deleted successfully' }; } catch (error) { logger.error(`Error deleting question: ${error}`); - const decodedToken = jwt.decode(request.token) as { id: number } | null; await auditService.logSync({ - userId: decodedToken?.id || 0, + userId: request.userId || 0, action: AuditAction.ERROR, entityType: 'Question', entityId: request.question_id, @@ -1680,14 +1640,13 @@ export class ChaptersLessonService { */ async updateQuiz(request: UpdateQuizInput): Promise { try { - const { token, course_id, lesson_id, title, description, passing_score, time_limit, shuffle_questions, shuffle_choices, show_answers_after_completion, is_skippable, allow_multiple_attempts } = request; - const decodedToken = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, title, description, passing_score, time_limit, shuffle_questions, shuffle_choices, show_answers_after_completion, is_skippable, allow_multiple_attempts } = request; await CoursesInstructorService.validateCourseStatus(course_id); - const user = await prisma.user.findUnique({ where: { id: decodedToken.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('Invalid token'); - const courseInstructor = await CoursesInstructorService.validateCourseInstructor(token, course_id); + const courseInstructor = await CoursesInstructorService.validateCourseInstructor(userId, course_id); if (!courseInstructor) throw new ForbiddenError('You are not permitted to modify this lesson'); // Verify lesson exists and is QUIZ type diff --git a/Backend/src/services/CoursesInstructor.service.ts b/Backend/src/services/CoursesInstructor.service.ts index e1b40d0c..959ef80f 100644 --- a/Backend/src/services/CoursesInstructor.service.ts +++ b/Backend/src/services/CoursesInstructor.service.ts @@ -1,9 +1,7 @@ import { prisma } from '../config/database'; import { Prisma } from '@prisma/client'; -import { config } from '../config'; import { logger } from '../config/logger'; -import { UnauthorizedError, ValidationError, ForbiddenError, NotFoundError } from '../middleware/errorHandler'; -import jwt from 'jsonwebtoken'; +import { ValidationError, ForbiddenError, NotFoundError } from '../middleware/errorHandler'; import { uploadFile, deleteFile, getPresignedUrl } from '../config/minio'; import { CreateCourseInput, @@ -27,6 +25,7 @@ import { SearchInstructorResponse, GetEnrolledStudentsInput, GetEnrolledStudentsResponse, + EnrolledStudentData, GetQuizScoresInput, GetQuizScoresResponse, GetQuizAttemptDetailInput, @@ -38,6 +37,7 @@ import { CloneCourseResponse, setCourseDraft, setCourseDraftResponse, + GetAllMyStudentsResponse, } from "../types/CoursesInstructor.types"; import { auditService } from './audit.service'; import { AuditAction } from '@prisma/client'; @@ -121,10 +121,9 @@ export class CoursesInstructorService { static async listMyCourses(input: ListMyCoursesInput): Promise { try { - const decoded = jwt.verify(input.token, config.jwt.secret) as { id: number; type: string }; const courseInstructors = await prisma.courseInstructor.findMany({ where: { - user_id: decoded.id, + user_id: input.userId, course: input.status ? { status: input.status } : undefined }, include: { @@ -157,9 +156,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to retrieve courses', { error }); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: 0, @@ -174,12 +172,10 @@ export class CoursesInstructorService { static async getmyCourse(getmyCourse: getmyCourse): Promise { try { - const decoded = jwt.verify(getmyCourse.token, config.jwt.secret) as { id: number; type: string }; - // Check if user is instructor of this course const courseInstructor = await prisma.courseInstructor.findFirst({ where: { - user_id: decoded.id, + user_id: getmyCourse.userId, course_id: getmyCourse.course_id }, include: { @@ -225,9 +221,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to retrieve course', { error }); - const decoded = jwt.decode(getmyCourse.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: getmyCourse.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: getmyCourse.course_id, @@ -240,9 +235,9 @@ export class CoursesInstructorService { } } - static async updateCourse(token: string, courseId: number, courseData: UpdateCourseInput): Promise { + static async updateCourse(userId: number, courseId: number, courseData: UpdateCourseInput): Promise { try { - await this.validateCourseInstructor(token, courseId); + await this.validateCourseInstructor(userId, courseId); const course = await prisma.course.update({ where: { @@ -258,9 +253,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to update course', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId, action: AuditAction.ERROR, entityType: 'Course', entityId: courseId, @@ -273,9 +267,9 @@ export class CoursesInstructorService { } } - static async uploadThumbnail(token: string, courseId: number, file: Express.Multer.File): Promise<{ code: number; message: string; data: { course_id: number; thumbnail_url: string } }> { + static async uploadThumbnail(userId: number, courseId: number, file: Express.Multer.File): Promise<{ code: number; message: string; data: { course_id: number; thumbnail_url: string } }> { try { - await this.validateCourseInstructor(token, courseId); + await this.validateCourseInstructor(userId, courseId); // Get current course to check for existing thumbnail const currentCourse = await prisma.course.findUnique({ @@ -322,9 +316,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to upload thumbnail', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId, action: AuditAction.ERROR, entityType: 'Course', entityId: courseId, @@ -337,9 +330,9 @@ export class CoursesInstructorService { } } - static async deleteCourse(token: string, courseId: number): Promise { + static async deleteCourse(userId: number, courseId: number): Promise { try { - const courseInstructorId = await this.validateCourseInstructor(token, courseId); + const courseInstructorId = await this.validateCourseInstructor(userId, courseId); if (!courseInstructorId.is_primary) { throw new ForbiddenError('You have no permission to delete this course'); } @@ -365,9 +358,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to delete course', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId, action: AuditAction.ERROR, entityType: 'Course', entityId: courseId, @@ -382,11 +374,10 @@ export class CoursesInstructorService { static async sendCourseForReview(sendCourseForReview: sendCourseForReview): Promise { try { - const decoded = jwt.verify(sendCourseForReview.token, config.jwt.secret) as { id: number; type: string }; await prisma.courseApproval.create({ data: { course_id: sendCourseForReview.course_id, - submitted_by: decoded.id, + submitted_by: sendCourseForReview.userId, } }); await prisma.course.update({ @@ -398,7 +389,7 @@ export class CoursesInstructorService { } }); await auditService.logSync({ - userId: decoded.id, + userId: sendCourseForReview.userId, action: AuditAction.UPDATE, entityType: 'Course', entityId: sendCourseForReview.course_id, @@ -412,9 +403,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to send course for review', { error }); - const decoded = jwt.decode(sendCourseForReview.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: sendCourseForReview.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: sendCourseForReview.course_id, @@ -429,7 +419,7 @@ export class CoursesInstructorService { static async setCourseDraft(setCourseDraft: setCourseDraft): Promise { try { - await this.validateCourseInstructor(setCourseDraft.token, setCourseDraft.course_id); + await this.validateCourseInstructor(setCourseDraft.userId, setCourseDraft.course_id); await prisma.course.update({ where: { id: setCourseDraft.course_id, @@ -445,9 +435,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to set course to draft', { error }); - const decoded = jwt.decode(setCourseDraft.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: setCourseDraft.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: setCourseDraft.course_id, @@ -460,7 +449,7 @@ export class CoursesInstructorService { } } - static async getCourseApprovals(token: string, courseId: number): Promise<{ + static async getCourseApprovals(userId: number, courseId: number): Promise<{ code: number; message: string; data: any[]; @@ -468,7 +457,7 @@ export class CoursesInstructorService { }> { try { // Validate instructor access - await this.validateCourseInstructor(token, courseId); + await this.validateCourseInstructor(userId, courseId); const approvals = await prisma.courseApproval.findMany({ where: { course_id: courseId }, @@ -491,9 +480,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to retrieve course approvals', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId, action: AuditAction.ERROR, entityType: 'Course', entityId: courseId, @@ -510,8 +498,6 @@ export class CoursesInstructorService { static async searchInstructors(input: SearchInstructorInput): Promise { try { - const decoded = jwt.verify(input.token, config.jwt.secret) as { id: number }; - // Get existing instructors in the course const existingInstructors = await prisma.courseInstructor.findMany({ where: { course_id: input.course_id }, @@ -528,7 +514,7 @@ export class CoursesInstructorService { ], role: { code: 'INSTRUCTOR' }, id: { - notIn: [decoded.id, ...existingInstructorIds], + notIn: [input.userId, ...existingInstructorIds], }, }, include: { @@ -563,9 +549,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to search instructors', { error }); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: input.course_id, @@ -581,7 +566,7 @@ export class CoursesInstructorService { static async addInstructorToCourse(addinstructorCourse: addinstructorCourse): Promise { try { // Validate user is instructor of this course - await this.validateCourseInstructor(addinstructorCourse.token, addinstructorCourse.course_id); + await this.validateCourseInstructor(addinstructorCourse.userId, addinstructorCourse.course_id); // Find user by email or username const user = await prisma.user.findFirst({ @@ -619,9 +604,8 @@ export class CoursesInstructorService { } }); - const decoded = jwt.decode(addinstructorCourse.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId: addinstructorCourse.userId, action: AuditAction.CREATE, entityType: 'Course', entityId: addinstructorCourse.course_id, @@ -637,9 +621,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to add instructor to course', { error }); - const decoded = jwt.decode(addinstructorCourse.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: addinstructorCourse.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: addinstructorCourse.course_id, @@ -654,7 +637,6 @@ export class CoursesInstructorService { static async removeInstructorFromCourse(removeinstructorCourse: removeinstructorCourse): Promise { try { - const decoded = jwt.verify(removeinstructorCourse.token, config.jwt.secret) as { id: number; type: string }; await prisma.courseInstructor.delete({ where: { course_id_user_id: { @@ -665,7 +647,7 @@ export class CoursesInstructorService { }); await auditService.logSync({ - userId: decoded?.id || 0, + userId: removeinstructorCourse.userId, action: AuditAction.DELETE, entityType: 'Course', entityId: removeinstructorCourse.course_id, @@ -682,9 +664,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to remove instructor from course', { error }); - const decoded = jwt.decode(removeinstructorCourse.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: removeinstructorCourse.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: removeinstructorCourse.course_id, @@ -699,7 +680,6 @@ export class CoursesInstructorService { static async listInstructorsOfCourse(listinstructorCourse: listinstructorCourse): Promise { try { - const decoded = jwt.verify(listinstructorCourse.token, config.jwt.secret) as { id: number; type: string }; const courseInstructors = await prisma.courseInstructor.findMany({ where: { course_id: listinstructorCourse.course_id, @@ -743,9 +723,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to retrieve instructors of course', { error }); - const decoded = jwt.decode(listinstructorCourse.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: listinstructorCourse.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: listinstructorCourse.course_id, @@ -760,7 +739,6 @@ export class CoursesInstructorService { static async setPrimaryInstructor(setprimaryCourseInstructor: setprimaryCourseInstructor): Promise { try { - const decoded = jwt.verify(setprimaryCourseInstructor.token, config.jwt.secret) as { id: number; type: string }; await prisma.courseInstructor.update({ where: { course_id_user_id: { @@ -774,7 +752,7 @@ export class CoursesInstructorService { }); await auditService.logSync({ - userId: decoded?.id || 0, + userId: setprimaryCourseInstructor.userId, action: AuditAction.UPDATE, entityType: 'Course', entityId: setprimaryCourseInstructor.course_id, @@ -791,9 +769,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error('Failed to set primary instructor', { error }); - const decoded = jwt.decode(setprimaryCourseInstructor.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: setprimaryCourseInstructor.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: setprimaryCourseInstructor.course_id, @@ -806,11 +783,10 @@ export class CoursesInstructorService { } } - static async validateCourseInstructor(token: string, courseId: number): Promise<{ user_id: number; is_primary: boolean }> { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string }; + static async validateCourseInstructor(userId: number, courseId: number): Promise<{ user_id: number; is_primary: boolean }> { const courseInstructor = await prisma.courseInstructor.findFirst({ where: { - user_id: decoded.id, + user_id: userId, course_id: courseId } }); @@ -839,10 +815,10 @@ export class CoursesInstructorService { */ static async getEnrolledStudents(input: GetEnrolledStudentsInput): Promise { try { - const { token, course_id, page = 1, limit = 20, search, status } = input; + const { userId, course_id, page = 1, limit = 20, search, status } = input; // Validate instructor - await this.validateCourseInstructor(token, course_id); + await this.validateCourseInstructor(userId, course_id); // Build where clause const whereClause: any = { course_id }; @@ -917,9 +893,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error(`Error getting enrolled students: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: input.course_id, @@ -938,11 +913,10 @@ export class CoursesInstructorService { */ static async getQuizScores(input: GetQuizScoresInput): Promise { try { - const { token, course_id, lesson_id, page = 1, limit = 20, search, is_passed } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, lesson_id, page = 1, limit = 20, search, is_passed } = input; // Validate instructor - await this.validateCourseInstructor(token, course_id); + await this.validateCourseInstructor(userId, course_id); // Get lesson and verify it's a QUIZ type const lesson = await prisma.lesson.findUnique({ @@ -1095,9 +1069,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error(`Error getting quiz scores: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: input.course_id, @@ -1116,10 +1089,10 @@ export class CoursesInstructorService { */ static async getQuizAttemptDetail(input: GetQuizAttemptDetailInput): Promise { try { - const { token, course_id, lesson_id, student_id } = input; + const { userId, course_id, lesson_id, student_id } = input; // Validate instructor - await this.validateCourseInstructor(token, course_id); + await this.validateCourseInstructor(userId, course_id); // Get lesson and verify it's a QUIZ type const lesson = await prisma.lesson.findUnique({ @@ -1219,9 +1192,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error(`Error getting quiz attempt detail: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: input.course_id, @@ -1240,10 +1212,10 @@ export class CoursesInstructorService { */ static async getEnrolledStudentDetail(input: GetEnrolledStudentDetailInput): Promise { try { - const { token, course_id, student_id } = input; + const { userId, course_id, student_id } = input; // Validate instructor - await this.validateCourseInstructor(token, course_id); + await this.validateCourseInstructor(userId, course_id); // Get student info const student = await prisma.user.findUnique({ @@ -1367,9 +1339,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error(`Error getting enrolled student detail: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: input.course_id, @@ -1386,12 +1357,10 @@ export class CoursesInstructorService { * ดึงประวัติการขออนุมัติคอร์ส * Get course approval history for instructor to see rejection reasons */ - static async getCourseApprovalHistory(token: string, courseId: number): Promise { + static async getCourseApprovalHistory(userId: number, courseId: number): Promise { try { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; - // Validate instructor access - await this.validateCourseInstructor(token, courseId); + await this.validateCourseInstructor(userId, courseId); // Get course with approval history const course = await prisma.course.findUnique({ @@ -1434,9 +1403,8 @@ export class CoursesInstructorService { }; } catch (error) { logger.error(`Error getting course approval history: ${error}`); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || undefined, + userId, action: AuditAction.ERROR, entityType: 'Course', entityId: courseId, @@ -1454,11 +1422,10 @@ export class CoursesInstructorService { */ static async cloneCourse(input: CloneCourseInput): Promise { try { - const { token, course_id, title } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, title } = input; // Validate instructor - const courseInstructor = await this.validateCourseInstructor(token, course_id); + const courseInstructor = await this.validateCourseInstructor(userId, course_id); if (!courseInstructor) { throw new ForbiddenError('You are not an instructor of this course'); } @@ -1508,7 +1475,7 @@ export class CoursesInstructorService { is_free: originalCourse.is_free, have_certificate: originalCourse.have_certificate, status: 'DRAFT', // Reset status - created_by: decoded.id + created_by: userId } }); @@ -1516,7 +1483,7 @@ export class CoursesInstructorService { await tx.courseInstructor.create({ data: { course_id: createdCourse.id, - user_id: decoded.id, + user_id: userId, is_primary: true } }); @@ -1589,7 +1556,7 @@ export class CoursesInstructorService { shuffle_questions: lesson.quiz.shuffle_questions, shuffle_choices: lesson.quiz.shuffle_choices, show_answers_after_completion: lesson.quiz.show_answers_after_completion, - created_by: decoded.id + created_by: userId } }); @@ -1636,7 +1603,7 @@ export class CoursesInstructorService { }); await auditService.logSync({ - userId: decoded.id, + userId: input.userId, action: AuditAction.CREATE, entityType: 'Course', entityId: newCourse.id, @@ -1658,9 +1625,8 @@ export class CoursesInstructorService { } catch (error) { logger.error(`Error cloning course: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Course', entityId: input.course_id, @@ -1672,4 +1638,45 @@ export class CoursesInstructorService { throw error; } } + + /** + * ดึงผู้เรียนทั้งหมดในทุกคอร์สของ instructor + * Get all enrolled students across all courses the instructor owns/teaches + */ + static async getMyAllStudents(userId: number): Promise { + try { + // หา course IDs ทั้งหมดที่ instructor สอน + const instructorCourses = await prisma.courseInstructor.findMany({ + where: { user_id: userId }, + select: { course_id: true } + }); + + const courseIds = instructorCourses.map(ci => ci.course_id); + + if (courseIds.length === 0) { + return { code: 200, message: 'Students retrieved successfully', total_students: 0, total_completed: 0 }; + } + + // unique students ทั้งหมด + const uniqueStudents = await prisma.enrollment.groupBy({ + by: ['user_id'], + where: { course_id: { in: courseIds } }, + }); + + // จำนวน enrollment ที่ COMPLETED + const totalCompleted = await prisma.enrollment.count({ + where: { course_id: { in: courseIds }, status: 'COMPLETED' } + }); + + return { + code: 200, + message: 'Students retrieved successfully', + total_students: uniqueStudents.length, + total_completed: totalCompleted, + }; + } catch (error) { + logger.error(`Error getting all students: ${error}`); + throw error; + } + } } diff --git a/Backend/src/services/CoursesStudent.service.ts b/Backend/src/services/CoursesStudent.service.ts index 986695b1..2ae599fc 100644 --- a/Backend/src/services/CoursesStudent.service.ts +++ b/Backend/src/services/CoursesStudent.service.ts @@ -133,7 +133,7 @@ export class CoursesStudentService { async enrollCourse(input: EnrollCourseInput): Promise { try { const { course_id } = input; - const decoded = jwt.verify(input.token, config.jwt.secret) as { id: number; type: string }; + const userId = input.userId; const course = await prisma.course.findUnique({ where: { id: course_id }, @@ -146,7 +146,7 @@ export class CoursesStudentService { const existingEnrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -159,7 +159,7 @@ export class CoursesStudentService { const enrollment = await prisma.enrollment.create({ data: { course_id, - user_id: decoded.id, + user_id: userId, status: 'ENROLLED', enrolled_at: new Date(), }, @@ -167,11 +167,11 @@ export class CoursesStudentService { // Audit log - ENROLL auditService.log({ - userId: decoded.id, + userId: userId, action: AuditAction.ENROLL, entityType: 'Enrollment', entityId: enrollment.id, - newValue: { course_id, user_id: decoded.id, status: 'ENROLLED' } + newValue: { course_id, user_id: userId, status: 'ENROLLED' } }); return { @@ -187,9 +187,9 @@ export class CoursesStudentService { }; } catch (error) { logger.error(`Error enrolling in course: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; + // userId from middleware await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Enrollment', entityId: 0, @@ -206,13 +206,13 @@ export class CoursesStudentService { async GetEnrolledCourses(input: ListEnrolledCoursesInput): Promise { try { - const { token } = input; + // destructure input const page = input.page ?? 1; const limit = input.limit ?? 20; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string }; + const userId = input.userId; const enrollments = await prisma.enrollment.findMany({ where: { - user_id: decoded.id, + user_id: userId, }, include: { course: { @@ -230,7 +230,7 @@ export class CoursesStudentService { }); const total = await prisma.enrollment.count({ where: { - user_id: decoded.id, + user_id: userId, }, }); @@ -274,9 +274,9 @@ export class CoursesStudentService { }; } catch (error) { logger.error(error); - const decoded = jwt.decode(input.token) as { id: number } | null; + // userId from middleware await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Enrollment', entityId: 0, @@ -290,8 +290,8 @@ export class CoursesStudentService { } async getCourseLearning(input: GetCourseLearningInput): Promise { try { - const { token, course_id } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string }; + const { course_id } = input; + const userId = input.userId; // Get course with chapters and lessons (basic info only) const course = await prisma.course.findUnique({ @@ -330,7 +330,7 @@ export class CoursesStudentService { const enrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -345,7 +345,7 @@ export class CoursesStudentService { prisma.enrollment.update({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -357,7 +357,7 @@ export class CoursesStudentService { const lessonIds = course.chapters.flatMap(ch => ch.lessons.map(l => l.id)); const lessonProgress = await prisma.lessonProgress.findMany({ where: { - user_id: decoded.id, + user_id: userId, lesson_id: { in: lessonIds }, }, }); @@ -453,9 +453,9 @@ export class CoursesStudentService { }; } catch (error) { logger.error(error); - const decoded = jwt.decode(input.token) as { id: number } | null; + // userId from middleware await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Enrollment', entityId: 0, @@ -470,8 +470,8 @@ export class CoursesStudentService { async getlessonContent(input: GetLessonContentInput): Promise { try { - const { token, course_id, lesson_id } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string }; + const { course_id, lesson_id } = input; + const userId = input.userId; // Import MinIO functions @@ -479,7 +479,7 @@ export class CoursesStudentService { const enrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -528,7 +528,7 @@ export class CoursesStudentService { const lessonProgress = await prisma.lessonProgress.findUnique({ where: { user_id_lesson_id: { - user_id: decoded.id, + user_id: userId, lesson_id, }, }, @@ -639,7 +639,7 @@ export class CoursesStudentService { // Get latest quiz attempt for this user latestQuizAttempt = await prisma.quizAttempt.findFirst({ where: { - user_id: decoded.id, + user_id: userId, quiz_id: lesson.quiz.id, }, orderBy: { @@ -726,9 +726,9 @@ export class CoursesStudentService { }; } catch (error) { logger.error(error); - const decoded = jwt.decode(input.token) as { id: number } | null; + // userId from middleware await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Enrollment', entityId: 0, @@ -744,14 +744,14 @@ export class CoursesStudentService { async checkAccessLesson(input: CheckLessonAccessInput): Promise { try { - const { token, course_id, lesson_id } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string }; + const { course_id, lesson_id } = input; + const userId = input.userId; // Check enrollment const enrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -845,7 +845,7 @@ export class CoursesStudentService { // Get user's progress for prerequisite lessons const prerequisiteProgress = await prisma.lessonProgress.findMany({ where: { - user_id: decoded.id, + user_id: userId, lesson_id: { in: prerequisiteIds }, }, }); @@ -879,7 +879,7 @@ export class CoursesStudentService { // Check if user passed the quiz const quizAttempt = await prisma.quizAttempt.findFirst({ where: { - user_id: decoded.id, + user_id: userId, quiz_id: prereqLesson.quiz.id, is_passed: true, }, @@ -925,9 +925,9 @@ export class CoursesStudentService { }; } catch (error) { logger.error(error); - const decoded = jwt.decode(input.token) as { id: number } | null; + // userId from middleware await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Enrollment', entityId: 0, @@ -942,8 +942,8 @@ export class CoursesStudentService { async getVideoProgress(input: GetVideoProgressInput): Promise { try { - const { token, lesson_id } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string }; + const { lesson_id } = input; + const userId = input.userId; // Get lesson to find course_id const lesson = await prisma.lesson.findUnique({ @@ -966,7 +966,7 @@ export class CoursesStudentService { const enrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -980,7 +980,7 @@ export class CoursesStudentService { const progress = await prisma.lessonProgress.findUnique({ where: { user_id_lesson_id: { - user_id: decoded.id, + user_id: userId, lesson_id, }, }, @@ -1010,9 +1010,9 @@ export class CoursesStudentService { }; } catch (error) { logger.error(error); - const decoded = jwt.decode(input.token) as { id: number } | null; + // userId from middleware await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Enrollment', entityId: 0, @@ -1027,8 +1027,8 @@ export class CoursesStudentService { async saveVideoProgress(input: SaveVideoProgressInput): Promise { try { - const { token, lesson_id, video_progress_seconds, video_duration_seconds } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string }; + const { lesson_id, video_progress_seconds, video_duration_seconds } = input; + const userId = input.userId; // Get lesson to find course_id const lesson = await prisma.lesson.findUnique({ @@ -1051,7 +1051,7 @@ export class CoursesStudentService { const enrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -1074,12 +1074,12 @@ export class CoursesStudentService { const progress = await prisma.lessonProgress.upsert({ where: { user_id_lesson_id: { - user_id: decoded.id, + user_id: userId, lesson_id, }, }, create: { - user_id: decoded.id, + user_id: userId, lesson_id, video_progress_seconds, video_duration_seconds: video_duration_seconds ?? null, @@ -1098,7 +1098,7 @@ export class CoursesStudentService { // If video completed, mark lesson as complete and update enrollment progress let enrollmentProgress: { progress_percentage: number; is_course_completed: boolean } | undefined; if (isCompleted) { - const result = await this.markLessonComplete(decoded.id, lesson_id, course_id); + const result = await this.markLessonComplete(userId, lesson_id, course_id); enrollmentProgress = result.enrollmentProgress; } @@ -1118,9 +1118,9 @@ export class CoursesStudentService { }; } catch (error) { logger.error(error); - const decoded = jwt.decode(input.token) as { id: number } | null; + // userId from middleware await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Enrollment', entityId: 0, @@ -1135,8 +1135,8 @@ export class CoursesStudentService { async completeLesson(input: CompleteLessonInput): Promise { try { - const { token, lesson_id } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string }; + const { lesson_id } = input; + const userId = input.userId; // Get lesson with chapter and course info const lesson = await prisma.lesson.findUnique({ @@ -1185,7 +1185,7 @@ export class CoursesStudentService { const enrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -1196,7 +1196,7 @@ export class CoursesStudentService { } // Mark lesson as complete and update enrollment progress - const { lessonProgress, enrollmentProgress } = await this.markLessonComplete(decoded.id, lesson_id, course_id); + const { lessonProgress, enrollmentProgress } = await this.markLessonComplete(userId, lesson_id, course_id); const { progress_percentage: course_progress_percentage, is_course_completed } = enrollmentProgress; // Find next lesson @@ -1225,7 +1225,7 @@ export class CoursesStudentService { // Check if certificate already exists const existingCertificate = await prisma.certificate.findFirst({ where: { - user_id: decoded.id, + user_id: userId, course_id, }, }); @@ -1233,10 +1233,10 @@ export class CoursesStudentService { if (!existingCertificate) { await prisma.certificate.create({ data: { - user_id: decoded.id, + user_id: userId, course_id, enrollment_id: enrollment.id, - file_path: `certificates/${course_id}/${decoded.id}/${Date.now()}.pdf`, + file_path: `certificates/${course_id}/${userId}/${Date.now()}.pdf`, issued_at: new Date(), }, }); @@ -1261,9 +1261,9 @@ export class CoursesStudentService { }; } catch (error) { logger.error(`Error completing lesson: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; + // userId from middleware await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'LessonProgress', entityId: input.lesson_id, @@ -1283,14 +1283,14 @@ export class CoursesStudentService { */ async submitQuiz(input: SubmitQuizInput): Promise { try { - const { token, course_id, lesson_id, answers } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + const { course_id, lesson_id, answers } = input; + const userId = input.userId; // Check enrollment const enrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -1331,7 +1331,7 @@ export class CoursesStudentService { // Get previous attempt count const previousAttempts = await prisma.quizAttempt.count({ where: { - user_id: decoded.id, + user_id: userId, quiz_id: quiz.id, }, }); @@ -1384,7 +1384,7 @@ export class CoursesStudentService { const now = new Date(); const quizAttempt = await prisma.quizAttempt.create({ data: { - user_id: decoded.id, + user_id: userId, quiz_id: quiz.id, score: earnedScore, total_questions: quiz.questions.length, @@ -1400,7 +1400,7 @@ export class CoursesStudentService { // If passed, mark lesson as complete and update enrollment progress let enrollmentProgress: { progress_percentage: number; is_course_completed: boolean } | undefined; if (isPassed) { - const result = await this.markLessonComplete(decoded.id, lesson_id, course_id); + const result = await this.markLessonComplete(userId, lesson_id, course_id); enrollmentProgress = result.enrollmentProgress; } @@ -1429,9 +1429,9 @@ export class CoursesStudentService { }; } catch (error) { logger.error(`Error submitting quiz: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; + // userId from middleware await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'QuizAttempt', entityId: 0, @@ -1452,14 +1452,14 @@ export class CoursesStudentService { */ async getQuizAttempts(input: GetQuizAttemptsInput): Promise { try { - const { token, course_id, lesson_id } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + const { course_id, lesson_id } = input; + const userId = input.userId; // Check enrollment const enrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -1494,7 +1494,7 @@ export class CoursesStudentService { // Get all quiz attempts for this user const attempts = await prisma.quizAttempt.findMany({ where: { - user_id: decoded.id, + user_id: userId, quiz_id: lesson.quiz.id, }, orderBy: { attempt_number: 'desc' }, @@ -1539,22 +1539,20 @@ export class CoursesStudentService { }; } catch (error) { logger.error(error); - const decoded = jwt.decode(input.token) as { id: number } | null; - if (decoded?.id) { - await auditService.logSync({ - userId: decoded.id, - action: AuditAction.ERROR, - entityType: 'QuizAttempt', - entityId: 0, - metadata: { - operation: 'get_quiz_attempts', - course_id: input.course_id, - lesson_id: input.lesson_id, - error: error instanceof Error ? error.message : String(error) - } - }); - } + // userId from middleware + await auditService.logSync({ + userId: input.userId, + action: AuditAction.ERROR, + entityType: 'QuizAttempt', + entityId: 0, + metadata: { + operation: 'get_quiz_attempts', + course_id: input.course_id, + lesson_id: input.lesson_id, + error: error instanceof Error ? error.message : String(error) + } + }); throw error; } } -} \ No newline at end of file +} diff --git a/Backend/src/services/RecommendedCourses.service.ts b/Backend/src/services/RecommendedCourses.service.ts index 22440eb2..750131c6 100644 --- a/Backend/src/services/RecommendedCourses.service.ts +++ b/Backend/src/services/RecommendedCourses.service.ts @@ -1,8 +1,6 @@ import { prisma } from '../config/database'; -import { config } from '../config'; import { logger } from '../config/logger'; import { NotFoundError, ValidationError } from '../middleware/errorHandler'; -import jwt from 'jsonwebtoken'; import { getPresignedUrl } from '../config/minio'; import { ListApprovedCoursesResponse, @@ -20,7 +18,7 @@ export class RecommendedCoursesService { * List all approved courses (for admin to manage recommendations) */ static async listApprovedCourses( - token: string, + userId: number, filters?: { search?: string; categoryId?: number } ): Promise { try { @@ -108,19 +106,16 @@ export class RecommendedCoursesService { }; } catch (error) { logger.error('Failed to list approved courses', { error }); - const decoded = jwt.decode(token) as { id: number } | null; - if (decoded?.id) { - await auditService.logSync({ - userId: decoded.id, - action: AuditAction.ERROR, - entityType: 'RecommendedCourses', - entityId: 0, - metadata: { - operation: 'list_approved_courses', - error: error instanceof Error ? error.message : String(error) - } - }); - } + await auditService.logSync({ + userId, + action: AuditAction.ERROR, + entityType: 'RecommendedCourses', + entityId: 0, + metadata: { + operation: 'list_approved_courses', + error: error instanceof Error ? error.message : String(error) + } + }); throw error; } } @@ -128,7 +123,7 @@ export class RecommendedCoursesService { /** * Get course by ID (for admin to view details) */ - static async getCourseById(token: string, courseId: number): Promise { + static async getCourseById(userId: number, courseId: number): Promise { try { const course = await prisma.course.findUnique({ where: { id: courseId }, @@ -213,19 +208,16 @@ export class RecommendedCoursesService { }; } catch (error) { logger.error('Failed to get course by ID', { error }); - const decoded = jwt.decode(token) as { id: number } | null; - if (decoded?.id) { - await auditService.logSync({ - userId: decoded.id, - action: AuditAction.ERROR, - entityType: 'RecommendedCourses', - entityId: 0, - metadata: { - operation: 'get_course_by_id', - error: error instanceof Error ? error.message : String(error) - } - }); - } + await auditService.logSync({ + userId, + action: AuditAction.ERROR, + entityType: 'RecommendedCourses', + entityId: 0, + metadata: { + operation: 'get_course_by_id', + error: error instanceof Error ? error.message : String(error) + } + }); throw error; } } @@ -234,12 +226,11 @@ export class RecommendedCoursesService { * Toggle course recommendation status */ static async toggleRecommended( - token: string, + userId: number, courseId: number, isRecommended: boolean ): Promise { try { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; const course = await prisma.course.findUnique({ where: { id: courseId } }); if (!course) { @@ -257,7 +248,7 @@ export class RecommendedCoursesService { // Audit log await auditService.logSync({ - userId: decoded.id, + userId, action: AuditAction.UPDATE, entityType: 'Course', entityId: courseId, @@ -276,9 +267,8 @@ export class RecommendedCoursesService { }; } catch (error) { logger.error('Failed to toggle recommended status', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId, action: AuditAction.ERROR, entityType: 'RecommendedCourses', entityId: courseId, diff --git a/Backend/src/services/announcements.service.ts b/Backend/src/services/announcements.service.ts index 7e8b2d3e..36adabca 100644 --- a/Backend/src/services/announcements.service.ts +++ b/Backend/src/services/announcements.service.ts @@ -1,8 +1,6 @@ import { prisma } from '../config/database'; -import { config } from '../config'; import { logger } from '../config/logger'; -import { UnauthorizedError, ForbiddenError, NotFoundError } from '../middleware/errorHandler'; -import jwt from 'jsonwebtoken'; +import { ForbiddenError, NotFoundError } from '../middleware/errorHandler'; import { ListAnnouncementResponse, CreateAnnouncementInput, @@ -31,27 +29,26 @@ export class AnnouncementsService { */ async listAnnouncement(input: ListAnnouncementInput): Promise { try { - const { token, course_id, page = 1, limit = 10 } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string }; + const { userId, course_id, page = 1, limit = 10 } = input; // Check user access - instructor, admin, or enrolled student const user = await prisma.user.findUnique({ - where: { id: decoded.id }, + where: { id: userId }, include: { role: true }, }); - if (!user) throw new UnauthorizedError('Invalid token'); + if (!user) throw new ForbiddenError('User not found'); // Admin can access all courses const isAdmin = user.role.code === 'ADMIN'; // Check if instructor of this course const isInstructor = await prisma.courseInstructor.findFirst({ - where: { course_id, user_id: decoded.id }, + where: { course_id, user_id: userId }, }); // Check if enrolled student const isEnrolled = await prisma.enrollment.findFirst({ - where: { course_id, user_id: decoded.id }, + where: { course_id, user_id: userId }, }); if (!isAdmin && !isInstructor && !isEnrolled) throw new ForbiddenError('You do not have access to this course announcements'); @@ -61,7 +58,7 @@ export class AnnouncementsService { // Students only see PUBLISHED announcements with published_at <= now const now = new Date(); const whereClause: any = { course_id }; - + if (!(isAdmin || isInstructor)) { // Students: only show PUBLISHED and published_at <= now whereClause.status = 'PUBLISHED'; @@ -130,9 +127,8 @@ export class AnnouncementsService { }; } catch (error) { logger.error(`Error listing announcements: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Announcement', entityId: 0, @@ -150,11 +146,10 @@ export class AnnouncementsService { */ async createAnnouncement(input: CreateAnnouncementInput): Promise { try { - const { token, course_id, title, content, status, is_pinned, published_at, files } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, title, content, status, is_pinned, published_at, files } = input; // Validate instructor access - await CoursesInstructorService.validateCourseInstructor(token, course_id); + await CoursesInstructorService.validateCourseInstructor(userId, course_id); // Determine published_at: use provided value or default to now if status is PUBLISHED let finalPublishedAt: Date | null = null; @@ -171,7 +166,7 @@ export class AnnouncementsService { status: status as any, is_pinned, published_at: finalPublishedAt, - created_by: decoded.id, + created_by: userId, }, }); @@ -236,9 +231,8 @@ export class AnnouncementsService { }; } catch (error) { logger.error(`Error creating announcement: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Announcement', entityId: 0, @@ -256,11 +250,10 @@ export class AnnouncementsService { */ async updateAnnouncement(input: UpdateAnnouncementInput): Promise { try { - const { token, course_id, announcement_id, title, content, status, is_pinned, published_at } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, announcement_id, title, content, status, is_pinned, published_at } = input; // Validate instructor access - await CoursesInstructorService.validateCourseInstructor(token, course_id); + await CoursesInstructorService.validateCourseInstructor(userId, course_id); // Check announcement exists and belongs to course const existing = await prisma.announcement.findFirst({ @@ -289,7 +282,7 @@ export class AnnouncementsService { status: status as any, is_pinned, published_at: finalPublishedAt, - updated_by: decoded.id, + updated_by: userId, }, include: { attachments: true, @@ -320,9 +313,8 @@ export class AnnouncementsService { }; } catch (error) { logger.error(`Error updating announcement: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Announcement', entityId: 0, @@ -340,11 +332,10 @@ export class AnnouncementsService { */ async deleteAnnouncement(input: DeleteAnnouncementInput): Promise { try { - const { token, course_id, announcement_id } = input; - jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, announcement_id } = input; // Validate instructor access - await CoursesInstructorService.validateCourseInstructor(token, course_id); + await CoursesInstructorService.validateCourseInstructor(userId, course_id); // Check announcement exists and belongs to course const existing = await prisma.announcement.findFirst({ @@ -376,9 +367,8 @@ export class AnnouncementsService { }; } catch (error) { logger.error(`Error deleting announcement: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Announcement', entityId: 0, @@ -396,11 +386,10 @@ export class AnnouncementsService { */ async uploadAttachment(input: UploadAnnouncementAttachmentInput): Promise { try { - const { token, course_id, announcement_id, file } = input; - jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, announcement_id, file } = input; // Validate instructor access - await CoursesInstructorService.validateCourseInstructor(token, course_id); + await CoursesInstructorService.validateCourseInstructor(userId, course_id); // Check announcement exists and belongs to course const existing = await prisma.announcement.findFirst({ @@ -451,9 +440,8 @@ export class AnnouncementsService { }; } catch (error) { logger.error(`Error uploading attachment: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Announcement', entityId: 0, @@ -471,11 +459,10 @@ export class AnnouncementsService { */ async deleteAttachment(input: DeleteAnnouncementAttachmentInput): Promise { try { - const { token, course_id, announcement_id, attachment_id } = input; - jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id, announcement_id, attachment_id } = input; // Validate instructor access - await CoursesInstructorService.validateCourseInstructor(token, course_id); + await CoursesInstructorService.validateCourseInstructor(userId, course_id); // Check attachment exists and belongs to announcement in this course const attachment = await prisma.announcementAttachment.findFirst({ @@ -508,9 +495,8 @@ export class AnnouncementsService { }; } catch (error) { logger.error(`Error deleting attachment: ${error}`); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Announcement', entityId: 0, diff --git a/Backend/src/services/auth.service.ts b/Backend/src/services/auth.service.ts index 66899bed..9d16d594 100644 --- a/Backend/src/services/auth.service.ts +++ b/Backend/src/services/auth.service.ts @@ -74,7 +74,6 @@ export class AuthService { data: { token, refreshToken, - user: await this.formatUserResponse(user) } }; } diff --git a/Backend/src/services/categories.service.ts b/Backend/src/services/categories.service.ts index 0e0defa2..e18ec617 100644 --- a/Backend/src/services/categories.service.ts +++ b/Backend/src/services/categories.service.ts @@ -1,10 +1,7 @@ import { prisma } from '../config/database'; import { Prisma } from '@prisma/client'; -import { config } from '../config'; import { logger } from '../config/logger'; -import jwt from 'jsonwebtoken'; import { createCategory, createCategoryResponse, deleteCategoryResponse, updateCategory, updateCategoryResponse, ListCategoriesResponse, Category } from '../types/categories.type'; -import { UnauthorizedError, ValidationError, ForbiddenError } from '../middleware/errorHandler'; import { auditService } from './audit.service'; import { AuditAction } from '@prisma/client'; @@ -26,14 +23,13 @@ export class CategoryService { } } - async createCategory(token: string, category: createCategory): Promise { + async createCategory(userId: number, category: createCategory): Promise { try { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; username: string; email: string; roleCode: string }; const newCategory = await prisma.category.create({ data: category }); auditService.log({ - userId: decoded.id, + userId, action: AuditAction.CREATE, entityType: 'Category', entityId: newCategory.id, @@ -47,13 +43,13 @@ export class CategoryService { name: newCategory.name as { th: string; en: string }, slug: newCategory.slug, description: newCategory.description as { th: string; en: string }, - created_by: decoded.id, + created_by: userId, } }; } catch (error) { logger.error('Failed to create category', { error }); await auditService.logSync({ - userId: 0, + userId, action: AuditAction.ERROR, entityType: 'Category', entityId: 0, @@ -66,15 +62,14 @@ export class CategoryService { } } - async updateCategory(token: string, id: number, category: updateCategory): Promise { + async updateCategory(userId: number, id: number, category: updateCategory): Promise { try { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; username: string; email: string; roleCode: string }; const updatedCategory = await prisma.category.update({ where: { id }, data: category }); auditService.log({ - userId: decoded.id, + userId, action: AuditAction.UPDATE, entityType: 'Category', entityId: id, @@ -88,13 +83,13 @@ export class CategoryService { name: updatedCategory.name as { th: string; en: string }, slug: updatedCategory.slug, description: updatedCategory.description as { th: string; en: string }, - updated_by: decoded.id, + updated_by: userId, } }; } catch (error) { logger.error('Failed to update category', { error }); await auditService.logSync({ - userId: 0, + userId, action: AuditAction.ERROR, entityType: 'Category', entityId: 0, @@ -107,14 +102,13 @@ export class CategoryService { } } - async deleteCategory(token: string, id: number): Promise { + async deleteCategory(userId: number, id: number): Promise { try { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; username: string; email: string; roleCode: string }; const deletedCategory = await prisma.category.delete({ where: { id } }); auditService.log({ - userId: decoded.id, + userId, action: AuditAction.DELETE, entityType: 'Category', entityId: id, @@ -127,7 +121,7 @@ export class CategoryService { } catch (error) { logger.error('Failed to delete category', { error }); await auditService.logSync({ - userId: 0, + userId, action: AuditAction.ERROR, entityType: 'Category', entityId: 0, diff --git a/Backend/src/services/certificate.service.ts b/Backend/src/services/certificate.service.ts index 4041ec41..eafaffa0 100644 --- a/Backend/src/services/certificate.service.ts +++ b/Backend/src/services/certificate.service.ts @@ -1,8 +1,6 @@ import { prisma } from '../config/database'; -import { config } from '../config'; import { logger } from '../config/logger'; import { NotFoundError, ForbiddenError, ValidationError } from '../middleware/errorHandler'; -import jwt from 'jsonwebtoken'; import { PDFDocument, rgb } from 'pdf-lib'; import fontkit from '@pdf-lib/fontkit'; import * as fs from 'fs'; @@ -29,14 +27,13 @@ export class CertificateService { */ async generateCertificate(input: GenerateCertificateInput): Promise { try { - const { token, course_id } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id } = input; // Check enrollment and completion const enrollment = await prisma.enrollment.findUnique({ where: { unique_enrollment: { - user_id: decoded.id, + user_id: userId, course_id, }, }, @@ -65,7 +62,7 @@ export class CertificateService { // Check if certificate already exists const existingCertificate = await prisma.certificate.findFirst({ where: { - user_id: decoded.id, + user_id: userId, course_id, }, }); @@ -103,13 +100,13 @@ export class CertificateService { // Upload to MinIO const timestamp = Date.now(); - const filePath = `certificates/${course_id}/${decoded.id}/${timestamp}.pdf`; + const filePath = `certificates/${course_id}/${userId}/${timestamp}.pdf`; await uploadFile(filePath, Buffer.from(pdfBytes), 'application/pdf'); // Save to database const certificate = await prisma.certificate.create({ data: { - user_id: decoded.id, + user_id: userId, course_id, enrollment_id: enrollment.id, file_path: filePath, @@ -118,7 +115,7 @@ export class CertificateService { }); auditService.log({ - userId: decoded.id, + userId, action: AuditAction.CREATE, entityType: 'Certificate', entityId: certificate.id, @@ -139,9 +136,8 @@ export class CertificateService { }; } catch (error) { logger.error('Failed to generate certificate', { error }); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Certificate', entityId: 0, @@ -160,12 +156,11 @@ export class CertificateService { */ async getCertificate(input: GetCertificateInput): Promise { try { - const { token, course_id } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId, course_id } = input; const certificate = await prisma.certificate.findFirst({ where: { - user_id: decoded.id, + user_id: userId, course_id, }, include: { @@ -202,9 +197,8 @@ export class CertificateService { }; } catch (error) { logger.error('Failed to get certificate', { error }); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Certificate', entityId: 0, @@ -223,12 +217,11 @@ export class CertificateService { */ async listMyCertificates(input: ListMyCertificatesInput): Promise { try { - const { token } = input; - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + const { userId } = input; const certificates = await prisma.certificate.findMany({ where: { - user_id: decoded.id, + user_id: userId, }, include: { enrollment: { @@ -267,9 +260,8 @@ export class CertificateService { }; } catch (error) { logger.error('Failed to list certificates', { error }); - const decoded = jwt.decode(input.token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id, + userId: input.userId, action: AuditAction.ERROR, entityType: 'Certificate', entityId: 0, diff --git a/Backend/src/services/user.service.ts b/Backend/src/services/user.service.ts index 69153d51..552c7665 100644 --- a/Backend/src/services/user.service.ts +++ b/Backend/src/services/user.service.ts @@ -24,15 +24,10 @@ import { auditService } from './audit.service'; import { AuditAction } from '@prisma/client'; export class UserService { - async getUserProfile(token: string): Promise { + async getUserProfile(userId: number): Promise { try { - // Decode JWT token to get user ID - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; username: string; email: string; roleCode: string }; - const user = await prisma.user.findUnique({ - where: { - id: decoded.id - }, + where: { id: userId }, include: { profile: true, role: true @@ -68,14 +63,6 @@ export class UserService { } : undefined }; } catch (error) { - if (error instanceof jwt.JsonWebTokenError) { - logger.error('Invalid JWT token:', error); - throw new UnauthorizedError('Invalid token'); - } - if (error instanceof jwt.TokenExpiredError) { - logger.error('JWT token expired:', error); - throw new UnauthorizedError('Token expired'); - } logger.error('Error fetching user profile:', error); throw error; } @@ -84,12 +71,9 @@ export class UserService { /** * Change user password */ - async changePassword(token: string, oldPassword: string, newPassword: string): Promise { + async changePassword(userId: number, oldPassword: string, newPassword: string): Promise { try { - // Decode JWT token to get user ID - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; username: string; email: string; roleCode: string }; - - const user = await prisma.user.findUnique({ where: { id: decoded.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('User not found'); // Check if account is deactivated @@ -127,21 +111,12 @@ export class UserService { message: 'Password changed successfully' }; } catch (error) { - if (error instanceof jwt.JsonWebTokenError) { - logger.error('Invalid JWT token:', error); - throw new UnauthorizedError('Invalid token'); - } - if (error instanceof jwt.TokenExpiredError) { - logger.error('JWT token expired:', error); - throw new UnauthorizedError('Token expired'); - } logger.error('Failed to change password', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId, action: AuditAction.ERROR, entityType: 'User', - entityId: decoded?.id || 0, + entityId: userId, metadata: { operation: 'change_password', error: error instanceof Error ? error.message : String(error) @@ -154,12 +129,9 @@ export class UserService { /** * Update user profile */ - async updateProfile(token: string, profile: ProfileUpdate): Promise { + async updateProfile(userId: number, profile: ProfileUpdate): Promise { try { - // Decode JWT token to get user ID - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; username: string; email: string; roleCode: string }; - - const user = await prisma.user.findUnique({ where: { id: decoded.id } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) throw new UnauthorizedError('User not found'); // Check if account is deactivated @@ -189,21 +161,12 @@ export class UserService { } }; } catch (error) { - if (error instanceof jwt.JsonWebTokenError) { - logger.error('Invalid JWT token:', error); - throw new UnauthorizedError('Invalid token'); - } - if (error instanceof jwt.TokenExpiredError) { - logger.error('JWT token expired:', error); - throw new UnauthorizedError('Token expired'); - } logger.error('Failed to update profile', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId, action: AuditAction.UPDATE, entityType: 'UserProfile', - entityId: decoded?.id || 0, + entityId: userId, metadata: { operation: 'update_profile', error: error instanceof Error ? error.message : String(error) @@ -213,9 +176,8 @@ export class UserService { } } - async getRoles(token: string): Promise { + async getRoles(): Promise { try { - jwt.verify(token, config.jwt.secret); const roles = await prisma.role.findMany({ select: { id: true, @@ -224,14 +186,6 @@ export class UserService { }); return { roles }; } catch (error) { - if (error instanceof jwt.TokenExpiredError) { - logger.error('JWT token expired:', error); - throw new UnauthorizedError('Token expired'); - } - if (error instanceof jwt.JsonWebTokenError) { - logger.error('Invalid JWT token:', error); - throw new UnauthorizedError('Invalid token'); - } logger.error('Failed to get roles', { error }); throw error; } @@ -240,13 +194,11 @@ export class UserService { /** * Upload avatar picture to MinIO */ - async uploadAvatarPicture(token: string, file: Express.Multer.File): Promise { + async uploadAvatarPicture(userId: number, file: Express.Multer.File): Promise { try { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; - // Check if user exists const user = await prisma.user.findUnique({ - where: { id: decoded.id }, + where: { id: userId }, include: { profile: true } }); @@ -265,7 +217,7 @@ export class UserService { const fileName = file.originalname || 'avatar'; const extension = fileName.split('.').pop() || 'jpg'; const safeFilename = `${timestamp}-${uniqueId}.${extension}`; - const filePath = `avatars/${decoded.id}/${safeFilename}`; + const filePath = `avatars/${userId}/${safeFilename}`; // Delete old avatar if exists if (user.profile?.avatar_url) { @@ -285,13 +237,13 @@ export class UserService { // Update or create profile - store only file path if (user.profile) { await prisma.userProfile.update({ - where: { user_id: decoded.id }, + where: { user_id: userId }, data: { avatar_url: filePath } }); } else { await prisma.userProfile.create({ data: { - user_id: decoded.id, + user_id: userId, avatar_url: filePath, first_name: '', last_name: '' @@ -301,10 +253,10 @@ export class UserService { // Audit log - UPLOAD_AVATAR await auditService.logSync({ - userId: decoded.id, + userId, action: AuditAction.UPLOAD_FILE, entityType: 'User', - entityId: decoded.id, + entityId: userId, metadata: { operation: 'upload_avatar', filePath @@ -318,26 +270,17 @@ export class UserService { code: 200, message: 'Avatar uploaded successfully', data: { - id: decoded.id, + id: userId, avatar_url: presignedUrl } }; } catch (error) { - if (error instanceof jwt.JsonWebTokenError) { - logger.error('Invalid JWT token:', error); - throw new UnauthorizedError('Invalid token'); - } - if (error instanceof jwt.TokenExpiredError) { - logger.error('JWT token expired:', error); - throw new UnauthorizedError('Token expired'); - } logger.error('Failed to upload avatar', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId, action: AuditAction.UPLOAD_FILE, entityType: 'UserProfile', - entityId: decoded?.id || 0, + entityId: userId, metadata: { operation: 'upload_avatar', error: error instanceof Error ? error.message : String(error) @@ -390,12 +333,10 @@ export class UserService { /** * Send verification email to user */ - async sendVerifyEmail(token: string): Promise { + async sendVerifyEmail(userId: number): Promise { try { - const decoded = jwt.verify(token, config.jwt.secret) as { id: number; email: string; roleCode: string }; - const user = await prisma.user.findUnique({ - where: { id: decoded.id }, + where: { id: userId }, include: { role: true } }); @@ -453,15 +394,12 @@ export class UserService { message: 'Verification email sent successfully' }; } catch (error) { - if (error instanceof jwt.JsonWebTokenError) throw new UnauthorizedError('Invalid token'); - if (error instanceof jwt.TokenExpiredError) throw new UnauthorizedError('Token expired'); logger.error('Failed to send verification email', { error }); - const decoded = jwt.decode(token) as { id: number } | null; await auditService.logSync({ - userId: decoded?.id || 0, + userId, action: AuditAction.ERROR, entityType: 'UserProfile', - entityId: decoded?.id || 0, + entityId: userId, metadata: { operation: 'send_verification_email', error: error instanceof Error ? error.message : String(error) diff --git a/Backend/src/types/ChaptersLesson.typs.ts b/Backend/src/types/ChaptersLesson.typs.ts index 51a26e4b..a2dd9a37 100644 --- a/Backend/src/types/ChaptersLesson.typs.ts +++ b/Backend/src/types/ChaptersLesson.typs.ts @@ -98,18 +98,18 @@ export interface ChapterData { // ============================================ export interface ChaptersRequest { - token: string; + userId: number; course_id: number; } export interface GetChapterRequest { - token: string; + userId: number; course_id: number; chapter_id: number; } export interface CreateChapterInput { - token: string; + userId: number; course_id: number; title: MultiLanguageText; description?: MultiLanguageText; @@ -118,13 +118,13 @@ export interface CreateChapterInput { } export interface CreateChapterRequest { - token: string; + userId: number; course_id: number; data: CreateChapterInput; } export interface UpdateChapterInput { - token: string; + userId: number; course_id: number; chapter_id: number; title?: MultiLanguageText; @@ -134,20 +134,20 @@ export interface UpdateChapterInput { } export interface UpdateChapterRequest { - token: string; + userId: number; course_id: number; chapter_id: number; data: UpdateChapterInput; } export interface DeleteChapterRequest { - token: string; + userId: number; course_id: number; chapter_id: number; } export interface ReorderChapterRequest { - token: string; + userId: number; course_id: number; chapter_id: number; sort_order: number; @@ -199,7 +199,7 @@ export interface ReorderChapterResponse { // ============================================ export interface GetLessonRequest { - token: string; + userId: number; course_id: number; chapter_id: number; lesson_id: number; @@ -216,7 +216,7 @@ export interface UploadedFileInfo { } export interface CreateLessonInput { - token: string; + userId: number; course_id: number; chapter_id: number; title: MultiLanguageText; @@ -293,7 +293,7 @@ export interface QuizChoiceData { } export interface CreateLessonRequest { - token: string; + userId: number; course_id: number; chapter_id: number; data: CreateLessonInput; @@ -311,7 +311,7 @@ export interface UpdateLessonInput { } export interface UpdateLessonRequest { - token: string; + userId: number; course_id: number; chapter_id: number; lesson_id: number; @@ -319,14 +319,14 @@ export interface UpdateLessonRequest { } export interface DeleteLessonRequest { - token: string; + userId: number; course_id: number; chapter_id: number; lesson_id: number; } export interface ReorderLessonsRequest { - token: string; + userId: number; course_id: number; chapter_id: number; lesson_id: number; @@ -365,7 +365,7 @@ export interface UpdateLessonResponse { * Input for uploading video to a lesson */ export interface UploadVideoInput { - token: string; + userId: number; course_id: number; lesson_id: number; video: UploadedFileInfo; @@ -375,7 +375,7 @@ export interface UploadVideoInput { * Input for updating (replacing) video in a lesson */ export interface UpdateVideoInput { - token: string; + userId: number; course_id: number; lesson_id: number; video: UploadedFileInfo; @@ -385,7 +385,7 @@ export interface UpdateVideoInput { * Input for setting YouTube video to a lesson */ export interface SetYouTubeVideoInput { - token: string; + userId: number; course_id: number; lesson_id: number; youtube_video_id: string; @@ -411,7 +411,7 @@ export interface YouTubeVideoResponse { * Input for uploading a single attachment to a lesson */ export interface UploadAttachmentInput { - token: string; + userId: number; course_id: number; lesson_id: number; attachment: UploadedFileInfo; @@ -421,7 +421,7 @@ export interface UploadAttachmentInput { * Input for deleting an attachment from a lesson */ export interface DeleteAttachmentInput { - token: string; + userId: number; course_id: number; lesson_id: number; attachment_id: number; @@ -490,7 +490,7 @@ export interface LessonWithDetailsResponse { * Input for adding quiz to an existing QUIZ lesson */ export interface AddQuizToLessonInput { - token: string; + userId: number; course_id: number; lesson_id: number; quiz_data: { @@ -509,7 +509,7 @@ export interface AddQuizToLessonInput { * Input for adding a single question to a quiz lesson */ export interface AddQuestionInput { - token: string; + userId: number; course_id: number; lesson_id: number; question: MultiLanguageText; @@ -532,7 +532,7 @@ export interface AddQuestionResponse { * Input for updating a question */ export interface UpdateQuestionInput { - token: string; + userId: number; course_id: number; lesson_id: number; question_id: number; @@ -556,14 +556,14 @@ export interface UpdateQuestionResponse { * Input for deleting a question */ export interface DeleteQuestionInput { - token: string; + userId: number; course_id: number; lesson_id: number; question_id: number; } export interface ReorderQuestionInput { - token: string; + userId: number; course_id: number; lesson_id: number; question_id: number; @@ -588,7 +588,7 @@ export interface DeleteQuestionResponse { * Input for updating quiz settings */ export interface UpdateQuizInput { - token: string; + userId: number; course_id: number; lesson_id: number; title?: MultiLanguageText; diff --git a/Backend/src/types/CoursesInstructor.types.ts b/Backend/src/types/CoursesInstructor.types.ts index cc4aa149..8291a1d5 100644 --- a/Backend/src/types/CoursesInstructor.types.ts +++ b/Backend/src/types/CoursesInstructor.types.ts @@ -24,7 +24,7 @@ export interface createCourseResponse { } export interface ListMyCoursesInput { - token: string; + userId: number; status?: 'DRAFT' | 'PENDING' | 'APPROVED' | 'REJECTED' | 'ARCHIVED'; } @@ -42,7 +42,7 @@ export interface GetMyCourseResponse { } export interface getmyCourse { - token: string; + userId: number; course_id: number; } @@ -94,13 +94,13 @@ export interface listCourseinstructorResponse { } export interface addinstructorCourse { - token: string; + userId: number; email_or_username: string; course_id: number; } export interface SearchInstructorInput { - token: string; + userId: number; query: string; course_id: number; } @@ -145,12 +145,12 @@ export interface listinstructorCourseResponse { } export interface listinstructorCourse { - token: string; + userId: number; course_id: number; } export interface removeinstructorCourse { - token: string; + userId: number; user_id: number; course_id: number; } @@ -161,7 +161,7 @@ export interface removeinstructorCourseResponse { } export interface setprimaryCourseInstructor { - token: string; + userId: number; user_id: number; course_id: number; } @@ -172,12 +172,12 @@ export interface setprimaryCourseInstructorResponse { } export interface sendCourseForReview { - token: string; + userId: number; course_id: number; } export interface setCourseDraft { - token: string; + userId: number; course_id: number; } @@ -220,7 +220,7 @@ export interface GetCourseApprovalsResponse { // ============================================ export interface GetEnrolledStudentsInput { - token: string; + userId: number; course_id: number; page?: number; limit?: number; @@ -254,7 +254,7 @@ export interface GetEnrolledStudentsResponse { // ============================================ export interface GetQuizScoresInput { - token: string; + userId: number; course_id: number; lesson_id: number; page?: number; @@ -305,7 +305,7 @@ export interface GetQuizScoresResponse { // ============================================ export interface GetQuizAttemptDetailInput { - token: string; + userId: number; course_id: number; lesson_id: number; student_id: number; @@ -353,7 +353,7 @@ export interface GetQuizAttemptDetailResponse { // ============================================ export interface GetEnrolledStudentDetailInput { - token: string; + userId: number; course_id: number; student_id: number; } @@ -435,7 +435,7 @@ export interface GetCourseApprovalHistoryResponse { } export interface CloneCourseInput { - token: string; + userId: number; course_id: number; title: MultiLanguageText; } @@ -448,3 +448,14 @@ export interface CloneCourseResponse { title: MultiLanguageText; }; } + +// ============================================ +// Get All Students across all instructor courses +// ============================================ + +export interface GetAllMyStudentsResponse { + code: number; + message: string; + total_students: number; + total_completed: number; +} diff --git a/Backend/src/types/CoursesStudent.types.ts b/Backend/src/types/CoursesStudent.types.ts index 541787c1..2c92850f 100644 --- a/Backend/src/types/CoursesStudent.types.ts +++ b/Backend/src/types/CoursesStudent.types.ts @@ -9,7 +9,7 @@ export type MultiLangText = MultiLanguageText; // ============================================ export interface EnrollCourseInput { - token: string; + userId: number; course_id: number; } @@ -26,7 +26,7 @@ export interface EnrollCourseResponse { } export interface ListEnrolledCoursesInput { - token: string; + userId: number; page?: number; limit?: number; status?: EnrollmentStatus; @@ -64,7 +64,7 @@ export interface ListEnrolledCoursesResponse { // ============================================ export interface GetCourseLearningInput { - token: string; + userId: number; course_id: number; } @@ -126,7 +126,7 @@ export interface GetCourseLearningResponse { // ============================================ export interface GetLessonContentInput { - token: string; + userId: number; course_id: number; lesson_id: number; } @@ -204,7 +204,7 @@ export interface GetLessonContentResponse { // ============================================ export interface CheckLessonAccessInput { - token: string; + userId: number; course_id: number; lesson_id: number; } @@ -236,7 +236,7 @@ export interface CheckLessonAccessResponse { // ============================================ export interface SaveVideoProgressInput { - token: string; + userId: number; lesson_id: number; video_progress_seconds: number; video_duration_seconds?: number; @@ -258,7 +258,7 @@ export interface SaveVideoProgressResponse { } export interface GetVideoProgressInput { - token: string; + userId: number; lesson_id: number; } @@ -281,7 +281,7 @@ export interface GetVideoProgressResponse { // ============================================ export interface MarkLessonCompleteInput { - token: string; + userId: number; course_id: number; lesson_id: number; } @@ -314,7 +314,7 @@ export interface EnrollCourseBody { } export interface CompleteLessonInput { - token: string; + userId: number; lesson_id: number; } @@ -342,7 +342,7 @@ export interface QuizAnswerInput { } export interface SubmitQuizInput { - token: string; + userId: number; course_id: number; lesson_id: number; answers: QuizAnswerInput[]; @@ -384,7 +384,7 @@ export interface SubmitQuizResponse { // ============================================ export interface GetQuizAttemptsInput { - token: string; + userId: number; course_id: number; lesson_id: number; } diff --git a/Backend/src/types/announcements.types.ts b/Backend/src/types/announcements.types.ts index f960a961..b026809e 100644 --- a/Backend/src/types/announcements.types.ts +++ b/Backend/src/types/announcements.types.ts @@ -22,7 +22,7 @@ export interface AnnouncementAttachment { updated_at: Date; } -export interface ListAnnouncementResponse{ +export interface ListAnnouncementResponse { code: number; message: string; data: Announcement[]; @@ -31,15 +31,15 @@ export interface ListAnnouncementResponse{ limit: number; } -export interface ListAnnouncementInput{ - token: string; +export interface ListAnnouncementInput { + userId: number; course_id: number; page?: number; limit?: number; } -export interface CreateAnnouncementInput{ - token: string; +export interface CreateAnnouncementInput { + userId: number; course_id: number; title: MultiLanguageText; content: MultiLanguageText; @@ -49,39 +49,39 @@ export interface CreateAnnouncementInput{ files?: Express.Multer.File[]; } -export interface UploadAnnouncementAttachmentInput{ - token: string; +export interface UploadAnnouncementAttachmentInput { + userId: number; course_id: number; announcement_id: number; file: File; } -export interface UploadAnnouncementAttachmentResponse{ +export interface UploadAnnouncementAttachmentResponse { code: number; message: string; data: AnnouncementAttachment; } -export interface DeleteAnnouncementAttachmentInput{ - token: string; +export interface DeleteAnnouncementAttachmentInput { + userId: number; course_id: number; announcement_id: number; attachment_id: number; } -export interface DeleteAnnouncementAttachmentResponse{ +export interface DeleteAnnouncementAttachmentResponse { code: number; message: string; } -export interface CreateAnnouncementResponse{ +export interface CreateAnnouncementResponse { code: number; message: string; data: Announcement; } -export interface UpdateAnnouncementInput{ - token: string; +export interface UpdateAnnouncementInput { + userId: number; course_id: number; announcement_id: number; title: MultiLanguageText; @@ -92,19 +92,19 @@ export interface UpdateAnnouncementInput{ attachments?: AnnouncementAttachment[]; } -export interface UpdateAnnouncementResponse{ +export interface UpdateAnnouncementResponse { code: number; message: string; data: Announcement; } -export interface DeleteAnnouncementInput{ - token: string; +export interface DeleteAnnouncementInput { + userId: number; course_id: number; announcement_id: number; } -export interface DeleteAnnouncementResponse{ +export interface DeleteAnnouncementResponse { code: number; message: string; } diff --git a/Backend/src/types/auth.types.ts b/Backend/src/types/auth.types.ts index be1fe625..1ec9235a 100644 --- a/Backend/src/types/auth.types.ts +++ b/Backend/src/types/auth.types.ts @@ -28,7 +28,6 @@ export interface LoginResponse { data: { token: string; refreshToken: string; - user: UserResponse; }; } diff --git a/Backend/src/types/certificate.types.ts b/Backend/src/types/certificate.types.ts index a35caa19..ac442f76 100644 --- a/Backend/src/types/certificate.types.ts +++ b/Backend/src/types/certificate.types.ts @@ -3,7 +3,7 @@ // ============================================ export interface GenerateCertificateInput { - token: string; + userId: number; course_id: number; } @@ -19,7 +19,7 @@ export interface GenerateCertificateResponse { } export interface GetCertificateInput { - token: string; + userId: number; course_id: number; } @@ -37,7 +37,7 @@ export interface GetCertificateResponse { } export interface ListMyCertificatesInput { - token: string; + userId: number; } export interface ListMyCertificatesResponse { From 000f9eea5c3ed05f65c9a8df0c4ec1bc13b56802 Mon Sep 17 00:00:00 2001 From: supalerk-ar66 Date: Fri, 6 Mar 2026 09:23:15 +0700 Subject: [PATCH 02/10] feat: Add Dockerfile for containerization and package-lock.json for dependency locking. --- Frontend-Learner/Dockerfile | 4 +- Frontend-Learner/package-lock.json | 7875 +++++++++++++++------------- 2 files changed, 4324 insertions(+), 3555 deletions(-) diff --git a/Frontend-Learner/Dockerfile b/Frontend-Learner/Dockerfile index 1e21249f..15637029 100644 --- a/Frontend-Learner/Dockerfile +++ b/Frontend-Learner/Dockerfile @@ -7,8 +7,8 @@ WORKDIR /app # คัดลอกไฟล์จัดการ dependencies COPY package*.json ./ -# ติดตั้ง dependencies (ใช้ npm ci เพื่อความแม่นยำของเวอร์ชัน) -RUN npm ci +# ติดตั้ง dependencies +RUN npm install # คัดลอกไฟล์ทั้งหมดในโปรเจกต์ COPY . . diff --git a/Frontend-Learner/package-lock.json b/Frontend-Learner/package-lock.json index 4736d625..633bd93c 100644 --- a/Frontend-Learner/package-lock.json +++ b/Frontend-Learner/package-lock.json @@ -78,16 +78,6 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@asamuzakjp/dom-selector": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", @@ -102,16 +92,6 @@ "lru-cache": "^11.2.6" } }, - "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@asamuzakjp/nwsapi": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", @@ -120,12 +100,12 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -134,30 +114,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -183,13 +163,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -211,12 +191,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -226,6 +206,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -235,18 +224,24 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", + "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "engines": { @@ -288,27 +283,27 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -330,23 +325,23 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -396,13 +391,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -424,12 +419,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -439,12 +434,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -454,16 +449,16 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", - "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1" + "@babel/plugin-syntax-typescript": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -473,31 +468,31 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -517,31 +512,6 @@ "node": ">=6.9.0" } }, - "node_modules/@bomb.sh/tab": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/@bomb.sh/tab/-/tab-0.0.10.tgz", - "integrity": "sha512-6ALS2rh/4LKn0Yxwm35V6LcgQuSiECHbqQo7+9g4rkgGyXZ0siOc8K+IuWIq/4u0Zkv2mevP9QSqgKhGIvLJMw==", - "license": "MIT", - "bin": { - "tab": "dist/bin/cli.js" - }, - "peerDependencies": { - "cac": "^6.7.14", - "citty": "^0.1.6", - "commander": "^13.1.0" - }, - "peerDependenciesMeta": { - "cac": { - "optional": true - }, - "citty": { - "optional": true - }, - "commander": { - "optional": true - } - } - }, "node_modules/@bramus/specificity": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", @@ -556,50 +526,33 @@ } }, "node_modules/@clack/core": { - "version": "1.0.0-alpha.7", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.0.0-alpha.7.tgz", - "integrity": "sha512-3vdh6Ar09D14rVxJZIm3VQJkU+ZOKKT5I5cC0cOVazy70CNyYYjiwRj9unwalhESndgxx6bGc/m6Hhs4EKF5XQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.1.0.tgz", + "integrity": "sha512-SVcm4Dqm2ukn64/8Gub2wnlA5nS2iWJyCkdNHcvNHPIeBTGojpdJ+9cZKwLfmqy7irD4N5qLteSilJlE0WLAtA==", "license": "MIT", "dependencies": { - "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "node_modules/@clack/prompts": { - "version": "1.0.0-alpha.8", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.0.0-alpha.8.tgz", - "integrity": "sha512-YZGC4BmTKSF5OturNKEz/y4xNjYGmGk6NI785CQucJ7OEdX0qbMmL/zok+9bL6c7qE3WSYffyK5grh2RnkGNtQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.1.0.tgz", + "integrity": "sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==", "license": "MIT", "dependencies": { - "@clack/core": "1.0.0-alpha.7", - "picocolors": "^1.0.0", + "@clack/core": "1.1.0", "sisteransi": "^1.0.5" } }, "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.1.tgz", - "integrity": "sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz", + "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==", "license": "MIT OR Apache-2.0", - "dependencies": { - "mime": "^3.0.0" - }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@cloudflare/kv-asset-handler/node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/@csstools/color-helpers": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", @@ -697,9 +650,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.28.tgz", - "integrity": "sha512-1NRf1CUBjnr3K7hu8BLxjQrKCxEe8FP/xmPTenAxCRZWVLbmGotkFvG9mfNpjA6k7Bw1bw4BilZq9cu19RA5pg==", + "version": "1.0.29", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.29.tgz", + "integrity": "sha512-jx9GjkkP5YHuTmko2eWAvpPnb0mB4mGRr2U7XwVNwevm8nlpobZEVk+GNmiYMk2VuA75v+plfXWyroWKmICZXg==", "dev": true, "funding": [ { @@ -779,25 +732,25 @@ } }, "node_modules/@dxup/nuxt": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@dxup/nuxt/-/nuxt-0.2.2.tgz", - "integrity": "sha512-RNpJjDZs9+JcT9N87AnOuHsNM75DEd58itADNd/s1LIF6BZbTLZV0xxilJZb55lntn4TYvscTaXLCBX2fq9CXg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@dxup/nuxt/-/nuxt-0.3.2.tgz", + "integrity": "sha512-2f2usP4oLNsIGjPprvABe3f3GWuIhIDp0169pGLFxTDRI5A4d4sBbGpR+tD9bGZCT+1Btb6Q2GKlyv3LkDCW5g==", "license": "MIT", "dependencies": { "@dxup/unimport": "^0.1.2", - "@nuxt/kit": "^4.2.1", - "chokidar": "^4.0.3", + "@nuxt/kit": "^4.2.2", + "chokidar": "^5.0.0", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "node_modules/@dxup/nuxt/node_modules/@nuxt/kit": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.2.2.tgz", - "integrity": "sha512-ZAgYBrPz/yhVgDznBNdQj2vhmOp31haJbO0I0iah/P9atw+OHH7NJLUZ3PK+LOz/0fblKTN1XJVSi8YQ1TQ0KA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.3.1.tgz", + "integrity": "sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA==", "license": "MIT", "dependencies": { - "c12": "^3.3.2", + "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", @@ -810,46 +763,18 @@ "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", - "rc9": "^2.1.2", + "rc9": "^3.0.0", "scule": "^1.3.0", - "semver": "^7.7.3", + "semver": "^7.7.4", "tinyglobby": "^0.2.15", - "ufo": "^1.6.1", - "unctx": "^2.4.1", + "ufo": "^1.6.3", + "unctx": "^2.5.0", "untyped": "^2.0.0" }, "engines": { "node": ">=18.12.0" } }, - "node_modules/@dxup/nuxt/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@dxup/nuxt/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@dxup/unimport": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@dxup/unimport/-/unimport-0.1.2.tgz", @@ -888,20 +813,20 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.78.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.78.0.tgz", - "integrity": "sha512-rQkU5u8hNAq2NVRzHnIUUvR6arbO0b6AOlvpTNS48CkiKSn/xtNfOzBK23JE4SiW89DgvU7GtxLVgV4Vn2HBAw==", + "version": "0.84.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.84.0.tgz", + "integrity": "sha512-0xew1CxOam0gV5OMjh2KjFQZsKL2bByX1+q4j3E73MpYIdyUxcZb/xQct9ccUb+ve5KGUYbCUxyPnYB7RbuP+w==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.8", - "@typescript-eslint/types": "^8.46.4", - "comment-parser": "1.4.1", - "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~7.0.0" + "@typescript-eslint/types": "^8.54.0", + "comment-parser": "1.4.5", + "esquery": "^1.7.0", + "jsdoc-type-pratt-parser": "~7.1.1" }, "engines": { - "node": ">=20.11.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@es-joy/resolve.exports": { @@ -915,12 +840,13 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -931,12 +857,13 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -947,12 +874,13 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -963,12 +891,13 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -979,12 +908,13 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -995,12 +925,13 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1011,12 +942,13 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1027,12 +959,13 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1043,12 +976,13 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1059,12 +993,13 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1075,12 +1010,13 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1091,12 +1027,13 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1107,12 +1044,13 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1123,12 +1061,13 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1139,12 +1078,13 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1155,12 +1095,13 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1171,12 +1112,13 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1187,12 +1129,13 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1203,12 +1146,13 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1219,12 +1163,13 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1235,12 +1180,13 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1251,12 +1197,13 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1267,12 +1214,13 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1283,12 +1231,13 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1299,12 +1248,13 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1315,12 +1265,13 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1349,19 +1300,6 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "devOptional": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint-community/regexpp": { "version": "4.12.2", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", @@ -1373,19 +1311,19 @@ } }, "node_modules/@eslint/compat": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.4.1.tgz", - "integrity": "sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.0.2.tgz", + "integrity": "sha512-pR1DoD0h3HfF675QZx0xsyrsU8q70Z/plx7880NOhS02NuWLgBCOMDL787nUeQ7EWLkxv3bPQJaarjcPQb2Dwg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0" + "@eslint/core": "^1.1.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "peerDependencies": { - "eslint": "^8.40 || 9" + "eslint": "^8.40 || 9 || 10" }, "peerDependenciesMeta": { "eslint": { @@ -1393,6 +1331,19 @@ } } }, + "node_modules/@eslint/compat/node_modules/@eslint/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz", + "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, "node_modules/@eslint/config-array": { "version": "0.21.1", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", @@ -1408,6 +1359,13 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -1420,9 +1378,9 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "devOptional": true, "license": "ISC", "dependencies": { @@ -1459,20 +1417,20 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.4.tgz", + "integrity": "sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==", "devOptional": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", + "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", + "minimatch": "^3.1.3", "strip-json-comments": "^3.1.1" }, "engines": { @@ -1482,6 +1440,13 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -1493,37 +1458,6 @@ "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "devOptional": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "devOptional": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -1548,9 +1482,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "devOptional": true, "license": "ISC", "dependencies": { @@ -1561,9 +1495,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "version": "9.39.3", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz", + "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==", "devOptional": true, "license": "MIT", "engines": { @@ -1598,9 +1532,9 @@ } }, "node_modules/@exodus/bytes": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.14.1.tgz", - "integrity": "sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz", + "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", "dev": true, "license": "MIT", "engines": { @@ -1677,9 +1611,9 @@ } }, "node_modules/@intlify/bundle-utils": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-11.0.3.tgz", - "integrity": "sha512-dURCDz1rQXwAb1+Hv4NDit6aZSRaAt4zUYBPEeaDCe3FSs8dMtdF6kEvgd9JwsYFSTAHcvbTs2CqwBjjt9Ltsw==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-11.0.7.tgz", + "integrity": "sha512-fEO3CJGPymxieGh8BHox7d6stgajDQae7wgpH6YYw7WX+cdW6jTTXyljZqz7OV3JcwlS9M9UHSoO+YwiO56IhA==", "dev": true, "license": "MIT", "dependencies": { @@ -1705,489 +1639,12 @@ } } }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], + "node_modules/@intlify/bundle-utils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@intlify/bundle-utils/node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } + "license": "MIT" }, "node_modules/@intlify/core": { "version": "11.2.8", @@ -2271,14 +1728,14 @@ } }, "node_modules/@intlify/unplugin-vue-i18n": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-11.0.3.tgz", - "integrity": "sha512-iQuik0nXfdVZ5ab+IEyBFEuvMQ213zfbUpBXaEdHPk8DV+qB2CT/SdFuDhfUDRRBZc/e0qoLlfmc9urhnRYVWw==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-11.0.7.tgz", + "integrity": "sha512-wswKprS1D8VfnxxVhKxug5wa3MbDSOcCoXOBjnzhMK+6NfP6h6UI8pFqSBIvcW8nPDuzweTc0Sk3PeBCcubfoQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@intlify/bundle-utils": "11.0.3", + "@intlify/bundle-utils": "11.0.7", "@intlify/shared": "^11.1.12", "@intlify/vue-i18n-extensions": "^8.0.0", "@rollup/pluginutils": "^5.1.0", @@ -2308,6 +1765,22 @@ } } }, + "node_modules/@intlify/unplugin-vue-i18n/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/@intlify/utils": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@intlify/utils/-/utils-0.13.0.tgz", @@ -2427,9 +1900,9 @@ } }, "node_modules/@ioredis/commands": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.4.0.tgz", - "integrity": "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz", + "integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==", "license": "MIT" }, "node_modules/@isaacs/cliui": { @@ -2569,13 +2042,28 @@ "node": ">=18" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", + "node_modules/@mapbox/node-pre-gyp/node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "license": "ISC", "engines": { - "node": ">=8" + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "license": "ISC", + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/@miyaneee/rollup-plugin-json5": { @@ -2644,37 +2132,38 @@ } }, "node_modules/@nuxt/cli": { - "version": "3.31.3", - "resolved": "https://registry.npmjs.org/@nuxt/cli/-/cli-3.31.3.tgz", - "integrity": "sha512-K0T1ZpBXnlb41NU/RWf1F0U0C14KzlEXCoaSgD2y8BiLoCBWcgQ1UAlRtx4cThqWbJmIxaNZZTDL0NZ9d1U7ag==", + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/@nuxt/cli/-/cli-3.33.1.tgz", + "integrity": "sha512-/sCrcI0WemING9zASaXPgPDY7PrQTPlRyCXlSgGx8VwRAkWbxGaPhIc3kZQikgLwVAwy+muWVV4Wks8OTtW5Tw==", "license": "MIT", "dependencies": { - "@bomb.sh/tab": "^0.0.10", - "@clack/prompts": "1.0.0-alpha.8", - "c12": "^3.3.2", - "citty": "^0.1.6", - "confbox": "^0.2.2", + "@bomb.sh/tab": "^0.0.12", + "@clack/prompts": "^1.0.0", + "c12": "^3.3.3", + "citty": "^0.2.0", + "confbox": "^0.2.4", "consola": "^3.4.2", "copy-paste": "^2.2.0", "debug": "^4.4.3", "defu": "^6.1.4", "exsolve": "^1.0.8", "fuse.js": "^7.1.0", - "giget": "^2.0.0", + "fzf": "^0.5.2", + "giget": "^3.1.2", "jiti": "^2.6.1", "listhen": "^1.9.0", - "nypm": "^0.6.2", + "nypm": "^0.6.5", "ofetch": "^1.5.1", "ohash": "^2.0.11", "pathe": "^2.0.3", - "perfect-debounce": "^2.0.0", + "perfect-debounce": "^2.1.0", "pkg-types": "^2.3.0", "scule": "^1.3.0", - "semver": "^7.7.3", - "srvx": "^0.9.8", + "semver": "^7.7.4", + "srvx": "^0.11.2", "std-env": "^3.10.0", "tinyexec": "^1.0.2", - "ufo": "^1.6.1", + "ufo": "^1.6.3", "youch": "^4.1.0-beta.13" }, "bin": { @@ -2685,6 +2174,78 @@ }, "engines": { "node": "^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@nuxt/schema": "^4.3.0" + }, + "peerDependenciesMeta": { + "@nuxt/schema": { + "optional": true + } + } + }, + "node_modules/@nuxt/cli/node_modules/@bomb.sh/tab": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@bomb.sh/tab/-/tab-0.0.12.tgz", + "integrity": "sha512-dYRwg4MqfHR5/BcTy285XOGRhjQFmNpaJBZ0tl2oU+RY595MQ5ApTF6j3OvauPAooHL6cfoOZMySQrOQztT8RQ==", + "license": "MIT", + "bin": { + "tab": "dist/bin/cli.js" + }, + "peerDependencies": { + "cac": "^6.7.14", + "citty": "^0.1.6", + "commander": "^13.1.0" + }, + "peerDependenciesMeta": { + "cac": { + "optional": true + }, + "citty": { + "optional": true + }, + "commander": { + "optional": true + } + } + }, + "node_modules/@nuxt/cli/node_modules/citty": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.1.tgz", + "integrity": "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==", + "license": "MIT", + "peer": true + }, + "node_modules/@nuxt/cli/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/cli/node_modules/giget": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/giget/-/giget-3.1.2.tgz", + "integrity": "sha512-T2qUpKBHeUTwHcIhydgnJzhL0Hj785ms+JkxaaWQH9SDM/llXeewnOkfJcFShAHjWI+26hOChwUfCoupaXLm8g==", + "license": "MIT", + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/@nuxt/cli/node_modules/srvx": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.8.tgz", + "integrity": "sha512-2n9t0YnAXPJjinytvxccNgs7rOA5gmE7Wowt/8Dy2dx2fDC6sBhfBpbrCvjYKALlVukPS/Uq3QwkolKNa7P/2Q==", + "license": "MIT", + "bin": { + "srvx": "bin/srvx.mjs" + }, + "engines": { + "node": ">=20.16.0" } }, "node_modules/@nuxt/devalue": { @@ -2694,43 +2255,43 @@ "license": "MIT" }, "node_modules/@nuxt/devtools": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@nuxt/devtools/-/devtools-3.1.1.tgz", - "integrity": "sha512-UG8oKQqcSyzwBe1l0z24zypmwn6FLW/HQMHK/F/gscUU5LeMHzgBhLPD+cuLlDvwlGAbifexWNMsS/I7n95KlA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@nuxt/devtools/-/devtools-3.2.2.tgz", + "integrity": "sha512-b6roSuKed5XMg09oWejXb4bRG+iYPDFRHEP2HpAfwpFWgAhpiQIAdrdjZNt4f/pzbfhDqb1R5TSa1KmztOuMKw==", "license": "MIT", "dependencies": { - "@nuxt/devtools-kit": "3.1.1", - "@nuxt/devtools-wizard": "3.1.1", - "@nuxt/kit": "^4.2.1", - "@vue/devtools-core": "^8.0.5", - "@vue/devtools-kit": "^8.0.5", - "birpc": "^2.8.0", + "@nuxt/devtools-kit": "3.2.2", + "@nuxt/devtools-wizard": "3.2.2", + "@nuxt/kit": "^4.3.1", + "@vue/devtools-core": "^8.0.6", + "@vue/devtools-kit": "^8.0.6", + "birpc": "^4.0.0", "consola": "^3.4.2", "destr": "^2.0.5", "error-stack-parser-es": "^1.0.5", "execa": "^8.0.1", - "fast-npm-meta": "^0.4.7", + "fast-npm-meta": "^1.2.1", "get-port-please": "^3.2.0", - "hookable": "^5.5.3", + "hookable": "^6.0.1", "image-meta": "^0.2.2", "is-installed-globally": "^1.0.0", - "launch-editor": "^2.12.0", + "launch-editor": "^2.13.0", "local-pkg": "^1.1.2", - "magicast": "^0.5.1", - "nypm": "^0.6.2", + "magicast": "^0.5.2", + "nypm": "^0.6.5", "ohash": "^2.0.11", "pathe": "^2.0.3", - "perfect-debounce": "^2.0.0", + "perfect-debounce": "^2.1.0", "pkg-types": "^2.3.0", - "semver": "^7.7.3", - "simple-git": "^3.30.0", + "semver": "^7.7.4", + "simple-git": "^3.32.2", "sirv": "^3.0.2", "structured-clone-es": "^1.0.0", "tinyglobby": "^0.2.15", "vite-plugin-inspect": "^11.3.3", - "vite-plugin-vue-tracer": "^1.1.3", + "vite-plugin-vue-tracer": "^1.2.0", "which": "^5.0.0", - "ws": "^8.18.3" + "ws": "^8.19.0" }, "bin": { "devtools": "cli.mjs" @@ -2746,75 +2307,58 @@ } }, "node_modules/@nuxt/devtools-kit": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-3.1.1.tgz", - "integrity": "sha512-sjiKFeDCOy1SyqezSgyV4rYNfQewC64k/GhOsuJgRF+wR2qr6KTVhO6u2B+csKs74KrMrnJprQBgud7ejvOXAQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-2.7.0.tgz", + "integrity": "sha512-MIJdah6CF6YOW2GhfKnb8Sivu6HpcQheqdjOlZqShBr+1DyjtKQbAKSCAyKPaoIzZP4QOo2SmTFV6aN8jBeEIQ==", + "dev": true, "license": "MIT", "dependencies": { - "@nuxt/kit": "^4.2.1", + "@nuxt/kit": "^3.19.3", "execa": "^8.0.1" }, "peerDependencies": { "vite": ">=6.0" } }, - "node_modules/@nuxt/devtools-kit/node_modules/@nuxt/kit": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.2.2.tgz", - "integrity": "sha512-ZAgYBrPz/yhVgDznBNdQj2vhmOp31haJbO0I0iah/P9atw+OHH7NJLUZ3PK+LOz/0fblKTN1XJVSi8YQ1TQ0KA==", - "license": "MIT", - "dependencies": { - "c12": "^3.3.2", - "consola": "^3.4.2", - "defu": "^6.1.4", - "destr": "^2.0.5", - "errx": "^0.1.0", - "exsolve": "^1.0.8", - "ignore": "^7.0.5", - "jiti": "^2.6.1", - "klona": "^2.0.6", - "mlly": "^1.8.0", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "rc9": "^2.1.2", - "scule": "^1.3.0", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ufo": "^1.6.1", - "unctx": "^2.4.1", - "untyped": "^2.0.0" - }, - "engines": { - "node": ">=18.12.0" - } - }, "node_modules/@nuxt/devtools-wizard": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@nuxt/devtools-wizard/-/devtools-wizard-3.1.1.tgz", - "integrity": "sha512-6UORjapNKko2buv+3o57DQp69n5Z91TeJ75qdtNKcTvOfCTJrO78Ew0nZSgMMGrjbIJ4pFsHQEqXfgYLw3pNxg==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-wizard/-/devtools-wizard-3.2.2.tgz", + "integrity": "sha512-FaKV3xZF+Sj2ORxJNWTUalnEV8cpXW2rkg60KzQd7LryEHgUdFMuY/oTSVh9YmURqSzwVlfYd1Su56yi02pxlA==", "license": "MIT", "dependencies": { + "@clack/prompts": "^1.0.1", "consola": "^3.4.2", - "diff": "^8.0.2", + "diff": "^8.0.3", "execa": "^8.0.1", - "magicast": "^0.5.1", + "magicast": "^0.5.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", - "prompts": "^2.4.2", - "semver": "^7.7.3" + "semver": "^7.7.4" }, "bin": { "devtools-wizard": "cli.mjs" } }, - "node_modules/@nuxt/devtools/node_modules/@nuxt/kit": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.2.2.tgz", - "integrity": "sha512-ZAgYBrPz/yhVgDznBNdQj2vhmOp31haJbO0I0iah/P9atw+OHH7NJLUZ3PK+LOz/0fblKTN1XJVSi8YQ1TQ0KA==", + "node_modules/@nuxt/devtools/node_modules/@nuxt/devtools-kit": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-3.2.2.tgz", + "integrity": "sha512-07E1phqoVPNlexlkrYuOMPhTzLIRjcl9iEqyc/vZLH2zWeH/T1X3v+RLTVW5Oio40f/XBp9yQuyihmX34ddjgQ==", "license": "MIT", "dependencies": { - "c12": "^3.3.2", + "@nuxt/kit": "^4.3.1", + "execa": "^8.0.1" + }, + "peerDependencies": { + "vite": ">=6.0" + } + }, + "node_modules/@nuxt/devtools/node_modules/@nuxt/kit": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.3.1.tgz", + "integrity": "sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA==", + "license": "MIT", + "dependencies": { + "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", @@ -2827,49 +2371,79 @@ "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", - "rc9": "^2.1.2", + "rc9": "^3.0.0", "scule": "^1.3.0", - "semver": "^7.7.3", + "semver": "^7.7.4", "tinyglobby": "^0.2.15", - "ufo": "^1.6.1", - "unctx": "^2.4.1", + "ufo": "^1.6.3", + "unctx": "^2.5.0", "untyped": "^2.0.0" }, "engines": { "node": ">=18.12.0" } }, + "node_modules/@nuxt/devtools/node_modules/hookable": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.0.1.tgz", + "integrity": "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==", + "license": "MIT" + }, + "node_modules/@nuxt/devtools/node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/devtools/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/@nuxt/eslint-config": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.12.1.tgz", - "integrity": "sha512-fsKKtIIvVwQ5OGE30lJEhzwXxXj40ol7vR6h3eTH8sSBVZLOdmPn2BHrhoOjHTDXpLPw1AZ/8GcQfJZ2o3gcHQ==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.15.2.tgz", + "integrity": "sha512-vS6mWB87tYjB8h3TxG/QziaZ6CGJpEOBd7N/j+64/tjNipUJzNgKwDzyGoOifNqyDDnlvgi6T3m9XpeYm4qRaA==", "dev": true, "license": "MIT", "dependencies": { "@antfu/install-pkg": "^1.1.0", - "@clack/prompts": "^0.11.0", - "@eslint/js": "^9.39.1", - "@nuxt/eslint-plugin": "1.12.1", - "@stylistic/eslint-plugin": "^5.6.1", - "@typescript-eslint/eslint-plugin": "^8.49.0", - "@typescript-eslint/parser": "^8.49.0", - "eslint-config-flat-gitignore": "^2.1.0", - "eslint-flat-config-utils": "^2.1.4", + "@clack/prompts": "^1.0.1", + "@eslint/js": "^9.39.3", + "@nuxt/eslint-plugin": "1.15.2", + "@stylistic/eslint-plugin": "^5.9.0", + "@typescript-eslint/eslint-plugin": "^8.56.1", + "@typescript-eslint/parser": "^8.56.1", + "eslint-config-flat-gitignore": "^2.2.1", + "eslint-flat-config-utils": "^3.0.1", "eslint-merge-processors": "^2.0.0", - "eslint-plugin-import-lite": "^0.3.0", + "eslint-plugin-import-lite": "^0.5.2", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^61.5.0", - "eslint-plugin-regexp": "^2.10.0", - "eslint-plugin-unicorn": "^62.0.0", - "eslint-plugin-vue": "^10.6.2", + "eslint-plugin-jsdoc": "^62.7.1", + "eslint-plugin-regexp": "^3.0.0", + "eslint-plugin-unicorn": "^63.0.0", + "eslint-plugin-vue": "^10.8.0", "eslint-processor-vue-blocks": "^2.0.0", - "globals": "^16.5.0", + "globals": "^17.3.0", "local-pkg": "^1.1.2", "pathe": "^2.0.3", - "vue-eslint-parser": "^10.2.0" + "vue-eslint-parser": "^10.4.0" }, "peerDependencies": { - "eslint": "^9.0.0", + "eslint": "^9.0.0 || ^10.0.0", "eslint-plugin-format": "*" }, "peerDependenciesMeta": { @@ -2878,50 +2452,28 @@ } } }, - "node_modules/@nuxt/eslint-config/node_modules/@clack/core": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz", - "integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==", - "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^1.0.0", - "sisteransi": "^1.0.5" - } - }, - "node_modules/@nuxt/eslint-config/node_modules/@clack/prompts": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz", - "integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@clack/core": "0.5.0", - "picocolors": "^1.0.0", - "sisteransi": "^1.0.5" - } - }, "node_modules/@nuxt/eslint-plugin": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.12.1.tgz", - "integrity": "sha512-9EBWZTgJC2oclDIL53YG6paEoaTU2SDWVPybEQ0Pe2Bm/5YSbHd//6EGLvdGwAgN+xJQmEsPunUpd4Y+NX2OCQ==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.15.2.tgz", + "integrity": "sha512-LZ4gEcPP5GjzAkb6Kk04a4v0vvkTLOpmnEvdDatnkSlxtQLUSwX8v11vcDGXL92ZQ98dFoC1Q1IA6Tz3jdFIig==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "^8.49.0", - "@typescript-eslint/utils": "^8.49.0" + "@typescript-eslint/types": "^8.56.1", + "@typescript-eslint/utils": "^8.56.1" }, "peerDependencies": { - "eslint": "^9.0.0" + "eslint": "^9.0.0 || ^10.0.0" } }, "node_modules/@nuxt/kit": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.20.2.tgz", - "integrity": "sha512-laqfmMcWWNV1FsVmm1+RQUoGY8NIJvCRl0z0K8ikqPukoEry0LXMqlQ+xaf8xJRvoH2/78OhZmsEEsUBTXipcw==", + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.1.tgz", + "integrity": "sha512-QORZRjcuTKgo++XP1Pc2c2gqwRydkaExrIRfRI9vFsPA3AzuHVn5Gfmbv1ic8y34e78mr5DMBvJlelUaeOuajg==", "license": "MIT", + "peer": true, "dependencies": { - "c12": "^3.3.2", + "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", @@ -2935,12 +2487,12 @@ "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", - "rc9": "^2.1.2", + "rc9": "^3.0.0", "scule": "^1.3.0", - "semver": "^7.7.3", + "semver": "^7.7.4", "tinyglobby": "^0.2.15", - "ufo": "^1.6.1", - "unctx": "^2.4.1", + "ufo": "^1.6.3", + "unctx": "^2.5.0", "untyped": "^2.0.0" }, "engines": { @@ -2948,35 +2500,36 @@ } }, "node_modules/@nuxt/nitro-server": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/@nuxt/nitro-server/-/nitro-server-3.20.2.tgz", - "integrity": "sha512-IX43Fy0/7jjYve1D7hdkR/rfvww6u8aEbsdTVfh7wH14GGKJtsAn3DJlRb3CCKwtbo0dp25e3qLM4hOO5hZTCg==", + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/@nuxt/nitro-server/-/nitro-server-3.21.1.tgz", + "integrity": "sha512-eWe2RS75HSFQyjdVVK918aBBRMM/cDK5bzWSml07PBY+f9XRXHDf6gD4KqPR4gDDDafYneBPNWayHL+sxb/gDw==", "license": "MIT", "dependencies": { "@nuxt/devalue": "^2.0.2", - "@nuxt/kit": "3.20.2", - "@unhead/vue": "^2.0.19", - "@vue/shared": "^3.5.25", + "@nuxt/kit": "3.21.1", + "@unhead/vue": "^2.1.3", + "@vue/shared": "^3.5.27", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", - "devalue": "^5.6.0", + "devalue": "^5.6.2", "errx": "^0.1.0", "escape-string-regexp": "^5.0.0", "exsolve": "^1.0.8", - "h3": "^1.15.4", + "h3": "^1.15.5", "impound": "^1.0.0", "klona": "^2.0.6", "mocked-exports": "^0.1.1", - "nitropack": "^2.12.9", + "nitropack": "^2.13.1", + "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", - "radix3": "^1.1.2", + "rou3": "^0.7.12", "std-env": "^3.10.0", - "ufo": "^1.6.1", - "unctx": "^2.4.1", - "unstorage": "^1.17.3", - "vue": "^3.5.25", + "ufo": "^1.6.3", + "unctx": "^2.5.0", + "unstorage": "^1.17.4", + "vue": "^3.5.27", "vue-bundle-renderer": "^2.2.0", "vue-devtools-stub": "^0.1.0" }, @@ -2984,16 +2537,30 @@ "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "nuxt": "^3.20.2" + "nuxt": "^3.21.1" + } + }, + "node_modules/@nuxt/nitro-server/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@nuxt/schema": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.20.2.tgz", - "integrity": "sha512-fp584AiXON7vI6NDDpNTjxiJ485iM/ztJSPX9CqptKUNjULhBy9qlacF9+NiwQqxlEs3zvbxHpo/1qLPNSb4MQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-4.3.1.tgz", + "integrity": "sha512-S+wHJdYDuyk9I43Ej27y5BeWMZgi7R/UVql3b3qtT35d0fbpXW7fUenzhLRCCDC6O10sjguc6fcMcR9sMKvV8g==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@vue/shared": "^3.5.25", + "@vue/shared": "^3.5.27", "defu": "^6.1.4", "pathe": "^2.0.3", "pkg-types": "^2.3.0", @@ -3004,42 +2571,38 @@ } }, "node_modules/@nuxt/telemetry": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.6.6.tgz", - "integrity": "sha512-Zh4HJLjzvm3Cq9w6sfzIFyH9ozK5ePYVfCUzzUQNiZojFsI2k1QkSBrVI9BGc6ArKXj/O6rkI6w7qQ+ouL8Cag==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.7.0.tgz", + "integrity": "sha512-mrKC3NjAlBOooLLVTYcIUie1meipoYq5vkoESoVTEWTB34T3a0QJzOfOPch+HYlUR+5Lqy1zLMv6epHFgYAKLA==", "license": "MIT", "dependencies": { - "@nuxt/kit": "^3.15.4", - "citty": "^0.1.6", + "citty": "^0.2.0", "consola": "^3.4.2", - "destr": "^2.0.3", - "dotenv": "^16.4.7", - "git-url-parse": "^16.0.1", - "is-docker": "^3.0.0", - "ofetch": "^1.4.1", - "package-manager-detector": "^1.1.0", - "pathe": "^2.0.3", - "rc9": "^2.1.2", - "std-env": "^3.8.1" + "ofetch": "^2.0.0-alpha.3", + "rc9": "^3.0.0", + "std-env": "^3.10.0" }, "bin": { "nuxt-telemetry": "bin/nuxt-telemetry.mjs" }, "engines": { "node": ">=18.12.0" + }, + "peerDependencies": { + "@nuxt/kit": ">=3.0.0" } }, - "node_modules/@nuxt/telemetry/node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } + "node_modules/@nuxt/telemetry/node_modules/citty": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.1.tgz", + "integrity": "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==", + "license": "MIT" + }, + "node_modules/@nuxt/telemetry/node_modules/ofetch": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-2.0.0-alpha.3.tgz", + "integrity": "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==", + "license": "MIT" }, "node_modules/@nuxt/test-utils": { "version": "4.0.0", @@ -3148,146 +2711,25 @@ "sisteransi": "^1.0.5" } }, - "node_modules/@nuxt/test-utils/node_modules/@nuxt/devtools-kit": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-2.7.0.tgz", - "integrity": "sha512-MIJdah6CF6YOW2GhfKnb8Sivu6HpcQheqdjOlZqShBr+1DyjtKQbAKSCAyKPaoIzZP4QOo2SmTFV6aN8jBeEIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nuxt/kit": "^3.19.3", - "execa": "^8.0.1" - }, - "peerDependencies": { - "vite": ">=6.0" - } - }, - "node_modules/@nuxt/test-utils/node_modules/@nuxt/kit": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.1.tgz", - "integrity": "sha512-QORZRjcuTKgo++XP1Pc2c2gqwRydkaExrIRfRI9vFsPA3AzuHVn5Gfmbv1ic8y34e78mr5DMBvJlelUaeOuajg==", - "dev": true, - "license": "MIT", - "dependencies": { - "c12": "^3.3.3", - "consola": "^3.4.2", - "defu": "^6.1.4", - "destr": "^2.0.5", - "errx": "^0.1.0", - "exsolve": "^1.0.8", - "ignore": "^7.0.5", - "jiti": "^2.6.1", - "klona": "^2.0.6", - "knitwork": "^1.3.0", - "mlly": "^1.8.0", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "pkg-types": "^2.3.0", - "rc9": "^3.0.0", - "scule": "^1.3.0", - "semver": "^7.7.4", - "tinyglobby": "^0.2.15", - "ufo": "^1.6.3", - "unctx": "^2.5.0", - "untyped": "^2.0.0" - }, - "engines": { - "node": ">=18.12.0" - } - }, - "node_modules/@nuxt/test-utils/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/@nuxt/test-utils/node_modules/h3-next": { - "name": "h3", - "version": "2.0.1-rc.11", - "resolved": "https://registry.npmjs.org/h3/-/h3-2.0.1-rc.11.tgz", - "integrity": "sha512-2myzjCqy32c1As9TjZW9fNZXtLqNedjFSrdFy2AjFBQQ3LzrnGoDdFDYfC0tV2e4vcyfJ2Sfo/F6NQhO2Ly/Mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "rou3": "^0.7.12", - "srvx": "^0.10.1" - }, - "engines": { - "node": ">=20.11.1" - }, - "peerDependencies": { - "crossws": "^0.4.1" - }, - "peerDependenciesMeta": { - "crossws": { - "optional": true - } - } - }, - "node_modules/@nuxt/test-utils/node_modules/rc9": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.0.tgz", - "integrity": "sha512-MGOue0VqscKWQ104udASX/3GYDcKyPI4j4F8gu/jHHzglpmy9a/anZK3PNe8ug6aZFl+9GxLtdhe3kVZuMaQbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "defu": "^6.1.4", - "destr": "^2.0.5" - } - }, - "node_modules/@nuxt/test-utils/node_modules/srvx": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.10.1.tgz", - "integrity": "sha512-A//xtfak4eESMWWydSRFUVvCTQbSwivnGCEf8YGPe2eHU0+Z6znfUTCPF0a7oV3sObSOcrXHlL6Bs9vVctfXdg==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "srvx": "bin/srvx.mjs" - }, - "engines": { - "node": ">=20.16.0" - } - }, - "node_modules/@nuxt/test-utils/node_modules/unplugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", - "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "picomatch": "^4.0.3", - "webpack-virtual-modules": "^0.6.2" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/@nuxt/vite-builder": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-3.20.2.tgz", - "integrity": "sha512-xsWMn13mxTlwLKyZc67lNwOIS0Ih8L+wQnsLaAt/4jkkypRiQ09+oIljF6n7vVmnqIvuGXFL0e97ZIbyrkEBQw==", + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-3.21.1.tgz", + "integrity": "sha512-clm2/1/sL9W+EiJ4KIseg93sDoWNwCXTx/7raoBD+TCPOLeEFXliyJNpzCnKgp3QgKqxVG12whBWLX56uXD6UQ==", "license": "MIT", "dependencies": { - "@nuxt/kit": "3.20.2", + "@nuxt/kit": "3.21.1", "@rollup/plugin-replace": "^6.0.3", - "@vitejs/plugin-vue": "^6.0.2", - "@vitejs/plugin-vue-jsx": "^5.1.2", - "autoprefixer": "^10.4.22", + "@vitejs/plugin-vue": "^6.0.4", + "@vitejs/plugin-vue-jsx": "^5.1.4", + "autoprefixer": "^10.4.24", "consola": "^3.4.2", "cssnano": "^7.1.2", "defu": "^6.1.4", - "esbuild": "^0.27.1", + "esbuild": "^0.27.3", "escape-string-regexp": "^5.0.0", "exsolve": "^1.0.8", "externality": "^1.0.2", "get-port-please": "^3.2.0", - "h3": "^1.15.4", "jiti": "^2.6.1", "knitwork": "^1.3.0", "magic-string": "^0.30.21", @@ -3295,16 +2737,16 @@ "mocked-exports": "^0.1.1", "ohash": "^2.0.11", "pathe": "^2.0.3", - "perfect-debounce": "^2.0.0", + "perfect-debounce": "^2.1.0", "pkg-types": "^2.3.0", "postcss": "^8.5.6", "rollup-plugin-visualizer": "^6.0.5", - "seroval": "^1.4.0", + "seroval": "^1.5.0", "std-env": "^3.10.0", - "ufo": "^1.6.1", + "ufo": "^1.6.3", "unenv": "^2.0.0-rc.24", - "vite": "^7.2.7", - "vite-node": "^5.2.0", + "vite": "^7.3.1", + "vite-node": "^5.3.0", "vite-plugin-checker": "^0.12.0", "vue-bundle-renderer": "^2.2.0" }, @@ -3312,7 +2754,7 @@ "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "nuxt": "3.20.2", + "nuxt": "3.21.1", "rolldown": "^1.0.0-beta.38", "vue": "^3.3.4" }, @@ -3322,10 +2764,479 @@ } } }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/@nuxt/vite-builder/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@nuxtjs/i18n": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/@nuxtjs/i18n/-/i18n-10.2.1.tgz", - "integrity": "sha512-/CHAIpYbFgobxeMsnKcD8xBUHxBpqipRMjaI3ol9MVZKscJM+IetYdNL9lGNFdEtlxzkV8COxnoa60rE4sPjuQ==", + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/@nuxtjs/i18n/-/i18n-10.2.3.tgz", + "integrity": "sha512-nRAQJbWjbiBvW6XRsG3Q6olYw2EKz7V1J6cDCHLCPbF1EyNhrAH/9aCNQaR5PYcoXPeRLpF86DIPBEnamghyHw==", "dev": true, "license": "MIT", "dependencies": { @@ -3366,13 +3277,13 @@ } }, "node_modules/@nuxtjs/i18n/node_modules/@nuxt/kit": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.2.2.tgz", - "integrity": "sha512-ZAgYBrPz/yhVgDznBNdQj2vhmOp31haJbO0I0iah/P9atw+OHH7NJLUZ3PK+LOz/0fblKTN1XJVSi8YQ1TQ0KA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.3.1.tgz", + "integrity": "sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA==", "dev": true, "license": "MIT", "dependencies": { - "c12": "^3.3.2", + "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", @@ -3385,661 +3296,32 @@ "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", - "rc9": "^2.1.2", + "rc9": "^3.0.0", "scule": "^1.3.0", - "semver": "^7.7.3", + "semver": "^7.7.4", "tinyglobby": "^0.2.15", - "ufo": "^1.6.1", - "unctx": "^2.4.1", + "ufo": "^1.6.3", + "unctx": "^2.5.0", "untyped": "^2.0.0" }, "engines": { "node": ">=18.12.0" } }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-android-arm64": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.95.0.tgz", - "integrity": "sha512-dZyxhhvJigwWL1wgnLlqyEiSeuqO0WdDH9H+if0dPcBM4fKa5fjVkaUcJT1jBMcBTnkjxMwTXYZy5TK60N0fjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-darwin-arm64": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.95.0.tgz", - "integrity": "sha512-zun9+V33kyCtNec9oUSWwb0qi3fB8pXwum1yGFECPEr55g/CrWju6/Jv4hwwNBeW2tK9Ch/PRstEtYmOLMhHpg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-darwin-x64": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.95.0.tgz", - "integrity": "sha512-9djMQ/t6Ns/UXtziwUe562uVJMbhtuLtCj+Xav+HMVT/rhV9gWO8PQOG7AwDLUBjJanItsrfqrGtqhNxtZ701w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-freebsd-x64": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.95.0.tgz", - "integrity": "sha512-GK6k0PgCVkkeRZtHgcosCYbXIRySpJpuPw/OInfLGFh8f3x9gp2l8Fbcfx+YO+ZOHFBCd2NNedGqw8wMgouxfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.95.0.tgz", - "integrity": "sha512-+g/lFITtyHHEk69cunOHuiT5cX+mpUTcbGYNe8suguZ7FqgNwai+PnGv0ctCvtgxBPVfckfUK8c3RvFKo+vi/w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-linux-arm64-gnu": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.95.0.tgz", - "integrity": "sha512-0LzebARTU0ROfD6pDK4h1pFn+09meErCZ0MA2TaW08G72+GNneEsksPufOuI+9AxVSRa+jKE3fu0wavvhZgSkg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-linux-arm64-musl": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.95.0.tgz", - "integrity": "sha512-Pvi1lGe/G+mJZ3hUojMP/aAHAzHA25AEtVr8/iuz7UV72t/15NOgJYr9kELMUMNjPqpr3vKUgXTFmTtAxp11Qw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-linux-riscv64-gnu": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.95.0.tgz", - "integrity": "sha512-pUEVHIOVNDfhk4sTlLhn6mrNENhE4/dAwemxIfqpcSyBlYG0xYZND1F3jjR2yWY6DakXZ6VSuDbtiv1LPNlOLw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-linux-s390x-gnu": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.95.0.tgz", - "integrity": "sha512-5+olaepHTE3J/+w7g0tr3nocvv5BKilAJnzj4L8tWBCLEZbL6olJcGVoldUO+3cgg1SO1xJywP5BuLhT0mDUDw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-linux-x64-gnu": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.95.0.tgz", - "integrity": "sha512-8huzHlK/N98wrnYKxIcYsK8ZGBWomQchu/Mzi6m+CtbhjWOv9DmK0jQ2fUWImtluQVpTwS0uZT06d3g7XIkJrA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-linux-x64-musl": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.95.0.tgz", - "integrity": "sha512-bWnrLfGDcx/fab0+UQnFbVFbiykof/btImbYf+cI2pU/1Egb2x+OKSmM5Qt0nEUiIpM5fgJmYXxTopybSZOKYA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-wasm32-wasi": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.95.0.tgz", - "integrity": "sha512-0JLyqkZu1HnQIZ4e5LBGOtzqua1QwFEUOoMSycdoerXqayd4LK2b7WMfAx8eCIf+jGm1Uj6f3R00nlsx8g1faQ==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.7" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-win32-arm64-msvc": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.95.0.tgz", - "integrity": "sha512-RWvaA6s1SYlBj9CxwHfNn0CRlkPdv9fEUAXfZkGQPdP5e1ppIaO2KYE0sUov/zzp9hPTMMsTMHl4dcIbb+pHCQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-parser/binding-win32-x64-msvc": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.95.0.tgz", - "integrity": "sha512-BQpgl7rDjFvCIHudmUR0dCwc4ylBYZl4CPVinlD3NhkMif4WD5dADckoo5ES/KOpFyvwcbKZX+grP63cjHi26g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-project/types": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.95.0.tgz", - "integrity": "sha512-vACy7vhpMPhjEJhULNxrdR0D943TkA/MigMpJCHmBHvMXxRStRi/dPtTlfQ3uDwWSzRpT8z+7ImjZVf8JWBocQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-android-arm64": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.95.0.tgz", - "integrity": "sha512-eW+BCgRWOsMrDiz7FEV7BjAmaF9lGIc2ueGdRUYjRUMq4f5FSGS7gMBTYDxajdoIB3L5Gnksh1CWkIlgg95UVA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-darwin-arm64": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.95.0.tgz", - "integrity": "sha512-OUUaYZVss8tyDZZ7TGr2vnH3+i3Ouwsx0frQRGkiePNatXxaJJ3NS5+Kwgi9hh3WryXaQz2hWji4AM2RHYE7Cg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-darwin-x64": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.95.0.tgz", - "integrity": "sha512-49UPEgIlgWUndwcP3LH6dvmOewZ92DxCMpFMo11JhUlmNJxA3sjVImEBRB56/tJ+XF+xnya9kB1oCW4yRY+mRw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-freebsd-x64": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.95.0.tgz", - "integrity": "sha512-lNKrHKaDEm8pbKlVbn0rv2L97O0lbA0Tsrxx4GF/HhmdW+NgwGU1pMzZ4tB2QcylbqgKxOB+v9luebHyh1jfgA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-linux-arm-gnueabihf": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.95.0.tgz", - "integrity": "sha512-+VWcLeeizI8IjU+V+o8AmzPuIMiTrGr0vrmXU3CEsV05MrywCuJU+f6ilPs3JBKno9VIwqvRpHB/z39sQabHWg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-linux-arm64-gnu": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.95.0.tgz", - "integrity": "sha512-NLdrFuEHlmbiC1M1WESFV4luUcB/84GXi+cbnRXhgMjIW/CThRVJ989eTJy59QivkVlLcJSKTiKiKCt0O6TTlQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-linux-arm64-musl": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.95.0.tgz", - "integrity": "sha512-GL0ffCPW8JlFI0/jeSgCY665yDdojHxA0pbYG+k8oEHOWCYZUZK9AXL+r0oerNEWYJ8CRB+L5Yq87ZtU/YUitw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-linux-riscv64-gnu": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.95.0.tgz", - "integrity": "sha512-tbH7LaClSmN3YFVo1UjMSe7D6gkb5f+CMIbj9i873UUZomVRmAjC4ygioObfzM+sj/tX0WoTXx5L1YOfQkHL6Q==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-linux-s390x-gnu": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.95.0.tgz", - "integrity": "sha512-8jMqiURWa0iTiPMg7BWaln89VdhhWzNlPyKM90NaFVVhBIKCr2UEhrQWdpBw/E9C8uWf/4VabBEhfPMK+0yS4w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-linux-x64-gnu": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.95.0.tgz", - "integrity": "sha512-D5ULJ2uWipsTgfvHIvqmnGkCtB3Fyt2ZN7APRjVO+wLr+HtmnaWddKsLdrRWX/m/6nQ2xQdoQekdJrokYK9LtQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-linux-x64-musl": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.95.0.tgz", - "integrity": "sha512-DmCGU+FzRezES5wVAGVimZGzYIjMOapXbWpxuz8M8p3nMrfdBEQ5/tpwBp2vRlIohhABy4vhHJByl4c64ENCGQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-wasm32-wasi": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.95.0.tgz", - "integrity": "sha512-tSo1EU4Whd1gXyae7cwSDouhppkuz6Jkd5LY8Uch9VKsHVSRhDLDW19Mq6VSwtyPxDPTJnJ2jYJWm+n8SYXiXQ==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.7" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-win32-arm64-msvc": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.95.0.tgz", - "integrity": "sha512-6eaxlgj+J5n8zgJTSugqdPLBtKGRqvxYLcvHN8b+U9hVhF/2HG/JCOrcSYV/XgWGNPQiaRVzpR3hGhmFro9QTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/@oxc-transform/binding-win32-x64-msvc": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.95.0.tgz", - "integrity": "sha512-Y8JY79A7fTuBjEXZFu+mHbHzgsV3uJDUuUKeGffpOwI1ayOGCKeBJTiMhksYkiir1xS+DkGLEz73+xse9Is9rw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "node_modules/@nuxtjs/i18n/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", "dev": true, "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/oxc-parser": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.95.0.tgz", - "integrity": "sha512-Te8fE/SmiiKWIrwBwxz5Dod87uYvsbcZ9JAL5ylPg1DevyKgTkxCXnPEaewk1Su2qpfNmry5RHoN+NywWFCG+A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@oxc-project/types": "^0.95.0" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/Boshen" - }, - "optionalDependencies": { - "@oxc-parser/binding-android-arm64": "0.95.0", - "@oxc-parser/binding-darwin-arm64": "0.95.0", - "@oxc-parser/binding-darwin-x64": "0.95.0", - "@oxc-parser/binding-freebsd-x64": "0.95.0", - "@oxc-parser/binding-linux-arm-gnueabihf": "0.95.0", - "@oxc-parser/binding-linux-arm-musleabihf": "0.95.0", - "@oxc-parser/binding-linux-arm64-gnu": "0.95.0", - "@oxc-parser/binding-linux-arm64-musl": "0.95.0", - "@oxc-parser/binding-linux-riscv64-gnu": "0.95.0", - "@oxc-parser/binding-linux-s390x-gnu": "0.95.0", - "@oxc-parser/binding-linux-x64-gnu": "0.95.0", - "@oxc-parser/binding-linux-x64-musl": "0.95.0", - "@oxc-parser/binding-wasm32-wasi": "0.95.0", - "@oxc-parser/binding-win32-arm64-msvc": "0.95.0", - "@oxc-parser/binding-win32-x64-msvc": "0.95.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/oxc-transform": { - "version": "0.95.0", - "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.95.0.tgz", - "integrity": "sha512-SmS5aThb5K0SoUZgzGbikNBjrGHfOY4X5TEqBlaZb1uy5YgXbUSbpakpZJ13yW36LNqy8Im5+y+sIk5dlzpZ/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/Boshen" - }, - "optionalDependencies": { - "@oxc-transform/binding-android-arm64": "0.95.0", - "@oxc-transform/binding-darwin-arm64": "0.95.0", - "@oxc-transform/binding-darwin-x64": "0.95.0", - "@oxc-transform/binding-freebsd-x64": "0.95.0", - "@oxc-transform/binding-linux-arm-gnueabihf": "0.95.0", - "@oxc-transform/binding-linux-arm-musleabihf": "0.95.0", - "@oxc-transform/binding-linux-arm64-gnu": "0.95.0", - "@oxc-transform/binding-linux-arm64-musl": "0.95.0", - "@oxc-transform/binding-linux-riscv64-gnu": "0.95.0", - "@oxc-transform/binding-linux-s390x-gnu": "0.95.0", - "@oxc-transform/binding-linux-x64-gnu": "0.95.0", - "@oxc-transform/binding-linux-x64-musl": "0.95.0", - "@oxc-transform/binding-wasm32-wasi": "0.95.0", - "@oxc-transform/binding-win32-arm64-msvc": "0.95.0", - "@oxc-transform/binding-win32-x64-msvc": "0.95.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/oxc-walker": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-0.5.2.tgz", - "integrity": "sha512-XYoZqWwApSKUmSDEFeOKdy3Cdh95cOcSU8f7yskFWE4Rl3cfL5uwyY+EV7Brk9mdNLy+t5SseJajd6g7KncvlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "magic-regexp": "^0.10.0" - }, - "peerDependencies": { - "oxc-parser": ">=0.72.0" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/unplugin-utils": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", - "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", - "dev": true, - "license": "MIT", - "dependencies": { - "pathe": "^2.0.3", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" - } - }, - "node_modules/@nuxtjs/i18n/node_modules/unplugin-vue-router": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/unplugin-vue-router/-/unplugin-vue-router-0.16.2.tgz", - "integrity": "sha512-lE6ZjnHaXfS2vFI/PSEwdKcdOo5RwAbCKUnPBIN9YwLgSWas3x+qivzQvJa/uxhKzJldE6WK43aDKjGj9Rij9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/generator": "^7.28.5", - "@vue-macros/common": "^3.1.1", - "@vue/language-core": "^3.1.3", - "ast-walker-scope": "^0.8.3", - "chokidar": "^4.0.3", - "json5": "^2.2.3", - "local-pkg": "^1.1.2", - "magic-string": "^0.30.21", - "mlly": "^1.8.0", - "muggle-string": "^0.4.1", - "pathe": "^2.0.3", + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", "picomatch": "^4.0.3", - "scule": "^1.3.0", - "tinyglobby": "^0.2.15", - "unplugin": "^2.3.10", - "unplugin-utils": "^0.3.1", - "yaml": "^2.8.1" + "webpack-virtual-modules": "^0.6.2" }, - "peerDependencies": { - "@vue/compiler-sfc": "^3.5.17", - "vue-router": "^4.6.0" - }, - "peerDependenciesMeta": { - "vue-router": { - "optional": true - } + "engines": { + "node": ">=18.12.0" } }, "node_modules/@nuxtjs/tailwindcss": { @@ -4073,10 +3355,26 @@ "dev": true, "license": "MIT" }, + "node_modules/@oxc-minify/binding-android-arm-eabi": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm-eabi/-/binding-android-arm-eabi-0.112.0.tgz", + "integrity": "sha512-m7TGBR2hjsBJIN9UJ909KBoKsuogo6CuLsHKvUIBXdjI0JVHP8g4ZHeB+BJpGn5LJdeSGDfz9MWiuXrZDRzunw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-minify/binding-android-arm64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.102.0.tgz", - "integrity": "sha512-pknM+ttJTwRr7ezn1v5K+o2P4RRjLAzKI10bjVDPybwWQ544AZW6jxm7/YDgF2yUbWEV9o7cAQPkIUOmCiW8vg==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.112.0.tgz", + "integrity": "sha512-RvxOOkzvP5NeeoraBtgNJSBqO+XzlS7DooxST/drAXCfO52GsmxVB1N7QmifrsTYtH8GC2z3DTFjZQ1w/AJOWg==", "cpu": [ "arm64" ], @@ -4090,9 +3388,9 @@ } }, "node_modules/@oxc-minify/binding-darwin-arm64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.102.0.tgz", - "integrity": "sha512-BDLiH41ZctNND38+GCEL3ZxFn9j7qMZJLrr6SLWMt8xlG4Sl64xTkZ0zeUy4RdVEatKKZdrRIhFZ2e5wPDQT6Q==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.112.0.tgz", + "integrity": "sha512-hDslO3uVHza3kB9zkcsi25JzN65Gj5ZYty0OvylS11Mhg9ydCYxAzfQ/tISHW/YmV1NRUJX8+GGqM1cKmrHaTA==", "cpu": [ "arm64" ], @@ -4106,9 +3404,9 @@ } }, "node_modules/@oxc-minify/binding-darwin-x64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.102.0.tgz", - "integrity": "sha512-AcB8ZZ711w4hTDhMfMHNjT2d+hekTQ2XmNSUBqJdXB+a2bJbE50UCRq/nxXl44zkjaQTit3lcQbFvhk2wwKcpw==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.112.0.tgz", + "integrity": "sha512-mWA2Y5bUyNoGM+gSGGHesgtQ3LDWgpRe4zDGkBDovxNIiDLBXqu/7QcuS+G918w8oG9VYm1q1iinILer/2pD1Q==", "cpu": [ "x64" ], @@ -4122,9 +3420,9 @@ } }, "node_modules/@oxc-minify/binding-freebsd-x64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.102.0.tgz", - "integrity": "sha512-UlLEN9mR5QaviYVMWZQsN9DgAH3qyV67XUXDEzSrbVMLsqHsVHhFU8ZIeO0fxWTQW/cgpvldvKp9/+RdrggqWw==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.112.0.tgz", + "integrity": "sha512-T7fsegxcy82xS0jWPXkz/BMhrkb3D7YOCiV0R9pDksjaov+iIFoNEWAoBsaC5NtpdzkX+bmffwDpu336EIfEeg==", "cpu": [ "x64" ], @@ -4138,9 +3436,25 @@ } }, "node_modules/@oxc-minify/binding-linux-arm-gnueabihf": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.102.0.tgz", - "integrity": "sha512-CWyCwedZrUt47n56/RwHSwKXxVI3p98hB0ntLaBNeH5qjjBujs9uOh4bQ0aAlzUWunT77b3/Y+xcQnmV42HN4A==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.112.0.tgz", + "integrity": "sha512-yePavbIilAcpVYc8vRsDCn3xJxHMXDZIiamyH9fuLosAHNELcLib4/JR4fhDk4NmHVagQH3kRhsnm5Q9cm3pAw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-arm-musleabihf": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.112.0.tgz", + "integrity": "sha512-lmPWLXtW6FspERhy97iP0hwbmLtL66xI29QQ9GpHmTiE4k+zv/FaefuV/Qw+LuHnmFSYzUNrLcxh4ulOZTIP2g==", "cpu": [ "arm" ], @@ -4154,9 +3468,9 @@ } }, "node_modules/@oxc-minify/binding-linux-arm64-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.102.0.tgz", - "integrity": "sha512-W/DCw+Ys8rXj4j38ylJ2l6Kvp6SV+eO5SUWA11imz7yCWntNL001KJyGQ9PJNUFHg0jbxe3yqm4M50v6miWzeA==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.112.0.tgz", + "integrity": "sha512-gySS5XqU5MKs/oCjsTlVm8zb8lqcNKHEANsaRmhW2qvGKJoeGwFb6Fbq6TLCZMRuk143mLbncbverBCa1c3dog==", "cpu": [ "arm64" ], @@ -4170,9 +3484,9 @@ } }, "node_modules/@oxc-minify/binding-linux-arm64-musl": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.102.0.tgz", - "integrity": "sha512-DyH/t/zSZHuX4Nn239oBteeMC4OP7B13EyXWX18Qg8aJoZ+lZo90WPGOvhP04zII33jJ7di+vrtAUhsX64lp+A==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.112.0.tgz", + "integrity": "sha512-IRFMZX589lr3rjG0jc8N261/7wqFq2Vl0OMrJWeFls5BF8HiB+fRYuf0Zy2CyRH6NCY2vbdDdp+QCAavQGVsGw==", "cpu": [ "arm64" ], @@ -4185,10 +3499,42 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@oxc-minify/binding-linux-ppc64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.112.0.tgz", + "integrity": "sha512-V/69XqIW9hCUceDpcZh79oDg+F4ptEgIfKRENzYs41LRbSoJ7sNjjcW4zifqyviTvzcnXLgK4uoTyoymmNZBMQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-minify/binding-linux-riscv64-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.102.0.tgz", - "integrity": "sha512-CMvzrmOg+Gs44E7TRK/IgrHYp+wwVJxVV8niUrDR2b3SsrCO3NQz5LI+7bM1qDbWnuu5Cl1aiitoMfjRY61dSg==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.112.0.tgz", + "integrity": "sha512-zghvexySyGXGNW+MutjZN7UGTyOQl56RWMlPe1gb+knBm/+0hf9qjk7Q6ofm2tSte+vQolPfQttifGl0dP9uvQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-riscv64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.112.0.tgz", + "integrity": "sha512-E4a8VUFDJPb2mPcc7J4NQQPi1ssHKF7/g4r6KD2+SBVERIaEEd3cGNqR7SG3g82/BLGV2UDoQe/WvZCkt5M/bQ==", "cpu": [ "riscv64" ], @@ -4202,9 +3548,9 @@ } }, "node_modules/@oxc-minify/binding-linux-s390x-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.102.0.tgz", - "integrity": "sha512-tZWr6j2s0ddm9MTfWTI3myaAArg9GDy4UgvpF00kMQAjLcGUNhEEQbB9Bd9KtCvDQzaan8HQs0GVWUp+DWrymw==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.112.0.tgz", + "integrity": "sha512-2Hx87sK3y6jBV364Mvv0zyxiITIuy26Ixenv6pK7e+4an3HgNdhAj8nk3aLoLTTSvLik5/MaGhcZGEu9tYV1aA==", "cpu": [ "s390x" ], @@ -4218,9 +3564,9 @@ } }, "node_modules/@oxc-minify/binding-linux-x64-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.102.0.tgz", - "integrity": "sha512-0YEKmAIun1bS+Iy5Shx6WOTSj3GuilVuctJjc5/vP8/EMTZ/RI8j0eq0Mu3UFPoT/bMULL3MBXuHuEIXmq7Ddg==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.112.0.tgz", + "integrity": "sha512-2MSCnEPLk9ddSouMhJo78Xy2/JbYC80OYzWdR4yWTGSULsgH3d1VXg73DSwFL8vU7Ad9oK10DioBY2ww7sQTEg==", "cpu": [ "x64" ], @@ -4234,9 +3580,9 @@ } }, "node_modules/@oxc-minify/binding-linux-x64-musl": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.102.0.tgz", - "integrity": "sha512-Ew4QDpEsXoV+pG5+bJpheEy3GH436GBe6ASPB0X27Hh9cQ2gb1NVZ7cY7xJj68+fizwS/PtT8GHoG3uxyH17Pg==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.112.0.tgz", + "integrity": "sha512-HAPfmQKlkVi97/zRonVE9t/kKUG3ni+mOuU1Euw+3s37KwUuOJjmcwXdclVgXKBlTkCGO0FajPwW5dAJeIXCCw==", "cpu": [ "x64" ], @@ -4250,9 +3596,9 @@ } }, "node_modules/@oxc-minify/binding-openharmony-arm64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-openharmony-arm64/-/binding-openharmony-arm64-0.102.0.tgz", - "integrity": "sha512-wYPXS8IOu/sXiP3CGHJNPzZo4hfPAwJKevcFH2syvU2zyqUxym7hx6smfcK/mgJBiX7VchwArdGRwrEQKcBSaQ==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-openharmony-arm64/-/binding-openharmony-arm64-0.112.0.tgz", + "integrity": "sha512-bLnMojcPadYzMNpB6IAqMiTOag4etc0zbs8On73JsotO1W5c5/j/ncplpSokpEpNasKRUpHVRXpmq0KRXprNhw==", "cpu": [ "arm64" ], @@ -4266,25 +3612,25 @@ } }, "node_modules/@oxc-minify/binding-wasm32-wasi": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.102.0.tgz", - "integrity": "sha512-52SepCb9e+8cVisGa9S/F14K8PxW0AnbV1j4KEYi8uwfkUIxeDNKRHVHzPoBXNrr0yxW0EHLn/3i8J7a2YCpWw==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.112.0.tgz", + "integrity": "sha512-tv7PmHYq/8QBlqMaDjsy51GF5KQkG17Yc/PsgB5OVndU34kwbQuebBIic7UfK9ygzidI8moYq3ztnu3za/rqHw==", "cpu": [ "wasm32" ], "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.0" + "@napi-rs/wasm-runtime": "^1.1.1" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@oxc-minify/binding-win32-arm64-msvc": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.102.0.tgz", - "integrity": "sha512-kLs6H1y6sDBKcIimkNwu5th28SLkyvFpHNxdLtCChda0KIGeIXNSiupy5BqEutY+VlWJivKT1OV3Ev3KC5Euzg==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.112.0.tgz", + "integrity": "sha512-d+jes2jwRkcBSpcaZC6cL8GBi56Br6uAorn9dfquhWLczWL+hHSvvVrRgT1i5/6dkf5UWx2zdoEsAMiJ11w78A==", "cpu": [ "arm64" ], @@ -4297,10 +3643,26 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@oxc-minify/binding-win32-ia32-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.112.0.tgz", + "integrity": "sha512-TV1C3qDwj7//jNIi5tnNRhReSUgtaRQKi5KobDE6zVAc5gjeuBA8G2qizS9ziXlf/I0dlelrGmGMMDJmH9ekWg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-minify/binding-win32-x64-msvc": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.102.0.tgz", - "integrity": "sha512-XdyJZdSMN8rbBXH10CrFuU+Q9jIP2+MnxHmNzjK4+bldbTI1UxqwjUMS9bKVC5VCaIEZhh8IE8x4Vf8gmCgrKQ==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.112.0.tgz", + "integrity": "sha512-LML2Gld6VY8/+7a3VH4k1qngsBXvTkXgbmYgSYwaElqtiQiYaAcXfi0XKOUGe3k3GbBK4juAGixC31CrdFHAQw==", "cpu": [ "x64" ], @@ -4313,12 +3675,12 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-parser/binding-android-arm64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.102.0.tgz", - "integrity": "sha512-pD2if3w3cxPvYbsBSTbhxAYGDaG6WVwnqYG0mYRQ142D6SJ6BpNs7YVQrqpRA2AJQCmzaPP5TRp/koFLebagfQ==", + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.112.0.tgz", + "integrity": "sha512-retxBzJ39Da7Lh/eZTn9+HJgTeDUxZIpuI0urOsmcFsBKXAth3lc1jIvwseQ9qbAI/VrsoFOXiGIzgclARbAHg==", "cpu": [ - "arm64" + "arm" ], "license": "MIT", "optional": true, @@ -4329,13 +3691,31 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-parser/binding-darwin-arm64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.102.0.tgz", - "integrity": "sha512-RzMN6f6MrjjpQC2Dandyod3iOscofYBpHaTecmoRRbC5sJMwsurkqUMHzoJX9F6IM87kn8m/JcClnoOfx5Sesw==", + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.95.0.tgz", + "integrity": "sha512-dZyxhhvJigwWL1wgnLlqyEiSeuqO0WdDH9H+if0dPcBM4fKa5fjVkaUcJT1jBMcBTnkjxMwTXYZy5TK60N0fjg==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.95.0.tgz", + "integrity": "sha512-zun9+V33kyCtNec9oUSWwb0qi3fB8pXwum1yGFECPEr55g/CrWju6/Jv4hwwNBeW2tK9Ch/PRstEtYmOLMhHpg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4346,12 +3726,13 @@ } }, "node_modules/@oxc-parser/binding-darwin-x64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.102.0.tgz", - "integrity": "sha512-Sr2/3K6GEcejY+HgWp5HaxRPzW5XHe9IfGKVn9OhLt8fzVLnXbK5/GjXj7JjMCNKI3G3ZPZDG2Dgm6CX3MaHCA==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.95.0.tgz", + "integrity": "sha512-9djMQ/t6Ns/UXtziwUe562uVJMbhtuLtCj+Xav+HMVT/rhV9gWO8PQOG7AwDLUBjJanItsrfqrGtqhNxtZ701w==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4362,12 +3743,13 @@ } }, "node_modules/@oxc-parser/binding-freebsd-x64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.102.0.tgz", - "integrity": "sha512-s9F2N0KJCGEpuBW6ChpFfR06m2Id9ReaHSl8DCca4HvFNt8SJFPp8fq42n2PZy68rtkremQasM0JDrK2BoBeBQ==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.95.0.tgz", + "integrity": "sha512-GK6k0PgCVkkeRZtHgcosCYbXIRySpJpuPw/OInfLGFh8f3x9gp2l8Fbcfx+YO+ZOHFBCd2NNedGqw8wMgouxfA==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4378,12 +3760,13 @@ } }, "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.102.0.tgz", - "integrity": "sha512-zRCIOWzLbqhfY4g8KIZDyYfO2Fl5ltxdQI1v2GlePj66vFWRl8cf4qcBGzxKfsH3wCZHAhmWd1Ht59mnrfH/UQ==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.95.0.tgz", + "integrity": "sha512-+g/lFITtyHHEk69cunOHuiT5cX+mpUTcbGYNe8suguZ7FqgNwai+PnGv0ctCvtgxBPVfckfUK8c3RvFKo+vi/w==", "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4411,12 +3794,13 @@ } }, "node_modules/@oxc-parser/binding-linux-arm64-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.102.0.tgz", - "integrity": "sha512-5n5RbHgfjulRhKB0pW5p0X/NkQeOpI4uI9WHgIZbORUDATGFC8yeyPA6xYGEs+S3MyEAFxl4v544UEIWwqAgsA==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.95.0.tgz", + "integrity": "sha512-0LzebARTU0ROfD6pDK4h1pFn+09meErCZ0MA2TaW08G72+GNneEsksPufOuI+9AxVSRa+jKE3fu0wavvhZgSkg==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4427,12 +3811,29 @@ } }, "node_modules/@oxc-parser/binding-linux-arm64-musl": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.102.0.tgz", - "integrity": "sha512-/XWcmglH/VJ4yKAGTLRgPKSSikh3xciNxkwGiURt8dS30b+3pwc4ZZmudMu0tQ3mjSu0o7V9APZLMpbHK8Bp5w==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.95.0.tgz", + "integrity": "sha512-Pvi1lGe/G+mJZ3hUojMP/aAHAzHA25AEtVr8/iuz7UV72t/15NOgJYr9kELMUMNjPqpr3vKUgXTFmTtAxp11Qw==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.112.0.tgz", + "integrity": "sha512-lAQf8PQxfgy7h0bmcfSVE3hg3qMueshPYULFsCrHM+8KefGZ9W+ZMvRyU33gLrB4w1O3Fz1orR0hmKMCRxXNrQ==", + "cpu": [ + "ppc64" + ], "license": "MIT", "optional": true, "os": [ @@ -4443,9 +3844,26 @@ } }, "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.102.0.tgz", - "integrity": "sha512-2jtIq4nswvy6xdqv1ndWyvVlaRpS0yqomLCvvHdCFx3pFXo5Aoq4RZ39kgvFWrbAtpeYSYeAGFnwgnqjx9ftdw==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.95.0.tgz", + "integrity": "sha512-pUEVHIOVNDfhk4sTlLhn6mrNENhE4/dAwemxIfqpcSyBlYG0xYZND1F3jjR2yWY6DakXZ6VSuDbtiv1LPNlOLw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.112.0.tgz", + "integrity": "sha512-v06iu0osHszgqJ1dLQRb6leWFU1sjG/UQk4MoVBtE6ZPewgfTkby6G9II1SpEAf2onnAuQceVYxQH9iuU3NJqw==", "cpu": [ "riscv64" ], @@ -4459,12 +3877,13 @@ } }, "node_modules/@oxc-parser/binding-linux-s390x-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.102.0.tgz", - "integrity": "sha512-Yp6HX/574mvYryiqj0jNvNTJqo4pdAsNP2LPBTxlDQ1cU3lPd7DUA4MQZadaeLI8+AGB2Pn50mPuPyEwFIxeFg==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.95.0.tgz", + "integrity": "sha512-5+olaepHTE3J/+w7g0tr3nocvv5BKilAJnzj4L8tWBCLEZbL6olJcGVoldUO+3cgg1SO1xJywP5BuLhT0mDUDw==", "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4475,12 +3894,13 @@ } }, "node_modules/@oxc-parser/binding-linux-x64-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.102.0.tgz", - "integrity": "sha512-R4b0xZpDRhoNB2XZy0kLTSYm0ZmWeKjTii9fcv1Mk3/SIGPrrglwt4U6zEtwK54Dfi4Bve5JnQYduigR/gyDzw==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.95.0.tgz", + "integrity": "sha512-8huzHlK/N98wrnYKxIcYsK8ZGBWomQchu/Mzi6m+CtbhjWOv9DmK0jQ2fUWImtluQVpTwS0uZT06d3g7XIkJrA==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4491,12 +3911,13 @@ } }, "node_modules/@oxc-parser/binding-linux-x64-musl": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.102.0.tgz", - "integrity": "sha512-xM5A+03Ti3jvWYZoqaBRS3lusvnvIQjA46Fc9aBE/MHgvKgHSkrGEluLWg/33QEwBwxupkH25Pxc1yu97oZCtg==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.95.0.tgz", + "integrity": "sha512-bWnrLfGDcx/fab0+UQnFbVFbiykof/btImbYf+cI2pU/1Egb2x+OKSmM5Qt0nEUiIpM5fgJmYXxTopybSZOKYA==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4507,9 +3928,9 @@ } }, "node_modules/@oxc-parser/binding-openharmony-arm64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.102.0.tgz", - "integrity": "sha512-AieLlsliblyaTFq7Iw9Nc618tgwV02JT4fQ6VIUd/3ZzbluHIHfPjIXa6Sds+04krw5TvCS8lsegtDYAyzcyhg==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.112.0.tgz", + "integrity": "sha512-ZhrVmWFifVEFQX4XPwLoVFDHw9tAWH9p9vHsHFH+5uCKdfVR+jje4WxVo6YrokWCboGckoOzHq5KKMOcPZfkRg==", "cpu": [ "arm64" ], @@ -4523,28 +3944,46 @@ } }, "node_modules/@oxc-parser/binding-wasm32-wasi": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.102.0.tgz", - "integrity": "sha512-w6HRyArs1PBb9rDsQSHlooe31buUlUI2iY8sBzp62jZ1tmvaJo9EIVTQlRNDkwJmk9DF9uEyIJ82EkZcCZTs9A==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.95.0.tgz", + "integrity": "sha512-0JLyqkZu1HnQIZ4e5LBGOtzqua1QwFEUOoMSycdoerXqayd4LK2b7WMfAx8eCIf+jGm1Uj6f3R00nlsx8g1faQ==", "cpu": [ "wasm32" ], + "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.0" + "@napi-rs/wasm-runtime": "^1.0.7" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@oxc-parser/binding-win32-arm64-msvc": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.102.0.tgz", - "integrity": "sha512-pqP5UuLiiFONQxqGiUFMdsfybaK1EOK4AXiPlvOvacLaatSEPObZGpyCkAcj9aZcvvNwYdeY9cxGM9IT3togaA==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.95.0.tgz", + "integrity": "sha512-RWvaA6s1SYlBj9CxwHfNn0CRlkPdv9fEUAXfZkGQPdP5e1ppIaO2KYE0sUov/zzp9hPTMMsTMHl4dcIbb+pHCQ==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.112.0.tgz", + "integrity": "sha512-rZH0JynCCwnhe2HfRoyNOl/Kfd9pudoWxgpC5OZhj7j77pMK0UOAa35hYDfrtSOUk2HLzrikV5dPUOY2DpSBSA==", + "cpu": [ + "ia32" + ], "license": "MIT", "optional": true, "os": [ @@ -4555,12 +3994,13 @@ } }, "node_modules/@oxc-parser/binding-win32-x64-msvc": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.102.0.tgz", - "integrity": "sha512-ntMcL35wuLR1A145rLSmm7m7j8JBZGkROoB9Du0KFIFcfi/w1qk75BdCeiTl3HAKrreAnuhW3QOGs6mJhntowA==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.95.0.tgz", + "integrity": "sha512-BQpgl7rDjFvCIHudmUR0dCwc4ylBYZl4CPVinlD3NhkMif4WD5dADckoo5ES/KOpFyvwcbKZX+grP63cjHi26g==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4571,20 +4011,21 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.102.0.tgz", - "integrity": "sha512-8Skrw405g+/UJPKWJ1twIk3BIH2nXdiVlVNtYT23AXVwpsd79es4K+KYt06Fbnkc5BaTvk/COT2JuCLYdwnCdA==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.95.0.tgz", + "integrity": "sha512-vACy7vhpMPhjEJhULNxrdR0D943TkA/MigMpJCHmBHvMXxRStRi/dPtTlfQ3uDwWSzRpT8z+7ImjZVf8JWBocQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@oxc-transform/binding-android-arm64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.102.0.tgz", - "integrity": "sha512-JLBT7EiExsGmB6LuBBnm6qTfg0rLSxBU+F7xjqy6UXYpL7zhqelGJL7IAq6Pu5UYFT55zVlXXmgzLOXQfpQjXA==", + "node_modules/@oxc-transform/binding-android-arm-eabi": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm-eabi/-/binding-android-arm-eabi-0.112.0.tgz", + "integrity": "sha512-r4LuBaPnOAi0eUOBNi880Fm2tO2omH7N1FRrL6+nyz/AjQ+QPPLtoyZJva0O+sKi1buyN/7IzM5p9m+5ANSDbg==", "cpu": [ - "arm64" + "arm" ], "license": "MIT", "optional": true, @@ -4595,13 +4036,31 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-transform/binding-darwin-arm64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.102.0.tgz", - "integrity": "sha512-xmsBCk/NwE0khy8h6wLEexiS5abCp1ZqJUNHsAovJdGgIW21oGwhiC3VYg1vNLbq+zEXwOHuphVuNEYfBwyNTw==", + "node_modules/@oxc-transform/binding-android-arm64": { + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.95.0.tgz", + "integrity": "sha512-eW+BCgRWOsMrDiz7FEV7BjAmaF9lGIc2ueGdRUYjRUMq4f5FSGS7gMBTYDxajdoIB3L5Gnksh1CWkIlgg95UVA==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-transform/binding-darwin-arm64": { + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.95.0.tgz", + "integrity": "sha512-OUUaYZVss8tyDZZ7TGr2vnH3+i3Ouwsx0frQRGkiePNatXxaJJ3NS5+Kwgi9hh3WryXaQz2hWji4AM2RHYE7Cg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4612,12 +4071,13 @@ } }, "node_modules/@oxc-transform/binding-darwin-x64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.102.0.tgz", - "integrity": "sha512-EhBsiq8hSd5BRjlWACB9MxTUiZT2He1s1b3tRP8k3lB8ZTt6sXnDXIWhxRmmM0h//xe6IJ2HuMlbvjXPo/tATg==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.95.0.tgz", + "integrity": "sha512-49UPEgIlgWUndwcP3LH6dvmOewZ92DxCMpFMo11JhUlmNJxA3sjVImEBRB56/tJ+XF+xnya9kB1oCW4yRY+mRw==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4628,12 +4088,13 @@ } }, "node_modules/@oxc-transform/binding-freebsd-x64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.102.0.tgz", - "integrity": "sha512-eujvuYf0x7BFgKyFecbXUa2JBEXT4Ss6vmyrrhVdN07jaeJRiobaKAmeNXBkanoWL2KQLELJbSBgs1ykWYTkzg==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.95.0.tgz", + "integrity": "sha512-lNKrHKaDEm8pbKlVbn0rv2L97O0lbA0Tsrxx4GF/HhmdW+NgwGU1pMzZ4tB2QcylbqgKxOB+v9luebHyh1jfgA==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4644,12 +4105,13 @@ } }, "node_modules/@oxc-transform/binding-linux-arm-gnueabihf": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.102.0.tgz", - "integrity": "sha512-2x7Ro356PHBVp1SS/dOsHBSnrfs5MlPYwhdKg35t6qixt2bv1kzEH0tDmn4TNEbdjOirmvOXoCTEWUvh8A4f4Q==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.95.0.tgz", + "integrity": "sha512-+VWcLeeizI8IjU+V+o8AmzPuIMiTrGr0vrmXU3CEsV05MrywCuJU+f6ilPs3JBKno9VIwqvRpHB/z39sQabHWg==", "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4677,12 +4139,13 @@ } }, "node_modules/@oxc-transform/binding-linux-arm64-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.102.0.tgz", - "integrity": "sha512-Rz/RbPvT4QwcHKIQ/cOt6Lwl4c7AhK2b6whZfyL6oJ7Uz8UiVl1BCwk8thedrB5h+FEykmaPHoriW1hmBev60g==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.95.0.tgz", + "integrity": "sha512-NLdrFuEHlmbiC1M1WESFV4luUcB/84GXi+cbnRXhgMjIW/CThRVJ989eTJy59QivkVlLcJSKTiKiKCt0O6TTlQ==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4693,12 +4156,29 @@ } }, "node_modules/@oxc-transform/binding-linux-arm64-musl": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.102.0.tgz", - "integrity": "sha512-I08iWABrN7zakn3wuNIBWY3hALQGsDLPQbZT1mXws7tyiQqJNGe49uS0/O50QhX3KXj+mbRGsmjVXLXGJE1CVQ==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.95.0.tgz", + "integrity": "sha512-GL0ffCPW8JlFI0/jeSgCY665yDdojHxA0pbYG+k8oEHOWCYZUZK9AXL+r0oerNEWYJ8CRB+L5Yq87ZtU/YUitw==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-transform/binding-linux-ppc64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.112.0.tgz", + "integrity": "sha512-PXzmj82o1moA4IGphYImTRgc2youTi4VRfyFX3CHwLjxPcQ5JtcsgbDt4QUdOzXZ+zC07s5jf2ZzhRapEOlj2w==", + "cpu": [ + "ppc64" + ], "license": "MIT", "optional": true, "os": [ @@ -4709,9 +4189,26 @@ } }, "node_modules/@oxc-transform/binding-linux-riscv64-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.102.0.tgz", - "integrity": "sha512-9+SYW1ARAF6Oj/82ayoqKRe8SI7O1qvzs3Y0kijvhIqAaaZWcFRjI5DToyWRAbnzTtHlMcSllZLXNYdmxBjFxA==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.95.0.tgz", + "integrity": "sha512-tbH7LaClSmN3YFVo1UjMSe7D6gkb5f+CMIbj9i873UUZomVRmAjC4ygioObfzM+sj/tX0WoTXx5L1YOfQkHL6Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-transform/binding-linux-riscv64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.112.0.tgz", + "integrity": "sha512-cXWFb7z+2IjFUEcXtRwluq9oEG5qnyFCjiu3SWrgYNcWwPdHusv3I/7K5/CTbbi4StoZ5txbi7/iSfDHNyWuRw==", "cpu": [ "riscv64" ], @@ -4725,12 +4222,13 @@ } }, "node_modules/@oxc-transform/binding-linux-s390x-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.102.0.tgz", - "integrity": "sha512-HV9nTyQw0TTKYPu+gBhaJBioomiM9O4LcGXi+s5IylCGG6imP0/U13q/9xJnP267QFmiWWqnnSFcv0QAWCyh8A==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.95.0.tgz", + "integrity": "sha512-8jMqiURWa0iTiPMg7BWaln89VdhhWzNlPyKM90NaFVVhBIKCr2UEhrQWdpBw/E9C8uWf/4VabBEhfPMK+0yS4w==", "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4741,12 +4239,13 @@ } }, "node_modules/@oxc-transform/binding-linux-x64-gnu": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.102.0.tgz", - "integrity": "sha512-4wcZ08mmdFk8OjsnglyeYGu5PW3TDh87AmcMOi7tZJ3cpJjfzwDfY27KTEUx6G880OpjAiF36OFSPwdKTKgp2g==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.95.0.tgz", + "integrity": "sha512-D5ULJ2uWipsTgfvHIvqmnGkCtB3Fyt2ZN7APRjVO+wLr+HtmnaWddKsLdrRWX/m/6nQ2xQdoQekdJrokYK9LtQ==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4757,12 +4256,13 @@ } }, "node_modules/@oxc-transform/binding-linux-x64-musl": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.102.0.tgz", - "integrity": "sha512-rUHZSZBw0FUnUgOhL/Rs7xJz9KjH2eFur/0df6Lwq/isgJc/ggtBtFoZ+y4Fb8ON87a3Y2gS2LT7SEctX0XdPQ==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.95.0.tgz", + "integrity": "sha512-DmCGU+FzRezES5wVAGVimZGzYIjMOapXbWpxuz8M8p3nMrfdBEQ5/tpwBp2vRlIohhABy4vhHJByl4c64ENCGQ==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4773,9 +4273,9 @@ } }, "node_modules/@oxc-transform/binding-openharmony-arm64": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-openharmony-arm64/-/binding-openharmony-arm64-0.102.0.tgz", - "integrity": "sha512-98y4tccTQ/pA+r2KA/MEJIZ7J8TNTJ4aCT4rX8kWK4pGOko2YsfY3Ru9DVHlLDwmVj7wP8Z4JNxdBrAXRvK+0g==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-openharmony-arm64/-/binding-openharmony-arm64-0.112.0.tgz", + "integrity": "sha512-UOGVrGIv7yLJovyEXEyUTADuLq98vd/cbMHFLJweRXD+11I8Tn4jASi4WzdsN8C3BVYGRHrXH2NlSBmhz33a4g==", "cpu": [ "arm64" ], @@ -4789,28 +4289,46 @@ } }, "node_modules/@oxc-transform/binding-wasm32-wasi": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.102.0.tgz", - "integrity": "sha512-M6myOXxHty3L2TJEB1NlJPtQm0c0LmivAxcGv/+DSDadOoB/UnOUbjM8W2Utlh5IYS9ARSOjqHtBiPYLWJ15XA==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.95.0.tgz", + "integrity": "sha512-tSo1EU4Whd1gXyae7cwSDouhppkuz6Jkd5LY8Uch9VKsHVSRhDLDW19Mq6VSwtyPxDPTJnJ2jYJWm+n8SYXiXQ==", "cpu": [ "wasm32" ], + "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.0" + "@napi-rs/wasm-runtime": "^1.0.7" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@oxc-transform/binding-win32-arm64-msvc": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.102.0.tgz", - "integrity": "sha512-jzaA1lLiMXiJs4r7E0BHRxTPiwAkpoCfSNRr8npK/SqL4UQE4cSz3WDTX5wJWRrN2U+xqsDGefeYzH4reI8sgw==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.95.0.tgz", + "integrity": "sha512-6eaxlgj+J5n8zgJTSugqdPLBtKGRqvxYLcvHN8b+U9hVhF/2HG/JCOrcSYV/XgWGNPQiaRVzpR3hGhmFro9QTw==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-transform/binding-win32-ia32-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.112.0.tgz", + "integrity": "sha512-6QaB0qjNaou2YR+blncHdw7j0e26IOwOIjLbhVGDeuf9+4rjJeiqRXJ2hOtCcS4zblnao/MjdgQuZ3fM0nl+Kw==", + "cpu": [ + "ia32" + ], "license": "MIT", "optional": true, "os": [ @@ -4821,12 +4339,13 @@ } }, "node_modules/@oxc-transform/binding-win32-x64-msvc": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.102.0.tgz", - "integrity": "sha512-eYOm6mch+1cP9qlNkMdorfBFY8aEOxY/isqrreLmEWqF/hyXA0SbLKDigTbvh3JFKny/gXlHoCKckqfua4cwtg==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.95.0.tgz", + "integrity": "sha512-Y8JY79A7fTuBjEXZFu+mHbHzgsV3uJDUuUKeGffpOwI1ayOGCKeBJTiMhksYkiir1xS+DkGLEz73+xse9Is9rw==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4837,16 +4356,16 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", "hasInstallScript": true, "license": "MIT", "dependencies": { - "detect-libc": "^1.0.3", + "detect-libc": "^2.0.3", "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" }, "engines": { "node": ">= 10.0.0" @@ -4856,25 +4375,25 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", "cpu": [ "arm64" ], @@ -4892,9 +4411,9 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", "cpu": [ "arm64" ], @@ -4912,9 +4431,9 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", "cpu": [ "x64" ], @@ -4932,9 +4451,9 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", "cpu": [ "x64" ], @@ -4952,9 +4471,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", "cpu": [ "arm" ], @@ -4972,9 +4491,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", "cpu": [ "arm" ], @@ -4992,9 +4511,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", "cpu": [ "arm64" ], @@ -5012,9 +4531,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", "cpu": [ "arm64" ], @@ -5032,9 +4551,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", "cpu": [ "x64" ], @@ -5052,9 +4571,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", "cpu": [ "x64" ], @@ -5072,17 +4591,17 @@ } }, "node_modules/@parcel/watcher-wasm": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.5.1.tgz", - "integrity": "sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.5.6.tgz", + "integrity": "sha512-byAiBZ1t3tXQvc8dMD/eoyE7lTXYorhn+6uVW5AC+JGI1KtJC/LvDche5cfUE+qiefH+Ybq0bUCJU0aB1cSHUA==", "bundleDependencies": [ "napi-wasm" ], "license": "MIT", "dependencies": { "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "napi-wasm": "^1.1.0" + "napi-wasm": "^1.1.0", + "picomatch": "^4.0.3" }, "engines": { "node": ">= 10.0.0" @@ -5098,9 +4617,9 @@ "license": "MIT" }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", "cpu": [ "arm64" ], @@ -5118,9 +4637,9 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", "cpu": [ "ia32" ], @@ -5138,9 +4657,9 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", "cpu": [ "x64" ], @@ -5199,19 +4718,10 @@ "kleur": "^4.1.5" } }, - "node_modules/@poppinss/colors/node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/@poppinss/dumper": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz", - "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.7.0.tgz", + "integrity": "sha512-0UTYalzk2t6S4rA2uHOz5bSSW2CHdv4vggJI6Alg90yvl0UgXs6XSXpH96OH+bRkX4J/06djv29pqXJ0lq5Kag==", "license": "MIT", "dependencies": { "@poppinss/colors": "^4.1.5", @@ -5249,21 +4759,21 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.53", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", - "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", + "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", "license": "MIT" }, "node_modules/@rollup/plugin-alias": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz", - "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-6.0.0.tgz", + "integrity": "sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==", "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=20.19.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "rollup": ">=4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -5272,9 +4782,9 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "28.0.9", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.9.tgz", - "integrity": "sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.0.tgz", + "integrity": "sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ==", "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -5297,6 +4807,12 @@ } } }, + "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/@rollup/plugin-inject": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", @@ -5319,6 +4835,12 @@ } } }, + "node_modules/@rollup/plugin-inject/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/@rollup/plugin-json": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", @@ -5451,10 +4973,16 @@ } } }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", - "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], @@ -5465,9 +4993,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", - "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], @@ -5478,9 +5006,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", - "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], @@ -5491,9 +5019,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", - "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], @@ -5504,9 +5032,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", - "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], @@ -5517,9 +5045,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", - "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], @@ -5530,9 +5058,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", - "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], @@ -5543,9 +5071,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", - "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], @@ -5556,9 +5084,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", - "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], @@ -5569,9 +5097,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", - "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], @@ -5582,9 +5110,22 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", - "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], @@ -5595,9 +5136,22 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", - "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], @@ -5608,9 +5162,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", - "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], @@ -5621,9 +5175,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", - "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], @@ -5634,9 +5188,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", - "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], @@ -5647,9 +5201,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", - "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], @@ -5660,9 +5214,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", - "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -5672,10 +5226,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", - "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -5686,9 +5253,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", - "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], @@ -5699,9 +5266,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", - "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], @@ -5712,9 +5279,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", - "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", "cpu": [ "x64" ], @@ -5725,9 +5292,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", - "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], @@ -5788,17 +5355,16 @@ "license": "MIT" }, "node_modules/@stylistic/eslint-plugin": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.7.0.tgz", - "integrity": "sha512-PsSugIf9ip1H/mWKj4bi/BlEoerxXAda9ByRFsYuwsmr6af9NxJL0AaiNXs8Le7R21QR5KMiD/KdxZZ71LjAxQ==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.9.0.tgz", + "integrity": "sha512-FqqSkvDMYJReydrMhlugc71M76yLLQWNfmGq+SIlLa7N3kHp8Qq8i2PyWrVNAfjOyOIY+xv9XaaYwvVW7vroMA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/types": "^8.52.0", - "eslint-visitor-keys": "^5.0.0", - "espree": "^11.0.0", + "@typescript-eslint/types": "^8.56.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "estraverse": "^5.3.0", "picomatch": "^4.0.3" }, @@ -5806,7 +5372,20 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": ">=9.0.0" + "eslint": "^9.0.0 || ^10.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@tybys/wasm-util": { @@ -5851,9 +5430,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.19.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.8.tgz", - "integrity": "sha512-ebO/Yl+EAvVe8DnMfi+iaAyIqYdK0q/q0y0rw82INWEKJOBe6b/P3YWE8NW7oOlF/nXFNrHwhARrN/hdgDkraA==", + "version": "22.19.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz", + "integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==", "devOptional": true, "license": "MIT", "peer": true, @@ -5861,12 +5440,6 @@ "undici-types": "~6.21.0" } }, - "node_modules/@types/parse-path": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz", - "integrity": "sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==", - "license": "MIT" - }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", @@ -5874,17 +5447,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.52.0.tgz", - "integrity": "sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.52.0", - "@typescript-eslint/type-utils": "8.52.0", - "@typescript-eslint/utils": "8.52.0", - "@typescript-eslint/visitor-keys": "8.52.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -5897,23 +5470,23 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.52.0", - "eslint": "^8.57.0 || ^9.0.0", + "@typescript-eslint/parser": "^8.56.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.52.0.tgz", - "integrity": "sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.52.0", - "@typescript-eslint/types": "8.52.0", - "@typescript-eslint/typescript-estree": "8.52.0", - "@typescript-eslint/visitor-keys": "8.52.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3" }, "engines": { @@ -5924,19 +5497,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.52.0.tgz", - "integrity": "sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.52.0", - "@typescript-eslint/types": "^8.52.0", + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" }, "engines": { @@ -5951,14 +5524,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.52.0.tgz", - "integrity": "sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.52.0", - "@typescript-eslint/visitor-keys": "8.52.0" + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5969,9 +5542,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.52.0.tgz", - "integrity": "sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", "dev": true, "license": "MIT", "engines": { @@ -5986,15 +5559,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.52.0.tgz", - "integrity": "sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.52.0", - "@typescript-eslint/typescript-estree": "8.52.0", - "@typescript-eslint/utils": "8.52.0", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -6006,14 +5579,14 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.52.0.tgz", - "integrity": "sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "dev": true, "license": "MIT", "engines": { @@ -6025,18 +5598,18 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.52.0.tgz", - "integrity": "sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.52.0", - "@typescript-eslint/tsconfig-utils": "8.52.0", - "@typescript-eslint/types": "8.52.0", - "@typescript-eslint/visitor-keys": "8.52.0", + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" @@ -6053,16 +5626,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.52.0.tgz", - "integrity": "sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.52.0", - "@typescript-eslint/types": "8.52.0", - "@typescript-eslint/typescript-estree": "8.52.0" + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6072,19 +5645,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.52.0.tgz", - "integrity": "sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.52.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6095,26 +5668,26 @@ } }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@unhead/vue": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-2.1.1.tgz", - "integrity": "sha512-WYa8ORhfv7lWDSoNpkMKhbW1Dbsux/3HqMcVkZS3xZ2/c/VrcChLj+IMadpCd1WNR0srITfRJhBYZ1i9hON5Qw==", + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-2.1.10.tgz", + "integrity": "sha512-VP78Onh2HNezLPfhYjfHqn4dxlcQsE6PJgTTs61NksO/thvilNswtgBq0N0MWCLtn43N5akEPGW2y2zxM3PWgQ==", "license": "MIT", "dependencies": { - "hookable": "^5.5.3", - "unhead": "2.1.1" + "hookable": "^6.0.1", + "unhead": "2.1.10" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" @@ -6123,6 +5696,12 @@ "vue": ">=3.5.18" } }, + "node_modules/@unhead/vue/node_modules/hookable": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.0.1.tgz", + "integrity": "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==", + "license": "MIT" + }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", @@ -6406,9 +5985,9 @@ ] }, "node_modules/@vercel/nft": { - "version": "0.30.4", - "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.30.4.tgz", - "integrity": "sha512-wE6eAGSXScra60N2l6jWvNtVK0m+sh873CpfZW4KI2v8EHuUQp+mSEi4T+IcdPCSEDgCdAS/7bizbhQlkjzrSA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.3.2.tgz", + "integrity": "sha512-HC8venRc4Ya7vNeBsJneKHHMDDWpQie7VaKhAIOst3MKO+DES+Y/SbzSp8mFkD7OzwAE2HhHkeSuSmwS20mz3A==", "license": "MIT", "dependencies": { "@mapbox/node-pre-gyp": "^2.0.0", @@ -6418,7 +5997,7 @@ "async-sema": "^3.1.1", "bindings": "^1.4.0", "estree-walker": "2.0.2", - "glob": "^10.5.0", + "glob": "^13.0.0", "graceful-fs": "^4.2.9", "node-gyp-build": "^4.2.2", "picomatch": "^4.0.2", @@ -6428,16 +6007,64 @@ "nft": "out/cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" + } + }, + "node_modules/@vercel/nft/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vercel/nft/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vercel/nft/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vercel/nft/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" } }, "node_modules/@vitejs/plugin-vue": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.3.tgz", - "integrity": "sha512-TlGPkLFLVOY3T7fZrwdvKpjprR3s4fxRln0ORDo1VQ7HHyxJwTlrjKU3kpVWTlaAjIEuCTokmjkZnr8Tpc925w==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.4.tgz", + "integrity": "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==", "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-beta.53" + "@rolldown/pluginutils": "1.0.0-rc.2" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -6448,15 +6075,15 @@ } }, "node_modules/@vitejs/plugin-vue-jsx": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-5.1.3.tgz", - "integrity": "sha512-I6Zr8cYVr5WHMW5gNOP09DNqW9rgO8RX73Wa6Czgq/0ndpTfJM4vfDChfOT1+3KtdrNqilNBtNlFwVeB02ZzGw==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-5.1.4.tgz", + "integrity": "sha512-70LmoVk9riR7qc4W2CpjsbNMWTPnuZb9dpFKX1emru0yP57nsc9k8nhLA6U93ngQapv5VDIUq2JatNfLbBIkrA==", "license": "MIT", "dependencies": { - "@babel/core": "^7.28.5", - "@babel/plugin-syntax-typescript": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.28.5", - "@rolldown/pluginutils": "^1.0.0-beta.56", + "@babel/core": "^7.29.0", + "@babel/plugin-syntax-typescript": "^7.28.6", + "@babel/plugin-transform-typescript": "^7.28.6", + "@rolldown/pluginutils": "^1.0.0-rc.2", "@vue/babel-plugin-jsx": "^2.0.1" }, "engines": { @@ -6467,12 +6094,6 @@ "vue": "^3.0.0" } }, - "node_modules/@vitejs/plugin-vue-jsx/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.58.tgz", - "integrity": "sha512-qWhDs6yFGR5xDfdrwiSa3CWGIHxD597uGE/A9xGqytBjANvh4rLCTTkq7szhMV4+Ygh+PMS90KVJ8xWG/TkX4w==", - "license": "MIT" - }, "node_modules/@vitest/expect": { "version": "4.0.18", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", @@ -6518,16 +6139,6 @@ } } }, - "node_modules/@vitest/mocker/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, "node_modules/@vitest/pretty-format": { "version": "4.0.18", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", @@ -6595,18 +6206,18 @@ } }, "node_modules/@volar/language-core": { - "version": "2.4.27", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.27.tgz", - "integrity": "sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==", + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", "license": "MIT", "dependencies": { - "@volar/source-map": "2.4.27" + "@volar/source-map": "2.4.28" } }, "node_modules/@volar/source-map": { - "version": "2.4.27", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.27.tgz", - "integrity": "sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==", + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", "license": "MIT" }, "node_modules/@vue-macros/common": { @@ -6715,6 +6326,12 @@ "source-map-js": "^1.2.1" } }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/@vue/compiler-dom": { "version": "3.5.29", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.29.tgz", @@ -6743,6 +6360,12 @@ "source-map-js": "^1.2.1" } }, + "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/@vue/compiler-ssr": { "version": "3.5.29", "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.29.tgz", @@ -6760,53 +6383,52 @@ "license": "MIT" }, "node_modules/@vue/devtools-core": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.0.5.tgz", - "integrity": "sha512-dpCw8nl0GDBuiL9SaY0mtDxoGIEmU38w+TQiYEPOLhW03VDC0lfNMYXS/qhl4I0YlysGp04NLY4UNn6xgD0VIQ==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.0.7.tgz", + "integrity": "sha512-PmpiPxvg3Of80ODHVvyckxwEW1Z02VIAvARIZS1xegINn3VuNQLm9iHUmKD+o6cLkMNWV8OG8x7zo0kgydZgdg==", "license": "MIT", "dependencies": { - "@vue/devtools-kit": "^8.0.5", - "@vue/devtools-shared": "^8.0.5", - "mitt": "^3.0.1", - "nanoid": "^5.1.5", - "pathe": "^2.0.3", - "vite-hot-client": "^2.1.0" + "@vue/devtools-kit": "^8.0.7", + "@vue/devtools-shared": "^8.0.7" }, "peerDependencies": { "vue": "^3.0.0" } }, "node_modules/@vue/devtools-kit": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.5.tgz", - "integrity": "sha512-q2VV6x1U3KJMTQPUlRMyWEKVbcHuxhqJdSr6Jtjz5uAThAIrfJ6WVZdGZm5cuO63ZnSUz0RCsVwiUUb0mDV0Yg==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.7.tgz", + "integrity": "sha512-H6esJGHGl5q0E9iV3m2EoBQHJ+V83WMW83A0/+Fn95eZ2iIvdsq4+UCS6yT/Fdd4cGZSchx/MdWDreM3WqMsDw==", "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^8.0.5", + "@vue/devtools-shared": "^8.0.7", "birpc": "^2.6.1", "hookable": "^5.5.3", - "mitt": "^3.0.1", - "perfect-debounce": "^2.0.0", - "speakingurl": "^14.0.1", - "superjson": "^2.2.2" + "perfect-debounce": "^2.0.0" + } + }, + "node_modules/@vue/devtools-kit/node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vue/devtools-shared": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.5.tgz", - "integrity": "sha512-bRLn6/spxpmgLk+iwOrR29KrYnJjG9DGpHGkDFG82UM21ZpJ39ztUT9OXX3g+usW7/b2z+h46I9ZiYyB07XMXg==", - "license": "MIT", - "dependencies": { - "rfdc": "^1.4.1" - } + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.7.tgz", + "integrity": "sha512-CgAb9oJH5NUmbQRdYDj/1zMiaICYSLtm+B1kxcP72LBrifGAjUmt8bx52dDH1gWRPlQgxGPqpAMKavzVirAEhA==", + "license": "MIT" }, "node_modules/@vue/language-core": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.1.tgz", - "integrity": "sha512-g6oSenpnGMtpxHGAwKuu7HJJkNZpemK/zg3vZzZbJ6cnnXq1ssxuNrXSsAHYM3NvH8p4IkTw+NLmuxyeYz4r8A==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.5.tgz", + "integrity": "sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==", "license": "MIT", "dependencies": { - "@volar/language-core": "2.4.27", + "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", "alien-signals": "^3.0.0", @@ -6878,12 +6500,13 @@ } }, "node_modules/abbrev": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", - "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, "license": "ISC", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/abort-controller": { @@ -6933,9 +6556,9 @@ } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", "peer": true, "bin": { @@ -6974,9 +6597,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7198,9 +6821,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.23", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", - "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", + "version": "10.4.27", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", + "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", "funding": [ { "type": "opencollective", @@ -7218,7 +6841,7 @@ "license": "MIT", "dependencies": { "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001760", + "caniuse-lite": "^1.0.30001774", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -7234,9 +6857,9 @@ } }, "node_modules/b4a": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", - "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", "license": "Apache-2.0", "peerDependencies": { "react-native-b4a": "*" @@ -7248,16 +6871,20 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/bare-events": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "bare-abort-controller": "*" }, @@ -7267,6 +6894,79 @@ } } }, + "node_modules/bare-fs": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.5.tgz", + "integrity": "sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.7.1.tgz", + "integrity": "sha512-ebvMaS5BgZKmJlvuWh14dg9rbUI84QeV3WlWn6Ph6lFI8jJoh7ADtVTyD2c93euwbe+zgi0DVrl4YmqXeM9aIA==", + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz", + "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==", + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.21.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", + "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -7288,12 +6988,15 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", - "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/bidi-js": { @@ -7328,9 +7031,9 @@ } }, "node_modules/birpc": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", - "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.0.0.tgz", + "integrity": "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" @@ -7343,12 +7046,15 @@ "license": "ISC" }, "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==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/braces": { @@ -7492,6 +7198,16 @@ } } }, + "node_modules/c12/node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -7597,9 +7313,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001762", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", - "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", + "version": "1.0.30001776", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz", + "integrity": "sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==", "funding": [ { "type": "opencollective", @@ -7674,9 +7390,9 @@ } }, "node_modules/ci-info": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", - "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", "dev": true, "funding": [ { @@ -7694,7 +7410,6 @@ "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", "license": "MIT", - "peer": true, "dependencies": { "consola": "^3.2.3" } @@ -7854,10 +7569,20 @@ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", "license": "MIT" }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.5.tgz", + "integrity": "sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw==", "dev": true, "license": "MIT", "engines": { @@ -7911,9 +7636,9 @@ "license": "MIT" }, "node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", "license": "MIT" }, "node_modules/config-chain": { @@ -7927,13 +7652,6 @@ "proto-list": "~1.2.1" } }, - "node_modules/config-chain/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "license": "ISC" - }, "node_modules/consola": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", @@ -7989,21 +7707,6 @@ "node": ">= 0.8" } }, - "node_modules/copy-anything": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", - "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", - "license": "MIT", - "dependencies": { - "is-what": "^5.2.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, "node_modules/copy-paste": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/copy-paste/-/copy-paste-2.2.0.tgz", @@ -8013,13 +7716,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", - "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", + "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.28.0" + "browserslist": "^4.28.1" }, "funding": { "type": "opencollective", @@ -8080,34 +7783,21 @@ "node": ">= 8" } }, - "node_modules/cross-spawn/node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/crossws": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", - "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.4.4.tgz", + "integrity": "sha512-w6c4OdpRNnudVmcgr7brb/+/HmYjMQvYToO/oTrprTwxRUiom3LYWU1PMWuD006okbUWpII1Ea9/+kwpUfmyRg==", + "dev": true, "license": "MIT", - "dependencies": { - "uncrypto": "^0.1.3" + "optional": true, + "peer": true, + "peerDependencies": { + "srvx": ">=0.7.1" + }, + "peerDependenciesMeta": { + "srvx": { + "optional": true + } } }, "node_modules/css-declaration-sorter": { @@ -8285,13 +7975,13 @@ "license": "CC0-1.0" }, "node_modules/cssstyle": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.1.0.tgz", - "integrity": "sha512-Ml4fP2UT2K3CUBQnVlbdV/8aFDdlY69E+YnwJM+3VUWl08S3J8c8aRuJqCkD9Py8DHZ7zNNvsfKl8psocHZEFg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.2.0.tgz", + "integrity": "sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^5.0.0", + "@asamuzakjp/css-color": "^5.0.1", "@csstools/css-syntax-patches-for-csstree": "^1.0.28", "css-tree": "^3.1.0", "lru-cache": "^11.2.6" @@ -8300,16 +7990,6 @@ "node": ">=20" } }, - "node_modules/cssstyle/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -8330,44 +8010,6 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/data-urls/node_modules/tr46": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", - "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/data-urls/node_modules/webidl-conversions": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", - "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20" - } - }, - "node_modules/data-urls/node_modules/whatwg-url": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", - "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.11.0", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, "node_modules/db0": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/db0/-/db0-0.3.4.tgz", @@ -8449,9 +8091,9 @@ } }, "node_modules/default-browser": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", - "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", @@ -8532,21 +8174,18 @@ } }, "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, "engines": { - "node": ">=0.10" + "node": ">=8" } }, "node_modules/devalue": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.1.tgz", - "integrity": "sha512-jDwizj+IlEZBunHcOuuFVBnIMPAEHvTsJj0BcIp94xYguLRVBcXO853px/MyIJvbVzWdsGvrRweIUWJw8hBP7A==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz", + "integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==", "license": "MIT" }, "node_modules/didyoumean": { @@ -8556,9 +8195,9 @@ "license": "Apache-2.0" }, "node_modules/diff": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", - "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -8653,9 +8292,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -8691,15 +8330,15 @@ "license": "MIT" }, "node_modules/editorconfig": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", "dev": true, "license": "MIT", "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", - "minimatch": "9.0.1", + "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { @@ -8709,24 +8348,31 @@ "node": ">=14" } }, - "node_modules/editorconfig/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "node_modules/editorconfig/node_modules/balanced-match": { + "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/editorconfig/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==", "dev": true, "license": "MIT", - "engines": { - "node": ">=14" + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -8742,9 +8388,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -8763,13 +8409,13 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.4", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", - "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" @@ -8821,9 +8467,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "license": "MIT" }, "node_modules/es-object-atoms": { @@ -8839,9 +8485,10 @@ } }, "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -8851,32 +8498,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { @@ -8895,12 +8542,13 @@ "license": "MIT" }, "node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8928,21 +8576,10 @@ "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "version": "9.39.3", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz", + "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "devOptional": true, "license": "MIT", "peer": true, @@ -8953,7 +8590,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", + "@eslint/js": "9.39.3", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -9001,34 +8638,61 @@ } }, "node_modules/eslint-config-flat-gitignore": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.1.0.tgz", - "integrity": "sha512-cJzNJ7L+psWp5mXM7jBX+fjHtBvvh06RBlcweMhKD8jWqQw0G78hOW5tpVALGHGFPsBV+ot2H+pdDGJy6CV8pA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.2.1.tgz", + "integrity": "sha512-wA5EqN0era7/7Gt5Botlsfin/UNY0etJSEeBgbUlFLFrBi47rAN//+39fI7fpYcl8RENutlFtvp/zRa/M/pZNg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint/compat": "^1.2.5" + "@eslint/compat": "^2.0.2" }, "funding": { "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "eslint": "^9.5.0" + "eslint": "^9.5.0 || ^10.0.0" } }, "node_modules/eslint-flat-config-utils": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/eslint-flat-config-utils/-/eslint-flat-config-utils-2.1.4.tgz", - "integrity": "sha512-bEnmU5gqzS+4O+id9vrbP43vByjF+8KOs+QuuV4OlqAuXmnRW2zfI/Rza1fQvdihQ5h4DUo0NqFAiViD4mSrzQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-flat-config-utils/-/eslint-flat-config-utils-3.0.1.tgz", + "integrity": "sha512-VMA3u86bLzNAwD/7DkLtQ9lolgIOx2Sj0kTMMnBvrvEz7w0rQj4aGCR+lqsqtld63gKiLyT4BnQZ3gmGDXtvjg==", "dev": true, "license": "MIT", "dependencies": { + "@eslint/config-helpers": "^0.5.2", "pathe": "^2.0.3" }, "funding": { "url": "https://github.com/sponsors/antfu" } }, + "node_modules/eslint-flat-config-utils/node_modules/@eslint/config-helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.2.tgz", + "integrity": "sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/eslint-flat-config-utils/node_modules/@eslint/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz", + "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, "node_modules/eslint-import-context": { "version": "0.1.9", "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", @@ -9068,22 +8732,16 @@ } }, "node_modules/eslint-plugin-import-lite": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-lite/-/eslint-plugin-import-lite-0.3.1.tgz", - "integrity": "sha512-9+EByHZatvWFn/lRsUja5pwah0U5lhOA6SXqTI/iIzoIJHMgmsHUHEaTlLzKU/ukyCRwKEU5E92aUURPgVWq0A==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-lite/-/eslint-plugin-import-lite-0.5.2.tgz", + "integrity": "sha512-XvfdWOC5dSLEI9krIPRlNmKSI2ViIE9pVylzfV9fCq0ZpDaNeUk6o0wZv0OzN83QdadgXp1NsY0qjLINxwYCsw==", "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": ">=9.0.0", - "typescript": ">=4.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": ">=9.0.0" } }, "node_modules/eslint-plugin-import-x": { @@ -9124,94 +8782,100 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "61.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-61.7.1.tgz", - "integrity": "sha512-36DpldF95MlTX//n3/naULFVt8d1cV4jmSkx7ZKrE9ikkKHAgMLesuWp1SmwpVwAs5ndIM6abKd6PeOYZUgdWg==", + "version": "62.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.7.1.tgz", + "integrity": "sha512-4Zvx99Q7d1uggYBUX/AIjvoyqXhluGbbKrRmG8SQTLprPFg6fa293tVJH1o1GQwNe3lUydd8ZHzn37OaSncgSQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.78.0", + "@es-joy/jsdoccomment": "~0.84.0", "@es-joy/resolve.exports": "1.2.0", "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", + "comment-parser": "1.4.5", "debug": "^4.4.3", "escape-string-regexp": "^4.0.0", - "espree": "^11.0.0", + "espree": "^11.1.0", "esquery": "^1.7.0", "html-entities": "^2.6.0", "object-deep-merge": "^2.0.0", "parse-imports-exports": "^0.2.4", - "semver": "^7.7.3", + "semver": "^7.7.4", "spdx-expression-parse": "^4.0.0", "to-valid-identifier": "^1.0.0" }, "engines": { - "node": ">=20.11.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.1.1.tgz", + "integrity": "sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-plugin-regexp": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.10.0.tgz", - "integrity": "sha512-ovzQT8ESVn5oOe5a7gIDPD5v9bCSjIFJu57sVPDqgPRXicQzOnYfFN21WoQBQF18vrhT5o7UMKFwJQVVjyJ0ng==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-3.0.0.tgz", + "integrity": "sha512-iW7hgAV8NOG6E2dz+VeKpq67YLQ9jaajOKYpoOSic2/q8y9BMdXBKkSR9gcMtbqEhNQzdW41E3wWzvhp8ExYwQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", "comment-parser": "^1.4.0", - "jsdoc-type-pratt-parser": "^4.0.0", + "jsdoc-type-pratt-parser": "^7.0.0", "refa": "^0.12.1", "regexp-ast-analysis": "^0.7.1", "scslre": "^0.3.0" }, "engines": { - "node": "^18 || >=20" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "peerDependencies": { - "eslint": ">=8.44.0" - } - }, - "node_modules/eslint-plugin-regexp/node_modules/jsdoc-type-pratt-parser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.8.0.tgz", - "integrity": "sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" + "eslint": ">=9.38.0" } }, "node_modules/eslint-plugin-unicorn": { - "version": "62.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-62.0.0.tgz", - "integrity": "sha512-HIlIkGLkvf29YEiS/ImuDZQbP12gWyx5i3C6XrRxMvVdqMroCI9qoVYCoIl17ChN+U89pn9sVwLxhIWj5nEc7g==", + "version": "63.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-63.0.0.tgz", + "integrity": "sha512-Iqecl9118uQEXYh7adylgEmGfkn5es3/mlQTLLkd4pXkIk9CTGrAbeUux+YljSa2ohXCBmQQ0+Ej1kZaFgcfkA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "@eslint-community/eslint-utils": "^4.9.0", - "@eslint/plugin-kit": "^0.4.0", "change-case": "^5.4.4", "ci-info": "^4.3.1", "clean-regexp": "^1.0.0", "core-js-compat": "^3.46.0", - "esquery": "^1.6.0", "find-up-simple": "^1.0.1", "globals": "^16.4.0", "indent-string": "^5.0.0", @@ -9233,10 +8897,23 @@ "eslint": ">=9.38.0" } }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-plugin-vue": { - "version": "10.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.6.2.tgz", - "integrity": "sha512-nA5yUs/B1KmKzvC42fyD0+l9Yd+LtEpVhWRbXuDj0e+ZURcTtyRbMDWUeJmTAh2wC6jC83raS63anNM2YT3NPw==", + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.8.0.tgz", + "integrity": "sha512-f1J/tcbnrpgC8suPN5AtdJ5MQjuXbSU9pGRSSYAuF3SHoiYCOdEX6O22pLaRyLHXvDcOe+O5ENgc1owQ587agA==", "dev": true, "license": "MIT", "dependencies": { @@ -9253,7 +8930,7 @@ "peerDependencies": { "@stylistic/eslint-plugin": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", "@typescript-eslint/parser": "^7.0.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "vue-eslint-parser": "^10.0.0" }, "peerDependenciesMeta": { @@ -9297,18 +8974,25 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", - "dev": true, + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "devOptional": true, "license": "Apache-2.0", "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -9320,19 +9004,6 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", @@ -9346,7 +9017,30 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/espree": { + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", @@ -9364,55 +9058,14 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "devOptional": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "devOptional": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-11.0.0.tgz", - "integrity": "sha512-+gMeWRrIh/NsG+3NaLeWHuyeyk70p2tbvZIWBYcqQ4/7Xvars6GYTZNhF1sIeLcc6Wb11He5ffz3hsHyXFrw5A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -9469,10 +9122,13 @@ } }, "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } }, "node_modules/esutils": { "version": "2.0.3", @@ -9616,6 +9272,18 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -9631,10 +9299,13 @@ "license": "MIT" }, "node_modules/fast-npm-meta": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/fast-npm-meta/-/fast-npm-meta-0.4.7.tgz", - "integrity": "sha512-aZU3i3eRcSb2NCq8i6N6IlyiTyF6vqAqzBGl2NBF6ngNx/GIqfYbkLDIKZ4z4P0o/RmtsFnVqHwdrSm13o4tnQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-npm-meta/-/fast-npm-meta-1.3.0.tgz", + "integrity": "sha512-Yz48hvMPiD+J5vPQj767Gdd3i6TOzqwBuvc0ylkzyxh2+VEJmtWBBy1OT1/CoeStcKhS6lBK8opUf13BNXBBYw==", "license": "MIT", + "bin": { + "fast-npm-meta": "dist/cli.mjs" + }, "funding": { "url": "https://github.com/sponsors/antfu" } @@ -9741,9 +9412,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", + "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", "devOptional": true, "license": "ISC" }, @@ -9807,9 +9478,9 @@ "license": "ISC" }, "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "hasInstallScript": true, "license": "MIT", "optional": true, @@ -9838,6 +9509,12 @@ "node": ">=10" } }, + "node_modules/fzf": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fzf/-/fzf-0.5.2.tgz", + "integrity": "sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==", + "license": "BSD-3-Clause" + }, "node_modules/generator-function": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", @@ -9921,9 +9598,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", "dev": true, "license": "MIT", "dependencies": { @@ -9950,29 +9627,11 @@ "giget": "dist/cli.mjs" } }, - "node_modules/git-up": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz", - "integrity": "sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==", - "license": "MIT", - "dependencies": { - "is-ssh": "^1.4.0", - "parse-url": "^9.2.0" - } - }, - "node_modules/git-url-parse": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-16.1.0.tgz", - "integrity": "sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==", - "license": "MIT", - "dependencies": { - "git-up": "^8.1.0" - } - }, "node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -9990,15 +9649,45 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/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/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/global-directory": { @@ -10016,10 +9705,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/globals": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", + "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", "dev": true, "license": "MIT", "engines": { @@ -10030,17 +9728,17 @@ } }, "node_modules/globby": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-15.0.0.tgz", - "integrity": "sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.1.1.tgz", + "integrity": "sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==", "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "fast-glob": "^3.3.3", "ignore": "^7.0.5", - "path-type": "^6.0.0", + "is-path-inside": "^4.0.0", "slash": "^5.1.0", - "unicorn-magic": "^0.3.0" + "unicorn-magic": "^0.4.0" }, "engines": { "node": ">=20" @@ -10099,6 +9797,38 @@ "uncrypto": "^0.1.3" } }, + "node_modules/h3-next": { + "name": "h3", + "version": "2.0.1-rc.11", + "resolved": "https://registry.npmjs.org/h3/-/h3-2.0.1-rc.11.tgz", + "integrity": "sha512-2myzjCqy32c1As9TjZW9fNZXtLqNedjFSrdFy2AjFBQQ3LzrnGoDdFDYfC0tV2e4vcyfJ2Sfo/F6NQhO2Ly/Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "rou3": "^0.7.12", + "srvx": "^0.10.1" + }, + "engines": { + "node": ">=20.11.1" + }, + "peerDependencies": { + "crossws": "^0.4.1" + }, + "peerDependenciesMeta": { + "crossws": { + "optional": true + } + } + }, + "node_modules/h3/node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -10366,16 +10096,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/impound": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/impound/-/impound-1.0.0.tgz", @@ -10389,6 +10109,21 @@ "unplugin-utils": "^0.2.4" } }, + "node_modules/impound/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -10430,21 +10165,19 @@ "license": "ISC" }, "node_modules/ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" }, "node_modules/ioredis": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.8.2.tgz", - "integrity": "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.0.tgz", + "integrity": "sha512-HVBe9OFuqs+Z6n64q09PQvP1/R4Bm+30PAyyD4wIEqssh3v9L21QjCVk4kRLucMBcDokJTcLjsGeVRlq/nH6DA==", "license": "MIT", "dependencies": { - "@ioredis/commands": "1.4.0", + "@ioredis/commands": "1.5.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", @@ -10673,15 +10406,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-ssh": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", - "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", - "license": "MIT", - "dependencies": { - "protocols": "^2.0.1" - } - }, "node_modules/is-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", @@ -10694,22 +10418,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-what": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", - "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" @@ -10743,13 +10455,10 @@ "license": "MIT" }, "node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "license": "ISC", - "engines": { - "node": ">=16" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, "node_modules/jackspeak": { "version": "3.4.3", @@ -10798,32 +10507,6 @@ "node": ">=14" } }, - "node_modules/js-beautify/node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/js-beautify/node_modules/nopt": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/js-cookie": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", @@ -10854,9 +10537,9 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.0.0.tgz", - "integrity": "sha512-c7YbokssPOSHmqTbSAmTtnVgAVa/7lumWNYqomgd5KOMyPrRve2anx6lonfOsXEQacqF9FKVUj7bLg4vRSvdYA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.1.1.tgz", + "integrity": "sha512-/2uqY7x6bsrpi3i9LVU6J89352C0rpMk0as8trXxCtvd4kPk1ke/Eyif6wqfSLvoNJqcDG9Vk4UsXgygzCt2xA==", "dev": true, "license": "MIT", "engines": { @@ -10905,44 +10588,6 @@ } } }, - "node_modules/jsdom/node_modules/tr46": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", - "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/jsdom/node_modules/webidl-conversions": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", - "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20" - } - }, - "node_modules/jsdom/node_modules/whatwg-url": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", - "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.11.0", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, "node_modules/jsdom/node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -11017,19 +10662,6 @@ "url": "https://github.com/sponsors/ota-meshi" } }, - "node_modules/jsonc-eslint-parser/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/jsonc-eslint-parser/node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -11064,7 +10696,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "license": "MIT", "dependencies": { "tsscmp": "1.0.6" @@ -11084,9 +10715,9 @@ } }, "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "license": "MIT", "engines": { "node": ">=6" @@ -11108,9 +10739,9 @@ "license": "MIT" }, "node_modules/koa": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.16.3.tgz", - "integrity": "sha512-zPPuIt+ku1iCpFBRwseMcPYQ1cJL8l60rSmKeOuGfOXyE6YnTBmf2aEFNL2HQGrD0cPcLO/t+v9RTgC+fwEh/g==", + "version": "2.16.4", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.16.4.tgz", + "integrity": "sha512-3An0GCLDSR34tsCO4H8Tef8Pp2ngtaZDAZnsWJYelqXUK5wyiHvGItgK/xcSkmHLSTn1Jcho1mRQs2ehRzvKKw==", "license": "MIT", "dependencies": { "accepts": "^1.3.5", @@ -11283,9 +10914,9 @@ } }, "node_modules/launch-editor": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz", - "integrity": "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.13.1.tgz", + "integrity": "sha512-lPSddlAAluRKJ7/cjRFoXUFzaX7q/YKI7yPHuEvSJVqoXvFnJov1/Ud87Aa4zULIbA9Nja4mSPK8l0z/7eV2wA==", "license": "MIT", "dependencies": { "picocolors": "^1.1.1", @@ -11396,6 +11027,15 @@ "listhen": "bin/listhen.mjs" } }, + "node_modules/listhen/node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, "node_modules/listhen/node_modules/pathe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", @@ -11436,9 +11076,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, "node_modules/lodash.defaults": { @@ -11473,12 +11113,12 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, "node_modules/magic-regexp": { @@ -11496,13 +11136,19 @@ "unplugin": "^2.0.0" } }, - "node_modules/magic-regexp/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/magic-regexp/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0" + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" } }, "node_modules/magic-string": { @@ -11530,13 +11176,13 @@ } }, "node_modules/magicast": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", - "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, @@ -11678,25 +11324,25 @@ } }, "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", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -11713,12 +11359,6 @@ "node": ">= 18" } }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "license": "MIT" - }, "node_modules/mlly": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", @@ -11787,9 +11427,9 @@ } }, "node_modules/nanoid": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", - "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", @@ -11798,16 +11438,16 @@ ], "license": "MIT", "bin": { - "nanoid": "bin/nanoid.js" + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": "^18 || >=20" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/nanotar": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nanotar/-/nanotar-0.2.0.tgz", - "integrity": "sha512-9ca1h0Xjvo9bEkE4UOxgAzLV0jHKe6LMaxo37ND2DAhhAtd0j8pR1Wxz+/goMrZO8AEZTWCmyaOsFI/W5AdpCQ==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/nanotar/-/nanotar-0.2.1.tgz", + "integrity": "sha512-MUrzzDUcIOPbv7ubhDV/L4CIfVTATd9XhDE2ixFeCrM5yp9AlzUpn91JrnN0HD6hksdxvz9IW9aKANz0Bta0GA==", "license": "MIT" }, "node_modules/napi-postinstall": { @@ -11843,23 +11483,23 @@ } }, "node_modules/nitropack": { - "version": "2.12.9", - "resolved": "https://registry.npmjs.org/nitropack/-/nitropack-2.12.9.tgz", - "integrity": "sha512-t6qqNBn2UDGMWogQuORjbL2UPevB8PvIPsPHmqvWpeGOlPr4P8Oc5oA8t3wFwGmaolM2M/s2SwT23nx9yARmOg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/nitropack/-/nitropack-2.13.1.tgz", + "integrity": "sha512-2dDj89C4wC2uzG7guF3CnyG+zwkZosPEp7FFBGHB3AJo11AywOolWhyQJFHDzve8COvGxJaqscye9wW2IrUsNw==", "license": "MIT", "dependencies": { - "@cloudflare/kv-asset-handler": "^0.4.0", - "@rollup/plugin-alias": "^5.1.1", - "@rollup/plugin-commonjs": "^28.0.9", + "@cloudflare/kv-asset-handler": "^0.4.2", + "@rollup/plugin-alias": "^6.0.0", + "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-inject": "^5.0.5", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.3", - "@rollup/plugin-replace": "^6.0.2", + "@rollup/plugin-replace": "^6.0.3", "@rollup/plugin-terser": "^0.4.4", - "@vercel/nft": "^0.30.3", + "@vercel/nft": "^1.2.0", "archiver": "^7.0.1", - "c12": "^3.3.1", - "chokidar": "^4.0.3", + "c12": "^3.3.3", + "chokidar": "^5.0.0", "citty": "^0.1.6", "compatx": "^0.2.0", "confbox": "^0.2.2", @@ -11871,52 +11511,52 @@ "defu": "^6.1.4", "destr": "^2.0.5", "dot-prop": "^10.1.0", - "esbuild": "^0.25.11", + "esbuild": "^0.27.2", "escape-string-regexp": "^5.0.0", "etag": "^1.8.1", - "exsolve": "^1.0.7", - "globby": "^15.0.0", + "exsolve": "^1.0.8", + "globby": "^16.1.0", "gzip-size": "^7.0.0", - "h3": "^1.15.4", + "h3": "^1.15.5", "hookable": "^5.5.3", "httpxy": "^0.1.7", - "ioredis": "^5.8.2", + "ioredis": "^5.9.1", "jiti": "^2.6.1", "klona": "^2.0.6", - "knitwork": "^1.2.0", + "knitwork": "^1.3.0", "listhen": "^1.9.0", "magic-string": "^0.30.21", - "magicast": "^0.5.0", + "magicast": "^0.5.1", "mime": "^4.1.0", "mlly": "^1.8.0", "node-fetch-native": "^1.6.7", - "node-mock-http": "^1.0.3", - "ofetch": "^1.5.0", + "node-mock-http": "^1.0.4", + "ofetch": "^1.5.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "pretty-bytes": "^7.1.0", "radix3": "^1.1.2", - "rollup": "^4.52.5", + "rollup": "^4.55.1", "rollup-plugin-visualizer": "^6.0.5", "scule": "^1.3.0", "semver": "^7.7.3", "serve-placeholder": "^2.0.2", - "serve-static": "^2.2.0", + "serve-static": "^2.2.1", "source-map": "^0.7.6", "std-env": "^3.10.0", - "ufo": "^1.6.1", + "ufo": "^1.6.3", "ultrahtml": "^1.6.0", "uncrypto": "^0.1.3", - "unctx": "^2.4.1", - "unenv": "^2.0.0-rc.23", - "unimport": "^5.5.0", + "unctx": "^2.5.0", + "unenv": "^2.0.0-rc.24", + "unimport": "^5.6.0", "unplugin-utils": "^0.3.1", - "unstorage": "^1.17.1", + "unstorage": "^1.17.4", "untyped": "^2.0.0", - "unwasm": "^0.3.11", - "youch": "^4.1.0-beta.11", + "unwasm": "^0.5.3", + "youch": "^4.1.0-beta.13", "youch-core": "^0.3.3" }, "bin": { @@ -11936,9 +11576,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", "cpu": [ "ppc64" ], @@ -11952,9 +11592,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", "cpu": [ "arm" ], @@ -11968,9 +11608,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", "cpu": [ "arm64" ], @@ -11984,9 +11624,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", "cpu": [ "x64" ], @@ -12000,9 +11640,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", "cpu": [ "arm64" ], @@ -12016,9 +11656,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", "cpu": [ "x64" ], @@ -12032,9 +11672,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", "cpu": [ "arm64" ], @@ -12048,9 +11688,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", "cpu": [ "x64" ], @@ -12064,9 +11704,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", "cpu": [ "arm" ], @@ -12080,9 +11720,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", "cpu": [ "arm64" ], @@ -12096,9 +11736,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", "cpu": [ "ia32" ], @@ -12112,9 +11752,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", "cpu": [ "loong64" ], @@ -12128,9 +11768,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", "cpu": [ "mips64el" ], @@ -12144,9 +11784,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", "cpu": [ "ppc64" ], @@ -12160,9 +11800,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", "cpu": [ "riscv64" ], @@ -12176,9 +11816,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", "cpu": [ "s390x" ], @@ -12192,9 +11832,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", "cpu": [ "x64" ], @@ -12208,9 +11848,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", "cpu": [ "arm64" ], @@ -12224,9 +11864,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", "cpu": [ "x64" ], @@ -12240,9 +11880,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", "cpu": [ "arm64" ], @@ -12256,9 +11896,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", "cpu": [ "x64" ], @@ -12272,9 +11912,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", "cpu": [ "arm64" ], @@ -12288,9 +11928,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", "cpu": [ "x64" ], @@ -12304,9 +11944,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", "cpu": [ "arm64" ], @@ -12320,9 +11960,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", "cpu": [ "ia32" ], @@ -12336,9 +11976,9 @@ } }, "node_modules/nitropack/node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "cpu": [ "x64" ], @@ -12351,31 +11991,25 @@ "node": ">=18" } }, - "node_modules/nitropack/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/nitropack/node_modules/cookie-es": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.0.tgz", "integrity": "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==", "license": "MIT" }, + "node_modules/nitropack/node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, "node_modules/nitropack/node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -12385,45 +12019,53 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, - "node_modules/nitropack/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "node_modules/nitropack/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">=12" }, "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nitropack/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" } }, "node_modules/nitropack/node_modules/unplugin-utils": { @@ -12474,6 +12116,28 @@ "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", "license": "MIT" }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", @@ -12501,24 +12165,25 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", "license": "MIT" }, "node_modules/nopt": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", - "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, "license": "ISC", "dependencies": { - "abbrev": "^3.0.0" + "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/normalize-path": { @@ -12570,34 +12235,33 @@ } }, "node_modules/nuxt": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-3.20.2.tgz", - "integrity": "sha512-DoayekzYjYmGj7A5iI7crBiLRTq1K8U1DLgAR/vGADh1IQfOLagn5Klg1Jn1xxIyN8x0iiFDf3dGd2JWyiKBLA==", + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-3.21.1.tgz", + "integrity": "sha512-lrrQY2+nN7BhoaBOgWMks0xtKz4qjpczVmM0Uk7tCVQDQTs14eR/YDkjhMM1vCLfzlspW0lBHmJFcGvNUXiT7g==", "license": "MIT", - "peer": true, "dependencies": { - "@dxup/nuxt": "^0.2.2", - "@nuxt/cli": "^3.31.1", + "@dxup/nuxt": "^0.3.2", + "@nuxt/cli": "^3.33.0", "@nuxt/devtools": "^3.1.1", - "@nuxt/kit": "3.20.2", - "@nuxt/nitro-server": "3.20.2", - "@nuxt/schema": "3.20.2", - "@nuxt/telemetry": "^2.6.6", - "@nuxt/vite-builder": "3.20.2", - "@unhead/vue": "^2.0.19", - "@vue/shared": "^3.5.25", - "c12": "^3.3.2", + "@nuxt/kit": "3.21.1", + "@nuxt/nitro-server": "3.21.1", + "@nuxt/schema": "3.21.1", + "@nuxt/telemetry": "^2.7.0", + "@nuxt/vite-builder": "3.21.1", + "@unhead/vue": "^2.1.3", + "@vue/shared": "^3.5.27", + "c12": "^3.3.3", "chokidar": "^5.0.0", "compatx": "^0.2.0", "consola": "^3.4.2", "cookie-es": "^2.0.0", "defu": "^6.1.4", "destr": "^2.0.5", - "devalue": "^5.6.0", + "devalue": "^5.6.2", "errx": "^0.1.0", "escape-string-regexp": "^5.0.0", "exsolve": "^1.0.8", - "h3": "^1.15.4", + "h3": "^1.15.5", "hookable": "^5.5.3", "ignore": "^7.0.5", "impound": "^1.0.0", @@ -12607,32 +12271,32 @@ "magic-string": "^0.30.21", "mlly": "^1.8.0", "nanotar": "^0.2.0", - "nypm": "^0.6.2", + "nypm": "^0.6.5", "ofetch": "^1.5.1", "ohash": "^2.0.11", - "on-change": "^6.0.1", - "oxc-minify": "^0.102.0", - "oxc-parser": "^0.102.0", - "oxc-transform": "^0.102.0", - "oxc-walker": "^0.6.0", + "on-change": "^6.0.2", + "oxc-minify": "^0.112.0", + "oxc-parser": "^0.112.0", + "oxc-transform": "^0.112.0", + "oxc-walker": "^0.7.0", "pathe": "^2.0.3", - "perfect-debounce": "^2.0.0", + "perfect-debounce": "^2.1.0", "pkg-types": "^2.3.0", - "radix3": "^1.1.2", + "rou3": "^0.7.12", "scule": "^1.3.0", - "semver": "^7.7.3", + "semver": "^7.7.4", "std-env": "^3.10.0", "tinyglobby": "^0.2.15", - "ufo": "^1.6.1", + "ufo": "^1.6.3", "ultrahtml": "^1.6.0", "uncrypto": "^0.1.3", - "unctx": "^2.4.1", - "unimport": "^5.5.0", - "unplugin": "^2.3.11", - "unplugin-vue-router": "^0.19.0", + "unctx": "^2.5.0", + "unimport": "^5.6.0", + "unplugin": "^3.0.0", + "unplugin-vue-router": "^0.19.2", "untyped": "^2.0.0", - "vue": "^3.5.25", - "vue-router": "^4.6.3" + "vue": "^3.5.27", + "vue-router": "^4.6.4" }, "bin": { "nuxi": "bin/nuxt.mjs", @@ -12665,9 +12329,9 @@ } }, "node_modules/nuxt-quasar-ui": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/nuxt-quasar-ui/-/nuxt-quasar-ui-3.0.0.tgz", - "integrity": "sha512-STM4HFt5c57swSR2EwScLGASy67lkV/UJmadkiSsvda4ejpRpAf3AmuwbiE0MWnrouMObDZ8U3CrQ/bTBgQDjA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nuxt-quasar-ui/-/nuxt-quasar-ui-3.0.1.tgz", + "integrity": "sha512-m4mgHgCfinCseWhaamAn+W7hX/X0Mi79R6WuRZizVMXyzsLZGmUEW5ks/PL6QIwqc1/VQb0NZYpZ+lQHaG0iwQ==", "license": "MIT", "dependencies": { "@nuxt/kit": "^4.2.1", @@ -12683,12 +12347,12 @@ } }, "node_modules/nuxt-quasar-ui/node_modules/@nuxt/kit": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.2.2.tgz", - "integrity": "sha512-ZAgYBrPz/yhVgDznBNdQj2vhmOp31haJbO0I0iah/P9atw+OHH7NJLUZ3PK+LOz/0fblKTN1XJVSi8YQ1TQ0KA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.3.1.tgz", + "integrity": "sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA==", "license": "MIT", "dependencies": { - "c12": "^3.3.2", + "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", @@ -12701,24 +12365,691 @@ "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", - "rc9": "^2.1.2", + "rc9": "^3.0.0", "scule": "^1.3.0", - "semver": "^7.7.3", + "semver": "^7.7.4", "tinyglobby": "^0.2.15", - "ufo": "^1.6.1", - "unctx": "^2.4.1", + "ufo": "^1.6.3", + "unctx": "^2.5.0", "untyped": "^2.0.0" }, "engines": { "node": ">=18.12.0" } }, + "node_modules/nuxt/node_modules/@nuxt/schema": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.21.1.tgz", + "integrity": "sha512-9cTtB0IFoly+/51yHK5eBooangJuFH9twZJCBPxttxQPwsdG9OgInMuESmGhSVzp8QG4P0lPF7i9ZlgFiQkNgw==", + "license": "MIT", + "dependencies": { + "@vue/shared": "^3.5.27", + "defu": "^6.1.4", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "std-env": "^3.10.0" + }, + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.112.0.tgz", + "integrity": "sha512-pRkbBRbuIIsufUWpOJ+JHWfJFNupkidy4sbjfcm37e6xwYrn9LSKMLubPHvNaL1Zf92ZRhGiwaYkEcmaFg2VcA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.112.0.tgz", + "integrity": "sha512-fh6/KQL/cbH5DukT3VkdCqnULLuvVnszVKySD5IgSE0WZb32YZo/cPsPdEv052kk6w3N4agu+NTiMnZjcvhUIg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.112.0.tgz", + "integrity": "sha512-vUBOOY1E30vlu/DoTGDoT1UbLlwu5Yv9tqeBabAwRzwNDz8Skho16VKhsBDUiyqddtpsR3//v6vNk38w4c+6IA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.112.0.tgz", + "integrity": "sha512-hnEtO/9AVnYWzrgnp6L+oPs/6UqlFeteUL6n7magkd2tttgmx1C01hyNNh6nTpZfLzEVJSNJ0S+4NTsK2q2CxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.112.0.tgz", + "integrity": "sha512-WxJrUz3pcIc2hp4lvJbvt/sTL33oX9NPvkD3vDDybE6tc0V++rS+hNOJxwXdD2FDIFPkHs/IEn5asEZFVH+VKw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.112.0.tgz", + "integrity": "sha512-jj8A8WWySaJQqM9XKAIG8U2Q3qxhFQKrXPWv98d1oC35at+L1h+C+V4M3l8BAKhpHKCu3dYlloaAbHd5q1Hw6A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.112.0.tgz", + "integrity": "sha512-G2F8H6FcAExVK5vvhpSh61tqWx5QoaXXUnSsj5FyuDiFT/K7AMMVSQVqnZREDc+YxhrjB0vnKjCcuobXK63kIw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.112.0.tgz", + "integrity": "sha512-3R0iqjM3xYOZCnwgcxOQXH7hrz64/USDIuLbNTM1kZqQzRqaR4w7SwoWKU934zABo8d0op2oSwOp+CV3hZnM7A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.112.0.tgz", + "integrity": "sha512-2QlvQBUhHuAE3ezD4X3CAEKMXdfgInggQ5Bj/7gb5NcYP3GyfLTj7c+mMu+BRwfC9B3AXBNyqHWbqEuuUvZyRQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.112.0.tgz", + "integrity": "sha512-+5HhNHtxsdcd7+ljXFnn9FOoCNXJX3UPgIfIE6vdwS1HqdGNH6eAcVobuqGOp54l8pvcxDQA6F4cPswCgLrQfQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.112.0.tgz", + "integrity": "sha512-jKwO7ZLNkjxwg7FoCLw+fJszooL9yXRZsDN0AQ1AQUTWq1l8GH/2e44k68N3fcP19jl8O8jGpqLAZcQTYk6skA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.112.0.tgz", + "integrity": "sha512-TYqnuKV/p3eOc+N61E0961nA7DC+gaCeJ3+V2LcjJdTwFMdikqWL6uVk1jlrpUCBrozHDATVUKDZYH7r4FQYjQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.112.0.tgz", + "integrity": "sha512-Gr8X2PUU3hX1g3F5oLWIZB8DhzDmjr5TfOrmn5tlBOo9l8ojPGdKjnIBfObM7X15928vza8QRKW25RTR7jfivg==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.112.0.tgz", + "integrity": "sha512-t5CDLbU70Ea88bGRhvU/dLJTc/Wcrtf2Jp534E8P3cgjAvHDjdKsfDDqBZrhybJ8Jv9v9vW5ngE40EK51BluDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.112.0.tgz", + "integrity": "sha512-oGHluohzmVFAuQrkEnl1OXAxMz2aYmimxUqIgKXpBgbr7PvFv0doELB273sX+5V3fKeggohKg1A2Qq21W9Z9cQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-project/types": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.112.0.tgz", + "integrity": "sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-android-arm64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.112.0.tgz", + "integrity": "sha512-ve46vQcQrY8eGe8990VSlS9gkD+AogJqbtfOkeua+5sQGQTDgeIRRxOm7ktCo19uZc2bEBwXRJITgosd+NRVmQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-darwin-arm64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.112.0.tgz", + "integrity": "sha512-ddbmLU3Tr+i7MOynfwAXxUXud3SjJKlv7XNjaq08qiI8Av/QvhXVGc2bMhXkWQSMSBUeTDoiughKjK+Zsb6y/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-darwin-x64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.112.0.tgz", + "integrity": "sha512-TKvmNw96jQZPqYb4pRrzLFDailNB3YS14KNn+x2hwRbqc6CqY96S9PYwyOpVpYdxfoRjYO9WgX9SoS+62a1DPA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-freebsd-x64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.112.0.tgz", + "integrity": "sha512-YPMkSCDaelO8HHYRMYjm+Q+IfkfIbdtQzwPuasItYkq8UUkNeHNPheNh2JkvQa3c+io3E9ePOgHQ2yihpk7o/Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-linux-arm-gnueabihf": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.112.0.tgz", + "integrity": "sha512-nA7kzQGNEpuTRknst/IJ3l8hqmDmEda3aun6jkXgp7gKxESjuHeaNH04mKISxvJ7fIacvP2g/wtTSnm4u5jL8Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-linux-arm-musleabihf": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.112.0.tgz", + "integrity": "sha512-w8GuLmckKlGc3YujaZKhtbFxziCcosvM2l9GnQjCb/yENWLGDiyQOy0BTAgPGdJwpYTiOeJblEXSuXYvlE1Ong==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-linux-arm64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.112.0.tgz", + "integrity": "sha512-9LwwGnJ8+WT0rXcrI8M0RJtDNt91eMqcDPPEvJxhRFHIMcHTy5D5xT+fOl3Us0yMqKo3HUWkbfUYqAp4GoZ3Jw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-linux-arm64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.112.0.tgz", + "integrity": "sha512-Lg6VOuSd3oXv7J0eGywgqh/086h+qQzIBOD+47pYKMTTJcbDe+f3h/RgGoMKJE5HhiwT5sH1aGEJfIfaYUiVSw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-linux-riscv64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.112.0.tgz", + "integrity": "sha512-vhJsMsVH/6xwa3bt1LGts33FXUkGjaEGDwsRyp4lIfOjSfQVWMtCmWMFNaA0dW9FVWdD2Gt2fSFBSZ+azDxlpg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-linux-s390x-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.112.0.tgz", + "integrity": "sha512-eEFu4SRqJTJ20/88KRWmp+jpHKAw0Y1DsnSgpEeXyBIIcsOaLIUMU/TfYWUmqRbvbMV9rmOmI3kp5xWYUq6kSQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-linux-x64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.112.0.tgz", + "integrity": "sha512-ST1MDT+TlOyZ1c5btrGinRSUW2Jf4Pa+0gdKwsyjDSOC3dxy2ZNkN3mosTf4ywc3J+mxfYKqtjs7zSwHz03ILA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-linux-x64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.112.0.tgz", + "integrity": "sha512-ISQoA3pD4cyTGpf9sXXeerH6pL2L6EIpdy6oAy2ttkswyVFDyQNVOVIGIdLZDgbpmqGljxZnWqt/J/N68pQaig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-wasm32-wasi": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.112.0.tgz", + "integrity": "sha512-XIX7Gpq9koAvzBVHDlVFHM79r5uOVK6kTEsdsN4qaajpjkgtv4tdsAOKIYK6l7fUbsbE6xS+6w1+yRFrDeC1kg==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-win32-arm64-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.112.0.tgz", + "integrity": "sha512-EgXef9kOne9BNsbYBbuRqxk2hteT0xsAGcx/VbtCBMJYNj8fANFhT271DUSOgfa4DAgrQQmsyt/Kr1aV9mpU9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/nuxt/node_modules/@oxc-transform/binding-win32-x64-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.112.0.tgz", + "integrity": "sha512-FRKYlY959QeqRPx9kXs0HjU2xuXPT1cdF+vvA200D9uAX/KLcC34MwRqUKTYml4kCc2Vf/P2pBR9cQuBm3zECQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/nuxt/node_modules/cookie-es": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.0.tgz", "integrity": "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==", "license": "MIT" }, + "node_modules/nuxt/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nuxt/node_modules/oxc-parser": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.112.0.tgz", + "integrity": "sha512-7rQ3QdJwobMQLMZwQaPuPYMEF2fDRZwf51lZ//V+bA37nejjKW5ifMHbbCwvA889Y4RLhT+/wLJpPRhAoBaZYw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oxc-project/types": "^0.112.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.112.0", + "@oxc-parser/binding-android-arm64": "0.112.0", + "@oxc-parser/binding-darwin-arm64": "0.112.0", + "@oxc-parser/binding-darwin-x64": "0.112.0", + "@oxc-parser/binding-freebsd-x64": "0.112.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.112.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.112.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.112.0", + "@oxc-parser/binding-linux-arm64-musl": "0.112.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.112.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.112.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.112.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.112.0", + "@oxc-parser/binding-linux-x64-gnu": "0.112.0", + "@oxc-parser/binding-linux-x64-musl": "0.112.0", + "@oxc-parser/binding-openharmony-arm64": "0.112.0", + "@oxc-parser/binding-wasm32-wasi": "0.112.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.112.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.112.0", + "@oxc-parser/binding-win32-x64-msvc": "0.112.0" + } + }, + "node_modules/nuxt/node_modules/oxc-transform": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.112.0.tgz", + "integrity": "sha512-cIRRvZgrHfsAHrkt8LWdAX4+Do8R0MzQSfeo9yzErzHeYiuyNiP4PCTPbOy/wBXL4MYzt3ebrBa5jt3akQkKAg==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-transform/binding-android-arm-eabi": "0.112.0", + "@oxc-transform/binding-android-arm64": "0.112.0", + "@oxc-transform/binding-darwin-arm64": "0.112.0", + "@oxc-transform/binding-darwin-x64": "0.112.0", + "@oxc-transform/binding-freebsd-x64": "0.112.0", + "@oxc-transform/binding-linux-arm-gnueabihf": "0.112.0", + "@oxc-transform/binding-linux-arm-musleabihf": "0.112.0", + "@oxc-transform/binding-linux-arm64-gnu": "0.112.0", + "@oxc-transform/binding-linux-arm64-musl": "0.112.0", + "@oxc-transform/binding-linux-ppc64-gnu": "0.112.0", + "@oxc-transform/binding-linux-riscv64-gnu": "0.112.0", + "@oxc-transform/binding-linux-riscv64-musl": "0.112.0", + "@oxc-transform/binding-linux-s390x-gnu": "0.112.0", + "@oxc-transform/binding-linux-x64-gnu": "0.112.0", + "@oxc-transform/binding-linux-x64-musl": "0.112.0", + "@oxc-transform/binding-openharmony-arm64": "0.112.0", + "@oxc-transform/binding-wasm32-wasi": "0.112.0", + "@oxc-transform/binding-win32-arm64-msvc": "0.112.0", + "@oxc-transform/binding-win32-ia32-msvc": "0.112.0", + "@oxc-transform/binding-win32-x64-msvc": "0.112.0" + } + }, + "node_modules/nuxt/node_modules/oxc-walker": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-0.7.0.tgz", + "integrity": "sha512-54B4KUhrzbzc4sKvKwVYm7E2PgeROpGba0/2nlNZMqfDyca+yOor5IMb4WLGBatGDT0nkzYdYuzylg7n3YfB7A==", + "license": "MIT", + "dependencies": { + "magic-regexp": "^0.10.0" + }, + "peerDependencies": { + "oxc-parser": ">=0.98.0" + } + }, + "node_modules/nuxt/node_modules/unplugin-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/nuxt/node_modules/unplugin-vue-router": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/unplugin-vue-router/-/unplugin-vue-router-0.19.2.tgz", + "integrity": "sha512-u5dgLBarxE5cyDK/hzJGfpCTLIAyiTXGlo85COuD4Nssj6G7NxS+i9mhCWz/1p/ud1eMwdcUbTXehQe41jYZUA==", + "deprecated": "Merged into vuejs/router. Migrate: https://router.vuejs.org/guide/migration/v4-to-v5.html", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.28.5", + "@vue-macros/common": "^3.1.1", + "@vue/language-core": "^3.2.1", + "ast-walker-scope": "^0.8.3", + "chokidar": "^5.0.0", + "json5": "^2.2.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "muggle-string": "^0.4.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "scule": "^1.3.0", + "tinyglobby": "^0.2.15", + "unplugin": "^2.3.11", + "unplugin-utils": "^0.3.1", + "yaml": "^2.8.2" + }, + "peerDependencies": { + "@vue/compiler-sfc": "^3.5.17", + "vue-router": "^4.6.0" + }, + "peerDependenciesMeta": { + "vue-router": { + "optional": true + } + } + }, + "node_modules/nuxt/node_modules/unplugin-vue-router/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/nypm": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.5.tgz", @@ -12795,9 +13126,9 @@ "license": "MIT" }, "node_modules/on-change": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/on-change/-/on-change-6.0.1.tgz", - "integrity": "sha512-P7o0hkMahOhjb1niG28vLNAXsJrRcfpJvYWcTmPt/Tf4xedcF2PA1E9++N1tufY8/vIsaiJgHhjQp53hJCe+zw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/on-change/-/on-change-6.0.2.tgz", + "integrity": "sha512-08+12qcOVEA0fS9g/VxKS27HaT94nRutUT77J2dr8zv/unzXopvhBuF8tNLWsoLQ5IgrQ6eptGeGqUYat82U1w==", "license": "MIT", "engines": { "node": ">=20" @@ -12911,9 +13242,9 @@ } }, "node_modules/oxc-minify": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/oxc-minify/-/oxc-minify-0.102.0.tgz", - "integrity": "sha512-FphAHDyTCNepQbiQTSyWFMbNc9zdUmj1WBsoLwvZhWm7rEe/IeIKYKRhy75lWOjwFsi5/i4Qucq43hgs3n2Exw==", + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/oxc-minify/-/oxc-minify-0.112.0.tgz", + "integrity": "sha512-rkVSeeIRSt+RYI9uX6xonBpLUpvZyegxIg0UL87ev7YAfUqp7IIZlRjkgQN5Us1lyXD//TOo0Dcuuro/TYOWoQ==", "license": "MIT", "engines": { "node": "^20.19.0 || >=22.12.0" @@ -12922,31 +13253,37 @@ "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-minify/binding-android-arm64": "0.102.0", - "@oxc-minify/binding-darwin-arm64": "0.102.0", - "@oxc-minify/binding-darwin-x64": "0.102.0", - "@oxc-minify/binding-freebsd-x64": "0.102.0", - "@oxc-minify/binding-linux-arm-gnueabihf": "0.102.0", - "@oxc-minify/binding-linux-arm64-gnu": "0.102.0", - "@oxc-minify/binding-linux-arm64-musl": "0.102.0", - "@oxc-minify/binding-linux-riscv64-gnu": "0.102.0", - "@oxc-minify/binding-linux-s390x-gnu": "0.102.0", - "@oxc-minify/binding-linux-x64-gnu": "0.102.0", - "@oxc-minify/binding-linux-x64-musl": "0.102.0", - "@oxc-minify/binding-openharmony-arm64": "0.102.0", - "@oxc-minify/binding-wasm32-wasi": "0.102.0", - "@oxc-minify/binding-win32-arm64-msvc": "0.102.0", - "@oxc-minify/binding-win32-x64-msvc": "0.102.0" + "@oxc-minify/binding-android-arm-eabi": "0.112.0", + "@oxc-minify/binding-android-arm64": "0.112.0", + "@oxc-minify/binding-darwin-arm64": "0.112.0", + "@oxc-minify/binding-darwin-x64": "0.112.0", + "@oxc-minify/binding-freebsd-x64": "0.112.0", + "@oxc-minify/binding-linux-arm-gnueabihf": "0.112.0", + "@oxc-minify/binding-linux-arm-musleabihf": "0.112.0", + "@oxc-minify/binding-linux-arm64-gnu": "0.112.0", + "@oxc-minify/binding-linux-arm64-musl": "0.112.0", + "@oxc-minify/binding-linux-ppc64-gnu": "0.112.0", + "@oxc-minify/binding-linux-riscv64-gnu": "0.112.0", + "@oxc-minify/binding-linux-riscv64-musl": "0.112.0", + "@oxc-minify/binding-linux-s390x-gnu": "0.112.0", + "@oxc-minify/binding-linux-x64-gnu": "0.112.0", + "@oxc-minify/binding-linux-x64-musl": "0.112.0", + "@oxc-minify/binding-openharmony-arm64": "0.112.0", + "@oxc-minify/binding-wasm32-wasi": "0.112.0", + "@oxc-minify/binding-win32-arm64-msvc": "0.112.0", + "@oxc-minify/binding-win32-ia32-msvc": "0.112.0", + "@oxc-minify/binding-win32-x64-msvc": "0.112.0" } }, "node_modules/oxc-parser": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.102.0.tgz", - "integrity": "sha512-xMiyHgr2FZsphQ12ZCsXRvSYzmKXCm1ejmyG4GDZIiKOmhyt5iKtWq0klOfFsEQ6jcgbwrUdwcCVYzr1F+h5og==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.95.0.tgz", + "integrity": "sha512-Te8fE/SmiiKWIrwBwxz5Dod87uYvsbcZ9JAL5ylPg1DevyKgTkxCXnPEaewk1Su2qpfNmry5RHoN+NywWFCG+A==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@oxc-project/types": "^0.102.0" + "@oxc-project/types": "^0.95.0" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -12955,27 +13292,28 @@ "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-parser/binding-android-arm64": "0.102.0", - "@oxc-parser/binding-darwin-arm64": "0.102.0", - "@oxc-parser/binding-darwin-x64": "0.102.0", - "@oxc-parser/binding-freebsd-x64": "0.102.0", - "@oxc-parser/binding-linux-arm-gnueabihf": "0.102.0", - "@oxc-parser/binding-linux-arm64-gnu": "0.102.0", - "@oxc-parser/binding-linux-arm64-musl": "0.102.0", - "@oxc-parser/binding-linux-riscv64-gnu": "0.102.0", - "@oxc-parser/binding-linux-s390x-gnu": "0.102.0", - "@oxc-parser/binding-linux-x64-gnu": "0.102.0", - "@oxc-parser/binding-linux-x64-musl": "0.102.0", - "@oxc-parser/binding-openharmony-arm64": "0.102.0", - "@oxc-parser/binding-wasm32-wasi": "0.102.0", - "@oxc-parser/binding-win32-arm64-msvc": "0.102.0", - "@oxc-parser/binding-win32-x64-msvc": "0.102.0" + "@oxc-parser/binding-android-arm64": "0.95.0", + "@oxc-parser/binding-darwin-arm64": "0.95.0", + "@oxc-parser/binding-darwin-x64": "0.95.0", + "@oxc-parser/binding-freebsd-x64": "0.95.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.95.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.95.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.95.0", + "@oxc-parser/binding-linux-arm64-musl": "0.95.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.95.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.95.0", + "@oxc-parser/binding-linux-x64-gnu": "0.95.0", + "@oxc-parser/binding-linux-x64-musl": "0.95.0", + "@oxc-parser/binding-wasm32-wasi": "0.95.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.95.0", + "@oxc-parser/binding-win32-x64-msvc": "0.95.0" } }, "node_modules/oxc-transform": { - "version": "0.102.0", - "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.102.0.tgz", - "integrity": "sha512-MR5ohiBS6/kvxRpmUZ3LIDTTJBEC4xLAEZXfYr7vrA0eP7WHewQaNQPFDgT4Bee89TdmVQ5ZKrifGwxLjSyHHw==", + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.95.0.tgz", + "integrity": "sha512-SmS5aThb5K0SoUZgzGbikNBjrGHfOY4X5TEqBlaZb1uy5YgXbUSbpakpZJ13yW36LNqy8Im5+y+sIk5dlzpZ/w==", + "dev": true, "license": "MIT", "engines": { "node": "^20.19.0 || >=22.12.0" @@ -12984,33 +13322,34 @@ "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-transform/binding-android-arm64": "0.102.0", - "@oxc-transform/binding-darwin-arm64": "0.102.0", - "@oxc-transform/binding-darwin-x64": "0.102.0", - "@oxc-transform/binding-freebsd-x64": "0.102.0", - "@oxc-transform/binding-linux-arm-gnueabihf": "0.102.0", - "@oxc-transform/binding-linux-arm64-gnu": "0.102.0", - "@oxc-transform/binding-linux-arm64-musl": "0.102.0", - "@oxc-transform/binding-linux-riscv64-gnu": "0.102.0", - "@oxc-transform/binding-linux-s390x-gnu": "0.102.0", - "@oxc-transform/binding-linux-x64-gnu": "0.102.0", - "@oxc-transform/binding-linux-x64-musl": "0.102.0", - "@oxc-transform/binding-openharmony-arm64": "0.102.0", - "@oxc-transform/binding-wasm32-wasi": "0.102.0", - "@oxc-transform/binding-win32-arm64-msvc": "0.102.0", - "@oxc-transform/binding-win32-x64-msvc": "0.102.0" + "@oxc-transform/binding-android-arm64": "0.95.0", + "@oxc-transform/binding-darwin-arm64": "0.95.0", + "@oxc-transform/binding-darwin-x64": "0.95.0", + "@oxc-transform/binding-freebsd-x64": "0.95.0", + "@oxc-transform/binding-linux-arm-gnueabihf": "0.95.0", + "@oxc-transform/binding-linux-arm-musleabihf": "0.95.0", + "@oxc-transform/binding-linux-arm64-gnu": "0.95.0", + "@oxc-transform/binding-linux-arm64-musl": "0.95.0", + "@oxc-transform/binding-linux-riscv64-gnu": "0.95.0", + "@oxc-transform/binding-linux-s390x-gnu": "0.95.0", + "@oxc-transform/binding-linux-x64-gnu": "0.95.0", + "@oxc-transform/binding-linux-x64-musl": "0.95.0", + "@oxc-transform/binding-wasm32-wasi": "0.95.0", + "@oxc-transform/binding-win32-arm64-msvc": "0.95.0", + "@oxc-transform/binding-win32-x64-msvc": "0.95.0" } }, "node_modules/oxc-walker": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-0.6.0.tgz", - "integrity": "sha512-BA3hlxq5+Sgzp7TCQF52XDXCK5mwoIZuIuxv/+JuuTzOs2RXkLqWZgZ69d8pJDDjnL7wiREZTWHBzFp/UWH88Q==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-0.5.2.tgz", + "integrity": "sha512-XYoZqWwApSKUmSDEFeOKdy3Cdh95cOcSU8f7yskFWE4Rl3cfL5uwyY+EV7Brk9mdNLy+t5SseJajd6g7KncvlA==", + "dev": true, "license": "MIT", "dependencies": { "magic-regexp": "^0.10.0" }, "peerDependencies": { - "oxc-parser": ">=0.98.0" + "oxc-parser": ">=0.72.0" } }, "node_modules/p-limit": { @@ -13083,6 +13422,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "dev": true, "license": "MIT" }, "node_modules/parent-module": { @@ -13108,15 +13448,6 @@ "parse-statements": "1.0.11" } }, - "node_modules/parse-path": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", - "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", - "license": "MIT", - "dependencies": { - "protocols": "^2.0.0" - } - }, "node_modules/parse-statements": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", @@ -13124,19 +13455,6 @@ "dev": true, "license": "MIT" }, - "node_modules/parse-url": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-9.2.0.tgz", - "integrity": "sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==", - "license": "MIT", - "dependencies": { - "@types/parse-path": "^7.0.0", - "parse-path": "^7.0.0" - }, - "engines": { - "node": ">=14.13.0" - } - }, "node_modules/parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", @@ -13240,18 +13558,6 @@ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "license": "MIT" }, - "node_modules/path-type": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -13344,21 +13650,6 @@ "node": ">=18" } }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -13383,9 +13674,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "funding": [ { "type": "opencollective", @@ -13991,24 +14282,6 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -14046,19 +14319,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -14066,12 +14326,6 @@ "dev": true, "license": "ISC" }, - "node_modules/protocols": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", - "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", - "license": "MIT" - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -14159,13 +14413,13 @@ } }, "node_modules/rc9": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", - "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.0.tgz", + "integrity": "sha512-MGOue0VqscKWQ104udASX/3GYDcKyPI4j4F8gu/jHHzglpmy9a/anZK3PNe8ug6aZFl+9GxLtdhe3kVZuMaQbA==", "license": "MIT", "dependencies": { "defu": "^6.1.4", - "destr": "^2.0.3" + "destr": "^2.0.5" } }, "node_modules/read-cache": { @@ -14202,10 +14456,25 @@ "minimatch": "^5.1.0" } }, + "node_modules/readdir-glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "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==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -14314,6 +14583,12 @@ "node": ">=10" } }, + "node_modules/replace-in-file/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, "node_modules/replace-in-file/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -14328,7 +14603,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -14346,9 +14621,9 @@ } }, "node_modules/replace-in-file/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -14410,12 +14685,13 @@ } }, "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/resolve-path": { @@ -14496,16 +14772,10 @@ "node": ">=0.10.0" } }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "license": "MIT" - }, "node_modules/rollup": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", - "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "license": "MIT", "peer": true, "dependencies": { @@ -14519,35 +14789,38 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.54.0", - "@rollup/rollup-android-arm64": "4.54.0", - "@rollup/rollup-darwin-arm64": "4.54.0", - "@rollup/rollup-darwin-x64": "4.54.0", - "@rollup/rollup-freebsd-arm64": "4.54.0", - "@rollup/rollup-freebsd-x64": "4.54.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", - "@rollup/rollup-linux-arm-musleabihf": "4.54.0", - "@rollup/rollup-linux-arm64-gnu": "4.54.0", - "@rollup/rollup-linux-arm64-musl": "4.54.0", - "@rollup/rollup-linux-loong64-gnu": "4.54.0", - "@rollup/rollup-linux-ppc64-gnu": "4.54.0", - "@rollup/rollup-linux-riscv64-gnu": "4.54.0", - "@rollup/rollup-linux-riscv64-musl": "4.54.0", - "@rollup/rollup-linux-s390x-gnu": "4.54.0", - "@rollup/rollup-linux-x64-gnu": "4.54.0", - "@rollup/rollup-linux-x64-musl": "4.54.0", - "@rollup/rollup-openharmony-arm64": "4.54.0", - "@rollup/rollup-win32-arm64-msvc": "4.54.0", - "@rollup/rollup-win32-ia32-msvc": "4.54.0", - "@rollup/rollup-win32-x64-gnu": "4.54.0", - "@rollup/rollup-win32-x64-msvc": "4.54.0", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, "node_modules/rollup-plugin-visualizer": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.5.tgz", - "integrity": "sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.11.tgz", + "integrity": "sha512-TBwVHVY7buHjIKVLqr9scTVFwqZqMXINcCphPwIWKPDCOBIa+jCQfafvbjRJDZgXdq/A996Dy6yGJ/+/NtAXDQ==", "license": "MIT", "dependencies": { "open": "^8.0.0", @@ -14574,11 +14847,19 @@ } } }, + "node_modules/rollup-plugin-visualizer/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/rou3": { "version": "0.7.12", "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.7.12.tgz", "integrity": "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==", - "dev": true, "license": "MIT" }, "node_modules/run-applescript": { @@ -14660,10 +14941,13 @@ "license": "MIT" }, "node_modules/sax": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz", - "integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==", - "license": "BlueOak-1.0.0" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", + "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } }, "node_modules/saxes": { "version": "6.0.0", @@ -14747,9 +15031,9 @@ } }, "node_modules/seroval": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.2.tgz", - "integrity": "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.0.tgz", + "integrity": "sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==", "license": "MIT", "engines": { "node": ">=10" @@ -14842,9 +15126,9 @@ } }, "node_modules/simple-git": { - "version": "3.30.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.30.0.tgz", - "integrity": "sha512-q6lxyDsCmEal/MEGhP1aVyQ3oxnagGlBDOVSIB4XUVLl1iZh0Pah6ebC9V4xBap/RfgP2WlI8EKs0WS0rMEJHg==", + "version": "3.32.3", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.32.3.tgz", + "integrity": "sha512-56a5oxFdWlsGygOXHWrG+xjj5w9ZIt2uQbzqiIGdR/6i5iococ7WQ/bNPzWxCJdEUGUCmyMH0t9zMpRJTaKxmw==", "license": "MIT", "dependencies": { "@kwsites/file-exists": "^1.1.1", @@ -14889,18 +15173,21 @@ } }, "node_modules/smob": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", - "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", - "license": "MIT" + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.6.1.tgz", + "integrity": "sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } }, "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "license": "BSD-3-Clause", "engines": { - "node": ">= 12" + "node": ">=0.10.0" } }, "node_modules/source-map-js": { @@ -14922,15 +15209,6 @@ "source-map": "^0.6.0" } }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", @@ -14950,26 +15228,19 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.0" }, - "node_modules/speakingurl": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", - "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/srvx": { - "version": "0.9.8", - "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.9.8.tgz", - "integrity": "sha512-RZaxTKJEE/14HYn8COLuUOJAt0U55N9l1Xf6jj+T0GoA01EUH1Xz5JtSUOI+EHn+AEgPCVn7gk6jHJffrr06fQ==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.10.1.tgz", + "integrity": "sha512-A//xtfak4eESMWWydSRFUVvCTQbSwivnGCEf8YGPe2eHU0+Z6znfUTCPF0a7oV3sObSOcrXHlL6Bs9vVctfXdg==", + "dev": true, "license": "MIT", + "peer": true, "bin": { "srvx": "bin/srvx.mjs" }, @@ -15095,12 +15366,12 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -15240,18 +15511,6 @@ "node": ">= 6" } }, - "node_modules/superjson": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", - "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", - "license": "MIT", - "dependencies": { - "copy-anything": "^4" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -15424,7 +15683,6 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "license": "MIT", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -15493,18 +15751,6 @@ "node": ">= 6" } }, - "node_modules/tailwindcss/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/tailwindcss/node_modules/jiti": { "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", @@ -15565,9 +15811,9 @@ } }, "node_modules/tar": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", - "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.9.tgz", + "integrity": "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg==", "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", @@ -15581,29 +15827,30 @@ } }, "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", + "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", "license": "MIT", "dependencies": { "b4a": "^1.6.4", + "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, - "node_modules/tar/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" } }, "node_modules/terser": { - "version": "5.44.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", - "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -15625,9 +15872,9 @@ "license": "MIT" }, "node_modules/text-decoder": { - "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==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" @@ -15703,22 +15950,22 @@ } }, "node_modules/tldts": { - "version": "7.0.23", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.23.tgz", - "integrity": "sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==", + "version": "7.0.24", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.24.tgz", + "integrity": "sha512-1r6vQTTt1rUiJkI5vX7KG8PR342Ru/5Oh13kEQP2SMbRSZpOey9SrBe27IDxkoWulx8ShWu4K6C0BkctP8Z1bQ==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.0.23" + "tldts-core": "^7.0.24" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.23", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.23.tgz", - "integrity": "sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==", + "version": "7.0.24", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.24.tgz", + "integrity": "sha512-pj7yygNMoMRqG7ML2SDQ0xNIOfN3IBDUcPVM2Sg6hP96oFNN2nqnzHreT3z9xLq85IWJyNTvD38O002DdOrPMw==", "dev": true, "license": "MIT" }, @@ -15792,10 +16039,17 @@ } }, "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } }, "node_modules/ts-api-utils": { "version": "2.4.0", @@ -15846,9 +16100,9 @@ } }, "node_modules/type-fest": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.3.1.tgz", - "integrity": "sha512-VCn+LMHbd4t6sF3wfU/+HKT63C9OoyrSIf4b+vtWHpt2U7/4InZG467YDNMFMR70DdHjAdpPWmw2lzRdg0Xqqg==", + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.4.4.tgz", + "integrity": "sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==", "license": "(MIT OR CC0-1.0)", "dependencies": { "tagged-tag": "^1.0.0" @@ -15945,13 +16199,19 @@ "unplugin": "^2.3.11" } }, - "node_modules/unctx/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/unctx/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0" + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" } }, "node_modules/undici": { @@ -15981,36 +16241,42 @@ } }, "node_modules/unhead": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.1.tgz", - "integrity": "sha512-NOt8n2KybAOxSLfNXegAVai4SGU8bPKqWnqCzNAvnRH2i8mW+0bbFjN/L75LBgCSTiOjJSpANe5w2V34Grr7Cw==", + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.10.tgz", + "integrity": "sha512-We8l9uNF8zz6U8lfQaVG70+R/QBfQx1oPIgXin4BtZnK2IQpz6yazQ0qjMNVBDw2ADgF2ea58BtvSK+XX5AS7g==", "license": "MIT", "dependencies": { - "hookable": "^5.5.3" + "hookable": "^6.0.1" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" } }, + "node_modules/unhead/node_modules/hookable": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.0.1.tgz", + "integrity": "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==", + "license": "MIT" + }, "node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/unimport": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/unimport/-/unimport-5.6.0.tgz", - "integrity": "sha512-8rqAmtJV8o60x46kBAJKtHpJDJWkA2xcBqWKPI14MgUb05o1pnpnCnXSxedUXyeq7p8fR5g3pTo2BaswZ9lD9A==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/unimport/-/unimport-5.7.0.tgz", + "integrity": "sha512-njnL6sp8lEA8QQbZrt+52p/g4X0rw3bnGGmUcJnt1jeG8+iiqO779aGz0PirCtydAIVcuTBRlJ52F0u46z309Q==", "license": "MIT", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", "local-pkg": "^1.1.2", @@ -16029,13 +16295,31 @@ "node": ">=18.12.0" } }, - "node_modules/unimport/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/unimport/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unimport/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0" + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" } }, "node_modules/unimport/node_modules/unplugin-utils": { @@ -16064,18 +16348,17 @@ } }, "node_modules/unplugin": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", - "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", - "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" }, "engines": { - "node": ">=18.12.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/unplugin-utils": { @@ -16095,16 +16378,18 @@ } }, "node_modules/unplugin-vue-router": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/unplugin-vue-router/-/unplugin-vue-router-0.19.2.tgz", - "integrity": "sha512-u5dgLBarxE5cyDK/hzJGfpCTLIAyiTXGlo85COuD4Nssj6G7NxS+i9mhCWz/1p/ud1eMwdcUbTXehQe41jYZUA==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/unplugin-vue-router/-/unplugin-vue-router-0.16.2.tgz", + "integrity": "sha512-lE6ZjnHaXfS2vFI/PSEwdKcdOo5RwAbCKUnPBIN9YwLgSWas3x+qivzQvJa/uxhKzJldE6WK43aDKjGj9Rij9w==", + "deprecated": "Merged into vuejs/router. Migrate: https://router.vuejs.org/guide/migration/v4-to-v5.html", + "dev": true, "license": "MIT", "dependencies": { "@babel/generator": "^7.28.5", "@vue-macros/common": "^3.1.1", - "@vue/language-core": "^3.2.1", + "@vue/language-core": "^3.1.3", "ast-walker-scope": "^0.8.3", - "chokidar": "^5.0.0", + "chokidar": "^4.0.3", "json5": "^2.2.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", @@ -16114,9 +16399,9 @@ "picomatch": "^4.0.3", "scule": "^1.3.0", "tinyglobby": "^0.2.15", - "unplugin": "^2.3.11", + "unplugin": "^2.3.10", "unplugin-utils": "^0.3.1", - "yaml": "^2.8.2" + "yaml": "^2.8.1" }, "peerDependencies": { "@vue/compiler-sfc": "^3.5.17", @@ -16128,10 +16413,57 @@ } } }, + "node_modules/unplugin-vue-router/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/unplugin-vue-router/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/unplugin-vue-router/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/unplugin-vue-router/node_modules/unplugin-utils": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "dev": true, "license": "MIT", "dependencies": { "pathe": "^2.0.3", @@ -16181,19 +16513,19 @@ } }, "node_modules/unstorage": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.3.tgz", - "integrity": "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==", + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.4.tgz", + "integrity": "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==", "license": "MIT", "dependencies": { "anymatch": "^3.1.3", - "chokidar": "^4.0.3", + "chokidar": "^5.0.0", "destr": "^2.0.5", - "h3": "^1.15.4", - "lru-cache": "^10.4.3", + "h3": "^1.15.5", + "lru-cache": "^11.2.0", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", - "ufo": "^1.6.1" + "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", @@ -16202,14 +16534,14 @@ "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", - "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", - "@vercel/kv": "^1.0.1", + "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", @@ -16276,40 +16608,6 @@ } } }, - "node_modules/unstorage/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/unstorage/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/unstorage/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/untun": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/untun/-/untun-0.1.3.tgz", @@ -16347,17 +16645,17 @@ } }, "node_modules/unwasm": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/unwasm/-/unwasm-0.3.11.tgz", - "integrity": "sha512-Vhp5gb1tusSQw5of/g3Q697srYgMXvwMgXMjcG4ZNga02fDX9coxJ9fAb0Ci38hM2Hv/U1FXRPGgjP2BYqhNoQ==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/unwasm/-/unwasm-0.5.3.tgz", + "integrity": "sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==", "license": "MIT", "dependencies": { - "knitwork": "^1.2.0", - "magic-string": "^0.30.17", - "mlly": "^1.7.4", + "exsolve": "^1.0.8", + "knitwork": "^1.3.0", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", "pathe": "^2.0.3", - "pkg-types": "^2.2.0", - "unplugin": "^2.3.6" + "pkg-types": "^2.3.0" } }, "node_modules/update-browserslist-db": { @@ -16422,9 +16720,9 @@ } }, "node_modules/vite": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", - "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "license": "MIT", "peer": true, "dependencies": { @@ -16512,6 +16810,15 @@ "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0" } }, + "node_modules/vite-dev-rpc/node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/vite-hot-client": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.1.0.tgz", @@ -16525,16 +16832,16 @@ } }, "node_modules/vite-node": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-5.2.0.tgz", - "integrity": "sha512-7UT39YxUukIA97zWPXUGb0SGSiLexEGlavMwU3HDE6+d/HJhKLjLqu4eX2qv6SQiocdhKLRcusroDwXHQ6CnRQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-5.3.0.tgz", + "integrity": "sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ==", "license": "MIT", "dependencies": { "cac": "^6.7.14", - "es-module-lexer": "^1.7.0", - "obug": "^2.0.0", + "es-module-lexer": "^2.0.0", + "obug": "^2.1.1", "pathe": "^2.0.3", - "vite": "^7.2.2" + "vite": "^7.3.1" }, "bin": { "vite-node": "dist/cli.mjs" @@ -16666,6 +16973,18 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/vite-plugin-checker/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/vite-plugin-inspect": { "version": "11.3.3", "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.3.3.tgz", @@ -16763,13 +17082,475 @@ "vue": "^3.5.0" } }, - "node_modules/vite-plugin-vue-tracer/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/vitest": { @@ -16861,6 +17642,13 @@ "@nuxt/test-utils": ">=3.13.1" } }, + "node_modules/vitest/node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/vscode-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", @@ -16912,17 +17700,17 @@ "license": "MIT" }, "node_modules/vue-eslint-parser": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.2.0.tgz", - "integrity": "sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.4.0.tgz", + "integrity": "sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "debug": "^4.4.0", - "eslint-scope": "^8.2.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "eslint-scope": "^8.2.0 || ^9.0.0", + "eslint-visitor-keys": "^4.2.0 || ^5.0.0", + "espree": "^10.3.0 || ^11.0.0", "esquery": "^1.6.0", "semver": "^7.6.3" }, @@ -16933,35 +17721,17 @@ "url": "https://github.com/sponsors/mysticatea" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" } }, "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/vue-eslint-parser/node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -17029,10 +17799,14 @@ } }, "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", @@ -17051,28 +17825,33 @@ } }, "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, "license": "MIT", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/which": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { - "isexe": "^3.1.1" + "isexe": "^2.0.0" }, "bin": { - "node-which": "bin/which.js" + "node-which": "bin/node-which" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">= 8" } }, "node_modules/why-is-node-running": { @@ -17197,9 +17976,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -17259,10 +18038,13 @@ } }, "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "license": "ISC" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } }, "node_modules/yaml": { "version": "2.8.2", @@ -17297,19 +18079,6 @@ "url": "https://github.com/sponsors/ota-meshi" } }, - "node_modules/yaml-eslint-parser/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -17401,14 +18170,14 @@ } }, "node_modules/youch": { - "version": "4.1.0-beta.13", - "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.13.tgz", - "integrity": "sha512-3+AG1Xvt+R7M7PSDudhbfbwiyveW6B8PLBIwTyEC598biEYIjHhC89i6DBEvR0EZUjGY3uGSnC429HpIa2Z09g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0.tgz", + "integrity": "sha512-cYekNh2tUoU+voS11X0D0UQntVCSO6LQ1h10VriQGmfbpf0mnGTruwZICts23UUNiZCXm8H8hQBtRrdsbhuNNg==", "license": "MIT", "dependencies": { - "@poppinss/colors": "^4.1.5", - "@poppinss/dumper": "^0.6.5", - "@speed-highlight/core": "^1.2.9", + "@poppinss/colors": "^4.1.6", + "@poppinss/dumper": "^0.7.0", + "@speed-highlight/core": "^1.2.14", "cookie-es": "^2.0.0", "youch-core": "^0.3.3" } From 0205aab46177733daa9b9fc8bb4e6f91db267ef0 Mon Sep 17 00:00:00 2001 From: Missez Date: Fri, 6 Mar 2026 11:24:10 +0700 Subject: [PATCH 03/10] feat: Introduce core authentication service, several new admin management pages, and instructor feature tests. --- .../pages/admin/audit-log/index.vue | 26 +- .../pages/admin/categories/index.vue | 13 +- .../pages/admin/courses/[id].vue | 2 +- .../pages/admin/recommended-courses/index.vue | 5 +- frontend_management/pages/register.vue | 2 +- frontend_management/services/auth.service.ts | 72 +-- .../tests/auth/register.spec.ts | 50 +-- .../instructor/course-detail-tabs.spec.ts | 298 +++++++++++++ .../tests/instructor/courses-list.spec.ts | 33 +- .../tests/instructor/create-course.spec.ts | 417 ++++++++++++++++++ .../tests/instructor/dashboard.spec.ts | 21 +- 11 files changed, 818 insertions(+), 121 deletions(-) create mode 100644 frontend_management/tests/instructor/course-detail-tabs.spec.ts create mode 100644 frontend_management/tests/instructor/create-course.spec.ts diff --git a/frontend_management/pages/admin/audit-log/index.vue b/frontend_management/pages/admin/audit-log/index.vue index c456b0c1..1214298e 100644 --- a/frontend_management/pages/admin/audit-log/index.vue +++ b/frontend_management/pages/admin/audit-log/index.vue @@ -168,7 +168,7 @@ {{ selectedLog.action }}
-
Time
+
Date & Time
{{ formatDate(selectedLog.created_at) }}
@@ -291,7 +291,7 @@ const columns = [ { name: 'entity_type', label: 'Entity Type', field: 'entity_type', align: 'left' }, { name: 'entity_id', label: 'Entity ID', field: 'entity_id', align: 'left' }, - { name: 'created_at', label: 'Time', field: 'created_at', align: 'left' }, + { name: 'created_at', label: 'Date & Time', field: 'created_at', align: 'left' }, { name: 'actions', label: '', field: 'actions', align: 'center' } ]; @@ -421,13 +421,23 @@ const formatDate = (date: string) => { return new Date(date).toLocaleString('th-TH'); }; +const ACTION_COLOR_MAP: Record = { + DELETE: 'negative', + REJECT: 'negative', + DEACTIVATE: 'negative', + ERROR: 'negative', + UPDATE: 'warning', + CHANGE: 'warning', + CREATE: 'positive', + APPROVE: 'positive', + ACTIVATE: 'positive', + LOGIN: 'info', +}; + const getActionColor = (action: string) => { - if (!action) return 'grey'; - if (action.includes('DELETE') || action.includes('REJECT') || action.includes('DEACTIVATE') || action.includes('ERROR')) return 'negative'; - if (action.includes('UPDATE') || action.includes('CHANGE')) return 'warning'; - if (action.includes('CREATE') || action.includes('APPROVE') || action.includes('ACTIVATE')) return 'positive'; - if (action.includes('LOGIN')) return 'info'; - return 'grey-8'; + if (!action) return 'grey'; + const keyword = Object.keys(ACTION_COLOR_MAP).find((key) => action.includes(key)); + return keyword ? ACTION_COLOR_MAP[keyword] : 'grey-8'; }; // Check for deep link to detail diff --git a/frontend_management/pages/admin/categories/index.vue b/frontend_management/pages/admin/categories/index.vue index 65bf74fd..02648abe 100644 --- a/frontend_management/pages/admin/categories/index.vue +++ b/frontend_management/pages/admin/categories/index.vue @@ -307,8 +307,17 @@ const handleSave = async () => { const confirmDelete = (category: CategoryResponse) => { $q.dialog({ title: 'ยืนยันการลบ', - message: `คุณต้องการลบหมวดหมู่ "${category.name.th}" หรือไม่?`, - cancel: true, + message: `คุณต้องการลบหมวดหมู่ "${category.name.th}" หรือไม่?
การลบหมวดหมู่นี้จะทำให้หมวดหมู่ถูกลบออกจากหลักสูตรทั้งหมดที่ใช้งานอยู่`, + html: true, + cancel: { + label: 'ยกเลิก', + color: 'grey', + flat: true + }, + ok: { + label: 'ลบหมวดหมู่', + color: 'negative' + }, persistent: true }).onOk(async () => { try { diff --git a/frontend_management/pages/admin/courses/[id].vue b/frontend_management/pages/admin/courses/[id].vue index ad2dd0f7..07c78cf3 100644 --- a/frontend_management/pages/admin/courses/[id].vue +++ b/frontend_management/pages/admin/courses/[id].vue @@ -56,7 +56,7 @@
- + diff --git a/frontend_management/pages/admin/recommended-courses/index.vue b/frontend_management/pages/admin/recommended-courses/index.vue index c8aac610..73b414ba 100644 --- a/frontend_management/pages/admin/recommended-courses/index.vue +++ b/frontend_management/pages/admin/recommended-courses/index.vue @@ -153,7 +153,8 @@
หมวดหมู่ (Category):
-
{{ selectedCourse.category.name.th }} ({{ selectedCourse.category.name.en }})
+
{{ selectedCourse.category.name.th }} ({{ selectedCourse.category.name.en }})
+
ไม่มีหมวดหมู่
@@ -262,7 +263,7 @@ const columns = [ field: (row: RecommendedCourse) => row.instructors?.find((i: any) => i.is_primary)?.user.username || '', align: 'left' as const }, - { name: 'category', label: 'Category', field: (row: RecommendedCourse) => row.category.name.th, sortable: true, align: 'left' as const }, + { name: 'category', label: 'Category', field: (row: RecommendedCourse) => row.category?.name?.th || 'ไม่มีหมวดหมู่', sortable: true, align: 'left' as const }, { name: 'price', label: 'Price', field: 'price', sortable: true, align: 'right' as const }, { name: 'is_recommended', label: 'Recommended', field: 'is_recommended', sortable: true, align: 'center' as const }, { name: 'actions', label: 'Actions', field: 'actions', align: 'center' as const }, diff --git a/frontend_management/pages/register.vue b/frontend_management/pages/register.vue index 24235ee9..a080d082 100644 --- a/frontend_management/pages/register.vue +++ b/frontend_management/pages/register.vue @@ -36,7 +36,7 @@ { }); test('should show password min length validation', async ({ page }) => { - const passwordInput = page.locator('label').filter({ hasText: 'รหัสผ่าน *' }).locator('input'); + const usernameInput = page.locator('label').filter({ hasText: 'ชื่อผู้ใช้ (Username)' }).locator('input'); + await usernameInput.fill('abeee'); + const emailInput = page.locator('label').filter({ hasText: 'อีเมล' }).locator('input'); + await emailInput.fill('test@example.com'); + const passwordInput = page.getByRole('textbox', { name: 'รหัสผ่าน *', exact: true }); await passwordInput.fill('1234'); await page.getByRole('button', { name: 'ลงทะเบียน' }).click(); @@ -71,8 +55,12 @@ test.describe('Register Page', () => { }); test('should show password mismatch validation', async ({ page }) => { - const passwordInput = page.locator('label').filter({ hasText: 'รหัสผ่าน *' }).locator('input'); - const confirmInput = page.locator('label').filter({ hasText: 'ยืนยันรหัสผ่าน' }).locator('input'); + const usernameInput = page.locator('label').filter({ hasText: 'ชื่อผู้ใช้ (Username)' }).locator('input'); + await usernameInput.fill('abeee'); + const emailInput = page.locator('label').filter({ hasText: 'อีเมล' }).locator('input'); + await emailInput.fill('test@example.com'); + const passwordInput = page.getByRole('textbox', { name: 'รหัสผ่าน *', exact: true }); + const confirmInput = page.getByRole('textbox', { name: 'ยืนยันรหัสผ่าน *', exact: true }); await passwordInput.fill('password123'); await confirmInput.fill('differentpass'); @@ -82,7 +70,11 @@ test.describe('Register Page', () => { }); test('should toggle password visibility', async ({ page }) => { - const passwordInput = page.locator('label').filter({ hasText: 'รหัสผ่าน *' }).locator('input'); + const usernameInput = page.locator('label').filter({ hasText: 'ชื่อผู้ใช้ (Username)' }).locator('input'); + await usernameInput.fill('abeee'); + const emailInput = page.locator('label').filter({ hasText: 'อีเมล' }).locator('input'); + await emailInput.fill('test@example.com'); + const passwordInput = page.getByRole('textbox', { name: 'รหัสผ่าน *', exact: true }); await passwordInput.fill('test1234'); // Click visibility icon @@ -110,9 +102,9 @@ test.describe('Register Page', () => { const usernameInput = page.locator('label').filter({ hasText: 'ชื่อผู้ใช้ (Username)' }).locator('input'); await usernameInput.fill(username); - await page.locator('input[type="email"]').fill(email); + await page.locator('label').filter({ hasText: 'อีเมล' }).locator('input').fill(email); - const passwordInput = page.locator('label').filter({ hasText: 'รหัสผ่าน *' }).locator('input'); + const passwordInput = page.getByRole('textbox', { name: 'รหัสผ่าน *', exact: true }); await passwordInput.fill(password); const confirmInput = page.locator('label').filter({ hasText: 'ยืนยันรหัสผ่าน' }).locator('input'); diff --git a/frontend_management/tests/instructor/course-detail-tabs.spec.ts b/frontend_management/tests/instructor/course-detail-tabs.spec.ts new file mode 100644 index 00000000..fff2fce8 --- /dev/null +++ b/frontend_management/tests/instructor/course-detail-tabs.spec.ts @@ -0,0 +1,298 @@ +import { test, expect } from '@playwright/test'; +import { TEST_URLS } from '../fixtures/test-data'; +import { faker, fakerTH } from '@faker-js/faker'; + +/** + * Instructor Course Detail Tabs Tests + * ทดสอบการเข้าดูแต่ละ tab ในหน้ารายละเอียดหลักสูตร + * ใช้ cookies จาก instructor-setup project (ไม่ต้อง login ซ้ำ) + */ + +test.describe.serial('Course Detail Tabs', () => { + let courseUrl: string; + + // ── Step 1: ค้นหาและเข้าหลักสูตร "พื้นฐาน Python สำหรับผู้เริ่มต้น" ── + test('navigate to Python course detail page', async ({ page }) => { + await page.goto(TEST_URLS.instructorCourses); + await page.waitForLoadState('networkidle'); + + // ค้นหาหลักสูตร (debounce 600ms) + await page.getByPlaceholder('ค้นหาหลักสูตร...').fill('พื้นฐาน Python'); + await page.waitForTimeout(1000); + + // หา course card ที่มีชื่อตรง แล้วกดปุ่ม visibility (ดูรายละเอียด) + const courseCard = page.locator('.bg-white.rounded-xl').filter({ hasText: 'พื้นฐาน Python สำหรับผู้เริ่มต้น' }).first(); + await expect(courseCard).toBeVisible({ timeout: 10_000 }); + await courseCard.locator('button').filter({ has: page.locator('.q-icon:has-text("visibility")') }).click(); + + // รอเข้าหน้ารายละเอียด + await page.waitForURL('**/instructor/courses/*', { timeout: 10_000 }); + await page.waitForLoadState('networkidle'); + + // เก็บ URL + courseUrl = page.url(); + + // ตรวจสอบ header elements + await expect(page.locator('h1')).toBeVisible(); + // ตรวจสอบว่ามี tabs ครบ + await expect(page.getByRole('tab', { name: 'โครงสร้าง' })).toBeVisible(); + await expect(page.getByRole('tab', { name: 'ผู้เรียน' })).toBeVisible(); + await expect(page.getByRole('tab', { name: 'ผู้สอน' })).toBeVisible(); + await expect(page.getByRole('tab', { name: 'ผลการทดสอบ' })).toBeVisible(); + await expect(page.getByRole('tab', { name: 'ประวัติการขออนุมัติ' })).toBeVisible(); + await expect(page.getByRole('tab', { name: 'ประกาศ' })).toBeVisible(); + }); + + // ── Step 2: tab โครงสร้าง (default) ── + test('display structure tab and preview a lesson', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + // tab โครงสร้างเป็น default → ควรแสดงอยู่แล้ว + const structureTab = page.getByRole('tab', { name: 'โครงสร้าง' }); + await expect(structureTab).toBeVisible(); + + // ตรวจสอบว่ามี chapters หรือ empty state + const hasChapters = await page.locator('.font-semibold').getByText(/^Chapter/).first().isVisible().catch(() => false); + const hasEmptyState = await page.getByText('ยังไม่มีบทเรียน').isVisible().catch(() => false); + + expect(hasChapters || hasEmptyState).toBeTruthy(); + + // ถ้ามี chapters → กดเข้าดู lesson แรก + if (hasChapters) { + // หา lesson แรกใน structure tab แล้วกด + const firstLesson = page.locator('.q-item').filter({ hasText: /^Lesson/ }).first(); + await expect(firstLesson).toBeVisible(); + await firstLesson.click(); + + // ตรวจสอบว่า LessonPreviewDialog เปิด + const dialog = page.locator('.q-dialog'); + await expect(dialog).toBeVisible({ timeout: 5_000 }); + + // ตรวจสอบว่าแสดง title ของ lesson + await expect(dialog.locator('.text-h6')).toBeVisible(); + + // ปิด dialog + await dialog.locator('button').filter({ has: page.locator('.q-icon:has-text("close")') }).click(); + await expect(dialog).toBeHidden({ timeout: 3_000 }); + } + }); + + // ── Step 3: tab ผู้เรียน ── + test('display students tab and view student detail', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + // กด tab ผู้เรียน + await page.getByRole('tab', { name: 'ผู้เรียน' }).click(); + await page.waitForTimeout(500); + + // ตรวจสอบ: stat cards หรือ empty state + const hasStats = await page.getByText('ผู้เรียนทั้งหมด').isVisible().catch(() => false); + const hasEmptyState = await page.getByText('ยังไม่มีผู้เรียนในหลักสูตรนี้').isVisible().catch(() => false); + + expect(hasStats || hasEmptyState).toBeTruthy(); + + // ถ้ามีผู้เรียน → กดเข้าดูรายละเอียดคนแรก + if (hasStats) { + await expect(page.getByPlaceholder('ค้นหาผู้เรียน...')).toBeVisible(); + + // กดที่นักเรียนคนแรกในรายการ + const firstStudent = page.locator('.q-item.cursor-pointer').first(); + await expect(firstStudent).toBeVisible(); + await firstStudent.click(); + + // ตรวจสอบว่า detail modal เปิด (maximized) + const dialog = page.locator('.q-dialog'); + await expect(dialog).toBeVisible({ timeout: 10_000 }); + + // ตรวจสอบ progress info + await expect(dialog.getByText('ความคืบหน้าทั้งหมด')).toBeVisible({ timeout: 10_000 }); + + // ปิด modal + await dialog.locator('button').filter({ has: page.locator('.q-icon:has-text("close")') }).click(); + await expect(dialog).toBeHidden({ timeout: 3_000 }); + } + }); + + // ── Step 4: tab ผู้สอน ── + test('display instructors tab and search to add instructor', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + // กด tab ผู้สอน + await page.getByRole('tab', { name: 'ผู้สอน' }).click(); + await page.waitForTimeout(500); + + // ตรวจสอบ header + await expect(page.getByText('ผู้สอนในรายวิชา')).toBeVisible(); + + // ตรวจสอบ: มีการ์ดผู้สอนอย่างน้อย 1 คน หรือ empty state + const hasInstructors = await page.getByText('หัวหน้าผู้สอน').isVisible().catch(() => false); + const hasEmptyState = await page.getByText('ยังไม่มีข้อมูลผู้สอน').isVisible().catch(() => false); + + expect(hasInstructors || hasEmptyState).toBeTruthy(); + + // ถ้ามีปุ่มเพิ่มผู้สอน (แสดงเฉพาะ primary instructor) + const addBtn = page.getByRole('button', { name: 'เพิ่มผู้สอน' }); + const hasAddBtn = await addBtn.isVisible().catch(() => false); + + if (hasAddBtn) { + // กดปุ่มเพิ่มผู้สอน + await addBtn.click(); + + // ตรวจสอบว่า dialog เปิด + const dialog = page.locator('.q-dialog'); + await expect(dialog).toBeVisible({ timeout: 5_000 }); + await expect(dialog.getByText('เพิ่มผู้สอน')).toBeVisible(); + + // ค้นหา "lertp" ใน q-select (use-input) + const selectInput = dialog.locator('.q-select input[type="search"]'); + await selectInput.fill('lertp'); + await page.waitForTimeout(1500); + + // ตรวจสอบว่ามีผลลัพธ์ (dropdown options) หรือ "ไม่พบผู้ใช้" + const hasResults = await page.locator('.q-menu .q-item').first().isVisible().catch(() => false); + expect(hasResults).toBeTruthy(); + + // ปิด dialog + await dialog.getByRole('button', { name: 'ยกเลิก' }).click(); + await expect(dialog).toBeHidden({ timeout: 3_000 }); + } + }); + + // ── Step 5: tab ผลการทดสอบ ── + test('display quiz results and view student detail', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + // กด tab ผลการทดสอบ + await page.getByRole('tab', { name: 'ผลการทดสอบ' }).click(); + await page.waitForTimeout(1000); + + // ตรวจสอบ: มี quiz selector หรือ empty state + const hasQuizSelector = await page.getByText('เลือกแบบทดสอบ').isVisible().catch(() => false); + const hasEmptyState = await page.getByText('หลักสูตรนี้ยังไม่มีแบบทดสอบ').isVisible().catch(() => false); + + expect(hasQuizSelector || hasEmptyState).toBeTruthy(); + + // ถ้ามีแบบทดสอบ → ตรวจสอบตาราง + กดดูรายละเอียดนักเรียน + if (hasQuizSelector) { + // รอตารางโหลด (auto-select quiz แรก) + await page.waitForTimeout(1500); + + // ตรวจสอบว่ามี stats cards (คะแนนเฉลี่ย) + const hasStats = await page.getByText('คะแนนเฉลี่ย').isVisible().catch(() => false); + + // ตรวจสอบว่ามี row ในตาราง + const firstRow = page.locator('.q-tr.cursor-pointer').first(); + const hasStudents = await firstRow.isVisible().catch(() => false); + + if (hasStudents) { + // กดนักเรียนคนแรก + await firstRow.click(); + + // ตรวจสอบ detail dialog + const dialog = page.locator('.q-dialog'); + await expect(dialog).toBeVisible({ timeout: 10_000 }); + + // ตรวจสอบข้อมูลคะแนน + await expect(dialog.getByText('คะแนนที่ได้')).toBeVisible({ timeout: 10_000 }); + + // ปิด dialog + await dialog.locator('button').filter({ has: page.locator('.q-icon:has-text("close")') }).click(); + await expect(dialog).toBeHidden({ timeout: 3_000 }); + } + } + }); + + // ── Step 6: tab ประวัติการขออนุมัติ ── + test('should display approval history tab content', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + // กด tab ประวัติการขออนุมัติ + await page.getByRole('tab', { name: 'ประวัติการขออนุมัติ' }).click(); + await page.waitForTimeout(500); + + // ตรวจสอบ: มี timeline หรือ empty state + const hasTimeline = await page.locator('.q-timeline').isVisible().catch(() => false); + const hasEmptyState = await page.getByText('ไม่พบประวัติการขออนุมัติ').isVisible().catch(() => false); + + expect(hasTimeline || hasEmptyState).toBeTruthy(); + }); + + // ── Step 7: tab ประกาศ ── + test('display announcements tab and create a new announcement', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + // กด tab ประกาศ + await page.getByRole('tab', { name: 'ประกาศ' }).click(); + await page.waitForTimeout(500); + + // ตรวจสอบ header + await expect(page.getByText('ประกาศ').first()).toBeVisible(); + + // สร้างข้อมูลประกาศ + const announcementTitle = fakerTH.lorem.sentence({ min: 3, max: 6 }); + const announcementTitleEn = faker.lorem.sentence({ min: 3, max: 6 }); + const announcementContent = fakerTH.lorem.paragraphs(1); + const announcementContentEn = faker.lorem.paragraphs(1); + + // กดปุ่มสร้างประกาศ + const createBtn = page.getByRole('button', { name: 'สร้างประกาศ' }); + await expect(createBtn).toBeVisible(); + await createBtn.click(); + + // ตรวจสอบว่า dialog เปิด + const dialog = page.locator('.q-dialog'); + await expect(dialog).toBeVisible({ timeout: 5_000 }); + await expect(dialog.getByText('สร้างประกาศใหม่')).toBeVisible(); + + // กรอกหัวข้อ (ภาษาไทย) + await dialog.locator('input').filter({ has: page.locator('[aria-label="หัวข้อ (ภาษาไทย) *"]') }).first().click(); + await dialog.getByLabel('หัวข้อ (ภาษาไทย) *').fill(announcementTitle); + + // กรอกหัวข้อ (English) + await dialog.getByLabel('หัวข้อ (English)').fill(announcementTitleEn); + + // กรอกเนื้อหา (ภาษาไทย) + await dialog.getByLabel('เนื้อหา (ภาษาไทย) *').fill(announcementContent); + + // กรอกเนื้อหา (English) + await dialog.getByLabel('เนื้อหา (English)').fill(announcementContentEn); + + // กดสร้าง + await dialog.getByRole('button', { name: 'สร้าง' }).click(); + + // รอ dialog ปิด + ตรวจสอบ success + await expect(dialog).toBeHidden({ timeout: 10_000 }); + + // ตรวจสอบว่าประกาศที่สร้างแสดงในรายการ + await page.waitForTimeout(500); + await expect(page.getByText(announcementTitle)).toBeVisible({ timeout: 5_000 }); + }); + + // ── Step 8: ทดสอบสลับ tabs อย่างรวดเร็ว ── + test('should switch between all tabs without errors', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + const tabs = ['โครงสร้าง', 'ผู้เรียน', 'ผู้สอน', 'ผลการทดสอบ', 'ประวัติการขออนุมัติ', 'ประกาศ']; + + for (const tabName of tabs) { + await page.getByRole('tab', { name: tabName }).click(); + await page.waitForTimeout(300); + + // ตรวจสอบว่า tab active (ไม่ crash) + const tabPanel = page.locator('.q-tab-panel:visible'); + await expect(tabPanel).toBeVisible({ timeout: 5_000 }); + } + + // สลับกลับไปที่ tab แรก + await page.getByRole('tab', { name: 'โครงสร้าง' }).click(); + await page.waitForTimeout(300); + await expect(page.locator('.q-tab-panel:visible')).toBeVisible(); + }); +}); diff --git a/frontend_management/tests/instructor/courses-list.spec.ts b/frontend_management/tests/instructor/courses-list.spec.ts index fadb8452..854fac5a 100644 --- a/frontend_management/tests/instructor/courses-list.spec.ts +++ b/frontend_management/tests/instructor/courses-list.spec.ts @@ -14,30 +14,23 @@ test.describe('Instructor Courses List', () => { test('should display page header', async ({ page }) => { await expect(page.getByText('หลักสูตรของฉัน')).toBeVisible(); await expect(page.getByText('จัดการหลักสูตรที่คุณสร้าง')).toBeVisible(); - }); - - test('should have create course button', async ({ page }) => { const createBtn = page.getByRole('button', { name: /สร้างหลักสูตรใหม่/ }); await expect(createBtn).toBeVisible(); }); + test('should navigate to create course page', async ({ page }) => { await page.getByRole('button', { name: /สร้างหลักสูตรใหม่/ }).click(); await page.waitForURL('**/instructor/courses/create**'); await expect(page).toHaveURL(/\/instructor\/courses\/create/); }); - test('should display stats cards', async ({ page }) => { - await expect(page.getByText('หลักสูตรทั้งหมด')).toBeVisible(); - await expect(page.getByText('เผยแพร่แล้ว')).toBeVisible(); - await expect(page.getByText('รอตรวจสอบ')).toBeVisible(); - await expect(page.getByText('แบบร่าง')).toBeVisible(); - await expect(page.getByText('ถูกปฏิเสธ')).toBeVisible(); - }); - test('should have search input', async ({ page }) => { const searchInput = page.locator('input[placeholder*="ค้นหา"]'); await expect(searchInput).toBeVisible(); + await searchInput.fill('JavaScript'); + await page.waitForLoadState('networkidle'); + await expect(page.getByText('พื้นฐาน JavaScript', { exact: true })).toBeVisible(); }); test('should have status filter dropdown', async ({ page }) => { @@ -46,17 +39,6 @@ test.describe('Instructor Courses List', () => { await expect(statusSelect).toBeVisible(); }); - test('should filter by status', async ({ page }) => { - // Open status dropdown - await page.locator('.q-select').first().click(); - - // Select "เผยแพร่แล้ว" (APPROVED) - await page.getByText('เผยแพร่แล้ว').click(); - - // Wait for API re-fetch - await page.waitForLoadState('networkidle'); - }); - test('should toggle between card and table view', async ({ page }) => { // Switch to table view await page.locator('.q-btn-toggle button').last().click(); @@ -66,9 +48,8 @@ test.describe('Instructor Courses List', () => { await expect(page.locator('.q-table')).toBeVisible(); // Table should have expected columns - await expect(page.getByText('หลักสูตร')).toBeVisible(); - await expect(page.getByText('สถานะ')).toBeVisible(); - await expect(page.getByText('ราคา')).toBeVisible(); + await expect(page.locator('thead').getByText('สถานะ')).toBeVisible(); + await expect(page.locator('thead').getByText('ราคา')).toBeVisible(); // Switch back to card view await page.locator('.q-btn-toggle button').first().click(); @@ -114,7 +95,7 @@ test.describe('Instructor Courses List', () => { test('should handle rejected course view details', async ({ page }) => { // Filter by rejected status await page.locator('.q-select').first().click(); - await page.getByText('ถูกปฏิเสธ').click(); + await page.getByRole('listbox').getByText('ถูกปฏิเสธ').click(); await page.waitForLoadState('networkidle'); // If there are rejected courses, clicking view should show rejection dialog diff --git a/frontend_management/tests/instructor/create-course.spec.ts b/frontend_management/tests/instructor/create-course.spec.ts new file mode 100644 index 00000000..a4b2bffc --- /dev/null +++ b/frontend_management/tests/instructor/create-course.spec.ts @@ -0,0 +1,417 @@ +import { test, expect } from '@playwright/test'; +import { TEST_URLS } from '../fixtures/test-data'; +import { faker } from '@faker-js/faker'; + +/** + * Instructor Create Course & Structure Tests + * ใช้ cookies จาก instructor-setup project (ไม่ต้อง login ซ้ำ) + * ใช้ faker สุ่มข้อมูลหลักสูตรจริงๆ + */ + +// ── Dynamic Course Data Generator (ไม่ hardcode) ──────────────── +const TOPICS = ['JavaScript', 'Python', 'React', 'Vue.js', 'Node.js', 'TypeScript', 'Docker', 'Kubernetes', 'GraphQL', 'Next.js', 'Flutter', 'Swift', 'Rust', 'Go', 'Machine Learning']; +const LEVELS = ['เบื้องต้น', 'พื้นฐาน', 'ขั้นสูง', 'สำหรับมือใหม่', 'เชิงปฏิบัติ']; +const LEVELS_EN = ['Fundamentals', 'Basics', 'Advanced', 'for Beginners', 'Hands-on']; +const ACTIONS_TH = ['เรียนรู้', 'ทำความเข้าใจ', 'ฝึกปฏิบัติ', 'ประยุกต์ใช้', 'สำรวจ']; +const ACTIONS_EN = ['Learn', 'Understand', 'Practice', 'Apply', 'Explore']; +const CHAPTER_THEMES_TH = ['แนะนำ', 'พื้นฐาน', 'การใช้งาน', 'เทคนิค', 'โปรเจกต์']; +const CHAPTER_THEMES_EN = ['Introduction to', 'Basics of', 'Working with', 'Techniques in', 'Projects with']; +const LESSON_TYPES: ('วิดีโอ' | 'แบบทดสอบ')[] = ['วิดีโอ', 'วิดีโอ', 'วิดีโอ', 'แบบทดสอบ']; // 75% video, 25% quiz + +const timestamp = Date.now(); +const topic = faker.helpers.arrayElement(TOPICS); +const levelIndex = faker.number.int({ min: 0, max: LEVELS.length - 1 }); + +/** สร้างข้อมูล lesson สุ่ม */ +function generateLesson(topic: string, chapterIndex: number, lessonIndex: number) { + const subtopic = faker.helpers.arrayElement([ + `${faker.helpers.arrayElement(ACTIONS_TH)} ${topic}`, + `${topic} ${faker.helpers.arrayElement(['ตอนที่', 'ส่วนที่', 'หัวข้อที่'])} ${chapterIndex + 1}.${lessonIndex + 1}`, + `${faker.helpers.arrayElement(['การตั้งค่า', 'การใช้งาน', 'แนวคิด', 'ตัวอย่าง', 'การทดลอง'])} ${topic} บทที่ ${chapterIndex + 1}`, + ]); + const subtopicEn = faker.helpers.arrayElement([ + `${faker.helpers.arrayElement(ACTIONS_EN)} ${topic}`, + `${topic} Part ${chapterIndex + 1}.${lessonIndex + 1}`, + `${faker.helpers.arrayElement(['Setting up', 'Using', 'Concepts of', 'Examples of', 'Experimenting with'])} ${topic} Ch.${chapterIndex + 1}`, + ]); + const type = faker.helpers.arrayElement(LESSON_TYPES); + + return { + title: { + th: type === 'แบบทดสอบ' ? `แบบทดสอบ ${chapterIndex + 1}.${lessonIndex + 1}: ${subtopic}` : subtopic, + en: type === 'แบบทดสอบ' ? `Quiz ${chapterIndex + 1}.${lessonIndex + 1}: ${subtopicEn}` : subtopicEn, + }, + type, + content: { + th: `ในบทเรียนนี้คุณจะได้${faker.helpers.arrayElement(ACTIONS_TH)} ${topic} ${faker.helpers.arrayElement(['แบบเจาะลึก', 'อย่างละเอียด', 'ผ่านตัวอย่างจริง', 'พร้อมแบบฝึกหัด'])}`, + en: `In this lesson you will ${faker.helpers.arrayElement(ACTIONS_EN).toLowerCase()} ${topic} ${faker.helpers.arrayElement(['in depth', 'in detail', 'through real examples', 'with exercises'])}`, + }, + }; +} + +/** สร้างข้อมูล chapter สุ่ม */ +function generateChapter(topic: string, chapterIndex: number, themeIndex: number) { + const lessonCount = faker.number.int({ min: 2, max: 3 }); + const lessons = Array.from({ length: lessonCount }, (_, i) => generateLesson(topic, chapterIndex, i)); + + // ทำให้ lesson สุดท้ายเป็นแบบทดสอบเสมอ + lessons[lessons.length - 1] = { + ...lessons[lessons.length - 1], + type: 'แบบทดสอบ', + title: { + th: `แบบทดสอบ: ${CHAPTER_THEMES_TH[themeIndex]} ${topic}`, + en: `Quiz: ${CHAPTER_THEMES_EN[themeIndex]} ${topic}`, + }, + }; + + return { + title: { + th: `${CHAPTER_THEMES_TH[themeIndex]} ${topic}`, + en: `${CHAPTER_THEMES_EN[themeIndex]} ${topic}`, + }, + description: { + th: `${faker.helpers.arrayElement(ACTIONS_TH)} ${CHAPTER_THEMES_TH[themeIndex].toLowerCase()} ${topic} ${faker.helpers.arrayElement(['อย่างเป็นระบบ', 'อย่างมีประสิทธิภาพ', 'แบบ step-by-step', 'ผ่านตัวอย่างจริง'])}`, + en: `${faker.helpers.arrayElement(ACTIONS_EN)} ${CHAPTER_THEMES_EN[themeIndex].toLowerCase()} ${topic} ${faker.helpers.arrayElement(['systematically', 'effectively', 'step by step', 'through real examples'])}`, + }, + lessons, + }; +} + +// ── สร้างข้อมูล course ────────────────────────────────────────── +const COURSE_DATA = { + title: { + th: `${topic} ${LEVELS[levelIndex]} ${timestamp}`, + en: `${topic} ${LEVELS_EN[levelIndex]} ${timestamp}`, + }, + slug: `${topic.toLowerCase().replace(/[^a-z0-9]+/g, '-')}-${timestamp}`, + description: { + th: `เรียนรู้ ${topic} ${LEVELS[levelIndex]} ครอบคลุมเนื้อหาสำคัญทั้งหมดที่จำเป็น พร้อมตัวอย่างและแบบฝึกหัดที่จะช่วยให้คุณเข้าใจอย่างลึกซึ้ง`, + en: `Learn ${topic} ${LEVELS_EN[levelIndex]} covering all essential topics with examples and exercises to help you gain deep understanding.`, + }, +}; + +const chapterCount = faker.number.int({ min: 2, max: 3 }); +// สุ่ม theme ที่ไม่ซ้ำกันสำหรับแต่ละบท +const shuffledThemeIndexes = faker.helpers.shuffle([0, 1, 2, 3, 4]).slice(0, chapterCount); +const CHAPTERS = shuffledThemeIndexes.map((themeIdx, i) => generateChapter(topic, i, themeIdx)); + +// ── Tests (serial — ต้องทำงานต่อเนื่องกัน) ───────────────────── +test.describe.serial('Create Course & Structure', () => { + let courseUrl: string; + + // ── Step 1: สร้างหลักสูตรใหม่ ── + test('create a new course with faker data', async ({ page }) => { + await page.goto(TEST_URLS.instructorCreateCourse); + await page.waitForLoadState('networkidle'); + + // กรอกชื่อหลักสูตร + await page.locator('input').filter({ hasText: '' }).nth(0) + .or(page.getByLabel('ชื่อหลักสูตร (ภาษาไทย) *')) + .fill(COURSE_DATA.title.th); + + await page.getByLabel('ชื่อหลักสูตร (English) *').fill(COURSE_DATA.title.en); + + // กรอก Slug + await page.getByLabel('Slug (URL) *').clear(); + await page.getByLabel('Slug (URL) *').fill(COURSE_DATA.slug); + + // เลือกหมวดหมู่ (เลือกตัวแรกจาก dropdown) + await page.locator('.q-select').click(); + await page.waitForTimeout(300); + await page.getByRole('listbox').locator('.q-item').first().click(); + + // กรอกคำอธิบาย + await page.getByLabel('คำอธิบาย (ภาษาไทย) *').fill(COURSE_DATA.description.th); + await page.getByLabel('คำอธิบาย (English) *').fill(COURSE_DATA.description.en); + + // ตั้งค่า — หลักสูตรฟรี (toggle อยู่แล้วเป็น default) + // ตรวจสอบว่า "หลักสูตรฟรี" toggle เปิดอยู่ + const freeToggle = page.getByText('หลักสูตรฟรี'); + await expect(freeToggle).toBeVisible(); + + // กดสร้าง + await page.getByRole('button', { name: 'สร้างหลักสูตร' }).click(); + + // รอ redirect ไปหน้า course detail + await page.waitForURL('**/instructor/courses/*', { timeout: 15_000 }); + await expect(page).toHaveURL(/\/instructor\/courses\/\d+/); + + // เก็บ URL สำหรับ test ถัดไป + courseUrl = page.url(); + + // ตรวจสอบว่าชื่อ course แสดงบนหน้า detail + await page.waitForLoadState('networkidle'); + await expect(page.getByText(COURSE_DATA.title.th)).toBeVisible({ timeout: 10_000 }); + }); + + // ── Step 2: อัปโหลดรูปหลักสูตร ── + test('upload course thumbnail', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + // สร้างไฟล์รูปทดสอบ (1x1 PNG ขนาดเล็ก) + const pngBuffer = Buffer.from( + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==', + 'base64' + ); + + // กดที่ thumbnail area เพื่อเปิด file input + const fileInput = page.locator('input[type="file"][accept="image/*"]'); + await fileInput.setInputFiles({ + name: `test-thumbnail-${Date.now()}.png`, + mimeType: 'image/png', + buffer: pngBuffer, + }); + + // รอ upload เสร็จ + await page.waitForLoadState('networkidle'); + await page.waitForTimeout(1000); + + // ตรวจสอบว่ารูปแสดง (img tag ปรากฏ) + await expect(page.locator('img[alt]').first()).toBeVisible({ timeout: 10_000 }); + }); + + // ── Step 3: ไปหน้าจัดการโครงสร้าง ── + test('navigate to structure page', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + // กดปุ่ม "จัดการโครงสร้าง" ใน Structure tab + await page.getByRole('button', { name: 'จัดการโครงสร้าง' }).click(); + await page.waitForURL('**/structure**', { timeout: 10_000 }); + await expect(page).toHaveURL(/\/structure/); + + // ตรวจสอบ header + await expect(page.getByText('จัดการโครงสร้างหลักสูตร')).toBeVisible(); + + // ตรวจสอบ empty state + await expect(page.getByText('ยังไม่มีบทเรียน')).toBeVisible(); + }); + + // ── Step 4: เพิ่มบทที่ 1 ── + test('add chapter 1 with faker data', async ({ page }) => { + // Navigate to structure page + const structureUrl = courseUrl + '/structure'; + await page.goto(structureUrl); + await page.waitForLoadState('networkidle'); + + // กดเพิ่มบทแรก + await page.getByRole('button', { name: 'เพิ่มบทแรก' }).click(); + await page.waitForTimeout(300); + + // กรอกข้อมูล chapter + const chapter = CHAPTERS[0]; + await page.getByLabel('ชื่อบท (ภาษาไทย) *').fill(chapter.title.th); + await page.getByLabel('ชื่อบท (English) *').fill(chapter.title.en); + await page.getByLabel('คำอธิบาย (ภาษาไทย) *').fill(chapter.description.th); + await page.getByLabel('คำอธิบาย (English) *').fill(chapter.description.en); + + // บันทึก + await page.getByRole('button', { name: 'บันทึก' }).click(); + await page.waitForLoadState('networkidle'); + + // ตรวจสอบ chapter แสดงผล + await expect(page.getByText(chapter.title.th)).toBeVisible({ timeout: 10_000 }); + }); + + // ── Step 5: เพิ่ม lessons ในบทที่ 1 ── + test('add lessons to chapter 1', async ({ page }) => { + const structureUrl = courseUrl + '/structure'; + await page.goto(structureUrl); + await page.waitForLoadState('networkidle'); + + const chapter = CHAPTERS[0]; + + for (const lesson of chapter.lessons) { + // กดปุ่มเพิ่มบทเรียน (ปุ่ม + ที่อยู่ข้าง chapter header) + const chapterCard = page.locator('.q-card').filter({ hasText: chapter.title.th }); + await chapterCard.locator('button').filter({ has: page.locator('.q-icon:has-text("add")') }).click(); + await page.waitForTimeout(300); + + // กรอกชื่อบทเรียน + await page.getByLabel('ชื่อบทเรียน (ภาษาไทย) *').fill(lesson.title.th); + await page.getByLabel('ชื่อบทเรียน (English) *').fill(lesson.title.en); + + // เลือกประเภท + await page.locator('.q-dialog .q-select').click(); + await page.waitForTimeout(200); + await page.getByRole('listbox').getByText(lesson.type).click(); + + // กรอกเนื้อหา + await page.getByLabel('เนื้อหา (ภาษาไทย) *').fill(lesson.content.th); + await page.getByLabel('เนื้อหา (English) *').fill(lesson.content.en); + + // บันทึก + await page.locator('.q-dialog').getByRole('button', { name: 'บันทึก' }).click(); + await page.waitForLoadState('networkidle'); + await page.waitForTimeout(500); + + // ตรวจสอบว่า lesson แสดง + await expect(page.getByText(lesson.title.th)).toBeVisible({ timeout: 10_000 }); + } + + // ตรวจสอบจำนวนบทเรียน + await expect(page.getByText(`${chapter.lessons.length} บทเรียน`)).toBeVisible(); + }); + + // ── Step 6: เพิ่มบทที่ 2 ── + test('add chapter 2 with faker data', async ({ page }) => { + const structureUrl = courseUrl + '/structure'; + await page.goto(structureUrl); + await page.waitForLoadState('networkidle'); + + // กดเพิ่มบท (ปุ่ม header) + await page.getByRole('button', { name: 'เพิ่มบท' }).click(); + await page.waitForTimeout(300); + + // กรอกข้อมูล chapter 2 + const chapter = CHAPTERS[1]; + await page.getByLabel('ชื่อบท (ภาษาไทย) *').fill(chapter.title.th); + await page.getByLabel('ชื่อบท (English) *').fill(chapter.title.en); + await page.getByLabel('คำอธิบาย (ภาษาไทย) *').fill(chapter.description.th); + await page.getByLabel('คำอธิบาย (English) *').fill(chapter.description.en); + + // บันทึก + await page.getByRole('button', { name: 'บันทึก' }).click(); + await page.waitForLoadState('networkidle'); + + // ตรวจสอบ chapter 2 แสดงผล + await expect(page.getByText(chapter.title.th)).toBeVisible({ timeout: 10_000 }); + }); + + // ── Step 7: เพิ่ม lessons ในบทที่ 2 ── + test('add lessons to chapter 2', async ({ page }) => { + const structureUrl = courseUrl + '/structure'; + await page.goto(structureUrl); + await page.waitForLoadState('networkidle'); + + const chapter = CHAPTERS[1]; + + for (const lesson of chapter.lessons) { + // กดปุ่มเพิ่มบทเรียนของบทที่ 2 (ปุ่มที่ 2) + // หาบทที่ 2 ก่อน แล้วกดปุ่ม add ของ chapter นั้น + const chapterCard = page.locator('.q-card').filter({ hasText: chapter.title.th }); + await chapterCard.locator('button').filter({ has: page.locator('.q-icon:text("add")') }).click(); + await page.waitForTimeout(300); + + // กรอกชื่อบทเรียน + await page.getByLabel('ชื่อบทเรียน (ภาษาไทย) *').fill(lesson.title.th); + await page.getByLabel('ชื่อบทเรียน (English) *').fill(lesson.title.en); + + // เลือกประเภท + await page.locator('.q-dialog .q-select').click(); + await page.waitForTimeout(200); + await page.getByRole('listbox').getByText(lesson.type).click(); + + // กรอกเนื้อหา + await page.getByLabel('เนื้อหา (ภาษาไทย) *').fill(lesson.content.th); + await page.getByLabel('เนื้อหา (English) *').fill(lesson.content.en); + + // บันทึก + await page.locator('.q-dialog').getByRole('button', { name: 'บันทึก' }).click(); + await page.waitForLoadState('networkidle'); + await page.waitForTimeout(500); + + // ตรวจสอบว่า lesson แสดง + await expect(page.getByText(lesson.title.th)).toBeVisible({ timeout: 10_000 }); + } + }); + + // ── Step 8: เพิ่มข้อสอบในแบบทดสอบ ── + test('add quiz questions to a quiz lesson', async ({ page }) => { + const structureUrl = courseUrl + '/structure'; + await page.goto(structureUrl); + await page.waitForLoadState('networkidle'); + + // หา quiz lesson แรกจากบทแรก → กดปุ่ม edit (icon "edit") เพื่อเข้าหน้า quiz + const firstQuizLesson = CHAPTERS[0].lessons.find(l => l.type === 'แบบทดสอบ'); + if (!firstQuizLesson) throw new Error('No quiz lesson found in chapter 1'); + + // Locate the quiz lesson row and click its edit button + const quizRow = page.locator('.q-item').filter({ hasText: firstQuizLesson.title.th }); + await quizRow.locator('button').filter({ has: page.locator('.q-icon:has-text("edit")') }).click(); + + // รอเข้าหน้า quiz + await page.waitForURL('**/quiz', { timeout: 10_000 }); + await page.waitForLoadState('networkidle'); + await expect(page.getByText('แก้ไขบทเรียน (แบบทดสอบ)')).toBeVisible(); + + // สุ่มจำนวนข้อสอบ 2-4 ข้อ + const questionCount = faker.number.int({ min: 2, max: 4 }); + + for (let q = 0; q < questionCount; q++) { + const questionTh = `${faker.helpers.arrayElement(ACTIONS_TH)} ${topic} คำถามที่ ${q + 1}: ${faker.helpers.arrayElement([ + 'ข้อใดถูกต้อง?', + 'ข้อใดเป็นจริง?', + 'ข้อใดคือคำตอบที่ดีที่สุด?', + 'ข้อใดต่อไปนี้ถูกต้อง?', + ])}`; + const questionEn = `${faker.helpers.arrayElement(ACTIONS_EN)} ${topic} Question ${q + 1}: ${faker.helpers.arrayElement([ + 'Which is correct?', + 'Which is true?', + 'Which is the best answer?', + 'Which of the following is correct?', + ])}`; + + // กดปุ่ม "เพิ่มคำถาม" + await page.getByRole('button', { name: 'เพิ่มคำถาม' }).click(); + await page.waitForTimeout(300); + + // กรอกคำถาม + const dialog = page.locator('.q-dialog'); + await dialog.getByLabel('คำถาม (ภาษาไทย) *').fill(questionTh); + await dialog.getByLabel('คำถาม (English)').fill(questionEn); + + // เพิ่มตัวเลือก (default มี 2 ตัว → เพิ่มอีก 2 ให้ครบ 4) + await dialog.getByRole('button', { name: 'เพิ่มตัวเลือก' }).click(); + await dialog.getByRole('button', { name: 'เพิ่มตัวเลือก' }).click(); + + // กรอก 4 ตัวเลือก + const choices = [ + { th: `${topic} คำตอบที่ถูกต้อง ${q + 1}`, en: `${topic} correct answer ${q + 1}` }, + { th: `${topic} ตัวเลือกที่ 2 ${q + 1}`, en: `${topic} option 2 ${q + 1}` }, + { th: `${topic} ตัวเลือกที่ 3 ${q + 1}`, en: `${topic} option 3 ${q + 1}` }, + { th: `${topic} ตัวเลือกที่ 4 ${q + 1}`, en: `${topic} option 4 ${q + 1}` }, + ]; + + for (let c = 0; c < 4; c++) { + await dialog.getByLabel(`ตัวเลือก ${c + 1} (TH)`).fill(choices[c].th); + await dialog.getByLabel(`ตัวเลือก ${c + 1} (EN)`).fill(choices[c].en); + } + + // ตัวเลือกแรก (index 0) เป็นคำตอบที่ถูก (default เลือกไว้แล้ว) + + // บันทึก + await dialog.getByRole('button', { name: 'บันทึก' }).click(); + await page.waitForLoadState('networkidle'); + await page.waitForTimeout(500); + + // ตรวจสอบว่าคำถามแสดงในรายการ + await expect(page.getByText(`คำถามที่ ${q + 1}`).first()).toBeVisible({ timeout: 10_000 }); + } + + // ตรวจสอบจำนวนข้อสอบทั้งหมด + await expect(page.getByText(`คำถาม (${questionCount} ข้อ)`)).toBeVisible(); + }); + + // ── Step 9: ตรวจสอบโครงสร้างทั้งหมดจากหน้า course detail ── + test('verify full structure on course detail page', async ({ page }) => { + await page.goto(courseUrl); + await page.waitForLoadState('networkidle'); + + // ตรวจสอบว่า tab โครงสร้างแสดง chapters ทั้งหมด + for (const chapter of CHAPTERS) { + // ตรวจสอบ chapter title (scope ไปที่ header element เพื่อกัน text ซ้ำ) + await expect(page.locator('.font-semibold').getByText(chapter.title.th)).toBeVisible({ timeout: 10_000 }); + + // ตรวจสอบ lessons ใน chapter + for (const lesson of chapter.lessons) { + await expect(page.locator('.q-item__label').getByText(lesson.title.th)).toBeVisible(); + } + } + + // ตรวจสอบจำนวนบทเรียนรวม + const totalLessons = CHAPTERS.reduce((sum, ch) => sum + ch.lessons.length, 0); + await expect(page.getByText(`${totalLessons} บทเรียน`)).toBeVisible(); + }); +}); diff --git a/frontend_management/tests/instructor/dashboard.spec.ts b/frontend_management/tests/instructor/dashboard.spec.ts index 0ac7b077..134a1f6b 100644 --- a/frontend_management/tests/instructor/dashboard.spec.ts +++ b/frontend_management/tests/instructor/dashboard.spec.ts @@ -11,25 +11,11 @@ test.describe('Instructor Dashboard', () => { await page.waitForLoadState('networkidle'); }); - test('should display welcome message', async ({ page }) => { - await expect(page.locator('h1')).toContainText('สวัสดี'); - }); - - test('should display stats cards', async ({ page }) => { + test('check display dashboard', async ({ page }) => { await expect(page.getByText('หลักสูตรทั้งหมด')).toBeVisible(); await expect(page.getByText('ผู้เรียนทั้งหมด')).toBeVisible(); await expect(page.getByText('เรียนจบแล้ว')).toBeVisible(); - }); - - test('should display course status breakdown', async ({ page }) => { await expect(page.getByText('สถานะหลักสูตร')).toBeVisible(); - await expect(page.getByText('เผยแพร่แล้ว')).toBeVisible(); - await expect(page.getByText('รอตรวจสอบ')).toBeVisible(); - await expect(page.getByText('แบบร่าง')).toBeVisible(); - }); - - test('should display recent courses section', async ({ page }) => { - await expect(page.getByText('หลักสูตร')).toBeVisible(); await expect(page.getByRole('button', { name: 'ดูทั้งหมด' })).toBeVisible(); }); @@ -43,7 +29,6 @@ test.describe('Instructor Dashboard', () => { await page.locator('.w-12.h-12.rounded-full').click(); await expect(page.getByText('โปรไฟล์')).toBeVisible(); - await expect(page.getByText('ออกจากระบบ')).toBeVisible(); }); test('should navigate to profile', async ({ page }) => { @@ -56,10 +41,10 @@ test.describe('Instructor Dashboard', () => { test('should logout and redirect to login', async ({ page }) => { await page.locator('.w-12.h-12.rounded-full').click(); - await page.getByText('ออกจากระบบ').click(); + await page.getByRole('menu').getByText('ออกจากระบบ').click(); // Confirm logout dialog - await page.locator('.q-dialog').getByText('ออกจากระบบ').click(); + await page.locator('.q-dialog').getByRole('button', { name: 'ออกจากระบบ' }).click(); await page.waitForURL('**/login**', { timeout: 10_000 }); await expect(page).toHaveURL(/\/login/); From b0b665f5884309543def9d5ff52dfa1b484cbf57 Mon Sep 17 00:00:00 2001 From: supalerk-ar66 Date: Fri, 6 Mar 2026 12:43:49 +0700 Subject: [PATCH 04/10] feat: Implement E2E tests for authentication, student account, discovery, and classroom features, alongside new browse pages and a `useAuth` composable. --- Frontend-Learner/composables/useAuth.ts | 39 ++- Frontend-Learner/pages/browse/discovery.vue | 52 ++-- Frontend-Learner/pages/browse/index.vue | 2 +- Frontend-Learner/playwright-report/index.html | 2 +- Frontend-Learner/tests/e2e/auth.spec.ts | 141 +++++----- Frontend-Learner/tests/e2e/classroom.spec.ts | 230 +++++++++++------ Frontend-Learner/tests/e2e/discovery.spec.ts | 82 +++--- .../tests/e2e/forgot-password.spec.ts | 102 -------- Frontend-Learner/tests/e2e/helpers.ts | 129 ++++++++++ Frontend-Learner/tests/e2e/login.spec.ts | 122 --------- Frontend-Learner/tests/e2e/quiz.spec.ts | 125 --------- Frontend-Learner/tests/e2e/register.spec.ts | 241 ------------------ .../tests/e2e/student-account.spec.ts | 141 +++++----- .../e2e/screenshots/discovery-curriculum.png | Bin 0 -> 55199 bytes .../e2e/screenshots/discovery-enroll-btn.png | Bin 0 -> 54333 bytes tests/e2e/screenshots/discovery-filter.png | Bin 0 -> 612294 bytes tests/e2e/screenshots/discovery-home.png | Bin 0 -> 1004319 bytes tests/e2e/screenshots/discovery-search.png | Bin 0 -> 221331 bytes tests/e2e/screenshots/forgot-01-smoke.png | Bin 48467 -> 48452 bytes .../e2e/screenshots/forgot-02-thai-email.png | Bin 48824 -> 48879 bytes .../e2e/screenshots/forgot-03-back-login.png | Bin 57976 -> 58742 bytes .../screenshots/forgot-04-mock-success.png | Bin 49526 -> 49543 bytes tests/e2e/screenshots/login-invalid-email.png | Bin 62192 -> 62171 bytes tests/e2e/screenshots/login-thai-email.png | Bin 60414 -> 60419 bytes tests/e2e/screenshots/login-to-dashboard.png | Bin 193995 -> 200356 bytes .../e2e/screenshots/login-wrong-password.png | Bin 67965 -> 66634 bytes tests/e2e/screenshots/register-go-login.png | Bin 57112 -> 57049 bytes .../register-invalid-email-thai.png | Bin 64155 -> 64177 bytes tests/e2e/screenshots/register-page.png | Bin 60464 -> 60577 bytes .../register-password-mismatch.png | Bin 69232 -> 69262 bytes .../screenshots/register-redirect-login.png | Bin 65826 -> 65536 bytes tests/e2e/screenshots/student-dashboard.png | Bin 0 -> 210479 bytes .../e2e/screenshots/student-edit-profile.png | Bin 0 -> 96713 bytes tests/e2e/screenshots/student-my-courses.png | Bin 0 -> 294599 bytes .../e2e/screenshots/student-search-empty.png | Bin 0 -> 61119 bytes 35 files changed, 546 insertions(+), 862 deletions(-) delete mode 100644 Frontend-Learner/tests/e2e/forgot-password.spec.ts create mode 100644 Frontend-Learner/tests/e2e/helpers.ts delete mode 100644 Frontend-Learner/tests/e2e/login.spec.ts delete mode 100644 Frontend-Learner/tests/e2e/quiz.spec.ts delete mode 100644 Frontend-Learner/tests/e2e/register.spec.ts create mode 100644 tests/e2e/screenshots/discovery-curriculum.png create mode 100644 tests/e2e/screenshots/discovery-enroll-btn.png create mode 100644 tests/e2e/screenshots/discovery-filter.png create mode 100644 tests/e2e/screenshots/discovery-home.png create mode 100644 tests/e2e/screenshots/discovery-search.png create mode 100644 tests/e2e/screenshots/student-dashboard.png create mode 100644 tests/e2e/screenshots/student-edit-profile.png create mode 100644 tests/e2e/screenshots/student-my-courses.png create mode 100644 tests/e2e/screenshots/student-search-empty.png diff --git a/Frontend-Learner/composables/useAuth.ts b/Frontend-Learner/composables/useAuth.ts index 61f5ee0a..e9e392d1 100644 --- a/Frontend-Learner/composables/useAuth.ts +++ b/Frontend-Learner/composables/useAuth.ts @@ -40,7 +40,7 @@ export const useAuth = () => { // ฟังก์ชันเข้าสู่ระบบ (Login) const login = async (credentials: { email: string; password: string }) => { try { - // API returns { code: 200, message: "...", data: { token, user, ... } } + // API returns { code: 200, message: "...", data: { token, refreshToken } } const response = await $fetch(`${API_BASE_URL}/auth/login`, { method: 'POST', body: credentials @@ -49,16 +49,35 @@ export const useAuth = () => { if (response && response.data) { const data = response.data - // Validation: Ensure user and role exist, then check for Role 'STUDENT' - if (!data.user || !data.user.role || data.user.role.code !== 'STUDENT') { - return { success: false, error: 'Email ไม่ถูกต้อง' } - } - + // บันทึก Token ก่อน เพื่อใช้เรียก /user/me token.value = data.token - refreshToken.value = data.refreshToken // บันทึก Refresh Token - - // API ส่งข้อมูล profile มาใน user object - user.value = data.user + refreshToken.value = data.refreshToken + + // ดึงข้อมูลผู้ใช้จาก /user/me (เพราะ API login ไม่ส่ง user กลับมาแล้ว) + try { + const userData = await $fetch(`${API_BASE_URL}/user/me`, { + headers: { + Authorization: `Bearer ${data.token}` + } + }) + + // Validation: ตรวจสอบ Role ต้องเป็น STUDENT เท่านั้น + if (!userData || !userData.role || userData.role.code !== 'STUDENT') { + // ถ้า Role ไม่ใช่ STUDENT ให้ล้าง Token ออก + token.value = null + refreshToken.value = null + return { success: false, error: 'Email ไม่ถูกต้อง' } + } + + // เก็บข้อมูล User ลง Cookie + user.value = userData + } catch (profileErr) { + // ดึงข้อมูลผู้ใช้ไม่สำเร็จ ให้ล้าง Token ออก + console.error('Failed to fetch user profile after login:', profileErr) + token.value = null + refreshToken.value = null + return { success: false, error: 'ไม่สามารถดึงข้อมูลผู้ใช้ได้' } + } return { success: true } } diff --git a/Frontend-Learner/pages/browse/discovery.vue b/Frontend-Learner/pages/browse/discovery.vue index e8f15f77..e44bb5ae 100644 --- a/Frontend-Learner/pages/browse/discovery.vue +++ b/Frontend-Learner/pages/browse/discovery.vue @@ -27,7 +27,7 @@ const sortBy = ref('ยอดนิยม'); const sortOptions = ['ยอดนิยม', 'ล่าสุด', 'ราคาต่ำ-สูงสุด', 'ราคาสูง-ต่ำสุด']; const categories = ref([]); -const courses = ref([]); +const allCourses = ref([]); // เก็บคอร์สทั้งหมดเพื่อกรอง client-side const selectedCourse = ref(null); const isLoading = ref(false); @@ -76,20 +76,17 @@ const loadCategories = async () => { if (res.success) categories.value = res.data || []; }; -const loadCourses = async (page = 1) => { +const loadCourses = async () => { isLoading.value = true; - const categoryId = activeCategory.value === 'all' ? undefined : activeCategory.value as number; + // โหลดคอร์สทั้งหมดครั้งเดียว (limit สูงๆ เพื่อ client-side filter) const res = await fetchCourses({ - category_id: categoryId, - search: searchQuery.value, - page: page, - limit: itemsPerPage, + limit: 500, forceRefresh: true, }); if (res.success) { - courses.value = (res.data || []).map(c => { + allCourses.value = (res.data || []).map(c => { const cat = categories.value.find(cat => cat.id === c.category_id); return { ...c, @@ -100,12 +97,33 @@ const loadCourses = async (page = 1) => { reviews_count: c.total_lessons ? c.total_lessons * 123 : Math.floor(Math.random() * 2000) + 100 } }); - totalPages.value = res.totalPages || 1; - currentPage.value = res.page || 1; } isLoading.value = false; }; +// Computed: กรองคอร์สแบบ real-time ตาม searchQuery + activeCategory +const filteredCourses = computed(() => { + let result = allCourses.value; + + // กรองตามหมวดหมู่ + if (activeCategory.value !== 'all') { + result = result.filter(c => c.category_id === activeCategory.value); + } + + // กรองตามคำค้นหา (ค้นจากชื่อทั้ง th และ en) + if (searchQuery.value.trim()) { + const query = searchQuery.value.trim().toLowerCase(); + result = result.filter(c => { + const titleTh = (c.title?.th || '').toLowerCase(); + const titleEn = (c.title?.en || '').toLowerCase(); + const titleStr = (typeof c.title === 'string' ? c.title : '').toLowerCase(); + return titleTh.includes(query) || titleEn.includes(query) || titleStr.includes(query); + }); + } + + return result; +}); + const selectCourse = async (id: number) => { isLoadingDetail.value = true; selectedCourse.value = null; @@ -137,10 +155,10 @@ watch( activeCategory, () => { currentPage.value = 1; - loadCourses(1); } ); + onMounted(async () => { await loadCategories(); @@ -150,7 +168,7 @@ onMounted(async () => { activeCategory.value = Number(route.query.category_id); } - await loadCourses(1); + await loadCourses(); if (route.query.course_id) { selectCourse(Number(route.query.course_id)); @@ -169,8 +187,8 @@ onMounted(async () => {

คอร์สเรียนทั้งหมด

- - + +
@@ -208,10 +226,10 @@ onMounted(async () => {
-
+
-
+
@@ -241,7 +259,7 @@ onMounted(async () => {
-
+
diff --git a/Frontend-Learner/pages/browse/index.vue b/Frontend-Learner/pages/browse/index.vue index 3e82a01d..c0e3f3c4 100644 --- a/Frontend-Learner/pages/browse/index.vue +++ b/Frontend-Learner/pages/browse/index.vue @@ -54,7 +54,7 @@ await useAsyncData('categories-list', () => fetchCategories()) const { data: coursesResponse, pending: isLoading, error, refresh } = await useAsyncData( 'browse-courses-list', () => { - const params: any = {} + const params: any = { limit: 500 } if (selectedCategory.value !== 'all') { const category = categories.value.find(c => c.slug === selectedCategory.value) if (category) { diff --git a/Frontend-Learner/playwright-report/index.html b/Frontend-Learner/playwright-report/index.html index 15686deb..ba7aaae5 100644 --- a/Frontend-Learner/playwright-report/index.html +++ b/Frontend-Learner/playwright-report/index.html @@ -82,4 +82,4 @@ Error generating stack: `+a.message+`
- \ No newline at end of file + \ No newline at end of file diff --git a/Frontend-Learner/tests/e2e/auth.spec.ts b/Frontend-Learner/tests/e2e/auth.spec.ts index 5a87d40f..bf16f492 100644 --- a/Frontend-Learner/tests/e2e/auth.spec.ts +++ b/Frontend-Learner/tests/e2e/auth.spec.ts @@ -1,40 +1,13 @@ +/** + * @file auth.spec.ts + * @description ทดสอบระบบยืนยันตัวตน (Authentication) — Login, Register, Forgot Password + */ import { test, expect, type Page, type Locator } from '@playwright/test'; - -const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; - -async function waitAppSettled(page: Page) { - await page.waitForLoadState('domcontentloaded'); - await page.waitForLoadState('networkidle').catch(() => {}); - await page.waitForTimeout(250); -} - -// --------------------------- -// Helpers: Login -// --------------------------- -const LOGIN_EMAIL = 'studentedtest@example.com'; -const LOGIN_PASSWORD = 'admin123'; - -function loginEmailLocator(page: Page): Locator { - return page.locator('input[type="email"]').or(page.getByRole('textbox', { name: /อีเมล|email/i })).first(); -} -function loginPasswordLocator(page: Page): Locator { - return page.locator('input[type="password"]').or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })).first(); -} -function loginButtonLocator(page: Page): Locator { - return page.getByRole('button', { name: /เข้าสู่ระบบ|login/i }).or(page.locator('button[type="submit"]')).first(); -} -async function expectAnyVisible(page: Page, locators: Locator[], timeout = 20_000) { - const start = Date.now(); - while (Date.now() - start < timeout) { - for (const loc of locators) { - try { - if (await loc.isVisible()) return; - } catch {} - } - await page.waitForTimeout(200); - } - throw new Error('None of the expected locators became visible.'); -} +import { + BASE_URL, TEST_EMAIL, TEST_PASSWORD, TIMEOUT, + waitAppSettled, expectAnyVisible, + emailLocator, passwordLocator, loginButtonLocator, +} from './helpers'; // --------------------------- // Helpers: Register @@ -53,6 +26,7 @@ function regLoginLink(page: Page) { return page.getByRole('link', { name: 'เ function regErrorBox(page: Page) { return page.locator(['.q-field__messages', '.q-field__bottom', '.text-negative', '.q-notification', '.q-banner', '[role="alert"]'].join(', ')); } + async function pickPrefix(page: Page, value: 'นาย' | 'นาง' | 'นางสาว' = 'นาย') { const combo = regPrefix(page); await combo.selectOption({ label: value }).catch(async () => { @@ -60,6 +34,7 @@ async function pickPrefix(page: Page, value: 'นาย' | 'นาง' | 'นา await page.getByRole('option', { name: value }).click(); }); } + function uniqueUser() { const n = Date.now().toString().slice(-6); const rand8 = Math.floor(Math.random() * 1e8).toString().padStart(8, '0'); @@ -90,10 +65,12 @@ test.describe('ระบบยืนยันตัวตน (Authentication)', test('Success Login แล้วเข้า /dashboard ได้', async ({ page }) => { await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); - await loginEmailLocator(page).fill(LOGIN_EMAIL); - await loginPasswordLocator(page).fill(LOGIN_PASSWORD); + + await emailLocator(page).fill(TEST_EMAIL); + await passwordLocator(page).fill(TEST_PASSWORD); await loginButtonLocator(page).click(); - await page.waitForURL('**/dashboard', { timeout: 25_000 }); + + await page.waitForURL('**/dashboard', { timeout: TIMEOUT.LOGIN }); await waitAppSettled(page); const dashboardEvidence = [ @@ -102,38 +79,45 @@ test.describe('ระบบยืนยันตัวตน (Authentication)', page.locator('img[src*="avataaars"]').first(), page.locator('img[alt],[alt="User Avatar"]').first() ]; - await expectAnyVisible(page, dashboardEvidence, 20_000); + await expectAnyVisible(page, dashboardEvidence, TIMEOUT.PAGE_LOAD); }); test('Invalid Email - Thai characters (พิมพ์ภาษาไทย)', async ({ page }) => { await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); - await loginEmailLocator(page).fill('ทดสอบภาษาไทย'); - await loginPasswordLocator(page).fill(LOGIN_PASSWORD); - const errorHint = page.getByText('ห้ามใส่ภาษาไทย'); - await expect(errorHint.first()).toBeVisible({ timeout: 12_000 }); + + await emailLocator(page).fill('ทดสอบภาษาไทย'); + await passwordLocator(page).fill(TEST_PASSWORD); + + await expect(page.getByText('ห้ามใส่ภาษาไทย').first()).toBeVisible({ timeout: TIMEOUT.ELEMENT }); }); test('Invalid Email Format (อีเมลผิดรูปแบบ)', async ({ page }) => { await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); - await loginEmailLocator(page).fill('test@domain'); - await loginPasswordLocator(page).fill(LOGIN_PASSWORD); + + await emailLocator(page).fill('test@domain'); + await passwordLocator(page).fill(TEST_PASSWORD); await loginButtonLocator(page).click(); await waitAppSettled(page); - const errorHint = page.getByText('กรุณากรอกอีเมลให้ถูกต้อง (you@example.com)'); - await expect(errorHint.first()).toBeVisible({ timeout: 12_000 }); + + await expect( + page.getByText('กรุณากรอกอีเมลให้ถูกต้อง (you@example.com)').first() + ).toBeVisible({ timeout: TIMEOUT.ELEMENT }); }); test('Wrong Password (รหัสผ่านผิด หรืออีเมลไม่ถูกต้องในระบบ)', async ({ page }) => { await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); - await loginEmailLocator(page).fill(LOGIN_EMAIL); - await loginPasswordLocator(page).fill('wrong-password-123'); + + await emailLocator(page).fill(TEST_EMAIL); + await passwordLocator(page).fill('wrong-password-123'); await loginButtonLocator(page).click(); await waitAppSettled(page); - const errorHint = page.getByText('กรุณาเช็ค Email หรือ รหัสผ่านใหม่อีกครั้ง'); - await expect(errorHint.first()).toBeVisible({ timeout: 12_000 }); + + await expect( + page.getByText('กรุณาเช็ค Email หรือ รหัสผ่านใหม่อีกครั้ง').first() + ).toBeVisible({ timeout: TIMEOUT.ELEMENT }); }); }); @@ -142,21 +126,22 @@ test.describe('ระบบยืนยันตัวตน (Authentication)', test('หน้า Register ต้องโหลดได้ (Smoke)', async ({ page }) => { await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); - await expect(regHeading(page)).toBeVisible({ timeout: 15_000 }); - await expect(regSubmit(page)).toBeVisible({ timeout: 15_000 }); + await expect(regHeading(page)).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); + await expect(regSubmit(page)).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); }); test('ลิงก์ "เข้าสู่ระบบ" ต้องกดแล้วไปหน้า login ได้', async ({ page }) => { await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); await regLoginLink(page).click(); - await page.waitForURL('**/auth/login', { timeout: 15_000 }); + await page.waitForURL('**/auth/login', { timeout: TIMEOUT.PAGE_LOAD }); }); test('สมัครสมาชิกสำเร็จ (Happy Path) → redirect ไป /auth/login', async ({ page }) => { const u = uniqueUser(); await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); + await regUsername(page).fill(u.username); await regEmail(page).fill(u.email); await pickPrefix(page, 'นาย'); @@ -168,15 +153,18 @@ test.describe('ระบบยืนยันตัวตน (Authentication)', await regSubmit(page).click(); await waitAppSettled(page); - const navToLogin = page.waitForURL('**/auth/login', { timeout: 25_000, waitUntil: 'domcontentloaded' }).then(() => 'login' as const).catch(() => null); - const successToast = page.getByText(/สมัครสมาชิกสำเร็จ|success/i, { exact: false }).first().waitFor({ state: 'visible', timeout: 25_000 }).then(() => 'success' as const).catch(() => null); - const anyError = regErrorBox(page).first().waitFor({ state: 'visible', timeout: 25_000 }).then(() => 'error' as const).catch(() => null); - + // รอ 3 สัญญาณ: redirect ไป login / success toast / error + const navToLogin = page.waitForURL('**/auth/login', { timeout: TIMEOUT.LOGIN, waitUntil: 'domcontentloaded' }).then(() => 'login' as const).catch(() => null); + const successToast = page.getByText(/สมัครสมาชิกสำเร็จ|success/i, { exact: false }).first().waitFor({ state: 'visible', timeout: TIMEOUT.LOGIN }).then(() => 'success' as const).catch(() => null); + const anyError = regErrorBox(page).first().waitFor({ state: 'visible', timeout: TIMEOUT.LOGIN }).then(() => 'error' as const).catch(() => null); + const result = await Promise.race([navToLogin, successToast, anyError]); if (result === 'error') { - throw new Error('Register errors visible'); + const errs = await regErrorBox(page).allInnerTexts().catch(() => []); + throw new Error(`Register failed with errors: ${errs.join(' | ')}`); } + // ถ้ามี toast แต่ยัง redirect ไม่ไป ให้ navigate เอง if (!page.url().includes('/auth/login')) { const hasSuccess = await page.getByText(/สมัครสมาชิกสำเร็จ/i, { exact: false }).first().isVisible().catch(() => false); if (hasSuccess) { @@ -185,24 +173,28 @@ test.describe('ระบบยืนยันตัวตน (Authentication)', } } - await expect(page).toHaveURL(/\/auth\/login/i, { timeout: 15_000 }); - await expect(page.getByRole('heading', { name: 'เข้าสู่ระบบ' })).toBeVisible({ timeout: 15_000 }); - await expect(page.getByRole('button', { name: 'เข้าสู่ระบบ' })).toBeVisible({ timeout: 15_000 }); + await expect(page).toHaveURL(/\/auth\/login/i, { timeout: TIMEOUT.PAGE_LOAD }); + await expect(page.getByRole('heading', { name: 'เข้าสู่ระบบ' })).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); + await expect(page.getByRole('button', { name: 'เข้าสู่ระบบ' })).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); }); test('Invalid Email - ใส่ภาษาไทย ต้องขึ้น error', async ({ page }) => { await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); await regEmail(page).fill('ทดสอบภาษาไทย'); - await regUsername(page).click(); - const err = page.getByText(/ห้ามใส่ภาษาไทย|อีเมลไม่ถูกต้อง|รูปแบบอีเมล/i, { exact: false }).or(regErrorBox(page).filter({ hasText: /ไทย|อีเมล|email|invalid/i })); - await expect(err.first()).toBeVisible({ timeout: 12_000 }); + await regUsername(page).click(); // blur trigger + + const err = page + .getByText(/ห้ามใส่ภาษาไทย|อีเมลไม่ถูกต้อง|รูปแบบอีเมล/i, { exact: false }) + .or(regErrorBox(page).filter({ hasText: /ไทย|อีเมล|email|invalid/i })); + await expect(err.first()).toBeVisible({ timeout: TIMEOUT.ELEMENT }); }); test('Password ไม่ตรงกัน ต้องขึ้น error (ต้องกดสร้างบัญชีก่อน)', async ({ page }) => { const u = uniqueUser(); await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); + await regUsername(page).fill(u.username); await regEmail(page).fill(u.email); await pickPrefix(page, 'นาย'); @@ -210,11 +202,14 @@ test.describe('ระบบยืนยันตัวตน (Authentication)', await regLastName(page).fill(u.lastName); await regPhone(page).fill(u.phone); await regPassword(page).fill('Admin12345!'); - await regConfirmPassword(page).fill('Admin12345?'); + await regConfirmPassword(page).fill('Admin12345?'); // mismatch await regSubmit(page).click(); await waitAppSettled(page); - const mismatchErr = page.getByText(/รหัสผ่านไม่ตรงกัน/i, { exact: false }).or(regErrorBox(page).filter({ hasText: /รหัสผ่านไม่ตรงกัน/i })); - await expect(mismatchErr.first()).toBeVisible({ timeout: 12_000 }); + + const mismatchErr = page + .getByText(/รหัสผ่านไม่ตรงกัน/i, { exact: false }) + .or(regErrorBox(page).filter({ hasText: /รหัสผ่านไม่ตรงกัน/i })); + await expect(mismatchErr.first()).toBeVisible({ timeout: TIMEOUT.ELEMENT }); }); }); @@ -235,13 +230,12 @@ test.describe('ระบบยืนยันตัวตน (Authentication)', test('Validation: ใส่อีเมลภาษาไทยแล้วขึ้น Error', async ({ page }) => { await forgotEmail(page).fill('ฟฟฟฟ'); await page.getByRole('heading', { name: /ลืมรหัสผ่าน/i }).click(); - const err = page.getByText(/ห้ามใส่ภาษาไทย/i).first(); - await expect(err).toBeVisible({ timeout: 10_000 }); + await expect(page.getByText(/ห้ามใส่ภาษาไทย/i).first()).toBeVisible({ timeout: TIMEOUT.ELEMENT }); }); test('กดลิงก์กลับไปหน้า Login ได้', async ({ page }) => { await forgotBackLink(page).click(); - await page.waitForURL('**/auth/login', { timeout: 10_000 }); + await page.waitForURL('**/auth/login', { timeout: TIMEOUT.ELEMENT }); await expect(page).toHaveURL(/\/auth\/login/i); }); @@ -257,9 +251,10 @@ test.describe('ระบบยืนยันตัวตน (Authentication)', } await route.continue(); }); + await forgotEmail(page).fill('test@gmail.com'); await forgotSubmit(page).click(); - await expect(page.getByText(/ส่งลิงก์เรียบร้อยแล้ว/i, { exact: false })).toBeVisible({ timeout: 10_000 }); + await expect(page.getByText(/ส่งลิงก์เรียบร้อยแล้ว/i, { exact: false })).toBeVisible({ timeout: TIMEOUT.ELEMENT }); await expect(page.getByText(/กรุณาตรวจสอบกล่องจดหมาย/i, { exact: false })).toBeVisible(); }); }); diff --git a/Frontend-Learner/tests/e2e/classroom.spec.ts b/Frontend-Learner/tests/e2e/classroom.spec.ts index 136ad904..6391fca6 100644 --- a/Frontend-Learner/tests/e2e/classroom.spec.ts +++ b/Frontend-Learner/tests/e2e/classroom.spec.ts @@ -1,95 +1,175 @@ +/** + * @file classroom.spec.ts + * @description ทดสอบระบบห้องเรียนออนไลน์ และระบบแบบทดสอบ + * (Classroom, Learning & Quiz System) + * + * รวม 2 module: + * - Classroom & Learning (Layout, Access Control, Video/Quiz area) + * - Quiz System (Start Screen, Pagination, Submit & Navigation) + */ import { test, expect } from '@playwright/test'; +import { BASE_URL, TIMEOUT, waitAppSettled, setupLogin } from './helpers'; -const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; +// ========================================== +// Mock: ข้อมูล Quiz สำหรับ test +// ========================================== +async function mockQuizData(page: any) { + await page.route('**/lessons/*', async (route: any) => { + const mockQuestions = Array.from({ length: 15 }, (_, i) => ({ + id: i + 1, + question: { th: `คำถามข้อที่ ${i + 1}?`, en: `Question ${i + 1}?` }, + text: { th: `คำถามข้อที่ ${i + 1}?`, en: `Question ${i + 1}?` }, + choices: [ + { id: i * 10 + 1, text: { th: 'ก', en: 'A' } }, + { id: i * 10 + 2, text: { th: 'ข', en: 'B' } }, + { id: i * 10 + 3, text: { th: 'ค', en: 'C' } } + ] + })); -async function waitAppSettled(page: any) { - await page.waitForLoadState('domcontentloaded'); - await page.waitForLoadState('networkidle').catch(() => {}); - await page.waitForTimeout(200); + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + success: true, + data: { + id: 17, + type: 'QUIZ', + quiz: { + id: 99, + title: { th: 'แบบทดสอบปลายภาค (Mock)', en: 'Final Exam (Mock)' }, + time_limit: 30, + questions: mockQuestions + } + }, + progress: {} + }) + }); + }); } -// ฟังก์ชันจำลองล็อกอิน -async function setupLogin(page: any) { - await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); - await waitAppSettled(page); - - await page.locator('input[type="email"]').or(page.getByRole('textbox', { name: /อีเมล|email/i })).first().fill('studentedtest@example.com'); - await page.locator('input[type="password"]').or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })).first().fill('admin123'); - await page.getByRole('button', { name: /เข้าสู่ระบบ|login/i }).or(page.locator('button[type="submit"]')).first().click(); - - await page.waitForURL('**/dashboard', { timeout: 15_000 }).catch(() => {}); - await waitAppSettled(page); -} - -test.describe('ระบบห้องเรียนออนไลน์ (Classroom & Learning)', () => { +// ========================================== +// Tests +// ========================================== +test.describe('ระบบห้องเรียนออนไลน์และแบบทดสอบ (Classroom & Quiz)', () => { test.beforeEach(async ({ page }) => { await setupLogin(page); }); - test('6.1 เข้าห้องเรียนหลัก (Classroom Basic Layout)', async ({ page }) => { - // สมมติว่ามี Course ID: 1 ทดสอบแบบเปิดหน้าตรงๆ - await page.goto(`${BASE_URL}/classroom/learning?course_id=1`); - - // 1. โครงร่างของหน้า (Top Bar) ควรมีปุ่มกลับ กับไอคอนแผงด้านข้าง - const backBtn = page.getByRole('button').filter({ has: page.locator('i.q-icon', { hasText: 'arrow_back' }) }).first(); - await expect(backBtn).toBeVisible({ timeout: 15_000 }); + // -------------------------------------------------- + // Section 1: ห้องเรียน (Classroom & Learning) + // -------------------------------------------------- + test.describe('ห้องเรียน (Classroom Layout & Access)', () => { - const menuCurriculumBtn = page.getByRole('button').filter({ has: page.locator('i.q-icon', { hasText: 'menu_open' }) }).first(); - await expect(menuCurriculumBtn).toBeVisible({ timeout: 15_000 }); + test('6.1 เข้าห้องเรียนหลัก (Classroom Basic Layout)', async ({ page }) => { + await page.goto(`${BASE_URL}/classroom/learning?course_id=1`); - // 2. เช็คว่ามีพื้นที่ Sidebar หลักสูตร (CurriculumSidebar Component) โผล่ขึ้นมาหรือมีอยู่ใน DOM - const sidebar = page.locator('.q-drawer').first(); - if (!await sidebar.isVisible()) { - await menuCurriculumBtn.click(); - } - await expect(sidebar).toBeVisible(); - }); + // 1. โครงร่างของหน้า — ปุ่มกลับ + ไอคอนแผงด้านข้าง + const backBtn = page.getByRole('button').filter({ has: page.locator('i.q-icon', { hasText: 'arrow_back' }) }).first(); + await expect(backBtn).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); - test('6.2 เช็คสถานะการเข้าถึงเนื้อหา (Access Control)', async ({ page }) => { - // ลองสุ่ม Course ID สูงๆ ที่อาจจะไม่อนุญาตให้เรียน (ไม่มีสิทธิ์) ควรรองรับกล่องแจ้งเตือนด้วย Alert ของระบบ - // ใน learning.vue จะมีการสั่ง `alert(msg)` แต่อาจจะต้องพึ่งกลไก Intercepter - - page.on('dialog', async dialog => { - // หน้าต่าง Alert ถ้ามีสิทธิ์ไม่อนุญาตมันจะเด้งอันนี้ - expect(dialog.message()).toBeTruthy(); - await dialog.accept(); + const menuCurriculumBtn = page.getByRole('button').filter({ has: page.locator('i.q-icon', { hasText: 'menu_open' }) }).first(); + await expect(menuCurriculumBtn).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); + + // 2. Sidebar หลักสูตร + const sidebar = page.locator('.q-drawer').first(); + if (!await sidebar.isVisible()) { + await menuCurriculumBtn.click(); + } + await expect(sidebar).toBeVisible(); }); - await page.goto(`${BASE_URL}/classroom/learning?course_id=99999`); - - // รอดู Loading หายไป - const loadingMask = page.locator('.animate-pulse, .q-spinner'); - await loadingMask.first().waitFor({ state: 'hidden', timeout: 20_000 }).catch(() => {}); + test('6.2 เช็คสถานะการเข้าถึงเนื้อหา (Access Control)', async ({ page }) => { + page.on('dialog', async dialog => { + expect(dialog.message()).toBeTruthy(); + await dialog.accept(); + }); + + await page.goto(`${BASE_URL}/classroom/learning?course_id=99999`); + + const loadingMask = page.locator('.animate-pulse, .q-spinner'); + await loadingMask.first().waitFor({ state: 'hidden', timeout: TIMEOUT.PAGE_LOAD }).catch(() => {}); + }); + + test('6.3 การแสดงผลช่องวิดีโอ หรือ พื้นที่ทำข้อสอบ (Video / Quiz)', async ({ page }) => { + await page.goto(`${BASE_URL}/classroom/learning?course_id=1`); + + const videoLocator = page.locator('video').first(); + const quizLocator = page.getByText(/เริ่มทำแบบทดสอบ|แบบทดสอบ/i).first(); + const errorLocator = page.getByText(/ไม่สามารถเข้าถึง/i).first(); + + try { + await Promise.race([ + videoLocator.waitFor({ state: 'visible', timeout: TIMEOUT.PAGE_LOAD }), + quizLocator.waitFor({ state: 'visible', timeout: TIMEOUT.PAGE_LOAD }), + errorLocator.waitFor({ state: 'visible', timeout: TIMEOUT.PAGE_LOAD }) + ]); + + const isOkay = (await videoLocator.isVisible()) || (await quizLocator.isVisible()) || (await errorLocator.isVisible()); + expect(isOkay).toBeTruthy(); + } catch { + await page.screenshot({ path: 'tests/e2e/screenshots/classroom-blank-state.png', fullPage: true }); + } + }); }); - test('6.3 การแสดงผลช่องวิดีโอ (Video Player) หรือ พื้นที่ทำข้อสอบ (Quiz)', async ({ page }) => { - // เข้าหน้าห้องเรียน Course id: 1 - await page.goto(`${BASE_URL}/classroom/learning?course_id=1`); - - // กรณีที่ 1: อาจแสดง Video ถ้าเป็นบทเรียนวิดีโอ - const videoLocator = page.locator('video').first(); - - // กรณีที่ 2: ถ้าบทแรกเป็น Quiz จะแสดงไอคอนแบบทดสอบ - const quizLocator = page.getByText(/เริ่มทำแบบทดสอบ|แบบทดสอบ/i).first(); - - // กรณีที่ 3: ไม่มีบทเรียนเนื้อหาใดๆ เลยให้แสดง - const errorLocator = page.getByText(/ไม่สามารถเข้าถึง/i).first(); + // -------------------------------------------------- + // Section 2: แบบทดสอบ (Quiz System) + // -------------------------------------------------- + test.describe('แบบทดสอบ (Quiz System)', () => { - try { - await Promise.race([ - videoLocator.waitFor({ state: 'visible', timeout: 20_000 }), - quizLocator.waitFor({ state: 'visible', timeout: 20_000 }), - errorLocator.waitFor({ state: 'visible', timeout: 20_000 }) - ]); - - const isOkay = (await videoLocator.isVisible()) || (await quizLocator.isVisible()) || (await errorLocator.isVisible()); - expect(isOkay).toBeTruthy(); - } catch { - // ถ้าไม่มีเลยใน 20 วิ ถือว่าหน้าอาจจะล้มเหลว หรือเป็น Content เปล่า - // ให้ลอง Capture เพื่อเก็บข้อมูลไปใช้งาน - await page.screenshot({ path: 'tests/e2e/screenshots/classroom-blank-state.png', fullPage: true }); - } + test('7.1 โหลดหน้า Quiz และเริ่มทำข้อสอบได้ (Start Screen)', async ({ page }) => { + await mockQuizData(page); + await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); + + const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); + await expect(startBtn).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); + + // กดเริ่มทำ + await startBtn.click(); + + // เช็คว่าหน้า Taking (คำถามข้อที่ 1) โผล่มา + const questionText = page.locator('h3').first(); + await expect(questionText).toBeVisible({ timeout: TIMEOUT.ELEMENT }); + }); + + test('7.2 แถบข้อสอบแบ่งหน้า (Pagination — เลื่อนซ้าย/ขวา)', async ({ page }) => { + await mockQuizData(page); + await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); + + const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); + await expect(startBtn).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); + await startBtn.click(); + + // ลูกศรเลื่อนหน้าข้อสอบ + const nextPaginationPageBtn = page.locator('button').filter({ has: page.locator('i.q-icon:has-text("chevron_right")') }).first(); + + if (await nextPaginationPageBtn.isVisible()) { + await expect(nextPaginationPageBtn).toBeEnabled(); + await nextPaginationPageBtn.click(); + + // ข้อที่ 11 ต้องแสดง + const question11Btn = page.locator('button').filter({ hasText: /^11$/ }).first(); + await expect(question11Btn).toBeVisible(); + } + }); + + test('7.3 การแสดงผลปุ่มถัดไป/ส่งคำตอบ (Submit & Navigation UI)', async ({ page }) => { + await mockQuizData(page); + await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); + + const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); + await expect(startBtn).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); + await startBtn.click(); + + // รอคำถามโหลดเสร็จ + await expect(page.locator('h3').first()).toBeVisible({ timeout: TIMEOUT.ELEMENT }); + + const submitBtn = page.locator('button').filter({ hasText: /(ส่งคำตอบ|Submit)/i }).first(); + const nextBtn = page.locator('button').filter({ hasText: /(ถัดไป|Next)/i }).first(); + + // ข้อแรกต้องมีปุ่มถัดไปหรือปุ่มส่ง + await expect(submitBtn.or(nextBtn)).toBeVisible({ timeout: TIMEOUT.ELEMENT }); + }); }); - }); diff --git a/Frontend-Learner/tests/e2e/discovery.spec.ts b/Frontend-Learner/tests/e2e/discovery.spec.ts index 2783d7da..52cf9ea3 100644 --- a/Frontend-Learner/tests/e2e/discovery.spec.ts +++ b/Frontend-Learner/tests/e2e/discovery.spec.ts @@ -1,91 +1,103 @@ +/** + * @file discovery.spec.ts + * @description ทดสอบหมวดหน้าค้นหาคอร์สและผลลัพธ์ (Discovery & Browse) + */ import { test, expect } from '@playwright/test'; - -const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; +import { BASE_URL, TIMEOUT, waitAppSettled } from './helpers'; test.describe('หมวดหน้าค้นหาคอร์สและผลลัพธ์ (Discovery & Browse)', () => { - + test.describe('ส่วนหน้าแรก (Home)', () => { test('โหลดหน้าแรก และตรวจสอบแสดงผลครบถ้วน (Hero, Cards, Categories)', async ({ page }) => { await page.goto(BASE_URL); + await waitAppSettled(page); + const heroTitle = page.locator('h1, h2, .hero-title').first(); - await expect(heroTitle).toBeVisible({ timeout: 15_000 }); - + await expect(heroTitle).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); + const ctaButton = page.locator('a[href="/browse"]').first(); if (await ctaButton.isVisible()) { - await expect(ctaButton).toBeVisible(); + await expect(ctaButton).toBeVisible(); } const courseSectionHeading = page.getByText(/คอร์สออนไลน์|Online Courses/i).first(); - await expect(courseSectionHeading).toBeVisible({ timeout: 10_000 }); + await expect(courseSectionHeading).toBeVisible({ timeout: TIMEOUT.ELEMENT }); const allCategoryBtn = page.getByRole('button', { name: /ทั้งหมด|All/i }).first(); await expect(allCategoryBtn).toBeVisible(); const courseCards = page.locator('div.cursor-pointer').filter({ has: page.locator('img') }); - await expect(courseCards.first()).toBeVisible({ timeout: 15_000 }); + await expect(courseCards.first()).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); expect(await courseCards.count()).toBeGreaterThan(0); + + await page.screenshot({ path: 'tests/e2e/screenshots/discovery-home.png', fullPage: true }); }); }); test.describe('ส่วนค้นหาและแคตตาล็อก (Browse)', () => { test('ค้นหาหลักสูตร (Search Course)', async ({ page }) => { await page.goto(`${BASE_URL}/browse`); - const searchInput = page.locator('input[placeholder="ค้นหาคอร์ส..."]').first(); - await searchInput.fill('การเขียนโปรแกรม'); - await searchInput.press('Enter'); + await waitAppSettled(page); - // ในหน้า browse จะใช้ ซึ่ง render เป็น tag + const searchInput = page.locator('input[placeholder="ค้นหาคอร์ส..."]').first(); + await expect(searchInput).toBeVisible({ timeout: TIMEOUT.ELEMENT }); + await searchInput.fill('Python'); + await searchInput.press('Enter'); + await waitAppSettled(page); + + // ต้องเจออย่างใดอย่างหนึ่ง: ผลลัพธ์คอร์ส หรือ empty state const searchResults = page.locator('a[href*="/course/"]').filter({ has: page.locator('img') }).first(); - await expect(searchResults).toBeVisible({ timeout: 15_000 }); + const emptyState = page.getByText(/ไม่พบ|ไม่เจอ|No result|not found/i).first() + .or(page.locator('i.q-icon').filter({ hasText: 'search_off' }).first()); + + await expect(searchResults.or(emptyState)).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); + + await page.screenshot({ path: 'tests/e2e/screenshots/discovery-search.png', fullPage: true }); }); test('ตัวกรองหมวดหมู่คอร์ส (Category Filter)', async ({ page }) => { await page.goto(`${BASE_URL}/browse`); + await waitAppSettled(page); + const categoryButton = page.locator('button').filter({ hasText: 'การออกแบบ' }).first(); - + if (await categoryButton.isVisible()) { await categoryButton.click(); - // ในหน้า browse จะใช้ ซึ่ง render เป็น tag const courseCard = page.locator('a[href*="/course/"]').filter({ has: page.locator('img') }).first(); - await expect(courseCard).toBeVisible({ timeout: 15_000 }); + await expect(courseCard).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); } + + await page.screenshot({ path: 'tests/e2e/screenshots/discovery-filter.png', fullPage: true }); }); }); test.describe('หน้ารายละเอียดคอร์ส (Course Detail)', () => { test('โหลดเนื้อหาวิชา (Curriculum) แถบรายละเอียดขึ้นปกติ', async ({ page }) => { - await page.goto(`${BASE_URL}`); - const courseCard = page.locator('div.cursor-pointer').filter({ has: page.locator('img') }).first(); - await expect(courseCard).toBeVisible({ timeout: 10_000 }); - // Get URL from navigating when clicking the div or finding another link. Since it's a div, we cannot easily get href. - // So let's click it or fallback to /course/1 - const targetUrl = '/course/1'; - - await page.goto(`${BASE_URL}${targetUrl}`); - + await page.goto(`${BASE_URL}/course/1`); + await waitAppSettled(page); + const courseTitle = page.locator('h1').first(); - await expect(courseTitle).toBeVisible({ timeout: 15_000 }); + await expect(courseTitle).toBeVisible({ timeout: TIMEOUT.PAGE_LOAD }); const curriculumTab = page.getByRole('tab', { name: /เนื้อหาวิชา|ส่วนหลักสูตร|Curriculum/i }).first(); if (await curriculumTab.isVisible()) { - await curriculumTab.click(); + await curriculumTab.click(); } const lessonItems = page.locator('.q-expansion-item, .lesson-item, [role="listitem"]'); await expect(lessonItems.first()).toBeVisible().catch(() => {}); + + await page.screenshot({ path: 'tests/e2e/screenshots/discovery-curriculum.png', fullPage: true }); }); test('การแสดงผลปุ่ม เข้าเรียน/ลงทะเบียน (Enroll / Start Learning)', async ({ page }) => { - await page.goto(`${BASE_URL}`); - const courseCard = page.locator('div.cursor-pointer').filter({ has: page.locator('img') }).first(); - await expect(courseCard).toBeVisible({ timeout: 10_000 }); - const targetUrl = '/course/1'; - - await page.goto(`${BASE_URL}${targetUrl}`); - await page.waitForLoadState('networkidle').catch(() => {}); + await page.goto(`${BASE_URL}/course/1`); + await waitAppSettled(page); const enrollStartBtn = page.locator('button').filter({ hasText: /(เข้าสู่ระบบ|ลงทะเบียน|เข้าเรียน|เรียนต่อ|ซื้อ|ฟรี|Enroll|Start|Buy|Login)/i }).first(); - await expect(enrollStartBtn).toBeVisible({ timeout: 10_000 }); + await expect(enrollStartBtn).toBeVisible({ timeout: TIMEOUT.ELEMENT }); + + await page.screenshot({ path: 'tests/e2e/screenshots/discovery-enroll-btn.png', fullPage: true }); }); }); }); diff --git a/Frontend-Learner/tests/e2e/forgot-password.spec.ts b/Frontend-Learner/tests/e2e/forgot-password.spec.ts deleted file mode 100644 index 24260d3e..00000000 --- a/Frontend-Learner/tests/e2e/forgot-password.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { test, expect, type Page } from '@playwright/test'; - -const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; - -// ✅ หน้าจริงคือ /auth/forgot-password (อ้างอิงจากรูป) -const FORGOT_URL = `${BASE_URL}/auth/forgot-password`; - -async function waitAppSettled(page: Page) { - await page.waitForLoadState('domcontentloaded'); - await page.waitForLoadState('networkidle').catch(() => {}); - await page.waitForTimeout(200); -} - -function emailInput(page: Page) { - // เผื่อบางที input ไม่ได้ type=email แต่เป็น textbox ธรรมดา - return page.locator('input[type="email"]').or(page.getByRole('textbox')).first(); -} - -function submitBtn(page: Page) { - // ปุ่มในรูปเป็น “ส่งลิงก์รีเซ็ต” - return page.getByRole('button', { name: /ส่งลิงก์รีเซ็ต/i }).first(); -} - -function backToLoginLink(page: Page) { - // ในรูปเป็นลิงก์ “กลับไปหน้าเข้าสู่ระบบ” - return page.getByRole('link', { name: /กลับไปหน้าเข้าสู่ระบบ/i }).first(); -} - -test.describe('หน้าลืมรหัสผ่าน (Forgot Password)', () => { - test.beforeEach(async ({ page }) => { - await page.goto(FORGOT_URL, { waitUntil: 'domcontentloaded' }); - await waitAppSettled(page); - }); - - test('3.1 โหลดหน้าลืมรหัสผ่านได้ครบถ้วน (Smoke Test)', async ({ page }) => { - await expect(page.getByRole('heading', { name: /ลืมรหัสผ่าน/i })).toBeVisible(); - await expect(emailInput(page)).toBeVisible(); - await expect(submitBtn(page)).toBeVisible(); - await expect(backToLoginLink(page)).toBeVisible(); - - await page.screenshot({ path: 'tests/e2e/screenshots/forgot-01-smoke.png', fullPage: true }); - }); - - test('3.2 Validation: ใส่อีเมลภาษาไทยแล้วขึ้น Error', async ({ page }) => { - await emailInput(page).fill('ฟฟฟฟ'); - - // trigger blur - await page.getByRole('heading', { name: /ลืมรหัสผ่าน/i }).click(); - - // ข้อความจริงในระบบ “ห้ามใส่ภาษาไทย” - const err = page.getByText(/ห้ามใส่ภาษาไทย/i).first(); - await expect(err).toBeVisible({ timeout: 10_000 }); - - await page.screenshot({ path: 'tests/e2e/screenshots/forgot-02-thai-email.png', fullPage: true }); - }); - - test('3.3 กดลิงก์กลับไปหน้า Login ได้', async ({ page }) => { - await backToLoginLink(page).click(); - await page.waitForURL('**/auth/login', { timeout: 10_000 }); - await expect(page).toHaveURL(/\/auth\/login/i); - - await page.screenshot({ path: 'tests/e2e/screenshots/forgot-03-back-login.png', fullPage: true }); - }); - - test('3.4 ทดลองส่งลิงก์รีเซ็ตรหัสผ่าน (API Mock)', async ({ page }) => { - // ✅ ดัก request แบบกว้างขึ้น: POST ที่ URL มี forgot/reset - await page.route('**/*', async (route) => { - const req = route.request(); - const url = req.url(); - const method = req.method(); - - const looksLikeForgotApi = - method === 'POST' && - /forgot|reset/i.test(url) && - // กันไม่ให้ไป intercept asset - !/\.(png|jpg|jpeg|webp|svg|css|js|map)$/i.test(url); - - if (looksLikeForgotApi) { - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ success: true, data: { message: 'Reset link sent' } }), - }); - return; - } - - await route.continue(); - }); - - await emailInput(page).fill('test@gmail.com'); - await submitBtn(page).click(); - - // ✅ ตรวจหน้าสำเร็จตามที่คุณคาดหวัง - await expect(page.getByText(/ส่งลิงก์เรียบร้อยแล้ว/i, { exact: false })).toBeVisible({ timeout: 10_000 }); - await expect(page.getByText(/กรุณาตรวจสอบกล่องจดหมาย/i, { exact: false })).toBeVisible(); - - // ปุ่ม “ส่งอีกครั้ง” (ถ้ามี) - await expect(page.getByRole('button', { name: /ส่งอีกครั้ง/i })).toBeVisible({ timeout: 10_000 }).catch(() => {}); - - await page.screenshot({ path: 'tests/e2e/screenshots/forgot-04-mock-success.png', fullPage: true }); - }); -}); diff --git a/Frontend-Learner/tests/e2e/helpers.ts b/Frontend-Learner/tests/e2e/helpers.ts new file mode 100644 index 00000000..6af1b81b --- /dev/null +++ b/Frontend-Learner/tests/e2e/helpers.ts @@ -0,0 +1,129 @@ +/** + * @file helpers.ts + * @description Shared E2E test helpers — ฟังก์ชันที่ใช้ร่วมกันในทุกไฟล์ test + * รวม: waitAppSettled, login helpers, common locators, constants + */ +import { type Page, type Locator, expect } from '@playwright/test'; + +// ========================================== +// Constants +// ========================================== +export const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; +export const TEST_EMAIL = 'studentedtest@example.com'; +export const TEST_PASSWORD = 'admin123'; + +/** Timeout configs — ปรับค่าได้ที่เดียว */ +export const TIMEOUT: Record = { + /** รอหน้าโหลด */ + PAGE_LOAD: 15_000, + /** รอ login + redirect */ + LOGIN: 25_000, + /** รอ element แสดงผล */ + ELEMENT: 12_000, + /** รอ network settle */ + SETTLE: 300, +}; + +// ========================================== +// Wait Helpers +// ========================================== + +/** + * รอให้แอปโหลดเสร็จสมบูรณ์ (DOM + Network + hydration) + */ +export async function waitAppSettled(page: Page, ms = TIMEOUT.SETTLE) { + await page.waitForLoadState('domcontentloaded'); + await page.waitForLoadState('networkidle').catch(() => {}); + await page.waitForTimeout(ms); +} + +/** + * รอจนกว่า locator ใดก็ได้ใน array จะ visible + * @throws เมื่อไม่มี locator ไหน visible ภายใน timeout + */ +export async function expectAnyVisible( + page: Page, + locators: Locator[], + timeout = TIMEOUT.PAGE_LOAD +) { + const start = Date.now(); + while (Date.now() - start < timeout) { + for (const loc of locators) { + try { + if (await loc.isVisible()) return; + } catch { /* locator detached / stale — ลองใหม่ */ } + } + await page.waitForTimeout(200); + } + throw new Error( + `None of the expected locators became visible within ${timeout}ms` + ); +} + +// ========================================== +// Login Locators +// ========================================== + +export function emailLocator(page: Page): Locator { + return page + .locator('input[type="email"]') + .or(page.getByRole('textbox', { name: /อีเมล|email/i })) + .first(); +} + +export function passwordLocator(page: Page): Locator { + return page + .locator('input[type="password"]') + .or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })) + .first(); +} + +export function loginButtonLocator(page: Page): Locator { + return page + .getByRole('button', { name: /เข้าสู่ระบบ|login/i }) + .or(page.locator('button[type="submit"]')) + .first(); +} + +// ========================================== +// Login Flow +// ========================================== + +/** + * ล็อกอินด้วย test account — ใช้ใน beforeEach ของ tests ที่ต้อง authenticate + * + * @param page — Playwright Page + * @param opts — ตัวเลือกเสริม + * @param opts.assertDashboard — (default: true) ถ้า true จะ assert ว่าเข้า dashboard สำเร็จ + * + * @throws หาก login ล้มเหลวหรือไม่ถึง dashboard + */ +export async function setupLogin( + page: Page, + opts: { assertDashboard?: boolean } = {} +) { + const { assertDashboard = true } = opts; + + await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + + // กรอกข้อมูล + await emailLocator(page).fill(TEST_EMAIL); + await passwordLocator(page).fill(TEST_PASSWORD); + await loginButtonLocator(page).click(); + + // รอ redirect ไป dashboard + await page.waitForURL('**/dashboard', { timeout: TIMEOUT.LOGIN }); + await waitAppSettled(page); + + if (assertDashboard) { + // ยืนยันว่าเข้า dashboard ได้จริง + const evidence = [ + page.locator('.q-page-container').first(), + page.locator('.q-drawer').first(), + page.locator('img[src*="avataaars"]').first(), + page.locator('img[alt],[alt="User Avatar"]').first(), + ]; + await expectAnyVisible(page, evidence, TIMEOUT.PAGE_LOAD); + } +} diff --git a/Frontend-Learner/tests/e2e/login.spec.ts b/Frontend-Learner/tests/e2e/login.spec.ts deleted file mode 100644 index 7a033655..00000000 --- a/Frontend-Learner/tests/e2e/login.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { test, expect, type Page, type Locator } from '@playwright/test'; - -const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; - -// ใช้ account ตามที่คุณให้มา -const EMAIL = 'studentedtest@example.com'; -const PASSWORD = 'admin123'; - -async function waitAppSettled(page: Page) { - await page.waitForLoadState('domcontentloaded'); - await page.waitForLoadState('networkidle').catch(() => {}); - await page.waitForTimeout(200); -} - -function emailLocator(page: Page): Locator { - return page - .locator('input[type="email"]') - .or(page.getByRole('textbox', { name: /อีเมล|email/i })) - .first(); -} - -function passwordLocator(page: Page): Locator { - return page - .locator('input[type="password"]') - .or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })) - .first(); -} - -function loginButtonLocator(page: Page): Locator { - return page - .getByRole('button', { name: /เข้าสู่ระบบ|login/i }) - .or(page.locator('button[type="submit"]')) - .first(); -} - -async function expectAnyVisible(page: Page, locators: Locator[], timeout = 20_000) { - const start = Date.now(); - while (Date.now() - start < timeout) { - for (const loc of locators) { - try { - if (await loc.isVisible()) return; - } catch {} - } - await page.waitForTimeout(200); - } - throw new Error('None of the expected dashboard locators became visible.'); -} - -test.describe('Login -> Dashboard', () => { - test('Success Login แล้วเข้า /dashboard ได้', async ({ page }) => { - await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); - await waitAppSettled(page); - - await emailLocator(page).fill(EMAIL); - await passwordLocator(page).fill(PASSWORD); - await loginButtonLocator(page).click(); - - await page.waitForURL('**/dashboard', { timeout: 25_000 }); - await waitAppSettled(page); - - // ✅ ใช้ Locator ที่พบเจอแน่นอนใน Layout/Page โดยไม่ยึดติดกับภาษาปัจจุบัน (I18n) - const dashboardEvidence = [ - // มองหา Layout container ฝั่ง Dashboard - page.locator('.q-page-container').first(), - page.locator('.q-drawer').first(), - // มองหารูปโปรไฟล์ (UserAvatar) - page.locator('img[src*="avataaars"]').first(), - page.locator('img[alt],[alt="User Avatar"]').first() - ]; - - await expectAnyVisible(page, dashboardEvidence, 20_000); - - await page.screenshot({ path: 'tests/e2e/screenshots/login-to-dashboard.png', fullPage: true }); - }); - - test('Invalid Email - Thai characters (พิมพ์ภาษาไทย)', async ({ page }) => { - await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); - await waitAppSettled(page); - - await emailLocator(page).fill('ทดสอบภาษาไทย'); - await passwordLocator(page).fill(PASSWORD); - - const errorHint = page.getByText('ห้ามใส่ภาษาไทย'); - - await expect(errorHint.first()).toBeVisible({ timeout: 12_000 }); - await page.screenshot({ path: 'tests/e2e/screenshots/login-thai-email.png', fullPage: true }); - }); - - test('Invalid Email Format (อีเมลผิดรูปแบบ)', async ({ page }) => { - await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); - await waitAppSettled(page); - - // *สำคัญ*: HTML5 จะดักจับ invalid-email-format ตั้งแต่กด Submit (native validation) - // ทำให้ Vue Form ไม่เริ่มทำงาน - // ดังนั้นเพื่อให้ทดสอบเจอ Error จาก useFormValidation จริงๆ เราใช้ 'test@domain' - // ซึ่ง HTML5 ปล่อยผ่าน แต่ /regex/ ของระบบตรวจเจอว่าไม่มี .com - await emailLocator(page).fill('test@domain'); - await passwordLocator(page).fill(PASSWORD); - await loginButtonLocator(page).click(); - await waitAppSettled(page); - - const errorHint = page.getByText('กรุณากรอกอีเมลให้ถูกต้อง (you@example.com)'); - - await expect(errorHint.first()).toBeVisible({ timeout: 12_000 }); - await page.screenshot({ path: 'tests/e2e/screenshots/login-invalid-email.png', fullPage: true }); - }); - - test('Wrong Password (รหัสผ่านผิด หรืออีเมลไม่ถูกต้องในระบบ)', async ({ page }) => { - await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); - await waitAppSettled(page); - - await emailLocator(page).fill(EMAIL); - await passwordLocator(page).fill('wrong-password-123'); - await loginButtonLocator(page).click(); - await waitAppSettled(page); - - const errorHint = page.getByText('กรุณาเช็ค Email หรือ รหัสผ่านใหม่อีกครั้ง'); - - await expect(errorHint.first()).toBeVisible({ timeout: 12_000 }); - await page.screenshot({ path: 'tests/e2e/screenshots/login-wrong-password.png', fullPage: true }); - }); -}); diff --git a/Frontend-Learner/tests/e2e/quiz.spec.ts b/Frontend-Learner/tests/e2e/quiz.spec.ts deleted file mode 100644 index 178d2abc..00000000 --- a/Frontend-Learner/tests/e2e/quiz.spec.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { test, expect } from '@playwright/test'; - -const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; - -async function waitAppSettled(page: any) { - await page.waitForLoadState('domcontentloaded'); - await page.waitForLoadState('networkidle').catch(() => {}); - await page.waitForTimeout(200); -} - -// ฟังก์ชันจำลองล็อกอิน (เพราะทำข้อสอบต้องล็อกอินเสมอ) -async function setupLogin(page: any) { - await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); - await waitAppSettled(page); - - await page.locator('input[type="email"]').or(page.getByRole('textbox', { name: /อีเมล|email/i })).first().fill('studentedtest@example.com'); - await page.locator('input[type="password"]').or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })).first().fill('admin123'); - await page.getByRole('button', { name: /เข้าสู่ระบบ|login/i }).or(page.locator('button[type="submit"]')).first().click(); - - await page.waitForURL('**/dashboard', { timeout: 15_000 }).catch(() => {}); - await waitAppSettled(page); -} - -// ฟังก์ชัน Mock ข้อมูลข้อสอบให้ Playwright ไม่ต้องไปดึงจากฐานข้อมูลจริงๆ (เพื่อป้องกันปัญหาคอร์ส/บทเรียนไม่มีอยู่จริง) -async function mockQuizData(page: any) { - await page.route('**/lessons/*', async (route: any) => { - // สมมติข้อมูลข้อสอบจำลองให้มี 15 ข้อเพื่อเทส Pagination ได้ - const mockQuestions = Array.from({ length: 15 }, (_, i) => ({ - id: i + 1, - question: { th: `คำถามข้อที่ ${i + 1}?`, en: `Question ${i + 1}?` }, - text: { th: `คำถามข้อที่ ${i + 1}?`, en: `Question ${i + 1}?` }, - choices: [ - { id: i * 10 + 1, text: { th: 'ก', en: 'A' } }, - { id: i * 10 + 2, text: { th: 'ข', en: 'B' } }, - { id: i * 10 + 3, text: { th: 'ค', en: 'C' } } - ] - })); - - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ - success: true, - data: { - id: 17, - type: 'QUIZ', - quiz: { - id: 99, - title: { th: 'แบบทดสอบปลายภาค (Mock)', en: 'Final Exam (Mock)' }, - time_limit: 30, - questions: mockQuestions - } - }, - progress: {} - }) - }); - }); -} - -test.describe('ระบบทำแบบทดสอบ (Quiz System)', () => { - - test.beforeEach(async ({ page }) => { - // ต้อง Login ก่อนเรียน! - await setupLogin(page); - }); - - test('โหลดหน้า Quiz และคลิกระบบเริ่มทำข้อสอบได้ (Start Screen)', async ({ page }) => { - await mockQuizData(page); - - // สมมติเอาที่ quiz ใน course 2 lesson 17 (ซึ่ง API เสาะหาจะถูกดักจับและ Mock ไว้ด้านบนแล้ว) - await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); - - // หน้าจอ Start Screen ต้องขึ้นมา - const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); - await expect(startBtn).toBeVisible({ timeout: 15_000 }); - - // ลองกดเริ่มทำ - await startBtn.click(); - - // เช็คว่าหน้า Taking (พื้นที่ทำข้อสอบข้อที่ 1) โผล่มา - const questionText = page.locator('h3').first(); // ชื่อคำถาม - await expect(questionText).toBeVisible({ timeout: 10_000 }); - }); - - test('ทดสอบระบบแถบข้อสอบ แบ่งหน้า (Pagination - เลื่อนซ้าย/ขวา)', async ({ page }) => { - await mockQuizData(page); - await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); - - // เข้าเมนูแบบทดสอบ - const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); - await expect(startBtn).toBeVisible({ timeout: 15_000 }); - await startBtn.click(); - - // เช็คว่ามีลูกศรเลื่อนหน้าข้อสอบ (Paginations) สำหรับแบบทดสอบเกิน 10 ข้อที่สร้างมาใหม่ - const nextPaginationPageBtn = page.locator('button').filter({ has: page.locator('i.q-icon:has-text("chevron_right")') }).first(); - - if (await nextPaginationPageBtn.isVisible()) { - // หากปุ่มแสดง (บอกว่ามีข้อสอบหลายหน้า) ลองกดข้าม - await expect(nextPaginationPageBtn).toBeEnabled(); - await nextPaginationPageBtn.click(); - - // เช็คว่ากดแล้ว ข้อที่ 11 โผล่มา - const question11Btn = page.locator('button').filter({ hasText: /^11$/ }).first(); - await expect(question11Btn).toBeVisible(); - } - }); - - test('การแสดงผลปุ่มถัดไป/ส่งคำตอบ (Submit & Navigation UI)', async ({ page }) => { - await mockQuizData(page); - await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); - const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); - await expect(startBtn).toBeVisible({ timeout: 15_000 }); - await startBtn.click(); - - // รอให้หน้าโหลดคำถามเสร็จก่อน ค่อยหาปุ่ม - await expect(page.locator('h3').first()).toBeVisible({ timeout: 10_000 }); - - const submitBtn = page.locator('button').filter({ hasText: /(ส่งคำตอบ|Submit)/i }).first(); - const nextBtn = page.locator('button').filter({ hasText: /(ถัดไป|Next)/i }).first(); - - // แบบทดสอบข้อแรก ต้องมีปุ่ม ถัดไป(Next) หรือปุ่มส่ง ถ้ามีแค่ 1 ข้อ - await expect(submitBtn.or(nextBtn)).toBeVisible({ timeout: 10_000 }); - }); - -}); diff --git a/Frontend-Learner/tests/e2e/register.spec.ts b/Frontend-Learner/tests/e2e/register.spec.ts deleted file mode 100644 index 5d3c6903..00000000 --- a/Frontend-Learner/tests/e2e/register.spec.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { test, expect, type Page, type Locator } from '@playwright/test'; - -const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; - -async function waitAppSettled(page: Page) { - await page.waitForLoadState('domcontentloaded'); - await page.waitForLoadState('networkidle').catch(() => {}); - await page.waitForTimeout(250); -} - -// ===== Anchors / Scope ===== -function headingRegister(page: Page) { - return page.getByRole('heading', { name: 'สร้างบัญชีผู้ใช้งาน' }); -} - -// ===== Inputs (ตาม snapshot ที่คุณส่งมา) ===== -function usernameInput(page: Page): Locator { - // snapshot: textbox "username" - return page.getByRole('textbox', { name: 'username' }).first(); -} - -function emailInput(page: Page): Locator { - // snapshot: textbox "student@example.com" - return page.getByRole('textbox', { name: 'student@example.com' }).first(); -} - -function prefixCombobox(page: Page): Locator { - // snapshot: combobox มี option นาย/นาง/นางสาว - return page.getByRole('combobox').first(); -} - -function firstNameInput(page: Page): Locator { - // snapshot: label "ชื่อ *" + textbox - return page.getByText(/^ชื่อ\s*\*$/).locator('..').getByRole('textbox').first(); -} - -function lastNameInput(page: Page): Locator { - return page.getByText(/^นามสกุล\s*\*$/).locator('..').getByRole('textbox').first(); -} - -function phoneInput(page: Page): Locator { - return page.getByText(/^เบอร์โทรศัพท์\s*\*$/).locator('..').getByRole('textbox').first(); -} - -function passwordInput(page: Page): Locator { - // snapshot: label "รหัสผ่าน *" + textbox (มีปุ่ม visibility อยู่ข้างๆ) - return page.getByText(/^รหัสผ่าน\s*\*$/).locator('..').getByRole('textbox').first(); -} - -function confirmPasswordInput(page: Page): Locator { - return page.getByText(/^ยืนยันรหัสผ่าน\s*\*$/).locator('..').getByRole('textbox').first(); -} - -function submitButton(page: Page): Locator { - return page.getByRole('button', { name: 'สร้างบัญชี' }); -} - -function loginLink(page: Page): Locator { - return page.getByRole('link', { name: 'เข้าสู่ระบบ' }); -} - -function errorBox(page: Page): Locator { - // ทั้ง field message และ notification/toast/alert - return page.locator( - ['.q-field__messages', '.q-field__bottom', '.text-negative', '.q-notification', '.q-banner', '[role="alert"]'].join( - ', ' - ) - ); -} - -async function pickPrefix(page: Page, value: 'นาย' | 'นาง' | 'นางสาว' = 'นาย') { - const combo = prefixCombobox(page); - - // ถ้าเป็น +
@@ -151,7 +152,7 @@ const viewMode = ref<'grid' | 'list'>('grid') @click="selectCategory('all')" :class="selectedCategory === 'all' ? 'bg-[#E9EFFD] dark:bg-blue-900/40 text-[#3B6BE8] border-transparent font-bold' : 'bg-white dark:bg-transparent border-slate-200 dark:border-slate-700 text-slate-800 dark:text-slate-300 hover:border-slate-300 font-medium'" class="px-5 py-2.5 rounded-full border text-[13px] sm:text-[14px] flex items-center justify-center gap-2 transition-all outline-none"> - ทั้งหมด + {{ $t('discovery.allCategory') }}
@@ -246,10 +247,10 @@ const viewMode = ref<'grid' | 'list'>('grid')
-

{{ searchQuery ? 'ไม่พบคอร์สที่คุณค้นหา' : 'ไม่มีคอร์สในหมวดหมู่นี้' }}

-

ลองใช้คำค้นหาอื่น หรือเลือกหมวดหมู่อื่นเพื่อดูคอร์สที่เรามีให้บริการ

+

{{ $t('discovery.emptyTitle') }}

+

{{ $t('discovery.emptyDesc') }}

From 9e4fcbf04e3ae34c5f106be48afbc8f45c2a6f62 Mon Sep 17 00:00:00 2001 From: Missez Date: Fri, 6 Mar 2026 15:47:37 +0700 Subject: [PATCH 06/10] Add tests result --- .../components/course/AnnouncementsTab.vue | 4 +- frontend_management/playwright.config.ts | 8 +- .../services/instructor.service.ts | 13 +++ frontend_management/stores/instructor.ts | 67 ++++---------- ...10a78b255dbe58da69e9b357af0e9f6017eebf.png | Bin 0 -> 79653 bytes ...6ca155ecb01b787bccd5b36e618f7bfffc2939.png | Bin 0 -> 92869 bytes ...9f8cf2c05bb4db31fe97fd503c31a69097fff5.png | Bin 0 -> 82187 bytes ...47243664146d9bb3273ddf0e15897ad4eba14b.png | Bin 0 -> 79674 bytes ...5217d322c9b956773badf48ef8f6d969ba6757.png | Bin 0 -> 85207 bytes ...bedd3e36d7e6a463160b2e39c6aedfad0c1ec7.png | Bin 0 -> 80342 bytes ...de8f5e141991d0f12359fdd5ac940e2c798b75.png | Bin 0 -> 81564 bytes .../Admin/Audit_Log_Page_Tests/index.html | 85 ++++++++++++++++++ ...e1d6d7d57c179e96128e40db55227dd86a7817.png | Bin 0 -> 66858 bytes ...df25d6cdde602ee836a293f5167004c1a5fa77.png | Bin 0 -> 43023 bytes ...90ba8133de6c748a59d2da9b782a04fc4c6db0.png | Bin 0 -> 95147 bytes ...e85c99c7d03cc714e887a691300a72ec49360c.png | Bin 0 -> 69730 bytes ...fdbc416f0e24dec95ce26a8d821ef9cb3765bf.png | Bin 0 -> 73757 bytes ...7f0948bcc7200f737fc0a088783bbea297f50f.png | Bin 0 -> 65790 bytes ...902bf323a4786f68fa00ea84781ba7957d7d7a.png | Bin 0 -> 65643 bytes ...f7ebb27025218191824d8efc9ca47e1c964b1e.png | Bin 0 -> 49303 bytes ...5e29ca1b01c21b07dca63fe776c2605caf1ccd.png | Bin 0 -> 47205 bytes .../Admin/Categories_Page_Tests/index.html | 85 ++++++++++++++++++ ...b70a62c5681aa2ef14d34994eccd60520d3e47.png | Bin 0 -> 79573 bytes ...5d3eb5a2e8a33833fc35360a3b8a045628cb2d.png | Bin 0 -> 94523 bytes ...6d6a06b33921ae112d5bfea6d92b229038f4bd.png | Bin 0 -> 91639 bytes ...d4e4da3ea2fb373b41f4adbb13d2b24b8ccfe1.png | Bin 0 -> 98014 bytes .../Admin/Dashboard_Tests/index.html | 85 ++++++++++++++++++ ...53f4201cd452cfa653e6439a05e46caba79eb8.png | Bin 0 -> 96549 bytes ...fbe1198619aae53dd8768e53e81002d0b357a5.png | Bin 0 -> 69342 bytes ...8b1769e5aa0373f08be5b1e93ca6bd4de71183.png | Bin 0 -> 57419 bytes ...599641f8347eea9faef8a04424075e5fc3e8dc.png | Bin 0 -> 176839 bytes ...0f425a2702d00bbdd804a1d4ca9fadf55a6562.png | Bin 0 -> 70364 bytes ...51465650cc45a9db3430a37a44a4cd60e679dd.png | Bin 0 -> 45045 bytes ...561250ddaf7ee9f68edf5ab096f616efd38664.png | Bin 0 -> 69407 bytes .../Pending_Courses_Page_Tests/index.html | 85 ++++++++++++++++++ ...9d36dffaf29e9ba9d4e6d0e2d50d69247e576d.png | Bin 0 -> 148128 bytes ...201a029c254b88c8fcee02d0222ed560bca040.png | Bin 0 -> 154851 bytes ...b564f25d91be7a7a19adc86618e4c587c22852.png | Bin 0 -> 98999 bytes ...9d78c1d16c81f14166fcc263feb68daff0b337.png | Bin 0 -> 95342 bytes .../Recommended_Courses_Page_Tests/index.html | 85 ++++++++++++++++++ ...131b544f7ef5ab6ae9159c7b3aeb54a6a35ace.png | Bin 0 -> 94733 bytes ...505851a4cfcd340a2c15e4eede8ba1b00a45f3.png | Bin 0 -> 89930 bytes ...c9b0535c23ea7767a4692c7b1cd5b7efa77198.png | Bin 0 -> 91511 bytes ...d29873e393b6d0d06b99325f7d44448dba4e7d.png | Bin 0 -> 93765 bytes ...36118b9393d5080e9936f45e76adb40b146c51.png | Bin 0 -> 51337 bytes ...4e6793c83ac936ea2d687bc0846ceb6356f757.png | Bin 0 -> 91562 bytes ...7dab7bdd78b963cffec28b4fc8d505bc610443.png | Bin 0 -> 52637 bytes ...0e2afd169f0d440483247810ca3f3aa12fcb8e.png | Bin 0 -> 91345 bytes .../Admin/Users_Page_Tests/index.html | 85 ++++++++++++++++++ ...aa583ffad06b8cb14b557facad1bd9f955f649.png | Bin 0 -> 53407 bytes ...663960da5071a13ba4d0efe05b15795a404dd5.png | Bin 0 -> 132272 bytes ...367ab188ae80996e584f9b58e0a689e5b7736c.png | Bin 0 -> 133279 bytes ...7022d29cc41e4c91622d52c4d4bec33e5ea27b.png | Bin 0 -> 118170 bytes ...4d5765838ec53396637363d765fe9999a23cef.png | Bin 0 -> 132455 bytes ...a76b0d67d10db9794f5eaaa0ad93900dc66ef9.png | Bin 0 -> 126187 bytes ...db8fa9d3f7eebe20c935bc28970c686729b80e.png | Bin 0 -> 138073 bytes ...269d490caef20a582ba9d9105b7d11a23a763a.png | Bin 0 -> 124330 bytes ...5921cba1eca4f1439b107ba699e33ec81efb98.png | Bin 0 -> 83044 bytes .../Course_Detail_Tabs_Tests/index.html | 85 ++++++++++++++++++ ...c8d6b6bda96733768c9040919a1f2a5e01baff.png | Bin 0 -> 144281 bytes ...4aa5c1e2968710d7151e06d900bb12f41eb2f3.png | Bin 0 -> 217693 bytes ...172ca5f26f33c946c982ccccb69b895adabc25.png | Bin 0 -> 49952 bytes ...76fc70092c9da0bdce1f5f6416f09fa381c305.png | Bin 0 -> 140461 bytes ...409841bc0a58fee9b289ae43471f82aeadced6.png | Bin 0 -> 218526 bytes ...b116131594ffd0289eefd700d6491505e1c71a.png | Bin 0 -> 79784 bytes ...b066997ecc48380fe55519c2c5201661b92d65.png | Bin 0 -> 55727 bytes ...fd2a77f7879d1bda44afce77a4e1b085add249.png | Bin 0 -> 217697 bytes ...b6e30487eeb33a334792f175969cd79b956af6.png | Bin 0 -> 216942 bytes .../Courses_List_Page_Tests/index.html | 85 ++++++++++++++++++ ...f0f34d39ba3afdcddd6292f21b1fb2e1f91347.png | Bin 0 -> 67434 bytes ...52458e5d775d7f6a5470a4ebe6dfce88202762.png | Bin 0 -> 52910 bytes ...57c7870ad1af4b313598a422bf95f9975bd4b3.png | Bin 0 -> 32556 bytes ...aead5182882b1c055b71b4263a086d49ae21f9.png | Bin 0 -> 42496 bytes ...f166853a6c394a6ca293b2395842ca32fa59fb.png | Bin 0 -> 55755 bytes ...18c639a925799e58f2c6cd7a6285d1bf3a63da.png | Bin 0 -> 66410 bytes ...3d46f246f6417be4064747a2cadbfce753066e.png | Bin 0 -> 51176 bytes ...e5afbe64b19d3bca6a5563b2b5fac4f58742ca.png | Bin 0 -> 80638 bytes ...a098f9935cd85e715e1c92119eb18b3cc23078.png | Bin 0 -> 54671 bytes ...57c0d509931d0977a2cc80bc5da68b6e474c23.png | Bin 0 -> 38540 bytes .../index.html | 85 ++++++++++++++++++ ...3d6902c0ca4fef1aa2fc65120adc1d08048286.png | Bin 0 -> 85210 bytes ...2ffe0882b032c2d3bab8fe7fe4b31907aa7ec5.png | Bin 0 -> 217748 bytes ...2f57b76392ddca8cf0d10da5302f65a7045e4f.png | Bin 0 -> 87369 bytes ...b3be3b178a6a2e49e992a3f9d0c366b9474fbc.png | Bin 0 -> 93858 bytes ...74e2d38891f831ce99cc3f497ad1b1090077de.png | Bin 0 -> 76654 bytes ...b7f4bf19a7a5908adc27d250a40618847c1cf2.png | Bin 0 -> 53522 bytes .../Instructor/Dashboard_Tests/index.html | 85 ++++++++++++++++++ ...708d259129df93cdd9a5cd6260b44467f430e0.png | Bin 0 -> 206942 bytes ...1c2ea22b6adeaed9641041947a76d74edc18b8.png | Bin 0 -> 204659 bytes ...f8acf6a09faed4c14ed6a633732862db853d36.png | Bin 0 -> 206042 bytes ...79c41c8858b523f5f00ca0d96ee66e8a87263c.png | Bin 0 -> 213305 bytes ...ee2be597a0472f1f34fba60dabc39a3397acc0.png | Bin 0 -> 203259 bytes ...f2781e64d249e5dcb8ae23681d82b7e0306f11.png | Bin 0 -> 208530 bytes ...9a2a90835ca972045b4e2fd9eedab17f6e1cab.png | Bin 0 -> 92020 bytes ...a2a979a4f710cebde1893e6fa7a420bbce07ca.png | Bin 0 -> 93746 bytes ...91cbda97e779364b7c6ab4a9c78a999b4aeef1.png | Bin 0 -> 177782 bytes .../auth/Login_Page_Tests/index.html | 85 ++++++++++++++++++ ...09b14cfe86a6650b5c9ccaea6ab6396a7c6882.png | Bin 0 -> 149491 bytes ...608ae454cb4fdde9edcfee7bc324ff6e9ac00a.png | Bin 0 -> 154481 bytes ...a7199dc793b5cc6db9a6e2ab253bbb974a12cd.png | Bin 0 -> 154032 bytes ...0da5fa1e26962ec6c30ce5825cb0d1385cf2cd.png | Bin 0 -> 214173 bytes ...fa2fbb70373a1485233cf195e488e69133bac6.png | Bin 0 -> 154403 bytes ...755655c173a8648e7d6d3c5b2f02a0946947fb.png | Bin 0 -> 151925 bytes ...5315ba929130c12a0cbd5bf9cb5d7f1cb08f5e.png | Bin 0 -> 153925 bytes ...bfcc1bab4f46872473695bb589c80be175f811.png | Bin 0 -> 202911 bytes .../auth/Register_Page_Tests/index.html | 85 ++++++++++++++++++ .../tests/admin/categories.spec.ts | 2 +- .../tests/admin/recommended-courses.spec.ts | 6 +- frontend_management/tests/auth/login.spec.ts | 8 ++ .../instructor/course-detail-tabs.spec.ts | 10 +-- .../tests/instructor/courses-list.spec.ts | 17 ++-- 111 files changed, 1078 insertions(+), 77 deletions(-) create mode 100644 frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/0410a78b255dbe58da69e9b357af0e9f6017eebf.png create mode 100644 frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/1d6ca155ecb01b787bccd5b36e618f7bfffc2939.png create mode 100644 frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/209f8cf2c05bb4db31fe97fd503c31a69097fff5.png create mode 100644 frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/4047243664146d9bb3273ddf0e15897ad4eba14b.png create mode 100644 frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/405217d322c9b956773badf48ef8f6d969ba6757.png create mode 100644 frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/e8bedd3e36d7e6a463160b2e39c6aedfad0c1ec7.png create mode 100644 frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/edde8f5e141991d0f12359fdd5ac940e2c798b75.png create mode 100644 frontend_management/test_result/Admin/Audit_Log_Page_Tests/index.html create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/data/1ee1d6d7d57c179e96128e40db55227dd86a7817.png create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/data/35df25d6cdde602ee836a293f5167004c1a5fa77.png create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/data/4090ba8133de6c748a59d2da9b782a04fc4c6db0.png create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/data/41e85c99c7d03cc714e887a691300a72ec49360c.png create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/data/65fdbc416f0e24dec95ce26a8d821ef9cb3765bf.png create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/data/827f0948bcc7200f737fc0a088783bbea297f50f.png create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/data/c8902bf323a4786f68fa00ea84781ba7957d7d7a.png create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/data/ccf7ebb27025218191824d8efc9ca47e1c964b1e.png create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/data/f25e29ca1b01c21b07dca63fe776c2605caf1ccd.png create mode 100644 frontend_management/test_result/Admin/Categories_Page_Tests/index.html create mode 100644 frontend_management/test_result/Admin/Dashboard_Tests/data/0db70a62c5681aa2ef14d34994eccd60520d3e47.png create mode 100644 frontend_management/test_result/Admin/Dashboard_Tests/data/4c5d3eb5a2e8a33833fc35360a3b8a045628cb2d.png create mode 100644 frontend_management/test_result/Admin/Dashboard_Tests/data/866d6a06b33921ae112d5bfea6d92b229038f4bd.png create mode 100644 frontend_management/test_result/Admin/Dashboard_Tests/data/a5d4e4da3ea2fb373b41f4adbb13d2b24b8ccfe1.png create mode 100644 frontend_management/test_result/Admin/Dashboard_Tests/index.html create mode 100644 frontend_management/test_result/Admin/Pending_Courses_Page_Tests/data/0453f4201cd452cfa653e6439a05e46caba79eb8.png create mode 100644 frontend_management/test_result/Admin/Pending_Courses_Page_Tests/data/2efbe1198619aae53dd8768e53e81002d0b357a5.png create mode 100644 frontend_management/test_result/Admin/Pending_Courses_Page_Tests/data/528b1769e5aa0373f08be5b1e93ca6bd4de71183.png create mode 100644 frontend_management/test_result/Admin/Pending_Courses_Page_Tests/data/6c599641f8347eea9faef8a04424075e5fc3e8dc.png create mode 100644 frontend_management/test_result/Admin/Pending_Courses_Page_Tests/data/aa0f425a2702d00bbdd804a1d4ca9fadf55a6562.png create mode 100644 frontend_management/test_result/Admin/Pending_Courses_Page_Tests/data/b051465650cc45a9db3430a37a44a4cd60e679dd.png create mode 100644 frontend_management/test_result/Admin/Pending_Courses_Page_Tests/data/c5561250ddaf7ee9f68edf5ab096f616efd38664.png create mode 100644 frontend_management/test_result/Admin/Pending_Courses_Page_Tests/index.html create mode 100644 frontend_management/test_result/Admin/Recommended_Courses_Page_Tests/data/069d36dffaf29e9ba9d4e6d0e2d50d69247e576d.png create mode 100644 frontend_management/test_result/Admin/Recommended_Courses_Page_Tests/data/20201a029c254b88c8fcee02d0222ed560bca040.png create mode 100644 frontend_management/test_result/Admin/Recommended_Courses_Page_Tests/data/adb564f25d91be7a7a19adc86618e4c587c22852.png create mode 100644 frontend_management/test_result/Admin/Recommended_Courses_Page_Tests/data/ae9d78c1d16c81f14166fcc263feb68daff0b337.png create mode 100644 frontend_management/test_result/Admin/Recommended_Courses_Page_Tests/index.html create mode 100644 frontend_management/test_result/Admin/Users_Page_Tests/data/01131b544f7ef5ab6ae9159c7b3aeb54a6a35ace.png create mode 100644 frontend_management/test_result/Admin/Users_Page_Tests/data/14505851a4cfcd340a2c15e4eede8ba1b00a45f3.png create mode 100644 frontend_management/test_result/Admin/Users_Page_Tests/data/61c9b0535c23ea7767a4692c7b1cd5b7efa77198.png create mode 100644 frontend_management/test_result/Admin/Users_Page_Tests/data/8cd29873e393b6d0d06b99325f7d44448dba4e7d.png create mode 100644 frontend_management/test_result/Admin/Users_Page_Tests/data/9136118b9393d5080e9936f45e76adb40b146c51.png create mode 100644 frontend_management/test_result/Admin/Users_Page_Tests/data/a54e6793c83ac936ea2d687bc0846ceb6356f757.png create mode 100644 frontend_management/test_result/Admin/Users_Page_Tests/data/c57dab7bdd78b963cffec28b4fc8d505bc610443.png create mode 100644 frontend_management/test_result/Admin/Users_Page_Tests/data/f00e2afd169f0d440483247810ca3f3aa12fcb8e.png create mode 100644 frontend_management/test_result/Admin/Users_Page_Tests/index.html create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/data/3daa583ffad06b8cb14b557facad1bd9f955f649.png create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/data/6a663960da5071a13ba4d0efe05b15795a404dd5.png create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/data/6f367ab188ae80996e584f9b58e0a689e5b7736c.png create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/data/7a7022d29cc41e4c91622d52c4d4bec33e5ea27b.png create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/data/bb4d5765838ec53396637363d765fe9999a23cef.png create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/data/c5a76b0d67d10db9794f5eaaa0ad93900dc66ef9.png create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/data/c9db8fa9d3f7eebe20c935bc28970c686729b80e.png create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/data/d8269d490caef20a582ba9d9105b7d11a23a763a.png create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/data/fd5921cba1eca4f1439b107ba699e33ec81efb98.png create mode 100644 frontend_management/test_result/Instructor/Course_Detail_Tabs_Tests/index.html create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/data/05c8d6b6bda96733768c9040919a1f2a5e01baff.png create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/data/124aa5c1e2968710d7151e06d900bb12f41eb2f3.png create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/data/3d172ca5f26f33c946c982ccccb69b895adabc25.png create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/data/3e76fc70092c9da0bdce1f5f6416f09fa381c305.png create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/data/59409841bc0a58fee9b289ae43471f82aeadced6.png create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/data/5ab116131594ffd0289eefd700d6491505e1c71a.png create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/data/ceb066997ecc48380fe55519c2c5201661b92d65.png create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/data/e7fd2a77f7879d1bda44afce77a4e1b085add249.png create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/data/ebb6e30487eeb33a334792f175969cd79b956af6.png create mode 100644 frontend_management/test_result/Instructor/Courses_List_Page_Tests/index.html create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/27f0f34d39ba3afdcddd6292f21b1fb2e1f91347.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/2a52458e5d775d7f6a5470a4ebe6dfce88202762.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/7957c7870ad1af4b313598a422bf95f9975bd4b3.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/aeaead5182882b1c055b71b4263a086d49ae21f9.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/bbf166853a6c394a6ca293b2395842ca32fa59fb.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/c218c639a925799e58f2c6cd7a6285d1bf3a63da.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/c33d46f246f6417be4064747a2cadbfce753066e.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/c7e5afbe64b19d3bca6a5563b2b5fac4f58742ca.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/f0a098f9935cd85e715e1c92119eb18b3cc23078.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/data/fa57c0d509931d0977a2cc80bc5da68b6e474c23.png create mode 100644 frontend_management/test_result/Instructor/Create_Course_&_Structure_Tests/index.html create mode 100644 frontend_management/test_result/Instructor/Dashboard_Tests/data/153d6902c0ca4fef1aa2fc65120adc1d08048286.png create mode 100644 frontend_management/test_result/Instructor/Dashboard_Tests/data/452ffe0882b032c2d3bab8fe7fe4b31907aa7ec5.png create mode 100644 frontend_management/test_result/Instructor/Dashboard_Tests/data/4e2f57b76392ddca8cf0d10da5302f65a7045e4f.png create mode 100644 frontend_management/test_result/Instructor/Dashboard_Tests/data/85b3be3b178a6a2e49e992a3f9d0c366b9474fbc.png create mode 100644 frontend_management/test_result/Instructor/Dashboard_Tests/data/c774e2d38891f831ce99cc3f497ad1b1090077de.png create mode 100644 frontend_management/test_result/Instructor/Dashboard_Tests/data/ccb7f4bf19a7a5908adc27d250a40618847c1cf2.png create mode 100644 frontend_management/test_result/Instructor/Dashboard_Tests/index.html create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/data/16708d259129df93cdd9a5cd6260b44467f430e0.png create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/data/631c2ea22b6adeaed9641041947a76d74edc18b8.png create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/data/65f8acf6a09faed4c14ed6a633732862db853d36.png create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/data/7e79c41c8858b523f5f00ca0d96ee66e8a87263c.png create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/data/84ee2be597a0472f1f34fba60dabc39a3397acc0.png create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/data/a9f2781e64d249e5dcb8ae23681d82b7e0306f11.png create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/data/bc9a2a90835ca972045b4e2fd9eedab17f6e1cab.png create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/data/dca2a979a4f710cebde1893e6fa7a420bbce07ca.png create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/data/e391cbda97e779364b7c6ab4a9c78a999b4aeef1.png create mode 100644 frontend_management/test_result/auth/Login_Page_Tests/index.html create mode 100644 frontend_management/test_result/auth/Register_Page_Tests/data/0809b14cfe86a6650b5c9ccaea6ab6396a7c6882.png create mode 100644 frontend_management/test_result/auth/Register_Page_Tests/data/34608ae454cb4fdde9edcfee7bc324ff6e9ac00a.png create mode 100644 frontend_management/test_result/auth/Register_Page_Tests/data/34a7199dc793b5cc6db9a6e2ab253bbb974a12cd.png create mode 100644 frontend_management/test_result/auth/Register_Page_Tests/data/7d0da5fa1e26962ec6c30ce5825cb0d1385cf2cd.png create mode 100644 frontend_management/test_result/auth/Register_Page_Tests/data/9efa2fbb70373a1485233cf195e488e69133bac6.png create mode 100644 frontend_management/test_result/auth/Register_Page_Tests/data/bd755655c173a8648e7d6d3c5b2f02a0946947fb.png create mode 100644 frontend_management/test_result/auth/Register_Page_Tests/data/c95315ba929130c12a0cbd5bf9cb5d7f1cb08f5e.png create mode 100644 frontend_management/test_result/auth/Register_Page_Tests/data/efbfcc1bab4f46872473695bb589c80be175f811.png create mode 100644 frontend_management/test_result/auth/Register_Page_Tests/index.html diff --git a/frontend_management/components/course/AnnouncementsTab.vue b/frontend_management/components/course/AnnouncementsTab.vue index 1efe7f2b..aa529d46 100644 --- a/frontend_management/components/course/AnnouncementsTab.vue +++ b/frontend_management/components/course/AnnouncementsTab.vue @@ -343,10 +343,12 @@ const save = async () => { saving.value = true; try { // Convert local datetime to ISO string to preserve timezone - const payload = { ...form.value }; + const payload: any = { ...form.value }; if (payload.published_at) { const localDate = new Date(payload.published_at.replace(' ', 'T')); payload.published_at = localDate.toISOString(); + } else { + delete payload.published_at; } if (editing.value) { diff --git a/frontend_management/playwright.config.ts b/frontend_management/playwright.config.ts index 4c0c0541..647c4016 100644 --- a/frontend_management/playwright.config.ts +++ b/frontend_management/playwright.config.ts @@ -34,11 +34,11 @@ export default defineConfig({ use: { baseURL: 'http://localhost:3000/',// ปรับเป็น URL ที่ทดสอบ headless: false, // false = เห็น browser ขณะรัน - screenshot: 'only-on-failure', // เก็บ screenshot เมื่อ fail + screenshot: 'on', // เก็บ screenshot trace: 'retain-on-failure', // เก็บ trace เพื่อดีบักเมื่อ fail - // launchOptions: { - // slowMo: 1000, - // }, // ช้าลง 10 วินาที + launchOptions: { + slowMo: 500, + }, // ช้าลง 10 วินาที }, /* ──── Setup Projects: login ครั้งเดียว แล้ว save cookies ──── */ diff --git a/frontend_management/services/instructor.service.ts b/frontend_management/services/instructor.service.ts index 1c3ab0b4..f40d5588 100644 --- a/frontend_management/services/instructor.service.ts +++ b/frontend_management/services/instructor.service.ts @@ -610,6 +610,19 @@ export const instructorService = { { method: 'DELETE' } ); }, + async getMyStudentsStats(): Promise<{ total_students: number; total_completed: number }> { + const response = await authRequest<{ + code: number; + message: string; + total_students: number; + total_completed: number; + }>('/api/instructors/courses/my-students'); + return { + total_students: response.total_students, + total_completed: response.total_completed + }; + }, + async getCourseApprovalHistory(courseId: number): Promise { const response = await authRequest<{ code: number; diff --git a/frontend_management/stores/instructor.ts b/frontend_management/stores/instructor.ts index 57cade09..cf8e2152 100644 --- a/frontend_management/stores/instructor.ts +++ b/frontend_management/stores/instructor.ts @@ -51,56 +51,16 @@ export const useInstructorStore = defineStore('instructor', { async fetchDashboardData() { this.loading = true; try { - // Fetch real courses from API - const courses = await instructorService.getCourses(); + // Fetch courses and student stats in parallel + const [courses, studentStats] = await Promise.all([ + instructorService.getCourses(), + instructorService.getMyStudentsStats() + ]); - // Fetch student counts for each course - let totalStudents = 0; - let completedStudents = 0; - const courseDetails: Course[] = []; - - for (const course of courses.slice(0, 5)) { - try { - // Get student counts - const studentsResponse = await instructorService.getEnrolledStudents(course.id, 1, 1); - const courseStudents = studentsResponse.total || 0; - totalStudents += courseStudents; - - // Get completed count from full list (if small) or estimate - if (courseStudents > 0 && courseStudents <= 100) { - const allStudents = await instructorService.getEnrolledStudents(course.id, 1, 100); - completedStudents += allStudents.data.filter(s => s.status === 'COMPLETED').length; - } - - // Get lesson count from course detail - const courseDetail = await instructorService.getCourseById(course.id); - const lessonCount = courseDetail.chapters.reduce((sum, ch) => sum + ch.lessons.length, 0); - - courseDetails.push({ - id: course.id, - title: course.title.th, - students: courseStudents, - lessons: lessonCount, - icon: 'book', - thumbnail: course.thumbnail_url || null - }); - } catch (e) { - // Course might not have students endpoint - courseDetails.push({ - id: course.id, - title: course.title.th, - students: 0, - lessons: 0, - icon: 'book', - thumbnail: course.thumbnail_url || null - }); - } - } - - // Update stats + // Update student stats from dedicated API this.stats.totalCourses = courses.length; - this.stats.totalStudents = totalStudents; - this.stats.completedStudents = completedStudents; + this.stats.totalStudents = studentStats.total_students; + this.stats.completedStudents = studentStats.total_completed; // Update course status counts this.courseStatusCounts = { @@ -110,8 +70,15 @@ export const useInstructorStore = defineStore('instructor', { rejected: courses.filter(c => c.status === 'REJECTED').length }; - // Update recent courses (first 3) - this.recentCourses = courseDetails.slice(0, 3); + // Build recent courses list (first 3) from existing data + this.recentCourses = courses.slice(0, 3).map(course => ({ + id: course.id, + title: course.title.th, + students: 0, + lessons: 0, + icon: 'book', + thumbnail: course.thumbnail_url || null + })); } catch (error) { console.error('Failed to fetch dashboard data:', error); } finally { diff --git a/frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/0410a78b255dbe58da69e9b357af0e9f6017eebf.png b/frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/0410a78b255dbe58da69e9b357af0e9f6017eebf.png new file mode 100644 index 0000000000000000000000000000000000000000..b617029a289df19d626b14738165434603a0d4d0 GIT binary patch literal 79653 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 S!n?pPAR~RV>!rGm&;A8wlLBD? literal 0 HcmV?d00001 diff --git a/frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/1d6ca155ecb01b787bccd5b36e618f7bfffc2939.png b/frontend_management/test_result/Admin/Audit_Log_Page_Tests/data/1d6ca155ecb01b787bccd5b36e618f7bfffc2939.png new file mode 100644 index 0000000000000000000000000000000000000000..05815fe0ca75a8dfedc3e3e8aaf92966b14734cb GIT binary patch literal 92869 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
Date & Time
-
{{ formatDate(selectedLog.created_at) }}
+
{{ formatDateTime(selectedLog.created_at) }}
@@ -241,7 +241,7 @@ diff --git a/frontend_management/pages/instructor/profile/index.vue b/frontend_management/pages/instructor/profile/index.vue index 6a602a39..6a36b365 100644 --- a/frontend_management/pages/instructor/profile/index.vue +++ b/frontend_management/pages/instructor/profile/index.vue @@ -301,7 +301,7 @@