diff --git a/.dockerignore b/.dockerignore index 8f1d274..92a2d8f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,6 @@ .git .agents .codex -node_modules tests .env @@ -13,7 +12,6 @@ data/* !data/.gitkeep *.log -npm-debug.log* Dockerfile* compose*.yml compose*.yaml diff --git a/.gitignore b/.gitignore index 8349bd2..c1d75b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ -data/db.json -data/test-db.json data/*.sqlite data/*.sqlite-shm data/*.sqlite-wal -node_modules/ .env .env.docker *.log diff --git a/MIGRATION.md b/MIGRATION.md index 7e6ca60..fe0fe9c 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,6 +1,6 @@ # ASP.NET Core 10 迁移 -系统业务 API、认证、管理后台、审批流、考务编排、招生录取、Excel、文书和缓存均已迁移到 ASP.NET Core 10。生产宿主和容器不再启动或转发到 Node.js;旧 `.mjs` 服务端源码仅保留作历史行为对照。 +系统业务 API、认证、管理后台、审批流、考务编排、招生录取、Excel、文书和缓存均已迁移到 ASP.NET Core 10。生产宿主和容器只运行 .NET;旧 Node.js 服务端源码、依赖、测试和迁移对照工具已从仓库移除。 ## 完成情况 @@ -11,8 +11,11 @@ - [x] 指标资格、招生账户、志愿、计划、投档、录取、报到和退档 - [x] ClosedXML 文件导入导出、文书模板和 Redis/本机缓存 - [x] SQLite / MySQL 自动建库和基础配置初始化 +- [x] SQLite / MySQL 结构改为 .NET 内嵌原生 SQL 资源 - [x] 可发布的 .NET 数据库重建与 1200 人演示数据导入工具 - [x] 容器入口切换及 Node.js 后端运行依赖移除 +- [x] 浏览器静态资源归档到 `src/Eis.Web/wwwroot` +- [x] Node.js 源码、依赖和测试清理 ## 本地运行 @@ -36,7 +39,7 @@ dotnet run --project .\src\Eis.Web\Eis.Web.csproj - ClosedXML 处理班级、管理员、报名号、考生、缴费、考点考场、成绩、志愿、录取、报到和正式录取名册工作簿。 - 成绩导入先预检再确认,报到导入按招生学校和可维护批次限定范围。 - 录取通知书模板由原生接口保存;成绩单、准考证和录取通知书的数据及防伪验真均由 ASP.NET Core 提供。 -- CKEditor 浏览器资源已随 Web 项目发布,不依赖 `node_modules`。 +- CKEditor 和全部浏览器资源均位于 `src/Eis.Web/wwwroot`,发布时由 Web SDK 自动收集。 ## 验证 @@ -48,4 +51,4 @@ pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\smoke-dotnet-native. docker compose up --build --detach ``` -`Eis.Tools.dll` 提供 `database init/reset/seed`;破坏性命令要求 `--confirm-target`,SQLite 自动保留原库备份,MySQL 拒绝系统库和未显式强制覆盖的非演示业务数据。`scripts/smoke-dotnet-native.ps1` 会发布并启动纯 .NET 产物,在操作系统临时目录创建一次性 SQLite 数据库,检查健康状态、首页、CKEditor、原生登录和未知 API 404 后清理。`scripts/smoke-dotnet-migration.ps1` 保留为迁移期 Node/.NET 行为对照工具,不属于生产启动链路。 +`Eis.Tools.dll` 提供 `database init/reset/seed`;破坏性命令要求 `--confirm-target`,SQLite 自动保留原库备份,MySQL 拒绝系统库和未显式强制覆盖的非演示业务数据。`scripts/smoke-dotnet-native.ps1` 会发布并启动纯 .NET 产物,在操作系统临时目录创建一次性 SQLite 数据库,检查健康状态、首页、CKEditor、原生登录和未知 API 404 后清理。 diff --git a/README.md b/README.md index 32d4ebb..ed9fd61 100644 --- a/README.md +++ b/README.md @@ -360,7 +360,7 @@ dotnet test .\Eis.slnx pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\smoke-dotnet-native.ps1 ``` -xUnit 测试使用独立临时 SQLite 数据库,覆盖认证兼容性、迁移开关约束、文书防伪码、文件处理、缓存以及空库 v20 初始化;测试不会连接或修改生产数据库。 +xUnit 测试使用独立临时 SQLite 数据库,覆盖认证与历史数据兼容性、端点启用约束、文书防伪码、文件处理、缓存以及空库 v20 初始化;测试不会连接或修改生产数据库。 ## 项目结构 @@ -372,15 +372,12 @@ src/Eis.Domain 领域模型与业务值 src/Eis.Application 应用服务契约 src/Eis.Infrastructure SQLite/MySQL、认证、缓存、Excel 与业务实现 src/Eis.Tools 可独立发布的数据库初始化、重建和演示数据工具 -src/Eis.Web ASP.NET Core 宿主、端点和发布静态资源 +src/Eis.Web ASP.NET Core 宿主、端点和静态资源 +src/Eis.Web/wwwroot 浏览器入口、样式、前端模块及 CKEditor tests/Eis.Infrastructure.Tests xUnit 自动化测试 -index.html / styles.css / app.js 前端入口、样式和控制器 -src/client 公共、考生、管理及招生前端模块 -src/database/schema.mjs 兼容 SQLite/MySQL 的 v20 建库定义 scripts/publish.ps1 Web 与数据库工具统一发布脚本 -scripts 迁移验证及演示数据包维护工具 -server.mjs / src/routes 仅保留的旧 Node 行为对照源码 +scripts/smoke-dotnet-native.ps1 纯 .NET 发布产物烟测 data/exam.sqlite 本地运行后生成的 SQLite 数据库 .env.example 开发与生产环境变量模板 ``` diff --git a/database.mjs b/database.mjs deleted file mode 100644 index 348c887..0000000 --- a/database.mjs +++ /dev/null @@ -1,1596 +0,0 @@ -import { mkdir } from 'node:fs/promises'; -import { dirname, join, resolve } from 'node:path'; -import { mysqlSchema, sqliteSchema } from './src/database/schema.mjs'; -import { createSqliteAdapter } from './src/database/sqlite-adapter.mjs'; -import { createMysqlAdapter } from './src/database/mysql-adapter.mjs'; -import { CURRENT_SCHEMA_VERSION } from './src/database/version.mjs'; - -export const relationalTables = [ - 'schema_metadata', - 'organization', - 'schools', - 'school_classes', - 'school_student_partitions', - 'users', - 'candidate_profiles', - 'notices', - 'exams', - 'exam_data_partitions', - 'exam_subjects', - 'registrations', - 'registration_subjects', - 'admission_number_rules', - 'exam_arrangement_plans', - 'admit_cards', - 'admit_card_subjects', - 'results', - 'test_centers', - 'test_rooms', - 'center_change_requests', - 'center_change_rooms', - 'number_rules', - 'number_rule_segments', - 'candidate_account_batches', - 'candidate_account_batch_items', - 'workflow_definitions', - 'workflow_steps', - 'workflow_instances', - 'workflow_actions', - 'admission_records', - 'audit_logs' -]; - -function validateState(state, source = '数据库') { - const collections = [ - 'schools', 'classes', 'users', 'candidateProfiles', 'notices', 'exams', 'registrations', 'results', - 'testCenters', 'testRooms', 'centerChangeRequests', 'centerChangeRooms', - 'admissionNumberRules', 'arrangementPlans', - 'numberRules', 'candidateAccountBatches', 'candidateAccountBatchItems', - 'workflows', 'workflowInstances', 'workflowActions', 'admissionRecords', 'auditLogs' - ]; - if (!state || typeof state !== 'object' || collections.some(name => !Array.isArray(state[name]))) { - throw new Error(`${source}中的应用数据格式无效`); - } - return state; -} - -export function buildSeedOperations(state) { - validateState(state); - const operations = []; - const add = (sql, ...params) => operations.push({ sql, params }); - const nullable = value => value == null || value === '' ? null : value; - - add( - `UPDATE schema_metadata SET schema_version = ${CURRENT_SCHEMA_VERSION}, app_version = ?, self_registration_enabled = ?, created_at = ? WHERE id = 1`, - Number(state.meta?.version || 1), state.settings?.selfRegistrationEnabled ? 1 : 0, - state.meta?.createdAt || new Date().toISOString() - ); - add( - 'INSERT INTO organization (id, name, code, phone, address) VALUES (1, ?, ?, ?, ?)', - state.organization?.name || '', state.organization?.code || '', state.organization?.phone || '', state.organization?.address || '' - ); - - for (const school of state.schools) { - add( - 'INSERT INTO schools (id, name, code, address, is_source_school, is_admission_school, active) VALUES (?, ?, ?, ?, ?, ?, ?)', - school.id, school.name, school.code, nullable(school.address), school.isSourceSchool === false ? 0 : 1, - school.isAdmissionSchool === false ? 0 : 1, school.active === false ? 0 : 1 - ); - } - - for (const schoolClass of state.classes) { - add( - 'INSERT INTO school_classes (id, school_id, name, grade, active) VALUES (?, ?, ?, ?, ?)', - schoolClass.id, schoolClass.schoolId, schoolClass.name, schoolClass.grade, schoolClass.active === false ? 0 : 1 - ); - } - - for (const user of state.users) { - add( - `INSERT INTO users ( - id, username, candidate_number, password_hash, role, admin_level, school_id, class_id, active, - must_change_password, archived_at, archived_by, display_name, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - user.id, user.username, nullable(user.candidateNumber), user.passwordHash, user.role, nullable(user.adminLevel), nullable(user.schoolId), - nullable(user.classId), user.active === false ? 0 : 1, user.mustChangePassword ? 1 : 0, nullable(user.archivedAt), - nullable(user.archivedBy), user.displayName, user.createdAt - ); - } - - for (const profile of state.candidateProfiles) { - add( - `INSERT INTO candidate_profiles ( - id, user_id, name, gender, id_number, phone, email, school, grade, school_id, class_id, - province_code, province_name, city_code, city_name, district_code, district_name, address, - emergency_contact, emergency_phone, native_place, birth_date, ethnicity, postal_code, guardian_name, - guardian_phone, specialty_category, specialty_type, specialty_types, specialty_certificate, policy_eligibility, - profile_completed, status, review_note, reviewed_at, reviewer_id, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - profile.id, profile.userId, profile.name, nullable(profile.gender), profile.idNumber, profile.phone, - nullable(profile.email), nullable(profile.school), nullable(profile.grade), nullable(profile.schoolId), - nullable(profile.classId), nullable(profile.provinceCode), nullable(profile.provinceName), - nullable(profile.cityCode), nullable(profile.cityName), nullable(profile.districtCode), nullable(profile.districtName), - nullable(profile.address), - nullable(profile.emergencyContact), nullable(profile.emergencyPhone), nullable(profile.nativePlace), nullable(profile.birthDate), - nullable(profile.ethnicity), nullable(profile.postalCode), nullable(profile.guardianName), nullable(profile.guardianPhone), - nullable(profile.specialtyCategory), nullable(profile.specialtyType), JSON.stringify(profile.specialtyTypes || []), - nullable(profile.specialtyCertificate), nullable(profile.policyEligibility), - profile.profileCompleted ? 1 : 0, profile.status, nullable(profile.reviewNote), - nullable(profile.reviewedAt), nullable(profile.reviewerId), profile.updatedAt - ); - } - - for (const notice of state.notices) { - add( - `INSERT INTO notices ( - id, title, summary, content, category, pinned, status, publish_at, created_at, author - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - notice.id, notice.title, notice.summary, notice.content, notice.category, notice.pinned ? 1 : 0, - notice.status, nullable(notice.publishAt), nullable(notice.createdAt), notice.author - ); - } - - for (const exam of state.exams) { - add( - `INSERT INTO exams ( - id, code, name, description, registration_start, registration_end, exam_start, exam_end, - admit_download_start, admit_download_end, location, pass_policy, pass_value, status, archived_at, archived_by, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - exam.id, exam.code, exam.name, exam.description || '', exam.registrationStart, exam.registrationEnd, - exam.examStart, exam.examEnd, exam.admitDownloadStart, exam.admitDownloadEnd, exam.location || '', - exam.passPolicy === 'score_ratio' ? 'rank_percent' : (exam.passPolicy || 'rank_percent'), Number(exam.passValue ?? 60), exam.status, - nullable(exam.archivedAt), nullable(exam.archivedBy), exam.createdAt - ); - exam.subjects.forEach((subject, index) => add( - `INSERT INTO exam_subjects ( - id, exam_id, name, subject_date, start_time, end_time, fee, full_score, pass_score, pass_rule, pass_value, position - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - subject.id, exam.id, subject.name, subject.date || String(exam.examStart).slice(0, 10), - subject.start || '', subject.end || '', Number(subject.fee || 0), Number(subject.fullScore || 150), - Number(subject.passScore ?? 0), subject.passRule === 'rank_percent' ? 'score_ratio' : (subject.passRule || 'fixed_score'), - Number(subject.passValue ?? subject.passScore ?? Number(subject.fullScore || 150) * .6), Number(subject.order || index + 1) - )); - } - - for (const registration of state.registrations) { - add( - `INSERT INTO registrations ( - id, user_id, exam_id, status, payment_status, paid_at, paid_by, created_at, reviewed_at, review_note, - registration_number, number_rule_id, feature_score - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - registration.id, registration.userId, registration.examId, registration.status, - registration.paymentStatus, nullable(registration.paidAt), nullable(registration.paidBy), registration.createdAt, - nullable(registration.reviewedAt), nullable(registration.reviewNote), - nullable(registration.registrationNumber), nullable(registration.numberRuleId), Number(registration.featureScore || 0) - ); - for (const subjectId of registration.subjectIds) { - add('INSERT INTO registration_subjects (registration_id, subject_id) VALUES (?, ?)', registration.id, subjectId); - } - } - - for (const result of state.results) { - add( - `INSERT INTO results ( - id, registration_id, subject_id, score, grade, published, updated_at, published_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - result.id, result.registrationId, result.subjectId, Number(result.score), result.grade, - result.published ? 1 : 0, nullable(result.updatedAt), nullable(result.publishedAt) - ); - } - - for (const center of state.testCenters) { - add( - `INSERT INTO test_centers ( - id, school_id, code, name, province_code, province_name, city_code, city_name, district_code, district_name, - address, contact, manager_name, manager_phone, emergency_phone, - gate_open_time, transport, status, notes, rooms, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - center.id, center.schoolId, center.code, center.name, - center.provinceCode, center.provinceName, center.cityCode, center.cityName, center.districtCode, center.districtName, - center.address, nullable(center.contact), - nullable(center.managerName), nullable(center.managerPhone), nullable(center.emergencyPhone), - nullable(center.gateOpenTime), nullable(center.transport), center.status || 'active', nullable(center.notes), - center.rooms || '', center.updatedAt - ); - } - - for (const room of state.testRooms) { - add( - `INSERT INTO test_rooms ( - id, center_id, code, name, building, floor, capacity, seat_plan, seat_start, seat_end, room_type, status, notes - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - room.id, room.centerId, room.code, room.name, room.building, nullable(room.floor), Number(room.capacity), - nullable(room.seatPlan), Number(room.seatStart || 1), Number(room.seatEnd || room.capacity), room.roomType, room.status || 'active', nullable(room.notes) - ); - } - - for (const rule of state.admissionNumberRules) { - add( - `INSERT INTO admission_number_rules ( - id, code, name, description, \`separator\`, segments_json, example, active, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - rule.id, rule.code, rule.name, rule.description, rule.separator || '', JSON.stringify(rule.segments || []), - rule.example || '', rule.active === false ? 0 : 1, rule.createdAt - ); - } - - for (const plan of state.arrangementPlans) { - add( - `INSERT INTO exam_arrangement_plans ( - id, exam_id, number_rule_id, mixing_scope, random_seed, candidate_count, center_count, - subject_assignment_count, subject_combination_count, same_school_center_rate, warnings_json, generated_by, generated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - plan.id, plan.examId, plan.numberRuleId, plan.mixingScope, plan.randomSeed, - Number(plan.candidateCount || 0), Number(plan.centerCount || 0), Number(plan.subjectAssignmentCount || 0), - Number(plan.subjectCombinationCount || 0), Number(plan.sameSchoolCenterRate || 0), JSON.stringify(plan.warnings || []), - nullable(plan.generatedBy), plan.generatedAt - ); - } - - for (const registration of state.registrations.filter(item => item.admitCard)) { - const card = registration.admitCard; - add( - `INSERT INTO admit_cards ( - registration_id, plan_id, card_number, center_id, test_center, center_code, center_address, generated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - registration.id, card.planId, card.number, nullable(card.centerId), card.testCenter, - card.centerCode || '', card.centerAddress || '', card.generatedAt - ); - for (const assignment of card.assignments || []) add( - `INSERT INTO admit_card_subjects ( - registration_id, subject_id, room_id, room, room_code, exam_room_code, building, floor, seat, subject_signature - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - registration.id, assignment.subjectId, nullable(assignment.roomId), assignment.roomName || assignment.room, - assignment.roomCode, assignment.examRoomCode, assignment.building || '', assignment.floor || '', assignment.seat, assignment.subjectSignature || '' - ); - } - - for (const request of state.centerChangeRequests) { - add( - `INSERT INTO center_change_requests ( - id, center_id, school_id, request_type, code, name, - province_code, province_name, city_code, city_name, district_code, district_name, - address, contact, manager_name, manager_phone, - emergency_phone, gate_open_time, transport, center_status, notes, status, review_note, - requested_by, created_at, reviewed_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - request.id, nullable(request.centerId), request.schoolId, request.requestType, request.code, request.name, - request.provinceCode, request.provinceName, request.cityCode, request.cityName, request.districtCode, request.districtName, - request.address, nullable(request.contact), nullable(request.managerName), nullable(request.managerPhone), - nullable(request.emergencyPhone), nullable(request.gateOpenTime), nullable(request.transport), - request.centerStatus || 'active', nullable(request.notes), request.status, nullable(request.reviewNote), - nullable(request.requestedBy), request.createdAt, nullable(request.reviewedAt) - ); - } - - for (const room of state.centerChangeRooms) { - add( - `INSERT INTO center_change_rooms ( - id, request_id, room_id, code, name, building, floor, capacity, seat_plan, seat_start, seat_end, room_type, status, notes - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - room.id, room.requestId, nullable(room.roomId), room.code, room.name, room.building, nullable(room.floor), - Number(room.capacity), nullable(room.seatPlan), Number(room.seatStart || 1), Number(room.seatEnd || room.capacity), room.roomType, - room.status || 'active', nullable(room.notes) - ); - } - - for (const rule of state.numberRules) { - add( - 'INSERT INTO number_rules (id, name, `separator`, active, created_by, updated_at) VALUES (?, ?, ?, ?, ?, ?)', - rule.id, rule.name, rule.separator || '', rule.active ? 1 : 0, nullable(rule.createdBy), rule.updatedAt - ); - rule.segments.forEach((segment, index) => add( - 'INSERT INTO number_rule_segments (id, rule_id, position, type, value, width) VALUES (?, ?, ?, ?, ?, ?)', - segment.id, rule.id, Number(segment.position || index + 1), segment.type, nullable(segment.value), Number(segment.width || 0) - )); - } - - for (const batch of state.candidateAccountBatches) { - add( - `INSERT INTO candidate_account_batches ( - id, school_id, requested_by, status, review_note, created_at, reviewed_at - ) VALUES (?, ?, ?, ?, ?, ?, ?)`, - batch.id, batch.schoolId, nullable(batch.requestedBy), batch.status, nullable(batch.reviewNote), - batch.createdAt, nullable(batch.reviewedAt) - ); - } - - for (const item of state.candidateAccountBatchItems) { - add( - `INSERT INTO candidate_account_batch_items ( - id, batch_id, class_id, position, candidate_number, initial_password, user_id, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - item.id, item.batchId, item.classId, Number(item.position), nullable(item.candidateNumber), - nullable(item.initialPassword), nullable(item.userId), nullable(item.createdAt) - ); - } - - for (const workflow of state.workflows) { - add( - `INSERT INTO workflow_definitions ( - id, business_type, name, active, updated_by, updated_at - ) VALUES (?, ?, ?, ?, ?, ?)`, - workflow.id, workflow.businessType, workflow.name, workflow.active === false ? 0 : 1, - nullable(workflow.updatedBy), workflow.updatedAt - ); - workflow.steps.forEach((step, index) => add( - `INSERT INTO workflow_steps ( - id, workflow_id, position, name, admin_level - ) VALUES (?, ?, ?, ?, ?)`, - step.id, workflow.id, Number(step.position || index + 1), step.name, step.adminLevel - )); - } - - for (const instance of state.workflowInstances) { - add( - `INSERT INTO workflow_instances ( - id, workflow_id, business_type, business_id, status, current_step, assignee_id, created_at, completed_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - instance.id, instance.workflowId, instance.businessType, instance.businessId, instance.status, - Number(instance.currentStep || 1), nullable(instance.assigneeId), instance.createdAt, nullable(instance.completedAt) - ); - } - - for (const action of state.workflowActions) { - add( - `INSERT INTO workflow_actions ( - id, instance_id, actor_id, action, note, from_assignee_id, to_assignee_id, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - action.id, action.instanceId, nullable(action.actorId), action.action, nullable(action.note), - nullable(action.fromAssigneeId), nullable(action.toAssigneeId), action.createdAt - ); - } - - for (const record of state.admissionRecords) { - add( - `INSERT INTO admission_records ( - id, kind, exam_id, user_id, school_id, status, payload_json, created_at, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - record.id, record.kind, record.examId, nullable(record.userId), nullable(record.schoolId), record.status, - JSON.stringify(record.payload || {}), record.createdAt, record.updatedAt - ); - } - - for (const log of state.auditLogs) { - add( - 'INSERT INTO audit_logs (id, actor_id, action, detail, created_at) VALUES (?, ?, ?, ?, ?)', - log.id, nullable(log.actorId), log.action, log.detail, log.createdAt - ); - } - - return operations; -} - -function stateFromRows(rows) { - const parseJson = (value, fallback) => { - if (value != null && typeof value === 'object') return value; - try { return JSON.parse(value || JSON.stringify(fallback)); } catch { return fallback; } - }; - const subjectsByExam = new Map(); - for (const row of rows.subjects) { - const fullScore = Number(row.full_score ?? 150); - const passRule = row.pass_rule === 'score_ratio' ? 'rank_percent' : (row.pass_rule || 'fixed_score'); - const passValue = Number(row.pass_value ?? row.pass_score ?? fullScore * .6); - const subject = { - id: row.id, - name: row.name, - date: row.subject_date, - start: row.start_time, - end: row.end_time, - fee: Number(row.fee), - fullScore, - passRule, - passValue, - passScore: passRule === 'fixed_score' ? Number(passValue.toFixed(2)) : null, - order: Number(row.position) - }; - const subjects = subjectsByExam.get(row.exam_id) || []; - subjects.push(subject); - subjectsByExam.set(row.exam_id, subjects); - } - - const registrationSubjects = new Map(); - for (const row of rows.registrationSubjects) { - const subjectIds = registrationSubjects.get(row.registration_id) || []; - subjectIds.push(row.subject_id); - registrationSubjects.set(row.registration_id, subjectIds); - } - const subjectPositions = new Map(rows.subjects.map(row => [row.id, Number(row.position)])); - const admitAssignments = new Map(); - for (const row of rows.admitCardSubjects) { - const assignments = admitAssignments.get(row.registration_id) || []; - assignments.push({ - subjectId: row.subject_id, - roomId: row.room_id, - roomName: row.room, - room: row.room, - roomCode: row.room_code, - examRoomCode: row.exam_room_code, - building: row.building || '', - floor: row.floor || '', - seat: row.seat, - subjectSignature: row.subject_signature || '' - }); - admitAssignments.set(row.registration_id, assignments); - } - for (const assignments of admitAssignments.values()) assignments.sort((left, right) => - (subjectPositions.get(left.subjectId) || 0) - (subjectPositions.get(right.subjectId) || 0) - ); - const admitCards = new Map(rows.admitCards.map(row => { - const assignments = admitAssignments.get(row.registration_id) || []; - const primary = assignments[0] || {}; - return [row.registration_id, { - planId: row.plan_id, - number: row.card_number, - centerId: row.center_id, - testCenter: row.test_center, - centerCode: row.center_code || '', - centerAddress: row.center_address || '', - room: primary.roomName || '', - seat: primary.seat || '', - assignments, - generatedAt: row.generated_at - }]; - })); - const ruleSegments = new Map(); - for (const row of rows.numberRuleSegments) { - const segments = ruleSegments.get(row.rule_id) || []; - segments.push({ - id: row.id, - type: row.type, - value: row.value || '', - width: Number(row.width || 0), - position: Number(row.position) - }); - ruleSegments.set(row.rule_id, segments); - } - const workflowSteps = new Map(); - for (const row of rows.workflowSteps) { - const steps = workflowSteps.get(row.workflow_id) || []; - steps.push({ - id: row.id, - name: row.name, - adminLevel: row.admin_level, - position: Number(row.position) - }); - workflowSteps.set(row.workflow_id, steps); - } - - const organization = rows.organization; - const state = { - meta: { version: Number(rows.system.app_version), createdAt: rows.system.created_at }, - settings: { selfRegistrationEnabled: Boolean(rows.system.self_registration_enabled) }, - organization: { - name: organization.name, - code: organization.code, - phone: organization.phone, - address: organization.address - }, - schools: rows.schools.map(row => ({ - id: row.id, - name: row.name, - code: row.code, - address: row.address || '', - isSourceSchool: row.is_source_school == null ? true : Boolean(row.is_source_school), - isAdmissionSchool: row.is_admission_school == null ? true : Boolean(row.is_admission_school), - active: Boolean(row.active) - })), - classes: rows.classes.map(row => ({ - id: row.id, - schoolId: row.school_id, - name: row.name, - grade: row.grade, - active: Boolean(row.active) - })), - users: rows.users.map(row => ({ - id: row.id, - username: row.username, - candidateNumber: row.candidate_number || '', - passwordHash: row.password_hash, - role: row.role, - adminLevel: row.admin_level || (row.role === 'admin' ? 'super' : null), - schoolId: row.school_id || null, - classId: row.class_id || null, - active: row.active == null ? true : Boolean(row.active), - mustChangePassword: Boolean(row.must_change_password), - totpEnabled: Boolean(row.totp_enabled), - totpSecretEncrypted: row.totp_secret_encrypted || null, - totpRecoveryCodes: (() => { try { return JSON.parse(row.totp_recovery_codes || '[]'); } catch { return []; } })(), - totpLastUsedStep: row.totp_last_used_step == null ? null : Number(row.totp_last_used_step), - archivedAt: row.archived_at || null, - archivedBy: row.archived_by || null, - displayName: row.display_name, - createdAt: row.created_at - })), - candidateProfiles: rows.profiles.map(row => ({ - id: row.id, - userId: row.user_id, - name: row.name, - gender: row.gender || '', - idNumber: row.id_number, - phone: row.phone, - email: row.email || '', - school: row.school || '', - grade: row.grade || '', - schoolId: row.school_id || null, - classId: row.class_id || null, - provinceCode: row.province_code || '', - provinceName: row.province_name || '', - cityCode: row.city_code || '', - cityName: row.city_name || '', - districtCode: row.district_code || '', - districtName: row.district_name || '', - address: row.address || '', - emergencyContact: row.emergency_contact || '', - emergencyPhone: row.emergency_phone || '', - nativePlace: row.native_place || '', - birthDate: row.birth_date || '', - ethnicity: row.ethnicity || '', - postalCode: row.postal_code || '', - guardianName: row.guardian_name || '', - guardianPhone: row.guardian_phone || '', - specialtyCategory: row.specialty_category || '', - specialtyType: row.specialty_type || '', - specialtyTypes: parseJson(row.specialty_types, []), - specialtyCertificate: row.specialty_certificate || '', - policyEligibility: row.policy_eligibility || '', - profileCompleted: Boolean(row.profile_completed), - status: row.status, - reviewNote: row.review_note || '', - reviewedAt: row.reviewed_at, - reviewerId: row.reviewer_id, - updatedAt: row.updated_at - })), - notices: rows.notices.map(row => ({ - id: row.id, - title: row.title, - summary: row.summary, - content: row.content, - category: row.category, - pinned: Boolean(row.pinned), - status: row.status, - publishAt: row.publish_at, - createdAt: row.created_at, - author: row.author - })), - exams: rows.exams.map(row => ({ - id: row.id, - code: row.code, - name: row.name, - description: row.description, - registrationStart: row.registration_start, - registrationEnd: row.registration_end, - examStart: row.exam_start, - examEnd: row.exam_end, - admitDownloadStart: row.admit_download_start, - admitDownloadEnd: row.admit_download_end, - location: row.location, - passPolicy: row.pass_policy === 'score_ratio' ? 'rank_percent' : (row.pass_policy || 'rank_percent'), - passValue: Number(row.pass_value ?? 60), - status: row.status, - archivedAt: row.archived_at || null, - archivedBy: row.archived_by || null, - createdAt: row.created_at, - subjects: subjectsByExam.get(row.id) || [] - })), - registrations: rows.registrations.map(row => ({ - id: row.id, - userId: row.user_id, - examId: row.exam_id, - subjectIds: registrationSubjects.get(row.id) || [], - status: row.status, - paymentStatus: row.payment_status, - paidAt: row.paid_at || null, - paidBy: row.paid_by || null, - createdAt: row.created_at, - reviewedAt: row.reviewed_at, - reviewNote: row.review_note || '', - registrationNumber: row.registration_number || '', - numberRuleId: row.number_rule_id || null, - featureScore: Number(row.feature_score || 0), - admitCard: admitCards.get(row.id) || null - })), - results: rows.results.map(row => ({ - id: row.id, - registrationId: row.registration_id, - subjectId: row.subject_id, - score: Number(row.score), - grade: row.grade, - published: Boolean(row.published), - updatedAt: row.updated_at, - publishedAt: row.published_at - })), - testCenters: rows.testCenters.map(row => ({ - id: row.id, - schoolId: row.school_id, - code: row.code || '', - name: row.name, - provinceCode: row.province_code || '', - provinceName: row.province_name || '', - cityCode: row.city_code || '', - cityName: row.city_name || '', - districtCode: row.district_code || '', - districtName: row.district_name || '', - address: row.address, - contact: row.contact || '', - managerName: row.manager_name || '', - managerPhone: row.manager_phone || '', - emergencyPhone: row.emergency_phone || '', - gateOpenTime: row.gate_open_time || '', - transport: row.transport || '', - status: row.status || 'active', - notes: row.notes || '', - rooms: row.rooms || '', - updatedAt: row.updated_at - })), - testRooms: rows.testRooms.map(row => ({ - id: row.id, - centerId: row.center_id, - code: row.code, - name: row.name, - building: row.building, - floor: row.floor || '', - capacity: Number(row.capacity), - seatPlan: row.seat_plan || '', - seatStart: Number(row.seat_start), - seatEnd: Number(row.seat_end), - roomType: row.room_type, - status: row.status, - notes: row.notes || '' - })), - centerChangeRequests: rows.centerChangeRequests.map(row => ({ - id: row.id, - centerId: row.center_id, - schoolId: row.school_id, - requestType: row.request_type, - code: row.code, - name: row.name, - provinceCode: row.province_code || '', - provinceName: row.province_name || '', - cityCode: row.city_code || '', - cityName: row.city_name || '', - districtCode: row.district_code || '', - districtName: row.district_name || '', - address: row.address, - contact: row.contact || '', - managerName: row.manager_name || '', - managerPhone: row.manager_phone || '', - emergencyPhone: row.emergency_phone || '', - gateOpenTime: row.gate_open_time || '', - transport: row.transport || '', - centerStatus: row.center_status, - notes: row.notes || '', - status: row.status, - reviewNote: row.review_note || '', - requestedBy: row.requested_by, - createdAt: row.created_at, - reviewedAt: row.reviewed_at - })), - centerChangeRooms: rows.centerChangeRooms.map(row => ({ - id: row.id, - requestId: row.request_id, - roomId: row.room_id, - code: row.code, - name: row.name, - building: row.building, - floor: row.floor || '', - capacity: Number(row.capacity), - seatPlan: row.seat_plan || '', - seatStart: Number(row.seat_start), - seatEnd: Number(row.seat_end), - roomType: row.room_type, - status: row.status, - notes: row.notes || '' - })), - admissionNumberRules: rows.admissionNumberRules.map(row => ({ - id: row.id, - code: row.code, - name: row.name, - description: row.description, - separator: row.separator || '', - segments: Array.isArray(row.segments_json) ? row.segments_json : JSON.parse(row.segments_json || '[]'), - example: row.example || '', - active: Boolean(row.active), - createdAt: row.created_at - })), - arrangementPlans: rows.arrangementPlans.map(row => ({ - id: row.id, - examId: row.exam_id, - numberRuleId: row.number_rule_id, - mixingScope: row.mixing_scope, - randomSeed: row.random_seed, - candidateCount: Number(row.candidate_count), - centerCount: Number(row.center_count), - subjectAssignmentCount: Number(row.subject_assignment_count), - subjectCombinationCount: Number(row.subject_combination_count), - sameSchoolCenterRate: Number(row.same_school_center_rate), - warnings: Array.isArray(row.warnings_json) ? row.warnings_json : JSON.parse(row.warnings_json || '[]'), - generatedBy: row.generated_by, - generatedAt: row.generated_at - })), - numberRules: rows.numberRules.map(row => ({ - id: row.id, - name: row.name, - separator: row.separator, - active: Boolean(row.active), - createdBy: row.created_by, - updatedAt: row.updated_at, - segments: ruleSegments.get(row.id) || [] - })), - candidateAccountBatches: rows.candidateAccountBatches.map(row => ({ - id: row.id, - schoolId: row.school_id, - requestedBy: row.requested_by, - status: row.status, - reviewNote: row.review_note || '', - createdAt: row.created_at, - reviewedAt: row.reviewed_at - })), - candidateAccountBatchItems: rows.candidateAccountBatchItems.map(row => ({ - id: row.id, - batchId: row.batch_id, - classId: row.class_id, - position: Number(row.position), - candidateNumber: row.candidate_number || '', - initialPassword: row.initial_password || '', - userId: row.user_id, - createdAt: row.created_at - })), - workflows: rows.workflows.map(row => ({ - id: row.id, - businessType: row.business_type, - name: row.name, - active: Boolean(row.active), - updatedBy: row.updated_by, - updatedAt: row.updated_at, - steps: workflowSteps.get(row.id) || [] - })), - workflowInstances: rows.workflowInstances.map(row => ({ - id: row.id, - workflowId: row.workflow_id, - businessType: row.business_type, - businessId: row.business_id, - status: row.status, - currentStep: Number(row.current_step), - assigneeId: row.assignee_id, - createdAt: row.created_at, - completedAt: row.completed_at - })), - workflowActions: rows.workflowActions.map(row => ({ - id: row.id, - instanceId: row.instance_id, - actorId: row.actor_id, - action: row.action, - note: row.note || '', - fromAssigneeId: row.from_assignee_id, - toAssigneeId: row.to_assignee_id, - createdAt: row.created_at - })), - admissionRecords: rows.admissionRecords.map(row => ({ - id: row.id, - kind: row.kind, - examId: row.exam_id, - userId: row.user_id || null, - schoolId: row.school_id || null, - status: row.status, - payload: parseJson(row.payload_json, {}), - createdAt: row.created_at, - updatedAt: row.updated_at - })), - auditLogs: rows.auditLogs.map(row => ({ - id: row.id, - actorId: row.actor_id, - action: row.action, - detail: row.detail, - createdAt: row.created_at - })) - }; - return state; -} - -function readSqliteRows(connection) { - return { - system: connection.prepare('SELECT * FROM schema_metadata WHERE id = 1').get(), - organization: connection.prepare('SELECT * FROM organization WHERE id = 1').get(), - schools: connection.prepare('SELECT * FROM schools ORDER BY name, id').all(), - classes: connection.prepare('SELECT * FROM school_classes ORDER BY school_id, grade, name, id').all(), - users: connection.prepare('SELECT * FROM users ORDER BY created_at, id').all(), - profiles: connection.prepare('SELECT * FROM candidate_profiles ORDER BY updated_at, id').all(), - notices: connection.prepare('SELECT * FROM notices ORDER BY publish_at, created_at, id').all(), - exams: connection.prepare('SELECT * FROM exams ORDER BY created_at, id').all(), - subjects: connection.prepare('SELECT * FROM exam_subjects ORDER BY exam_id, position, id').all(), - registrations: connection.prepare('SELECT * FROM registrations ORDER BY created_at, id').all(), - registrationSubjects: connection.prepare('SELECT * FROM registration_subjects ORDER BY registration_id, subject_id').all(), - admissionNumberRules: connection.prepare('SELECT * FROM admission_number_rules ORDER BY created_at, id').all(), - arrangementPlans: connection.prepare('SELECT * FROM exam_arrangement_plans ORDER BY generated_at DESC, id').all(), - admitCards: connection.prepare('SELECT * FROM admit_cards ORDER BY registration_id').all(), - admitCardSubjects: connection.prepare('SELECT * FROM admit_card_subjects ORDER BY registration_id, subject_id').all(), - results: connection.prepare('SELECT * FROM results ORDER BY id').all(), - testCenters: connection.prepare('SELECT * FROM test_centers ORDER BY school_id, name, id').all(), - testRooms: connection.prepare('SELECT * FROM test_rooms ORDER BY center_id, code, id').all(), - centerChangeRequests: connection.prepare('SELECT * FROM center_change_requests ORDER BY created_at DESC, id').all(), - centerChangeRooms: connection.prepare('SELECT * FROM center_change_rooms ORDER BY request_id, code, id').all(), - numberRules: connection.prepare('SELECT * FROM number_rules ORDER BY updated_at DESC, id').all(), - numberRuleSegments: connection.prepare('SELECT * FROM number_rule_segments ORDER BY rule_id, position, id').all(), - candidateAccountBatches: connection.prepare('SELECT * FROM candidate_account_batches ORDER BY created_at DESC, id').all(), - candidateAccountBatchItems: connection.prepare('SELECT * FROM candidate_account_batch_items ORDER BY batch_id, position, id').all(), - workflows: connection.prepare('SELECT * FROM workflow_definitions ORDER BY business_type, id').all(), - workflowSteps: connection.prepare('SELECT * FROM workflow_steps ORDER BY workflow_id, position, id').all(), - workflowInstances: connection.prepare('SELECT * FROM workflow_instances ORDER BY created_at DESC, id').all(), - workflowActions: connection.prepare('SELECT * FROM workflow_actions ORDER BY created_at, id').all(), - admissionRecords: connection.prepare('SELECT * FROM admission_records ORDER BY created_at, id').all(), - auditLogs: connection.prepare('SELECT * FROM audit_logs ORDER BY created_at DESC, id DESC').all() - }; -} - -async function readMysqlRows(connection) { - const query = async sql => (await connection.execute(sql))[0]; - const one = async sql => (await query(sql))[0]; - return { - system: await one('SELECT * FROM schema_metadata WHERE id = 1'), - organization: await one('SELECT * FROM organization WHERE id = 1'), - schools: await query('SELECT * FROM schools ORDER BY name, id'), - classes: await query('SELECT * FROM school_classes ORDER BY school_id, grade, name, id'), - users: await query('SELECT * FROM users ORDER BY created_at, id'), - profiles: await query('SELECT * FROM candidate_profiles ORDER BY updated_at, id'), - notices: await query('SELECT * FROM notices ORDER BY publish_at, created_at, id'), - exams: await query('SELECT * FROM exams ORDER BY created_at, id'), - subjects: await query('SELECT * FROM exam_subjects ORDER BY exam_id, position, id'), - registrations: await query('SELECT * FROM registrations ORDER BY created_at, id'), - registrationSubjects: await query('SELECT * FROM registration_subjects ORDER BY registration_id, subject_id'), - admissionNumberRules: await query('SELECT * FROM admission_number_rules ORDER BY created_at, id'), - arrangementPlans: await query('SELECT * FROM exam_arrangement_plans ORDER BY generated_at DESC, id'), - admitCards: await query('SELECT * FROM admit_cards ORDER BY registration_id'), - admitCardSubjects: await query('SELECT * FROM admit_card_subjects ORDER BY registration_id, subject_id'), - results: await query('SELECT * FROM results ORDER BY id'), - testCenters: await query('SELECT * FROM test_centers ORDER BY school_id, name, id'), - testRooms: await query('SELECT * FROM test_rooms ORDER BY center_id, code, id'), - centerChangeRequests: await query('SELECT * FROM center_change_requests ORDER BY created_at DESC, id'), - centerChangeRooms: await query('SELECT * FROM center_change_rooms ORDER BY request_id, code, id'), - numberRules: await query('SELECT * FROM number_rules ORDER BY updated_at DESC, id'), - numberRuleSegments: await query('SELECT * FROM number_rule_segments ORDER BY rule_id, position, id'), - candidateAccountBatches: await query('SELECT * FROM candidate_account_batches ORDER BY created_at DESC, id'), - candidateAccountBatchItems: await query('SELECT * FROM candidate_account_batch_items ORDER BY batch_id, position, id'), - workflows: await query('SELECT * FROM workflow_definitions ORDER BY business_type, id'), - workflowSteps: await query('SELECT * FROM workflow_steps ORDER BY workflow_id, position, id'), - workflowInstances: await query('SELECT * FROM workflow_instances ORDER BY created_at DESC, id'), - workflowActions: await query('SELECT * FROM workflow_actions ORDER BY created_at, id'), - admissionRecords: await query('SELECT * FROM admission_records ORDER BY created_at, id'), - auditLogs: await query('SELECT * FROM audit_logs ORDER BY created_at DESC, id DESC') - }; -} - -function operation(sql, ...params) { - return { sql, params }; -} - -function optional(value) { - return value == null || value === '' ? null : value; -} - -function auditOperation(log) { - return operation( - 'INSERT INTO audit_logs (id, actor_id, action, detail, created_at) VALUES (?, ?, ?, ?, ?)', - log.id, optional(log.actorId), log.action, log.detail, log.createdAt - ); -} - -function workflowInstanceOperation(instance) { - return operation( - `INSERT INTO workflow_instances ( - id, workflow_id, business_type, business_id, status, current_step, assignee_id, created_at, completed_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - instance.id, instance.workflowId, instance.businessType, instance.businessId, instance.status, - Number(instance.currentStep || 1), optional(instance.assigneeId), instance.createdAt, optional(instance.completedAt) - ); -} - -function workflowActionOperation(action) { - return operation( - `INSERT INTO workflow_actions ( - id, instance_id, actor_id, action, note, from_assignee_id, to_assignee_id, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - action.id, action.instanceId, optional(action.actorId), action.action, optional(action.note), - optional(action.fromAssigneeId), optional(action.toAssigneeId), action.createdAt - ); -} - -function workflowCreateOperations(instance, action) { - return [workflowInstanceOperation(instance), workflowActionOperation(action)]; -} - -function createRepository({ client, location, read, transaction, close }) { - return { - client, - location, - read, - close, - async createCandidate(user, profile, instance, action, log = null) { - const operations = [ - operation( - `INSERT INTO users ( - id, username, candidate_number, password_hash, role, admin_level, school_id, class_id, active, - must_change_password, archived_at, archived_by, display_name, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - user.id, user.username, optional(user.candidateNumber), user.passwordHash, user.role, optional(user.adminLevel), optional(user.schoolId), - optional(user.classId), user.active === false ? 0 : 1, user.mustChangePassword ? 1 : 0, optional(user.archivedAt), - optional(user.archivedBy), user.displayName, user.createdAt - ), - operation( - `INSERT INTO candidate_profiles ( - id, user_id, name, gender, id_number, phone, email, school, grade, school_id, class_id, - province_code, province_name, city_code, city_name, district_code, district_name, address, - emergency_contact, emergency_phone, native_place, birth_date, ethnicity, postal_code, guardian_name, - guardian_phone, profile_completed, status, review_note, reviewed_at, reviewer_id, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - profile.id, profile.userId, profile.name, optional(profile.gender), profile.idNumber, profile.phone, - optional(profile.email), optional(profile.school), optional(profile.grade), optional(profile.schoolId), - optional(profile.classId), optional(profile.provinceCode), optional(profile.provinceName), - optional(profile.cityCode), optional(profile.cityName), optional(profile.districtCode), optional(profile.districtName), - optional(profile.address), - optional(profile.emergencyContact), optional(profile.emergencyPhone), optional(profile.nativePlace), optional(profile.birthDate), - optional(profile.ethnicity), optional(profile.postalCode), optional(profile.guardianName), optional(profile.guardianPhone), - profile.profileCompleted ? 1 : 0, profile.status, optional(profile.reviewNote), - optional(profile.reviewedAt), optional(profile.reviewerId), profile.updatedAt - ) - ]; - if (instance && action) operations.push(...workflowCreateOperations(instance, action)); - if (log) operations.push(auditOperation(log)); - await transaction(operations); - }, - async createCandidateAccountBatch(batch, items, instance, action, log) { - const operations = [ - operation( - `INSERT INTO candidate_account_batches ( - id, school_id, requested_by, status, review_note, created_at, reviewed_at - ) VALUES (?, ?, ?, ?, ?, ?, ?)`, - batch.id, batch.schoolId, optional(batch.requestedBy), batch.status, optional(batch.reviewNote), - batch.createdAt, optional(batch.reviewedAt) - ) - ]; - for (const item of items) operations.push(operation( - `INSERT INTO candidate_account_batch_items ( - id, batch_id, class_id, position, candidate_number, initial_password, user_id, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - item.id, item.batchId, item.classId, Number(item.position), optional(item.candidateNumber), - optional(item.initialPassword), optional(item.userId), optional(item.createdAt) - )); - operations.push(...workflowCreateOperations(instance, action), auditOperation(log)); - await transaction(operations); - }, - async updateCandidateProfile(profile, displayName, instance, action) { - const operations = [ - operation( - `UPDATE candidate_profiles SET - name = ?, gender = ?, id_number = ?, phone = ?, email = ?, school = ?, grade = ?, - province_code = ?, province_name = ?, city_code = ?, city_name = ?, district_code = ?, district_name = ?, address = ?, - school_id = ?, class_id = ?, emergency_contact = ?, emergency_phone = ?, status = ?, review_note = ?, - native_place = ?, birth_date = ?, ethnicity = ?, postal_code = ?, guardian_name = ?, guardian_phone = ?, - specialty_category = ?, specialty_type = ?, specialty_types = ?, specialty_certificate = ?, policy_eligibility = ?, - profile_completed = ?, reviewed_at = ?, reviewer_id = ?, updated_at = ? - WHERE id = ?`, - profile.name, optional(profile.gender), profile.idNumber, profile.phone, optional(profile.email), - optional(profile.school), optional(profile.grade), optional(profile.provinceCode), optional(profile.provinceName), - optional(profile.cityCode), optional(profile.cityName), optional(profile.districtCode), optional(profile.districtName), - optional(profile.address), optional(profile.schoolId), - optional(profile.classId), optional(profile.emergencyContact), optional(profile.emergencyPhone), profile.status, - optional(profile.reviewNote), optional(profile.nativePlace), optional(profile.birthDate), optional(profile.ethnicity), - optional(profile.postalCode), optional(profile.guardianName), optional(profile.guardianPhone), optional(profile.specialtyCategory), - optional(profile.specialtyType), JSON.stringify(profile.specialtyTypes || []), - optional(profile.specialtyCertificate), optional(profile.policyEligibility), profile.profileCompleted ? 1 : 0, optional(profile.reviewedAt), - optional(profile.reviewerId), profile.updatedAt, profile.id - ), - operation('UPDATE users SET display_name = ? WHERE id = ?', displayName, profile.userId) - ]; - if (instance && action) operations.push(...workflowCreateOperations(instance, action)); - await transaction(operations); - }, - async changePassword(user, log) { - const operations = [operation( - 'UPDATE users SET password_hash = ?, must_change_password = ? WHERE id = ?', - user.passwordHash, user.mustChangePassword ? 1 : 0, user.id - )]; - if (log) operations.push(auditOperation(log)); - await transaction(operations); - }, - async updateTotpSecurity(user, log = null) { - const operations = [operation( - `UPDATE users SET - totp_enabled = ?, totp_secret_encrypted = ?, totp_recovery_codes = ?, totp_last_used_step = ? - WHERE id = ?`, - user.totpEnabled ? 1 : 0, optional(user.totpSecretEncrypted), JSON.stringify(user.totpRecoveryCodes || []), - optional(user.totpLastUsedStep), user.id - )]; - if (log) operations.push(auditOperation(log)); - await transaction(operations); - }, - async updateCandidateArchives(users, log) { - const operations = users.map(user => operation( - 'UPDATE users SET archived_at = ?, archived_by = ? WHERE id = ?', - optional(user.archivedAt), optional(user.archivedBy), user.id - )); - operations.push(auditOperation(log)); - await transaction(operations); - }, - async updateRegistrationSetting(enabled, log) { - await transaction([ - operation('UPDATE schema_metadata SET self_registration_enabled = ? WHERE id = 1', enabled ? 1 : 0), - auditOperation(log) - ]); - }, - async createRegistration(registration, instance, action) { - const operations = [operation( - `INSERT INTO registrations ( - id, user_id, exam_id, status, payment_status, paid_at, paid_by, created_at, reviewed_at, review_note, - registration_number, number_rule_id, feature_score - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - registration.id, registration.userId, registration.examId, registration.status, - registration.paymentStatus, optional(registration.paidAt), optional(registration.paidBy), registration.createdAt, - optional(registration.reviewedAt), optional(registration.reviewNote), - optional(registration.registrationNumber), optional(registration.numberRuleId), Number(registration.featureScore || 0) - )]; - for (const subjectId of registration.subjectIds) { - operations.push(operation( - 'INSERT INTO registration_subjects (registration_id, subject_id) VALUES (?, ?)', - registration.id, subjectId - )); - } - if (instance && action) operations.push(...workflowCreateOperations(instance, action)); - await transaction(operations); - }, - async reviewCandidate(profile, log) { - await transaction([ - operation( - `UPDATE candidate_profiles SET status = ?, review_note = ?, reviewed_at = ?, reviewer_id = ? WHERE id = ?`, - profile.status, optional(profile.reviewNote), profile.reviewedAt, profile.reviewerId, profile.id - ), - auditOperation(log) - ]); - }, - async reviewRegistration(registration, log) { - await transaction([ - operation( - `UPDATE registrations SET status = ?, payment_status = ?, reviewed_at = ?, review_note = ? WHERE id = ?`, - registration.status, registration.paymentStatus, registration.reviewedAt, - optional(registration.reviewNote), registration.id - ), - auditOperation(log) - ]); - }, - async updateRegistrationPayment(registration, log) { - await transaction([ - operation( - 'UPDATE registrations SET payment_status = ?, paid_at = ?, paid_by = ? WHERE id = ?', - registration.paymentStatus, optional(registration.paidAt), optional(registration.paidBy), registration.id - ), - auditOperation(log) - ]); - }, - async processWorkflow(instance, action, business, log) { - const operations = [ - operation( - `UPDATE workflow_instances SET - status = ?, current_step = ?, assignee_id = ?, completed_at = ? WHERE id = ?`, - instance.status, Number(instance.currentStep), optional(instance.assigneeId), - optional(instance.completedAt), instance.id - ), - workflowActionOperation(action) - ]; - if (instance.businessType === 'profile_change') { - operations.push(operation( - `UPDATE candidate_profiles SET - status = ?, review_note = ?, reviewed_at = ?, reviewer_id = ? WHERE id = ?`, - business.status, optional(business.reviewNote), optional(business.reviewedAt), - optional(business.reviewerId), business.id - )); - } else if (instance.businessType === 'registration_review') { - operations.push(operation( - `UPDATE registrations SET - status = ?, payment_status = ?, paid_at = ?, paid_by = ?, reviewed_at = ?, review_note = ?, - registration_number = ?, number_rule_id = ? WHERE id = ?`, - business.status, business.paymentStatus, optional(business.paidAt), optional(business.paidBy), - optional(business.reviewedAt), optional(business.reviewNote), - optional(business.registrationNumber), optional(business.numberRuleId), business.id - )); - } else if (instance.businessType === 'center_change') { - operations.push(operation( - `UPDATE center_change_requests SET - status = ?, review_note = ?, reviewed_at = ? WHERE id = ?`, - business.status, optional(business.reviewNote), optional(business.reviewedAt), business.id - )); - } else if (instance.businessType === 'candidate_account_batch') { - operations.push(operation( - `UPDATE candidate_account_batches SET - status = ?, review_note = ?, reviewed_at = ? WHERE id = ?`, - business.status, optional(business.reviewNote), optional(business.reviewedAt), business.id - )); - } else if (instance.businessType === 'score_appeal' && business) { - operations.push(operation( - `UPDATE results SET score = ?, grade = ?, published = ?, updated_at = ?, published_at = ? WHERE id = ?`, - Number(business.score), business.grade, business.published ? 1 : 0, - optional(business.updatedAt), optional(business.publishedAt), business.id - )); - } - if (log) operations.push(auditOperation(log)); - await transaction(operations); - }, - async completeCandidateAccountBatch(batch, items, users, profiles, instance, action, log) { - const operations = [ - operation( - `UPDATE workflow_instances SET - status = ?, current_step = ?, assignee_id = ?, completed_at = ? WHERE id = ?`, - instance.status, Number(instance.currentStep), optional(instance.assigneeId), optional(instance.completedAt), instance.id - ), - workflowActionOperation(action), - operation( - `UPDATE candidate_account_batches SET status = ?, review_note = ?, reviewed_at = ? WHERE id = ?`, - batch.status, optional(batch.reviewNote), optional(batch.reviewedAt), batch.id - ) - ]; - for (let index = 0; index < users.length; index += 1) { - const user = users[index]; - const profile = profiles[index]; - const item = items[index]; - operations.push( - operation( - `INSERT INTO users ( - id, username, candidate_number, password_hash, role, admin_level, school_id, class_id, active, - must_change_password, archived_at, archived_by, display_name, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - user.id, user.username, user.candidateNumber, user.passwordHash, user.role, optional(user.adminLevel), - user.schoolId, user.classId, 1, 1, null, null, user.displayName, user.createdAt - ), - operation( - `INSERT INTO candidate_profiles ( - id, user_id, name, gender, id_number, phone, email, school, grade, school_id, class_id, - province_code, province_name, city_code, city_name, district_code, district_name, address, - emergency_contact, emergency_phone, native_place, birth_date, ethnicity, postal_code, guardian_name, - guardian_phone, profile_completed, status, review_note, reviewed_at, reviewer_id, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - profile.id, profile.userId, profile.name, optional(profile.gender), profile.idNumber, profile.phone, - optional(profile.email), profile.school, profile.grade, profile.schoolId, profile.classId, - optional(profile.provinceCode), optional(profile.provinceName), optional(profile.cityCode), optional(profile.cityName), - optional(profile.districtCode), optional(profile.districtName), optional(profile.address), - optional(profile.emergencyContact), optional(profile.emergencyPhone), - optional(profile.nativePlace), optional(profile.birthDate), optional(profile.ethnicity), optional(profile.postalCode), - optional(profile.guardianName), optional(profile.guardianPhone), 0, profile.status, optional(profile.reviewNote), - optional(profile.reviewedAt), optional(profile.reviewerId), profile.updatedAt - ), - operation( - `UPDATE candidate_account_batch_items SET - candidate_number = ?, initial_password = ?, user_id = ?, created_at = ? WHERE id = ?`, - item.candidateNumber, item.initialPassword, item.userId, item.createdAt, item.id - ) - ); - } - operations.push(auditOperation(log)); - await transaction(operations); - }, - async transferWorkflow(instance, action, log) { - const operations = [ - operation('UPDATE workflow_instances SET assignee_id = ? WHERE id = ?', optional(instance.assigneeId), instance.id), - workflowActionOperation(action) - ]; - if (log) operations.push(auditOperation(log)); - await transaction(operations); - }, - async createWorkflow(instance, action, log = null) { - const operations = workflowCreateOperations(instance, action); - if (log) operations.push(auditOperation(log)); - await transaction(operations); - }, - async saveWorkflow(workflow, log) { - const operations = [ - operation( - `UPDATE workflow_definitions SET name = ?, active = ?, updated_by = ?, updated_at = ? WHERE id = ?`, - workflow.name, workflow.active ? 1 : 0, optional(workflow.updatedBy), workflow.updatedAt, workflow.id - ), - operation('DELETE FROM workflow_steps WHERE workflow_id = ?', workflow.id) - ]; - workflow.steps.forEach((step, index) => operations.push(operation( - `INSERT INTO workflow_steps (id, workflow_id, position, name, admin_level) VALUES (?, ?, ?, ?, ?)`, - step.id, workflow.id, Number(step.position || index + 1), step.name, step.adminLevel - ))); - operations.push(auditOperation(log)); - await transaction(operations); - }, - async saveNumberRule(rule, isNew, log) { - const operations = [operation('UPDATE number_rules SET active = 0 WHERE active = 1')]; - if (isNew) { - operations.push(operation( - 'INSERT INTO number_rules (id, name, `separator`, active, created_by, updated_at) VALUES (?, ?, ?, ?, ?, ?)', - rule.id, rule.name, rule.separator, rule.active ? 1 : 0, optional(rule.createdBy), rule.updatedAt - )); - } else { - operations.push( - operation( - 'UPDATE number_rules SET name = ?, `separator` = ?, active = ?, created_by = ?, updated_at = ? WHERE id = ?', - rule.name, rule.separator, rule.active ? 1 : 0, optional(rule.createdBy), rule.updatedAt, rule.id - ), - operation('DELETE FROM number_rule_segments WHERE rule_id = ?', rule.id) - ); - } - rule.segments.forEach((segment, index) => operations.push(operation( - `INSERT INTO number_rule_segments (id, rule_id, position, type, value, width) VALUES (?, ?, ?, ?, ?, ?)`, - segment.id, rule.id, Number(segment.position || index + 1), segment.type, - optional(segment.value), Number(segment.width || 0) - ))); - operations.push(auditOperation(log)); - await transaction(operations); - }, - async createAdmin(user, log) { - await transaction([ - operation( - `INSERT INTO users ( - id, username, password_hash, role, admin_level, school_id, class_id, active, display_name, created_at - ) VALUES (?, ?, ?, 'admin', ?, ?, ?, ?, ?, ?)`, - user.id, user.username, user.passwordHash, user.adminLevel, optional(user.schoolId), optional(user.classId), - user.active === false ? 0 : 1, user.displayName, user.createdAt - ), - auditOperation(log) - ]); - }, - async createAdmissionSchoolAccount(user, log) { - await transaction([ - operation( - `INSERT INTO users ( - id, username, password_hash, role, admin_level, school_id, class_id, active, display_name, created_at - ) VALUES (?, ?, ?, 'admission_school', NULL, ?, NULL, ?, ?, ?)`, - user.id, user.username, user.passwordHash, user.schoolId, user.active === false ? 0 : 1, user.displayName, user.createdAt - ), - auditOperation(log) - ]); - }, - async updateFeatureScore(registration, log) { - await transaction([ - operation('UPDATE registrations SET feature_score = ? WHERE id = ?', Number(registration.featureScore || 0), registration.id), - auditOperation(log) - ]); - }, - async updateFeatureScores(entries) { - const operations = []; - for (const { registration, log } of entries) { - operations.push(operation('UPDATE registrations SET feature_score = ? WHERE id = ?', Number(registration.featureScore || 0), registration.id)); - operations.push(auditOperation(log)); - } - await transaction(operations); - }, - async saveAdmissionRecord(record, log = null) { - const operations = [operation('DELETE FROM admission_records WHERE id = ?', record.id), operation( - `INSERT INTO admission_records ( - id, kind, exam_id, user_id, school_id, status, payload_json, created_at, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - record.id, record.kind, record.examId, optional(record.userId), optional(record.schoolId), record.status, - JSON.stringify(record.payload || {}), record.createdAt, record.updatedAt - )]; - if (log) operations.push(auditOperation(log)); - await transaction(operations); - }, - async saveAdmissionRecords(records, log = null) { - const operations = []; - for (const record of records) { - operations.push(operation('DELETE FROM admission_records WHERE id = ?', record.id)); - operations.push(operation( - `INSERT INTO admission_records ( - id, kind, exam_id, user_id, school_id, status, payload_json, created_at, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - record.id, record.kind, record.examId, optional(record.userId), optional(record.schoolId), record.status, - JSON.stringify(record.payload || {}), record.createdAt, record.updatedAt - )); - } - if (log) operations.push(auditOperation(log)); - await transaction(operations); - }, - async saveSchool(school, isNew, log) { - const change = isNew - ? operation( - 'INSERT INTO schools (id, name, code, address, is_source_school, is_admission_school, active) VALUES (?, ?, ?, ?, ?, ?, ?)', - school.id, school.name, school.code, optional(school.address), school.isSourceSchool ? 1 : 0, - school.isAdmissionSchool ? 1 : 0, school.active ? 1 : 0 - ) - : operation( - 'UPDATE schools SET name = ?, code = ?, address = ?, is_source_school = ?, is_admission_school = ?, active = ? WHERE id = ?', - school.name, school.code, optional(school.address), school.isSourceSchool ? 1 : 0, - school.isAdmissionSchool ? 1 : 0, school.active ? 1 : 0, school.id - ); - await transaction([change, auditOperation(log)]); - }, - async saveSchoolClass(schoolClass, isNew, log) { - const change = isNew - ? operation( - 'INSERT INTO school_classes (id, school_id, name, grade, active) VALUES (?, ?, ?, ?, ?)', - schoolClass.id, schoolClass.schoolId, schoolClass.name, schoolClass.grade, schoolClass.active ? 1 : 0 - ) - : operation( - 'UPDATE school_classes SET name = ?, grade = ?, active = ? WHERE id = ?', - schoolClass.name, schoolClass.grade, schoolClass.active ? 1 : 0, schoolClass.id - ); - await transaction([change, auditOperation(log)]); - }, - async updateAdmin(user, passwordChanged, log) { - const sql = passwordChanged - ? 'UPDATE users SET display_name = ?, class_id = ?, active = ?, password_hash = ? WHERE id = ?' - : 'UPDATE users SET display_name = ?, class_id = ?, active = ? WHERE id = ?'; - const params = passwordChanged - ? [user.displayName, optional(user.classId), user.active ? 1 : 0, user.passwordHash, user.id] - : [user.displayName, optional(user.classId), user.active ? 1 : 0, user.id]; - await transaction([operation(sql, ...params), auditOperation(log)]); - }, - async saveTestCenter(center, isNew, log) { - const centerOperation = isNew - ? operation( - `INSERT INTO test_centers ( - id, school_id, code, name, province_code, province_name, city_code, city_name, district_code, district_name, - address, contact, rooms, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - center.id, center.schoolId, center.code, center.name, - center.provinceCode, center.provinceName, center.cityCode, center.cityName, center.districtCode, center.districtName, - center.address, optional(center.contact), center.rooms, center.updatedAt - ) - : operation( - `UPDATE test_centers SET - code = ?, name = ?, province_code = ?, province_name = ?, city_code = ?, city_name = ?, - district_code = ?, district_name = ?, address = ?, contact = ?, rooms = ?, updated_at = ? WHERE id = ?`, - center.code, center.name, center.provinceCode, center.provinceName, center.cityCode, center.cityName, - center.districtCode, center.districtName, center.address, optional(center.contact), center.rooms, center.updatedAt, center.id - ); - await transaction([centerOperation, auditOperation(log)]); - }, - async createCenterChangeRequest(request, rooms, instance, action, log) { - const operations = [ - operation( - `INSERT INTO center_change_requests ( - id, center_id, school_id, request_type, code, name, - province_code, province_name, city_code, city_name, district_code, district_name, - address, contact, manager_name, manager_phone, - emergency_phone, gate_open_time, transport, center_status, notes, status, review_note, - requested_by, created_at, reviewed_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - request.id, optional(request.centerId), request.schoolId, request.requestType, request.code, request.name, - request.provinceCode, request.provinceName, request.cityCode, request.cityName, request.districtCode, request.districtName, - request.address, optional(request.contact), optional(request.managerName), optional(request.managerPhone), - optional(request.emergencyPhone), optional(request.gateOpenTime), optional(request.transport), - request.centerStatus, optional(request.notes), request.status, optional(request.reviewNote), - optional(request.requestedBy), request.createdAt, optional(request.reviewedAt) - ), - ...workflowCreateOperations(instance, action) - ]; - for (const room of rooms) operations.push(operation( - `INSERT INTO center_change_rooms ( - id, request_id, room_id, code, name, building, floor, capacity, seat_plan, seat_start, seat_end, room_type, status, notes - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - room.id, request.id, optional(room.roomId), room.code, room.name, room.building, optional(room.floor), - Number(room.capacity), optional(room.seatPlan), 1, Number(room.capacity), room.roomType, room.status, - optional(room.notes) - )); - operations.push(auditOperation(log)); - await transaction(operations); - }, - async applyCenterChange(request, instance, action, center, rooms, log) { - const operations = [ - operation( - `UPDATE workflow_instances SET - status = ?, current_step = ?, assignee_id = ?, completed_at = ? WHERE id = ?`, - instance.status, Number(instance.currentStep), optional(instance.assigneeId), optional(instance.completedAt), instance.id - ), - workflowActionOperation(action), - operation( - `UPDATE center_change_requests SET status = ?, review_note = ?, reviewed_at = ? WHERE id = ?`, - request.status, optional(request.reviewNote), optional(request.reviewedAt), request.id - ) - ]; - if (request.status === 'approved' && center) { - if (request.requestType === 'create') { - operations.push(operation( - `INSERT INTO test_centers ( - id, school_id, code, name, province_code, province_name, city_code, city_name, district_code, district_name, - address, contact, manager_name, manager_phone, emergency_phone, - gate_open_time, transport, status, notes, rooms, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - center.id, center.schoolId, center.code, center.name, - center.provinceCode, center.provinceName, center.cityCode, center.cityName, center.districtCode, center.districtName, - center.address, optional(center.contact), - optional(center.managerName), optional(center.managerPhone), optional(center.emergencyPhone), - optional(center.gateOpenTime), optional(center.transport), center.status, optional(center.notes), - center.rooms || '', center.updatedAt - )); - } else { - operations.push(operation( - `UPDATE test_centers SET - code = ?, name = ?, province_code = ?, province_name = ?, city_code = ?, city_name = ?, - district_code = ?, district_name = ?, address = ?, contact = ?, manager_name = ?, manager_phone = ?, - emergency_phone = ?, gate_open_time = ?, transport = ?, status = ?, notes = ?, rooms = ?, updated_at = ? - WHERE id = ?`, - center.code, center.name, center.provinceCode, center.provinceName, center.cityCode, center.cityName, - center.districtCode, center.districtName, center.address, optional(center.contact), optional(center.managerName), - optional(center.managerPhone), optional(center.emergencyPhone), optional(center.gateOpenTime), - optional(center.transport), center.status, optional(center.notes), center.rooms || '', center.updatedAt, center.id - )); - } - operations.push(operation('DELETE FROM test_rooms WHERE center_id = ?', center.id)); - for (const room of rooms) operations.push(operation( - `INSERT INTO test_rooms ( - id, center_id, code, name, building, floor, capacity, seat_plan, seat_start, seat_end, room_type, status, notes - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - room.id, center.id, room.code, room.name, room.building, optional(room.floor), Number(room.capacity), - optional(room.seatPlan), 1, Number(room.capacity), room.roomType, room.status, optional(room.notes) - )); - } - operations.push(auditOperation(log)); - await transaction(operations); - }, - async saveAdmissionArrangement(plan, cards, log) { - const operations = [ - operation('DELETE FROM exam_arrangement_plans WHERE exam_id = ?', plan.examId), - operation( - `INSERT INTO exam_arrangement_plans ( - id, exam_id, number_rule_id, mixing_scope, random_seed, candidate_count, center_count, - subject_assignment_count, subject_combination_count, same_school_center_rate, - warnings_json, generated_by, generated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - plan.id, plan.examId, plan.numberRuleId, plan.mixingScope, plan.randomSeed, - Number(plan.candidateCount), Number(plan.centerCount), Number(plan.subjectAssignmentCount), - Number(plan.subjectCombinationCount), Number(plan.sameSchoolCenterRate), JSON.stringify(plan.warnings || []), - optional(plan.generatedBy), plan.generatedAt - ) - ]; - for (const card of cards) { - operations.push(operation( - `INSERT INTO admit_cards ( - registration_id, plan_id, card_number, center_id, test_center, center_code, center_address, generated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - card.registrationId, plan.id, card.number, optional(card.centerId), card.testCenter, - card.centerCode || '', card.centerAddress || '', card.generatedAt - )); - for (const assignment of card.assignments) operations.push(operation( - `INSERT INTO admit_card_subjects ( - registration_id, subject_id, room_id, room, room_code, exam_room_code, building, floor, seat, subject_signature - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - card.registrationId, assignment.subjectId, optional(assignment.roomId), assignment.roomName, - assignment.roomCode, assignment.examRoomCode, assignment.building || '', assignment.floor || '', assignment.seat, assignment.subjectSignature - )); - } - operations.push(auditOperation(log)); - await transaction(operations); - }, - async createExam(exam, log) { - const operations = [operation( - `INSERT INTO exams ( - id, code, name, description, registration_start, registration_end, exam_start, exam_end, - admit_download_start, admit_download_end, location, pass_policy, pass_value, status, archived_at, archived_by, created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - exam.id, exam.code, exam.name, exam.description || '', exam.registrationStart, exam.registrationEnd, - exam.examStart, exam.examEnd, exam.admitDownloadStart, exam.admitDownloadEnd, - exam.location || '', exam.passPolicy, exam.passValue, exam.status, optional(exam.archivedAt), optional(exam.archivedBy), exam.createdAt - )]; - exam.subjects.forEach((subject, index) => operations.push(operation( - `INSERT INTO exam_subjects ( - id, exam_id, name, subject_date, start_time, end_time, fee, full_score, pass_score, pass_rule, pass_value, position - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - subject.id, exam.id, subject.name, subject.date || String(exam.examStart).slice(0, 10), - subject.start || '', subject.end || '', Number(subject.fee || 0), Number(subject.fullScore), - Number(subject.passScore ?? 0), subject.passRule === 'rank_percent' ? 'score_ratio' : (subject.passRule || 'fixed_score'), Number(subject.passValue ?? subject.passScore ?? 0), Number(subject.order || index + 1) - ))); - operations.push(auditOperation(log)); - await transaction(operations); - }, - async updateExam(exam, log, replaceSubjects = false) { - const operations = [ - operation( - `UPDATE exams SET - code = ?, name = ?, description = ?, registration_start = ?, registration_end = ?, - exam_start = ?, exam_end = ?, admit_download_start = ?, admit_download_end = ?, - location = ?, pass_policy = ?, pass_value = ?, status = ? WHERE id = ?`, - exam.code, exam.name, exam.description || '', exam.registrationStart, exam.registrationEnd, - exam.examStart, exam.examEnd, exam.admitDownloadStart, exam.admitDownloadEnd, - exam.location || '', exam.passPolicy, exam.passValue, exam.status, exam.id - ) - ]; - if (replaceSubjects) { - operations.push(operation('DELETE FROM exam_subjects WHERE exam_id = ?', exam.id)); - exam.subjects.forEach((subject, index) => operations.push(operation( - `INSERT INTO exam_subjects ( - id, exam_id, name, subject_date, start_time, end_time, fee, full_score, pass_score, pass_rule, pass_value, position - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - subject.id, exam.id, subject.name, subject.date || String(exam.examStart).slice(0, 10), - subject.start || '', subject.end || '', Number(subject.fee || 0), Number(subject.fullScore), - Number(subject.passScore ?? 0), subject.passRule === 'rank_percent' ? 'score_ratio' : (subject.passRule || 'fixed_score'), Number(subject.passValue ?? subject.passScore ?? 0), Number(subject.order || index + 1) - ))); - } - operations.push(auditOperation(log)); - await transaction(operations); - }, - async archiveExam(exam, log) { - await transaction([ - operation('UPDATE exams SET status = ?, archived_at = ?, archived_by = ? WHERE id = ? AND archived_at IS NULL', - exam.status, exam.archivedAt, exam.archivedBy, exam.id), - auditOperation(log) - ]); - }, - async createNotice(notice, log) { - await transaction([ - operation( - `INSERT INTO notices ( - id, title, summary, content, category, pinned, status, publish_at, created_at, author - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - notice.id, notice.title, notice.summary, notice.content, notice.category, notice.pinned ? 1 : 0, - notice.status, optional(notice.publishAt), optional(notice.createdAt), notice.author - ), - auditOperation(log) - ]); - }, - async updateNotice(notice, log) { - await transaction([ - operation( - `UPDATE notices SET title = ?, summary = ?, content = ?, category = ?, pinned = ?, status = ?, publish_at = ? WHERE id = ?`, - notice.title, notice.summary, notice.content, notice.category, notice.pinned ? 1 : 0, - notice.status, optional(notice.publishAt), notice.id - ), - auditOperation(log) - ]); - }, - async saveResult(result, isNew, log) { - const resultOperation = isNew - ? operation( - `INSERT INTO results ( - id, registration_id, subject_id, score, grade, published, updated_at, published_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - result.id, result.registrationId, result.subjectId, result.score, result.grade, - result.published ? 1 : 0, optional(result.updatedAt), optional(result.publishedAt) - ) - : operation( - `UPDATE results SET score = ?, grade = ?, published = ?, updated_at = ?, published_at = ? WHERE id = ?`, - result.score, result.grade, result.published ? 1 : 0, - optional(result.updatedAt), optional(result.publishedAt), result.id - ); - await transaction([resultOperation, auditOperation(log)]); - }, - async saveResults(entries) { - const operations = []; - for (const { result, isNew, log } of entries) { - operations.push(isNew - ? operation( - `INSERT INTO results ( - id, registration_id, subject_id, score, grade, published, updated_at, published_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - result.id, result.registrationId, result.subjectId, result.score, result.grade, - result.published ? 1 : 0, optional(result.updatedAt), optional(result.publishedAt) - ) - : operation( - `UPDATE results SET score = ?, grade = ?, published = ?, updated_at = ?, published_at = ? WHERE id = ?`, - result.score, result.grade, result.published ? 1 : 0, - optional(result.updatedAt), optional(result.publishedAt), result.id - )); - operations.push(auditOperation(log)); - } - await transaction(operations); - } - }; -} - -const adapterContext = { - mkdir, - dirname, - sqliteSchema, - mysqlSchema, - optional, - buildSeedOperations, - stateFromRows, - readSqliteRows, - readMysqlRows, - createRepository -}; -const createSqliteStore = createSqliteAdapter(adapterContext); -const createMysqlStore = createMysqlAdapter(adapterContext); - -export async function createDatabase({ root, seed }) { - const client = String(process.env.DATABASE_CLIENT || (process.env.NODE_ENV === 'production' ? 'mysql' : 'sqlite')).toLowerCase(); - if (!['sqlite', 'mysql'].includes(client)) { - throw new Error(`不支持的 DATABASE_CLIENT:${client}(可选 sqlite 或 mysql)`); - } - - if (client === 'mysql') return createMysqlStore({ seed }); - - const path = resolve(process.env.SQLITE_PATH || join(root, 'data', 'exam.sqlite')); - return createSqliteStore({ path, seed }); -} diff --git a/excel.mjs b/excel.mjs deleted file mode 100644 index ad9dad3..0000000 --- a/excel.mjs +++ /dev/null @@ -1,401 +0,0 @@ -import ExcelJS from 'exceljs'; - -const resourceSpecs = { - classes: { - title: '班级台账', sheet: '班级', - columns: [ - ['schoolCode', '学校代码*', 16, 'HZ01'], ['grade', '年级*', 14, '高三'], - ['name', '班级名称*', 22, '高三(3)班'], ['status', '状态*', 12, '启用'] - ], - validations: { status: ['启用', '停用'] } - }, - class_admins: { - title: '班级管理员台账', sheet: '班级管理员', - columns: [ - ['schoolCode', '学校代码*', 16, 'HZ01'], ['className', '班级名称*', 22, '高三(1)班'], - ['displayName', '管理员姓名*', 18, '张老师'], ['username', '登录账号*', 20, 'hz01_g301'], - ['initialPassword', '初始密码(新建必填)', 24, 'ChangeMe123!'], ['status', '状态*', 12, '启用'] - ], - validations: { status: ['启用', '停用'] } - }, - account_quotas: { - title: '批量报名号申领配额', sheet: '班级配额', - columns: [['className', '班级名称*', 24, '高三(1)班'], ['count', '申领数量*', 16, 30]], - numberColumns: ['count'] - }, - account_results: { - title: '报名号下发清单', sheet: '账号结果', - columns: [ - ['batchId', '批次编号', 30, ''], ['className', '班级', 22, ''], - ['candidateNumber', '固定报名号', 26, ''], ['initialPassword', '初始密码', 22, ''] - ] - }, - candidates: { - title: '考生资料台账', sheet: '考生资料', - columns: [ - ['candidateNumber', '报名号*', 26, '2026-HZ01-X-0001'], ['name', '姓名*', 16, '李明'], - ['gender', '性别*', 10, '男'], ['idNumber', '证件号码*', 24, '320101200801011234'], - ['phone', '手机号*', 18, '13800138000'], ['email', '邮箱', 24, 'student@example.com'], - ['nativePlace', '籍贯', 18, '江苏海州'], - ['provinceCode', '省级代码*', 14, '320000'], ['provinceName', '省份', 18, '江苏省'], - ['cityCode', '市级代码*', 14, '320700'], ['cityName', '城市', 18, '连云港市'], - ['districtCode', '区县代码*', 14, '320706'], ['districtName', '区县', 18, '海州区'], - ['address', '详细住址*', 32, '示例路 1 号'], - ['className', '班级*', 22, '高三(1)班'], ['ethnicity', '民族', 12, '汉族'], - ['birthDate', '出生日期', 16, '2008-01-01'], ['postalCode', '邮编', 14, '222000'], - ['guardianName', '监护人', 16, '李家长'], ['guardianPhone', '监护人电话', 18, '13900139000'] - ], - validations: { gender: ['男', '女'] } - }, - payments: { - title: '考试缴费名单', sheet: '缴费名单', - columns: [ - ['examCode', '考试代码', 18, ''], ['examName', '考试名称', 28, ''], - ['schoolName', '学校', 24, ''], ['className', '班级', 20, ''], - ['candidateNumber', '报名号', 26, ''], ['candidateName', '考生姓名', 16, ''], - ['subjectNames', '报考科目', 34, ''], ['amountDue', '应缴金额(元)', 18, ''], - ['paymentStatus', '缴费状态', 14, ''], ['paidAt', '确认时间', 24, ''], - ['paidByName', '确认人', 16, ''] - ], - numberColumns: ['amountDue'], - numberFormats: { amountDue: '0.00' } - }, - centers: { - title: '考点考场档案', sheet: '考点考场', - columns: [ - ['schoolCode', '学校代码*', 14, 'HZ01'], ['centerCode', '考点代码*', 18, 'HZ01-C02'], - ['centerName', '考点名称*', 24, '第一中学东区考点'], - ['provinceCode', '省级代码*', 14, '320000'], ['provinceName', '省份', 18, '江苏省'], - ['cityCode', '市级代码*', 14, '320700'], ['cityName', '城市', 18, '连云港市'], - ['districtCode', '区县代码*', 14, '320706'], ['districtName', '区县', 18, '海州区'], - ['address', '详细地址*', 30, '示例路 8 号'], - ['managerName', '负责人', 16, '王老师'], ['managerPhone', '负责人手机', 18, '13800138000'], - ['contact', '值班电话', 18, '0518-86020000'], ['emergencyPhone', '应急电话', 18, '0518-120'], - ['gateOpenTime', '开放时间', 14, '07:00'], ['transport', '交通提示', 30, '东门入场'], - ['centerStatus', '考点状态*', 14, '启用'], ['centerNotes', '考点备注', 26, ''], - ['roomCode', '考场代码*', 16, '001'], ['roomName', '考场名称*', 22, '第 001 考场'], - ['building', '楼栋*', 18, '教学楼 A'], ['floor', '楼层', 12, '1 层'], - ['capacity', '容量*', 12, 30], ['seatPlan', '座位编排说明', 28, '按教室现场座次表编排'], - ['roomType', '考场类型*', 16, '标准考场'], ['roomStatus', '考场状态*', 14, '启用'], - ['roomNotes', '考场备注', 26, ''] - ], - validations: { centerStatus: ['启用', '停用'], roomStatus: ['启用', '停用'], roomType: ['标准考场', '机考考场', '无障碍考场', '备用考场'] }, - numberColumns: ['capacity'] - }, - results: { - title: '考试成绩台账', sheet: '成绩', - columns: [ - ['candidateNumber', '报名号*', 26, '2026-HZ01-X-0001'], ['cardNumber', '准考证号(只读参考)', 24, ''], - ['candidateName', '姓名(只读参考)', 16, ''], ['schoolName', '学校(只读参考)', 24, ''], ['className', '班级(只读参考)', 20, ''], - ['examCode', '考试代码*', 20, 'EX-2026-AUT'], ['examName', '考试名称(只读参考)', 28, ''], - ['subjectName', '科目*', 16, '语文'], ['fullScore', '科目满分(只读参考)', 18, ''], - ['passRule', '单科及格规则(只读参考)', 26, ''], ['passScore', '实际及格分(只读参考)', 20, ''], - ['score', '成绩*', 12, 120], ['rank', '本科排名(导出计算)', 18, ''], - ['rankPercent', '排名百分位(导出计算)', 20, ''], ['qualified', '单科达线(导出计算)', 16, ''], ['grade', '排名等级(自动计算)', 18, ''], - ['published', '发布状态*', 14, '发布'], ['updatedAt', '更新时间(只读参考)', 24, ''] - ], - validations: { published: ['发布', '不发布'] }, - numberColumns: ['fullScore', 'passScore', 'score', 'rank', 'rankPercent'], - numberFormats: { fullScore: '0.00', passScore: '0.00', score: '0.00', rank: '0', rankPercent: '0.00' } - }, - admit_cards: { - title: '准考证信息台账', sheet: '准考证信息', - columns: [ - ['schoolName', '考生学校', 24, ''], ['className', '班级', 20, ''], - ['candidateNumber', '报名号', 24, ''], ['candidateName', '姓名', 14, ''], ['idNumber', '证件号码', 22, ''], - ['examCode', '考试代码', 18, ''], ['examName', '考试名称', 28, ''], ['cardNumber', '准考证号', 22, ''], - ['centerCode', '考点代码', 16, ''], ['centerName', '考点名称', 26, ''], ['centerAddress', '考点详细地址', 38, ''], - ['subjectName', '科目', 14, ''], ['subjectDate', '日期', 14, ''], ['subjectTime', '时间', 16, ''], - ['examRoomCode', '考试考场序号', 16, ''], ['roomName', '考场通用名称', 20, ''], ['roomCode', '物理场地代码', 16, ''], - ['building', '楼栋', 16, ''], ['floor', '楼层', 12, ''], ['seat', '座位号', 12, ''] - ] - }, - admitted_candidates: { - title: '录取考生信息表', sheet: '录取考生', - columns: [ - ['candidateNumber', '报名号', 26, ''], ['name', '姓名', 14, ''], ['gender', '性别', 10, ''], - ['idNumber', '证件号码', 24, ''], ['phone', '手机号', 18, ''], ['email', '邮箱', 24, ''], - ['birthDate', '出生日期', 14, ''], ['ethnicity', '民族', 12, ''], ['nativePlace', '籍贯', 18, ''], - ['sourceSchoolCode', '生源学校代码', 16, ''], ['sourceSchool', '生源学校', 26, ''], ['className', '班级', 18, ''], - ['address', '家庭住址', 36, ''], ['guardianName', '监护人', 14, ''], ['guardianPhone', '监护人电话', 18, ''], - ['specialty', '特长生资格', 20, ''], ['specialtyCertificate', '特长证明编号', 20, ''], ['policyEligibility', '政策资格说明', 24, ''], - ['featureScore', '特征分', 12, ''], ['subjectScores', '各科成绩', 42, ''], ['totalScore', '考生总成绩', 14, ''], - ['admittedSchool', '录取学校', 26, ''], ['categoryName', '录取类别', 20, ''], ['preferenceOrder', '志愿序号', 12, ''] - ], - numberColumns: ['featureScore', 'totalScore', 'preferenceOrder'], - numberFormats: { featureScore: '0.00', totalScore: '0.00', preferenceOrder: '0' } - }, - admission_preferences: { - title: '考生志愿填报实时台账', sheet: '志愿填报情况', - columns: [ - ['examCode', '考试代码', 20, 'EX-2026-ZK'], ['examName', '考试名称', 30, '初中学业水平考试'], - ['round', '填报轮次', 12, 1], ['fillStatus', '填报状态', 16, '已填报'], ['lockStatus', '锁定状态', 16, '未锁定'], - ['submissionCount', '已提交次数', 14, 1], ['maxSubmissions', '提交次数上限', 16, 3], - ['candidateNumber', '报名号', 26, '2026-HZ01-F-0001'], ['candidateName', '姓名', 14, '张同学'], - ['sourceSchoolCode', '生源学校代码', 18, 'HZ01'], ['sourceSchoolName', '生源学校', 26, '海州市第一中学'], ['className', '班级', 18, '九年级一班'], - ['specialty', '特长生资格', 22, '普通生'], ['indicatorStatus', '指标分配资格', 18, '有资格'], - ['preferenceOrder', '志愿顺序', 14, 1], ['preferenceType', '志愿类型', 14, '普通志愿'], - ['targetSchoolCode', '志愿学校代码', 18, 'AD01'], ['targetSchoolName', '志愿学校', 28, '海州市高级中学'], - ['categoryName', '招生类别', 20, '普通生'], ['submittedAt', '最近提交时间', 24, '2026-07-22 10:18'] - ], - numberColumns: ['round', 'submissionCount', 'maxSubmissions', 'preferenceOrder'], - numberFormats: { round: '0', submissionCount: '0', maxSubmissions: '0', preferenceOrder: '0' } - }, - admission_placements: { - title: '招生录取情况台账', sheet: '录取情况', - columns: [ - ['examCode', '考试代码', 20, 'EX-2026-ZK'], ['examName', '考试名称', 30, '初中学业水平考试'], ['round', '录取轮次', 12, 1], - ['candidateNumber', '报名号', 26, '2026-HZ01-F-0001'], ['candidateName', '姓名', 14, '张同学'], - ['sourceSchoolCode', '生源学校代码', 18, 'HZ01'], ['sourceSchoolName', '生源学校', 26, '海州市第一中学'], ['className', '班级', 18, '九年级一班'], - ['specialty', '特长生资格', 22, '普通生'], ['culturalScore', '文化课总分', 14, 560], ['featureScore', '特征分', 12, 0], ['totalScore', '投档总分', 14, 560], - ['preferenceOrder', '命中志愿序号', 16, 1], ['admissionSchoolCode', '招生学校代码', 18, 'AD01'], ['admissionSchoolName', '招生学校', 28, '海州市高级中学'], - ['categoryName', '招生类别', 20, '普通生'], ['quotaBucket', '计划类型', 18, '普通计划'], ['admissionStatus', '录取状态', 18, '正式录取'], - ['reportingStatus', '报到状态', 16, '已报到'], ['noticeNumber', '录取通知书编号', 34, 'AD01-EX-2026-ZK-000001'], - ['withdrawalReason', '退档或放弃原因', 34, ''], ['updatedAt', '状态更新时间', 24, '2026-07-22 10:18'] - ], - numberColumns: ['round', 'culturalScore', 'featureScore', 'totalScore', 'preferenceOrder'], - numberFormats: { round: '0', culturalScore: '0.00', featureScore: '0.00', totalScore: '0.00', preferenceOrder: '0' } - }, - admission_reporting: { - title: '录取考生报到状态维护表', sheet: '考生报到', - columns: [ - ['noticeNumber', '录取通知书编号*', 34, 'AD01-EX-2026-ZK-000001'], - ['candidateNumber', '报名号*', 26, '2026-HZ01-F-0001'], ['name', '姓名(只读)', 14, '张同学'], - ['examCode', '考试代码(只读)', 20, 'EX-2026-ZK'], ['schoolCode', '招生学校代码(只读)', 18, 'AD01'], - ['categoryName', '录取类别(只读)', 20, '普通生'], - ['reportingStatusCode', '报到状态码*(Y/N/P)', 22, 'P'], ['reportingNote', '报到备注', 36, ''] - ], - validations: { reportingStatusCode: ['Y', 'N', 'P'] } - } -}; - -export function hasExcelResource(resource) { - return Boolean(resourceSpecs[resource]); -} - -function cellValue(cell) { - const value = cell.value; - if (value == null) return ''; - if (value instanceof Date) return value.toISOString().slice(0, 10); - if (typeof value === 'object') { - if ('text' in value) return String(value.text || '').trim(); - if ('result' in value) return String(value.result ?? '').trim(); - } - return typeof value === 'number' ? value : String(value).trim(); -} - -export async function parseWorkbook(resource, buffer) { - const spec = resourceSpecs[resource]; - if (!spec) throw Object.assign(new Error('不支持的 Excel 数据类型'), { status: 404 }); - const workbook = new ExcelJS.Workbook(); - try { - await workbook.xlsx.load(buffer); - } catch { - throw Object.assign(new Error('无法读取 Excel 文件,请使用系统下载的 .xlsx 模板'), { status: 400 }); - } - const sheet = workbook.getWorksheet(spec.sheet) || workbook.worksheets[0]; - if (!sheet) throw Object.assign(new Error('Excel 文件中没有可读取的工作表'), { status: 400 }); - const headerMap = new Map(); - sheet.getRow(2).eachCell((cell, col) => headerMap.set(String(cell.value || '').replace(/\*/g, '').trim(), col)); - const missing = spec.columns.filter(([, label]) => !headerMap.has(label.replace(/\*/g, '').trim())); - if (missing.length) throw Object.assign(new Error(`模板列不完整:缺少 ${missing.map(([, label]) => label).join('、')}`), { status: 400 }); - const rows = []; - for (let rowNumber = 3; rowNumber <= sheet.rowCount; rowNumber += 1) { - const row = sheet.getRow(rowNumber); - const item = { __row: rowNumber }; - let populated = false; - for (const [key, label] of spec.columns) { - const value = cellValue(row.getCell(headerMap.get(label.replace(/\*/g, '').trim()))); - item[key] = value; - if (value !== '') populated = true; - } - if (populated) rows.push(item); - } - if (!rows.length) throw Object.assign(new Error('Excel 中没有可导入的数据行'), { status: 400 }); - return rows; -} - -export async function buildWorkbook(resource, rows = [], { template = false, subtitle = '' } = {}) { - const spec = resourceSpecs[resource]; - if (!spec) throw Object.assign(new Error('不支持的 Excel 数据类型'), { status: 404 }); - const workbook = new ExcelJS.Workbook(); - workbook.creator = '衡准考试信息管理系统'; - workbook.created = new Date(); - const sheet = workbook.addWorksheet(spec.sheet, { views: [{ state: 'frozen', ySplit: 2, showGridLines: false }] }); - const lastColumn = spec.columns.length; - sheet.columns = spec.columns.map(([key, , width]) => ({ key, width })); - spec.columns.forEach(([key], index) => { - sheet.getColumn(index + 1).numFmt = spec.numberFormats?.[key] || (spec.numberColumns?.includes(key) ? '0' : '@'); - }); - sheet.mergeCells(1, 1, 1, lastColumn); - const titleCell = sheet.getCell(1, 1); - titleCell.value = subtitle ? `${spec.title}|${subtitle}` : spec.title; - titleCell.font = { name: '微软雅黑', size: 16, bold: true, color: { argb: 'FFFFFFFF' } }; - titleCell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF173F60' } }; - titleCell.alignment = { vertical: 'middle', horizontal: 'left' }; - sheet.getRow(1).height = 34; - const header = sheet.getRow(2); - header.values = spec.columns.map(([, label]) => label); - header.height = 25; - header.font = { name: '微软雅黑', bold: true, color: { argb: 'FFFFFFFF' } }; - header.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF2C7080' } }; - header.alignment = { vertical: 'middle', horizontal: 'center' }; - const outputRows = rows.length ? rows : template ? [Object.fromEntries(spec.columns.map(([key, , , example]) => [key, example]))] : []; - for (const item of outputRows) { - const row = sheet.addRow(Object.fromEntries(spec.columns.map(([key]) => [key, resource === 'admission_reporting' && key === 'reportingNote' && !item[key] ? null : item[key] ?? '']))); - row.height = 23; - row.font = { name: '微软雅黑', size: 10, color: { argb: 'FF243B4A' } }; - row.alignment = { vertical: 'middle' }; - row.eachCell(cell => { - cell.border = { bottom: { style: 'hair', color: { argb: 'FFD8E2E7' } } }; - }); - } - if (resource === 'admission_reporting') { - const statusColumn = spec.columns.findIndex(([key]) => key === 'reportingStatusCode') + 1; - const noteColumn = spec.columns.findIndex(([key]) => key === 'reportingNote') + 1; - for (let row = 3; row <= Math.max(202, sheet.rowCount); row += 1) { - for (const column of [statusColumn, noteColumn]) sheet.getCell(row, column).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFF3CD' } }; - } - sheet.getCell('A1').value = `${spec.title}|仅修改黄色列;Y=已报到,N=未报到,P=待确认`; - } - sheet.autoFilter = { from: { row: 2, column: 1 }, to: { row: Math.max(2, sheet.rowCount), column: lastColumn } }; - for (const [key, values] of Object.entries(spec.validations || {})) { - const col = spec.columns.findIndex(([columnKey]) => columnKey === key) + 1; - for (let row = 3; row <= Math.max(202, sheet.rowCount); row += 1) { - sheet.getCell(row, col).dataValidation = { type: 'list', allowBlank: false, formulae: [`"${values.join(',')}"`] }; - } - } - const requiredColumns = spec.columns.map(([, label], index) => label.includes('*') ? index + 1 : 0).filter(Boolean); - for (const col of requiredColumns) header.getCell(col).font = { name: '微软雅黑', bold: true, color: { argb: 'FFFFE7A3' } }; - return workbook.xlsx.writeBuffer(); -} - -function addOperationalSheet(workbook, name, title, columns, rows, { landscape = true } = {}) { - const sheet = workbook.addWorksheet(name, { views: [{ state: 'frozen', ySplit: 2, showGridLines: false }] }); - sheet.columns = columns.map(([key, , width]) => ({ key, width })); - sheet.mergeCells(1, 1, 1, columns.length); - const titleCell = sheet.getCell(1, 1); - titleCell.value = title; - titleCell.font = { name: '微软雅黑', size: 16, bold: true, color: { argb: 'FFFFFFFF' } }; - titleCell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF173F60' } }; - titleCell.alignment = { vertical: 'middle', horizontal: 'left' }; - sheet.getRow(1).height = 34; - const header = sheet.getRow(2); - header.values = columns.map(([, label]) => label); - header.height = 28; - header.font = { name: '微软雅黑', bold: true, color: { argb: 'FFFFFFFF' } }; - header.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF2C7080' } }; - header.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }; - rows.forEach((item, index) => { - const row = sheet.addRow(Object.fromEntries(columns.map(([key]) => [key, item[key] ?? '']))); - row.height = 28; - row.font = { name: '微软雅黑', size: 10, color: { argb: 'FF243B4A' } }; - row.alignment = { vertical: 'middle', wrapText: true }; - if (index % 2 === 1) row.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF3F7F8' } }; - row.eachCell(cell => { cell.border = { bottom: { style: 'hair', color: { argb: 'FFD8E2E7' } } }; }); - }); - sheet.autoFilter = { from: { row: 2, column: 1 }, to: { row: Math.max(2, sheet.rowCount), column: columns.length } }; - sheet.pageSetup = { orientation: landscape ? 'landscape' : 'portrait', paperSize: 9, fitToPage: true, fitToWidth: 1, fitToHeight: 0, margins: { left: .25, right: .25, top: .4, bottom: .4, header: .2, footer: .2 } }; - sheet.printTitlesRow = '1:2'; - return sheet; -} - -function addDeskStickerSheet(workbook, rows) { - const sheet = workbook.addWorksheet('桌贴', { views: [{ showGridLines: false, zoomScale: 85 }] }); - const labelColumns = [14.5, 14.5, 14.5, 3, 14.5, 14.5, 14.5]; - labelColumns.forEach((width, index) => { sheet.getColumn(index + 1).width = width; }); - sheet.pageSetup = { - orientation: 'portrait', paperSize: 9, fitToPage: true, fitToWidth: 1, fitToHeight: 0, - margins: { left: .25, right: .25, top: .25, bottom: .25, header: 0, footer: 0 }, - horizontalCentered: true, verticalCentered: false - }; - sheet.headerFooter = { oddFooter: '&C第 &P / &N 页' }; - const rowsPerLabel = 8; - const labelsPerPage = 6; - const rowsPerPage = rowsPerLabel * 3; - const borderColor = { argb: 'FF173F60' }; - const paleBlue = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFEAF1F5' } }; - const paleGold = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFF1C7' } }; - const mergeLine = (row, startColumn) => { - sheet.mergeCells(row, startColumn, row, startColumn + 2); - return sheet.getCell(row, startColumn); - }; - const styleLine = (cell, { size = 10, bold = false, color = 'FF243B4A', fill = null } = {}) => { - cell.font = { name: '微软雅黑', size, bold, color: { argb: color } }; - cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true, shrinkToFit: true }; - if (fill) cell.fill = fill; - }; - - rows.forEach((item, index) => { - const page = Math.floor(index / labelsPerPage); - const slot = index % labelsPerPage; - const startRow = page * rowsPerPage + Math.floor(slot / 2) * rowsPerLabel + 1; - const startColumn = slot % 2 === 0 ? 1 : 5; - for (let row = startRow; row < startRow + rowsPerLabel; row += 1) sheet.getRow(row).height = 32.5; - const cells = Array.from({ length: rowsPerLabel }, (_, offset) => mergeLine(startRow + offset, startColumn)); - cells[0].value = item.examName; - styleLine(cells[0], { size: 11, bold: true, color: 'FFFFFFFF', fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF173F60' } } }); - cells[1].value = `${item.subjectName}|${item.subjectDate} ${item.subjectTime}`; - styleLine(cells[1], { size: 9, bold: true, fill: paleBlue }); - cells[2].value = '考试考场序号'; - styleLine(cells[2], { size: 9, bold: true, color: 'FF2C7080' }); - cells[3].value = { richText: [{ text: String(item.examRoomCode || '') }] }; - cells[3].numFmt = '@'; - styleLine(cells[3], { size: 25, bold: true, color: 'FF173F60' }); - cells[4].value = `座位号 ${item.seat}`; - styleLine(cells[4], { size: 20, bold: true, color: 'FF8A4B08', fill: paleGold }); - cells[5].value = `${item.roomName}(场地 ${item.roomCode})|${item.building} ${item.floor}`; - styleLine(cells[5], { size: 9, bold: true }); - cells[6].value = `${item.candidateName}|${item.schoolName} ${item.className}`; - styleLine(cells[6], { size: 10, bold: true, fill: paleBlue }); - cells[7].value = `${item.centerName}|准考证号 ${item.cardNumber}`; - styleLine(cells[7], { size: 8, color: 'FF526576' }); - - for (let row = startRow; row < startRow + rowsPerLabel; row += 1) { - for (let column = startColumn; column < startColumn + 3; column += 1) { - const cell = sheet.getCell(row, column); - cell.border = { - top: { style: row === startRow ? 'medium' : 'hair', color: borderColor }, - bottom: { style: row === startRow + rowsPerLabel - 1 ? 'medium' : 'hair', color: borderColor }, - left: { style: column === startColumn ? 'medium' : 'hair', color: borderColor }, - right: { style: column === startColumn + 2 ? 'medium' : 'hair', color: borderColor } - }; - } - } - if ((index + 1) % labelsPerPage === 0 && index + 1 < rows.length) sheet.getRow(startRow + rowsPerLabel - 1).addPageBreak(); - }); - if (rows.length) sheet.pageSetup.printArea = `A1:G${Math.ceil(rows.length / labelsPerPage) * rowsPerPage}`; - return sheet; -} - -export async function buildCenterMaterialsWorkbook(rows, subtitle = '') { - const workbook = new ExcelJS.Workbook(); - workbook.creator = '衡准考试信息管理系统'; - workbook.created = new Date(); - const sorted = [...rows].sort((a, b) => String(a.centerCode).localeCompare(String(b.centerCode)) - || String(a.subjectDate).localeCompare(String(b.subjectDate)) || String(a.subjectTime).localeCompare(String(b.subjectTime)) - || String(a.examRoomCode).localeCompare(String(b.examRoomCode)) || String(a.seat).localeCompare(String(b.seat))); - const baseTitle = subtitle ? `|${subtitle}` : ''; - addDeskStickerSheet(workbook, sorted); - - const doorMap = new Map(); - for (const item of sorted) { - const key = [item.examCode, item.subjectName, item.centerCode, item.examRoomCode, item.roomCode].join('|'); - const current = doorMap.get(key) || { ...item, candidateCount: 0 }; - current.candidateCount += 1; - doorMap.set(key, current); - } - addOperationalSheet(workbook, '门贴', `考场门贴${baseTitle}`, [ - ['examName', '考试', 28], ['subjectName', '科目', 14], ['subjectDate', '日期', 14], ['subjectTime', '时间', 16], - ['centerName', '考点', 24], ['examRoomCode', '考试考场序号', 16], ['roomName', '考场通用名称', 20], - ['roomCode', '场地代码', 14], ['building', '楼栋', 16], ['floor', '楼层', 10], ['candidateCount', '人数', 10] - ], [...doorMap.values()]); - - addOperationalSheet(workbook, '考场签名单', `考场考生签名单${baseTitle}`, [ - ['examName', '考试', 26], ['subjectName', '科目', 14], ['subjectDate', '日期', 14], ['subjectTime', '时间', 16], - ['examRoomCode', '考试考场序号', 16], ['roomName', '考场通用名称', 20], ['building', '楼栋', 16], ['floor', '楼层', 10], - ['seat', '座位号', 10], ['cardNumber', '准考证号', 22], ['candidateName', '姓名', 14], - ['schoolName', '考生学校', 24], ['className', '班级', 18], ['signature', '考生签名', 18] - ], sorted.map(item => ({ ...item, signature: '' }))); - return workbook.xlsx.writeBuffer(); -} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 8b4fdef..0000000 --- a/package-lock.json +++ /dev/null @@ -1,4355 +0,0 @@ -{ - "name": "hengzhun-exam-system", - "version": "1.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "hengzhun-exam-system", - "version": "1.1.0", - "dependencies": { - "ckeditor5": "^48.3.1", - "exceljs": "^4.4.0", - "mysql2": "^3.14.2", - "qrcode": "1.5.4", - "redis": "^5.12.1", - "sanitize-html": "^2.17.6" - }, - "engines": { - "node": ">=22.5" - } - }, - "node_modules/@ckeditor/ckeditor5-adapter-ckfinder": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-adapter-ckfinder/-/ckeditor5-adapter-ckfinder-48.3.1.tgz", - "integrity": "sha512-xv072kFznzCLzG6Kiro9Pwb6v3FNXMu6/NWQX+NCl0wlqit85hRbIMJW0WyWxuYY4XgcDn4cgB89vRJ5p0zKsQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-upload": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-alignment": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-alignment/-/ckeditor5-alignment-48.3.1.tgz", - "integrity": "sha512-ayiSLBtw4xvtMEPl6AhMX66Io6ajmq+2y2+FePfwu+9B8f8JblEApcWFLlj0HXxfWfJ470sEVMvwUJAwPLH9Jg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-autoformat": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-autoformat/-/ckeditor5-autoformat-48.3.1.tgz", - "integrity": "sha512-65TMkSDpfE63WquypME53ESV209U1iXuhX32x95nc45hSi4CMn25oxqansrCpxIlHWww3d7z3tUgSRFGXpFSag==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-heading": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-autosave": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-autosave/-/ckeditor5-autosave-48.3.1.tgz", - "integrity": "sha512-mc9UmTpyVBUn+V/pmzkP8PKJNuijytY8RuV7bckeq9OmxXOz2AD0lqlp+X48OcrgcefCA6e01D1hgElMhHQ/Hw==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-basic-styles": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-basic-styles/-/ckeditor5-basic-styles-48.3.1.tgz", - "integrity": "sha512-uVbKZLNScqYyvj/Wg3uP2sWCHVuvYyFCGSNA1osnmI4DwKi3BS4TW/rm3IYUPrD6q2y/GGJK05OyHr3hyw4oig==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-block-quote": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-block-quote/-/ckeditor5-block-quote-48.3.1.tgz", - "integrity": "sha512-9T03V/VjWYu6dhyKWZVrlggeOumQXpUt4lygK6NQuSQ9lIMEnhFgzjqtZsGe9l90zvnPaUvV9IC3u1xUFZvzhg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-enter": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-bookmark": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-bookmark/-/ckeditor5-bookmark-48.3.1.tgz", - "integrity": "sha512-EC5fmzUT5GKyIwQw+4tnHHJD4kUIBbiwP/+0gjHVZnHisRLfBOC3GAIczzq/AXDBIuaHqC9DZOAQQp+ltItHfQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-link": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-ckbox": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-ckbox/-/ckeditor5-ckbox-48.3.1.tgz", - "integrity": "sha512-ZaonwyuQjqjsho4iKDGSTn/M+SFs/OTl0WMkFU3tOhWpUikWKejNM94z+T6OR9oELWJVb58Jg6ubV6+ZYaLL7A==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-cloud-services": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-image": "48.3.1", - "@ckeditor/ckeditor5-link": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-upload": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "blurhash": "2.0.5", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-ckfinder": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-ckfinder/-/ckeditor5-ckfinder-48.3.1.tgz", - "integrity": "sha512-kZBp/eDhr8Y/CcE2UQZxFp3fZ+w4WYdYxmyuQ70mg4cOS1TMV9eh26Zz5khWAt+oAJsxVIDL5KNodak/hFpJ2w==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-adapter-ckfinder": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-image": "48.3.1", - "@ckeditor/ckeditor5-link": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-clipboard": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-48.3.1.tgz", - "integrity": "sha512-PNI7yw9ese+fyQz0LzExRPY1CkjA6q9XqLDeMuLgp92Mkd7Vp1wftbB0ZLVyrzTIw8DEUudKziVsY3A4mT5aWA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-cloud-services": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-cloud-services/-/ckeditor5-cloud-services-48.3.1.tgz", - "integrity": "sha512-pHJAj5RRhTV7uyexs0ryFj82zZNex91VtmwTOB/z+VPXSHq4jzpxFE1fVuoHgkydUF5S5Dl6TiFru48yYlK4YA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-upload": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-code-block": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-code-block/-/ckeditor5-code-block-48.3.1.tgz", - "integrity": "sha512-9mwgtcrNCTK/06HXH+o8yNbrN/nCAflQtJ6LmAf1Gw/6Fed9gQslMcs5+ADO98Jer5OetpuKeqgmBACAuQUTmg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-enter": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-core": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-core/-/ckeditor5-core-48.3.1.tgz", - "integrity": "sha512-wrAhYK5R8MkGAE0VrOMFQN9LSRpSATS7DFKr4CCJod9EgBT873SCu34Ey0fzSqGxeOqamlcXQJVh/77+3JP4SQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-watchdog": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-easy-image": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-easy-image/-/ckeditor5-easy-image-48.3.1.tgz", - "integrity": "sha512-A63AcmaAAGVUhALHVtwHrlBaWEaRjBhxWTwkQoy3RFPpSAXi1k0Cy55HhkVrnqVZSuKmljcX3FttpjOb6MQq8g==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-cloud-services": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-image": "48.3.1", - "@ckeditor/ckeditor5-upload": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-editor-balloon": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-editor-balloon/-/ckeditor5-editor-balloon-48.3.1.tgz", - "integrity": "sha512-Unmzb3E+O83gIAvIT/RHyV1EzaxQGOzBiXGJhQahhQg++EvHUt4tmAJ6VzSLgJbtr8z3rMkA+lYpD5+OzpGT4w==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-editor-classic": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-editor-classic/-/ckeditor5-editor-classic-48.3.1.tgz", - "integrity": "sha512-7azS8ry8+c3H8S1RM1Aphq8wCig4mmLpK/kTmdF2/+JkPUszRoVK1HThSmBkstKCHDv4UuSVR+FcJ6Co6Tavog==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-editor-decoupled": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-editor-decoupled/-/ckeditor5-editor-decoupled-48.3.1.tgz", - "integrity": "sha512-S9xGZS7Hl2jWQrZFVwk3o7x9Wwl7tgbQl8TCujr0Bi0zxoM286WkHbBUej9oLVVtDHvq7xDSafmUURbL/K5ZXw==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-editor-inline": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-editor-inline/-/ckeditor5-editor-inline-48.3.1.tgz", - "integrity": "sha512-uoXl+lfvGzH6HPHyjgcQcwK/WSDxchmkQvPrMHxTCyeimn4ffzFKzIH4WiOz39t1lXpMjI0hTy66eTB8F/+qvg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-editor-multi-root": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-editor-multi-root/-/ckeditor5-editor-multi-root-48.3.1.tgz", - "integrity": "sha512-5BUDEfVCsj4Al6lHWPDxUCRUymoWwmwwg9hZqd6iSkBtDOuZfiGC9IitMb6qYvrD2Q0MLRoiW0z9n6My4ZMHfQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-emoji": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-emoji/-/ckeditor5-emoji-48.3.1.tgz", - "integrity": "sha512-JQGLX9rMMnMY5/d8bJrF2htxKGxFfrW+E+rAy+Uc5FZ+cOCQCUfI0+kYpZYj/oyt5BH6VXn099e1Uu4xjicgAA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-mention": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1", - "fuzzysort": "3.1.0" - } - }, - "node_modules/@ckeditor/ckeditor5-engine": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-48.3.1.tgz", - "integrity": "sha512-CbOuKrm3g8T2Df6WMEYtQMm4DJTAlmRutQQFj94zaXqDPyb8dSLpdPZ0Z89Qg2tagh9IEw0maG40ei2H4FETiQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-enter": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-48.3.1.tgz", - "integrity": "sha512-+gs7yLyWSfYlBofKA1ce4O4fPBoMw4mSXNun9CZP2FgByvsnS/5sOE3c3UTJS2bSLYabNkZRH3SG4XWKKhunGg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-essentials": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-essentials/-/ckeditor5-essentials-48.3.1.tgz", - "integrity": "sha512-/yYMvcdYpwfQOumLNFccOnQvWfJoXN4Ny5a8m9OO/syGqeMtgpLy+Pn8be3nq4/pxdU6Qz0VnGVzU9OaHXxw4A==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-enter": "48.3.1", - "@ckeditor/ckeditor5-select-all": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-undo": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-find-and-replace": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-find-and-replace/-/ckeditor5-find-and-replace-48.3.1.tgz", - "integrity": "sha512-R4DPKGC5XmN68W2HuUBRo8VJJ1KCB5Y8gr6JbNDNGQ7aJWrgAjQU7H7d9EEwxU6wjxzNAT7MJqPOEX/WixUBhA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-font": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-font/-/ckeditor5-font-48.3.1.tgz", - "integrity": "sha512-Q8EVEjVix3HOleJ6XtJpXDqD7WGMU3WZR/9eK1hMvOHnvRWkHwXJve5IoaBseJXSSQopG98D1rvWuNvE+qsZNg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-fullscreen": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-fullscreen/-/ckeditor5-fullscreen-48.3.1.tgz", - "integrity": "sha512-/UQzJFhOMJrDBB+02jSNJVD6E0cjNZ43KgsR8croTDEPLQ2pRH50aUkBZTZn7TfSYx7X2aeaYbyegvSB+pfw6g==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-editor-classic": "48.3.1", - "@ckeditor/ckeditor5-editor-decoupled": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-heading": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-heading/-/ckeditor5-heading-48.3.1.tgz", - "integrity": "sha512-CPlf4wSatQLqbgsj7DWPaOtjTgqchQX4Mv57NbV/2ZvDnqDOpjMi06d49yQngiPFv/6zqszr8U1raUX1OUhfYA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-enter": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-paragraph": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-highlight": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-highlight/-/ckeditor5-highlight-48.3.1.tgz", - "integrity": "sha512-wlqHoOuHeA2qrE9rBeVHgVK75puzTFWn/V8IhAcVBCPB2AApLYNTO7fkfhOEpxqodE2It1lPpN4JfVRWUkoCIw==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-horizontal-line": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-horizontal-line/-/ckeditor5-horizontal-line-48.3.1.tgz", - "integrity": "sha512-yl25cVmB5T+fsC2VqJvDLnmS9ymn+4LLaGSnue2D8Tg1WK/YTyWxKg3n0anPzMWBBLr1XcKAyVmnGFI66AKwvA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-html-embed": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-html-embed/-/ckeditor5-html-embed-48.3.1.tgz", - "integrity": "sha512-AuXaTHSnxR6chWIz9Z9UY2x4ANHN6Uf0jkfiAFcP6POWaD7YLsviTEYk+YGYw/kcXExMw3CQriDK5KdsjZtnkA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-html-support": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-html-support/-/ckeditor5-html-support-48.3.1.tgz", - "integrity": "sha512-aQ0ZHvvOATsUBykQJcGCFOTJjBDX3OULfeJWV1bqdVWAQt0BHC5xkq6d1IpbyKDaW9IkcB19GOS9nQgs1FasNg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-enter": "48.3.1", - "@ckeditor/ckeditor5-heading": "48.3.1", - "@ckeditor/ckeditor5-image": "48.3.1", - "@ckeditor/ckeditor5-list": "48.3.1", - "@ckeditor/ckeditor5-remove-format": "48.3.1", - "@ckeditor/ckeditor5-table": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-icons": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-icons/-/ckeditor5-icons-48.3.1.tgz", - "integrity": "sha512-a8mE5oTQ8TKf/325UmDixhhqGbDyzd749kcrANyzxwc89PtTMdUayl+D0Sj92Xp5fqMHgDEqipUcoohH9OSFBg==", - "license": "SEE LICENSE IN LICENSE.md" - }, - "node_modules/@ckeditor/ckeditor5-image": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-image/-/ckeditor5-image-48.3.1.tgz", - "integrity": "sha512-3lQY0LEpUNle2nUrONOtOXax62JQE9ZYltMDkOhMy9hcto0BoIngBebBsBBKZmpPugvMTf4qPYh1VkorOAdH0g==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-undo": "48.3.1", - "@ckeditor/ckeditor5-upload": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-indent": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-indent/-/ckeditor5-indent-48.3.1.tgz", - "integrity": "sha512-hRuAPVDex46Ky86wuWNoPLpkPYQt0jGECKPnSYsjavm/il6rm57J/Y/jk7CKGJJVIovVLFftvWsI0yHLcsAP1w==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-heading": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-list": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-language": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-language/-/ckeditor5-language-48.3.1.tgz", - "integrity": "sha512-DGOxZyTvrXisV+3FhFEcagfSlTC7m2tdhD2CJJmBRkKX+2ZOdeP1D0QCD6ybFlO3D/wT57Po2QX2nCVI6U79dQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-link": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-link/-/ckeditor5-link-48.3.1.tgz", - "integrity": "sha512-E3pAhuNy77F55JUnX40apemSbsOC3RbUPIgPclNlh/1PXs1uN/bjkkyDVYQ/rT5MrophY3tw/bLZ/cRrbEuKBg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-enter": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-image": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-list": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-list/-/ckeditor5-list-48.3.1.tgz", - "integrity": "sha512-KyuXH0aAiiQCOB+yJAru/C5GJqT7a+OoHoanjZMsFq5jjK9r5Tjrh6hUfqXpw+okU1x7Ow+/J4QLVI3QqSnluQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-enter": "48.3.1", - "@ckeditor/ckeditor5-font": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-markdown-gfm": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-markdown-gfm/-/ckeditor5-markdown-gfm-48.3.1.tgz", - "integrity": "sha512-y+aa3uPNwaTKxSXRcW3DNP4CfXBmXDmQk24mDVE4q7rl6lWkdnAUeEvUsaGYTRjs4szvY+HIaCts8OcSgKfvhA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@types/hast": "3.0.4", - "hast-util-from-dom": "5.0.1", - "hast-util-to-html": "9.0.5", - "hast-util-to-mdast": "10.1.2", - "hastscript": "9.0.1", - "rehype-dom-parse": "5.0.2", - "rehype-dom-stringify": "4.0.2", - "rehype-remark": "10.0.1", - "remark-breaks": "4.0.0", - "remark-gfm": "4.0.1", - "remark-parse": "11.0.0", - "remark-rehype": "11.1.2", - "remark-stringify": "11.0.0", - "unified": "11.0.5", - "unist-util-visit": "5.0.0" - } - }, - "node_modules/@ckeditor/ckeditor5-media-embed": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-media-embed/-/ckeditor5-media-embed-48.3.1.tgz", - "integrity": "sha512-Asq6B/nuhhHCka4mtjbIM4RrHAOWwCAYmR4kaX8xh6G81FfXKI/X26rJ8TjLno5J7lNgacdB6OznNu/UcJO0gQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-undo": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-mention": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-mention/-/ckeditor5-mention-48.3.1.tgz", - "integrity": "sha512-TdmXZ+NnBXdbMtbA6Yo93mZpTs0oz9HfN8jY9yEJXsECOC0XPC1+nghQQrxJ3a9+eq6qba/JNLLM+ZV0W6DOaA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-minimap": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-minimap/-/ckeditor5-minimap-48.3.1.tgz", - "integrity": "sha512-kDJfTRv31WrFisXBKzHNtKhAseiSsJKw1oWIPqqLIN9rnYXnEpjqa5BRgypfFbS7LW0wgjKvCOH/yHMyPrv64A==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-page-break": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-page-break/-/ckeditor5-page-break-48.3.1.tgz", - "integrity": "sha512-Wbsq6ZEOQN+zmfhMx05Ey0mda6qCj74j34yEZrnJ5nfFAoody7q3hJ7yJ9Edu10zF8+LXfC8+ebpaXQr77IvLg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-paragraph": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-48.3.1.tgz", - "integrity": "sha512-TnfBhRiFMBbGoXaPOpUiG109IpUFjbdEQEtjlBfiB4bMG71J1pdVYBe+qN1kvr34cYgdR96P/wbUnqC4BZA6Jw==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-paste-from-office": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-paste-from-office/-/ckeditor5-paste-from-office-48.3.1.tgz", - "integrity": "sha512-PAyMPmRRTY9MvvfhLdfPwgDOAlzm9u9C97aS7S/JbeKl2uys9uJ7nZRBC9v+9zf6eJMHx90ThKyVBtstKDC6LQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-remove-format": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-remove-format/-/ckeditor5-remove-format-48.3.1.tgz", - "integrity": "sha512-ZVuLTxUupAnoilnhC6Sjev1+qdzzSJxZ0h1h41boaRHSoqXGtnvXosb4MYZ416LiLYDBkFdL1yLJhhPOsWNXMg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-restricted-editing": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-restricted-editing/-/ckeditor5-restricted-editing-48.3.1.tgz", - "integrity": "sha512-53u38P5fpz/8qwanJtGYtgmi5Szqg+6VhqnbSyPWOWK8dlJAUi0aMJy/ihseFkUFt2AfaUZHlUW7WzpwttbDCw==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-select-all": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-48.3.1.tgz", - "integrity": "sha512-bPXjCzqNeroJxnpW+dHXtBb5vigap7cwANJ6LS9lvTbQGKk3Ocq6jO0RlhmJ9RvcuHwAMH60a+23zW3PJAOkAQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-show-blocks": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-show-blocks/-/ckeditor5-show-blocks-48.3.1.tgz", - "integrity": "sha512-Frzw96nYEET7ymiEUvMHjkJ/QClUfsGTd+jJufXaT9hUx7t1nONVQVhzIEIruy8dgqt8prIRqVpczD3mQS8T4Q==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-source-editing": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-source-editing/-/ckeditor5-source-editing-48.3.1.tgz", - "integrity": "sha512-20rfbBZgZjEYnFCpS69U27TKZq9ZLMzKCBSXv8Kmv4qObHGgZMBY+R5UsG1VpIRG5DdUjP9lBWgmCVkzlof1EA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-special-characters": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-special-characters/-/ckeditor5-special-characters-48.3.1.tgz", - "integrity": "sha512-gqfxywMLASyjJV7AvhV3WCX3QYuizjWG0SxUy7zOils00UjIeImfQW07X5u/FSi2GLeUsOjSfttsAbtJXQXHzg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-style": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-style/-/ckeditor5-style-48.3.1.tgz", - "integrity": "sha512-rYikWptU+1Kd4UbzZ0s04tO6CqlEoPzfX09jfdwWSNYLbgB9+CfrxnkbnFvfg3SCAgtFDactc07TBtxsH9+Eag==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-html-support": "48.3.1", - "@ckeditor/ckeditor5-list": "48.3.1", - "@ckeditor/ckeditor5-table": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-table": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-table/-/ckeditor5-table-48.3.1.tgz", - "integrity": "sha512-aoVzI5Srl5g0AP2XslxNugJFeogQGstk8JiCwPN1cRvtOb/e7pvMYBsAXhqdf3GFeq3E7HMw/fceXmDLlWJPgw==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-typing": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-48.3.1.tgz", - "integrity": "sha512-kBtgdIA9oWqrmTk24WRxaK/p91N00Mz0XE9/w7NDiOLAPBJNeBvt8Le4zOzyeLt8tn+DCP2h/BQg0t04oFveNQ==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-ui": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-48.3.1.tgz", - "integrity": "sha512-bs0VgxH3xfs8B14it+5dNK9I5YIWDI27qxArJqmfDFbnVBVtxlaLtnntyykbrNWCck53LKZ2qCpDueVsCV2JmA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-editor-multi-root": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@types/color-convert": "2.0.4", - "color-convert": "3.1.0", - "color-parse": "2.0.2", - "es-toolkit": "1.45.1", - "vanilla-colorful": "0.7.2" - } - }, - "node_modules/@ckeditor/ckeditor5-undo": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-48.3.1.tgz", - "integrity": "sha512-psJd40k7knNqfbdCaBc6D6cC88exr4Y6AwQihUn/9DaQv8vBjJDNsifVsSgfBemT7QIchUDIoJwYkF8hmUDT9Q==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-upload": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-48.3.1.tgz", - "integrity": "sha512-6hEOB4rAgtbDhntBw7Vw1wyn6BxR03mXNSGaKHyJ+OCZ1FzNAcCCkHI+6CI5INpAiAp8ISXfzblKec+EB0iA0Q==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1" - } - }, - "node_modules/@ckeditor/ckeditor5-utils": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-48.3.1.tgz", - "integrity": "sha512-hLZLjgwWSQKB3/a7AULSB5066PujeqwQiiUwU71ObxLGAHJA5EWD102Jp093BmiFvf5k8/hXFqOtUuaihDCXtg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-ui": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-watchdog": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-watchdog/-/ckeditor5-watchdog-48.3.1.tgz", - "integrity": "sha512-qv0D8GdaRdP9kM5LFYNNZTT3kN70jeEilZIA8wqLDf2+nIkz68xNZiwMbad9yrjGbMe2iQqrURTmML1/2+FRqA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-widget": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-48.3.1.tgz", - "integrity": "sha512-2XrBEd0pz/aVmSlXYC/Q3vgGVLadtN2KK5T3euQv3MSWTZtA66ZQKeKLFwl5pNvv/ItnCHUDz/RMEAP1CqsfTg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-enter": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@ckeditor/ckeditor5-word-count": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-word-count/-/ckeditor5-word-count-48.3.1.tgz", - "integrity": "sha512-ylAMJ0LNVJasul0cVbZFSIXK4tdZ/850NXPjtTiL63K//2bYfxRj3Xwh+mN14H4NX3ozkJhN2jaA9PU6Gmfs3Q==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "es-toolkit": "1.45.1" - } - }, - "node_modules/@fast-csv/format": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", - "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", - "license": "MIT", - "dependencies": { - "@types/node": "^14.0.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isboolean": "^3.0.3", - "lodash.isequal": "^4.5.0", - "lodash.isfunction": "^3.0.9", - "lodash.isnil": "^4.0.0" - } - }, - "node_modules/@fast-csv/format/node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "license": "MIT" - }, - "node_modules/@fast-csv/parse": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", - "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", - "license": "MIT", - "dependencies": { - "@types/node": "^14.0.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.groupby": "^4.6.0", - "lodash.isfunction": "^3.0.9", - "lodash.isnil": "^4.0.0", - "lodash.isundefined": "^3.0.1", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/@fast-csv/parse/node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "license": "MIT" - }, - "node_modules/@redis/bloom": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.12.1.tgz", - "integrity": "sha512-PUUfv+ms7jgPSBVoo/DN4AkPHj4D5TZSd6SbJX7egzBplkYUcKmHRE8RKia7UtZ8bSQbLguLvxVO+asKtQfZWA==", - "license": "MIT", - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@redis/client": "^5.12.1" - } - }, - "node_modules/@redis/client": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.12.1.tgz", - "integrity": "sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==", - "license": "MIT", - "dependencies": { - "cluster-key-slot": "1.1.2" - }, - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@node-rs/xxhash": "^1.1.0", - "@opentelemetry/api": ">=1 <2" - }, - "peerDependenciesMeta": { - "@node-rs/xxhash": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - } - } - }, - "node_modules/@redis/json": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.12.1.tgz", - "integrity": "sha512-eOze75esLve4vfqDel7aMX08CNaiLLQS2fV8mpRN9NxPe1rVR4vQyYiW/OgtGUysF6QOr9ANhfxABKNOJfXdKg==", - "license": "MIT", - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@redis/client": "^5.12.1" - } - }, - "node_modules/@redis/search": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.12.1.tgz", - "integrity": "sha512-ItlxbxC9cKI6IU1TLWoczwJCRb6TdmkEpWv05UrPawqaAnWGRu3rcIqsc5vN483T2fSociuyV1UkWIL5I4//2w==", - "license": "MIT", - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@redis/client": "^5.12.1" - } - }, - "node_modules/@redis/time-series": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.12.1.tgz", - "integrity": "sha512-c6JL6E3EcZJuNqKFz+KM+l9l5mpcQiKvTwgA3blt5glWJ8hjDk0yeHN3beE/MpqYIQ8UEX44ItQzgkE/gCBELQ==", - "license": "MIT", - "engines": { - "node": ">= 18.19.0" - }, - "peerDependencies": { - "@redis/client": "^5.12.1" - } - }, - "node_modules/@types/color-convert": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-2.0.4.tgz", - "integrity": "sha512-Ub1MmDdyZ7mX//g25uBAoH/mWGd9swVbt8BseymnaE18SU4po/PjmCrHxqIIRjBo3hV/vh1KGr0eMxUhp+t+dQ==", - "license": "MIT", - "dependencies": { - "@types/color-name": "^1.1.0" - } - }, - "node_modules/@types/color-name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.5.tgz", - "integrity": "sha512-j2K5UJqGTxeesj6oQuGpMgifpT5k9HprgQd8D1Y0lOFqKHl3PJu5GMeS4Y5EgjS55AE6OQxf8mPED9uaGbf4Cg==", - "license": "MIT" - }, - "node_modules/@types/debug": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "26.1.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", - "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==", - "license": "MIT", - "peer": true, - "dependencies": { - "undici-types": "~8.3.0" - } - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", - "license": "ISC" - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ansi-styles/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ansi-styles/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", - "license": "MIT", - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "license": "MIT", - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, - "node_modules/aws-ssl-profiles": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", - "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", - "license": "MIT", - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "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/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "license": "Unlicense", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "license": "MIT", - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", - "license": "MIT" - }, - "node_modules/blurhash": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/blurhash/-/blurhash-2.0.5.tgz", - "integrity": "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==", - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "engines": { - "node": ">=0.2.0" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "license": "MIT/X11", - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/ckeditor5": { - "version": "48.3.1", - "resolved": "https://registry.npmjs.org/ckeditor5/-/ckeditor5-48.3.1.tgz", - "integrity": "sha512-uuWdrM7mHVO0NsO3DTGDXp2zBkcuSYoS78+Ovpuci3B1pxzG7eHeLfeaNKIltWorhcWCxY4G+JTWOobcwflCTA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@ckeditor/ckeditor5-adapter-ckfinder": "48.3.1", - "@ckeditor/ckeditor5-alignment": "48.3.1", - "@ckeditor/ckeditor5-autoformat": "48.3.1", - "@ckeditor/ckeditor5-autosave": "48.3.1", - "@ckeditor/ckeditor5-basic-styles": "48.3.1", - "@ckeditor/ckeditor5-block-quote": "48.3.1", - "@ckeditor/ckeditor5-bookmark": "48.3.1", - "@ckeditor/ckeditor5-ckbox": "48.3.1", - "@ckeditor/ckeditor5-ckfinder": "48.3.1", - "@ckeditor/ckeditor5-clipboard": "48.3.1", - "@ckeditor/ckeditor5-cloud-services": "48.3.1", - "@ckeditor/ckeditor5-code-block": "48.3.1", - "@ckeditor/ckeditor5-core": "48.3.1", - "@ckeditor/ckeditor5-easy-image": "48.3.1", - "@ckeditor/ckeditor5-editor-balloon": "48.3.1", - "@ckeditor/ckeditor5-editor-classic": "48.3.1", - "@ckeditor/ckeditor5-editor-decoupled": "48.3.1", - "@ckeditor/ckeditor5-editor-inline": "48.3.1", - "@ckeditor/ckeditor5-editor-multi-root": "48.3.1", - "@ckeditor/ckeditor5-emoji": "48.3.1", - "@ckeditor/ckeditor5-engine": "48.3.1", - "@ckeditor/ckeditor5-enter": "48.3.1", - "@ckeditor/ckeditor5-essentials": "48.3.1", - "@ckeditor/ckeditor5-find-and-replace": "48.3.1", - "@ckeditor/ckeditor5-font": "48.3.1", - "@ckeditor/ckeditor5-fullscreen": "48.3.1", - "@ckeditor/ckeditor5-heading": "48.3.1", - "@ckeditor/ckeditor5-highlight": "48.3.1", - "@ckeditor/ckeditor5-horizontal-line": "48.3.1", - "@ckeditor/ckeditor5-html-embed": "48.3.1", - "@ckeditor/ckeditor5-html-support": "48.3.1", - "@ckeditor/ckeditor5-icons": "48.3.1", - "@ckeditor/ckeditor5-image": "48.3.1", - "@ckeditor/ckeditor5-indent": "48.3.1", - "@ckeditor/ckeditor5-language": "48.3.1", - "@ckeditor/ckeditor5-link": "48.3.1", - "@ckeditor/ckeditor5-list": "48.3.1", - "@ckeditor/ckeditor5-markdown-gfm": "48.3.1", - "@ckeditor/ckeditor5-media-embed": "48.3.1", - "@ckeditor/ckeditor5-mention": "48.3.1", - "@ckeditor/ckeditor5-minimap": "48.3.1", - "@ckeditor/ckeditor5-page-break": "48.3.1", - "@ckeditor/ckeditor5-paragraph": "48.3.1", - "@ckeditor/ckeditor5-paste-from-office": "48.3.1", - "@ckeditor/ckeditor5-remove-format": "48.3.1", - "@ckeditor/ckeditor5-restricted-editing": "48.3.1", - "@ckeditor/ckeditor5-select-all": "48.3.1", - "@ckeditor/ckeditor5-show-blocks": "48.3.1", - "@ckeditor/ckeditor5-source-editing": "48.3.1", - "@ckeditor/ckeditor5-special-characters": "48.3.1", - "@ckeditor/ckeditor5-style": "48.3.1", - "@ckeditor/ckeditor5-table": "48.3.1", - "@ckeditor/ckeditor5-typing": "48.3.1", - "@ckeditor/ckeditor5-ui": "48.3.1", - "@ckeditor/ckeditor5-undo": "48.3.1", - "@ckeditor/ckeditor5-upload": "48.3.1", - "@ckeditor/ckeditor5-utils": "48.3.1", - "@ckeditor/ckeditor5-watchdog": "48.3.1", - "@ckeditor/ckeditor5-widget": "48.3.1", - "@ckeditor/ckeditor5-word-count": "48.3.1" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.0.tgz", - "integrity": "sha512-TVoqAq8ZDIpK5lsQY874DDnu65CSsc9vzq0wLpNQ6UMBq81GSZocVazPiBbYGzngzBOIRahpkTzCLVe2at4MfA==", - "license": "MIT", - "dependencies": { - "color-name": "^2.0.0" - }, - "engines": { - "node": ">=14.6" - } - }, - "node_modules/color-name": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", - "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", - "license": "MIT", - "engines": { - "node": ">=12.20" - } - }, - "node_modules/color-parse": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-2.0.2.tgz", - "integrity": "sha512-eCtOz5w5ttWIUcaKLiktF+DxZO1R9KLNY/xhbV6CkhM7sR3GhVghmt6X6yOnzeaM24po+Z9/S1apbXMwA3Iepw==", - "license": "MIT", - "dependencies": { - "color-name": "^2.0.0" - } - }, - "node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "license": "Apache-2.0", - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", - "license": "MIT", - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/dayjs": { - "version": "1.11.21", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", - "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decode-named-character-reference": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", - "license": "MIT", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "license": "MIT", - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dijkstrajs": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", - "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", - "license": "MIT" - }, - "node_modules/dom-serializer": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-3.1.1.tgz", - "integrity": "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==", - "license": "MIT", - "dependencies": { - "domelementtype": "^3.0.0", - "domhandler": "^6.0.0", - "entities": "^8.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-3.0.0.tgz", - "integrity": "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/domhandler": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-6.0.1.tgz", - "integrity": "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==", - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^3.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-4.0.2.tgz", - "integrity": "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==", - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^3.0.0", - "domelementtype": "^3.0.0", - "domhandler": "^6.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "license": "BSD-3-Clause", - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/duplexer2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/duplexer2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/entities": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", - "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-toolkit": { - "version": "1.45.1", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.1.tgz", - "integrity": "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, - "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/exceljs": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", - "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", - "license": "MIT", - "dependencies": { - "archiver": "^5.0.0", - "dayjs": "^1.8.34", - "fast-csv": "^4.3.1", - "jszip": "^3.10.1", - "readable-stream": "^3.6.0", - "saxes": "^5.0.1", - "tmp": "^0.2.0", - "unzipper": "^0.10.11", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" - }, - "node_modules/fast-csv": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", - "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", - "license": "MIT", - "dependencies": { - "@fast-csv/format": "4.3.5", - "@fast-csv/parse": "4.3.6" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/fuzzysort": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", - "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", - "license": "MIT" - }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "license": "MIT", - "dependencies": { - "is-property": "^1.0.2" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "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", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/hast-util-embedded": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-3.0.0.tgz", - "integrity": "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-is-element": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-dom": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", - "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==", - "license": "ISC", - "dependencies": { - "@types/hast": "^3.0.0", - "hastscript": "^9.0.0", - "web-namespaces": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-has-property": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", - "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-is-body-ok-link": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-3.0.1.tgz", - "integrity": "sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-is-element": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-minify-whitespace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hast-util-minify-whitespace/-/hast-util-minify-whitespace-1.0.1.tgz", - "integrity": "sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-embedded": "^3.0.0", - "hast-util-is-element": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-parse-selector": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-phrasing": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-3.0.1.tgz", - "integrity": "sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-embedded": "^3.0.0", - "hast-util-has-property": "^3.0.0", - "hast-util-is-body-ok-link": "^3.0.0", - "hast-util-is-element": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-dom": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/hast-util-to-dom/-/hast-util-to-dom-4.0.1.tgz", - "integrity": "sha512-z1VE7sZ8uFzS2baF3LEflX1IPw2gSzrdo3QFEsyoi23MkCVY3FoE9x6nLgOgjwJu8VNWgo+07iaxtONhDzKrUQ==", - "license": "ISC", - "dependencies": { - "@types/hast": "^3.0.0", - "property-information": "^7.0.0", - "web-namespaces": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-html": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", - "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-whitespace": "^3.0.0", - "html-void-elements": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "stringify-entities": "^4.0.0", - "zwitch": "^2.0.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-mdast": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/hast-util-to-mdast/-/hast-util-to-mdast-10.1.2.tgz", - "integrity": "sha512-FiCRI7NmOvM4y+f5w32jPRzcxDIz+PUqDwEqn1A+1q2cdp3B8Gx7aVrXORdOKjMNDQsD1ogOr896+0jJHW1EFQ==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "hast-util-phrasing": "^3.0.0", - "hast-util-to-html": "^9.0.0", - "hast-util-to-text": "^4.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "mdast-util-to-string": "^4.0.0", - "rehype-minify-whitespace": "^6.0.0", - "trim-trailing-lines": "^2.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-text": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", - "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "hast-util-is-element": "^3.0.0", - "unist-util-find-after": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hastscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", - "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/html-void-elements": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", - "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/htmlparser2": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-12.0.0.tgz", - "integrity": "sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^3.0.0", - "domhandler": "^6.0.0", - "domutils": "^4.0.2", - "entities": "^8.0.0" - }, - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", - "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", - "license": "MIT" - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/launder": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/launder/-/launder-1.7.1.tgz", - "integrity": "sha512-mU6WRz5EusL9ZZuiZ5SO4Y6C0P9PAUR9iwdb6bzj4KDihm28DiHFw+/yk9DBH4f+Pv1wuzQ4e2jV3oQ7mkIqvw==", - "license": "MIT", - "dependencies": { - "dayjs": "^1.11.7" - } - }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "license": "MIT", - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", - "license": "ISC" - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "license": "MIT" - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "license": "MIT" - }, - "node_modules/lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", - "license": "MIT" - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "license": "MIT" - }, - "node_modules/lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "license": "MIT" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", - "license": "MIT" - }, - "node_modules/lodash.isfunction": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", - "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", - "license": "MIT" - }, - "node_modules/lodash.isnil": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", - "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "license": "MIT" - }, - "node_modules/lodash.isundefined": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", - "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==", - "license": "MIT" - }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "license": "MIT" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "license": "MIT" - }, - "node_modules/long": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0" - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/lru.min": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", - "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==", - "license": "MIT", - "engines": { - "bun": ">=1.0.0", - "deno": ">=1.30.0", - "node": ">=8.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wellwelwel" - } - }, - "node_modules/markdown-table": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-find-and-replace": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", - "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", - "license": "MIT", - "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "ccount": "^2.0.0", - "devlop": "^1.0.0", - "mdast-util-find-and-replace": "^3.0.0", - "micromark-util-character": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-newline-to-break": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-newline-to-break/-/mdast-util-newline-to-break-2.0.0.tgz", - "integrity": "sha512-MbgeFca0hLYIEx/2zGsszCSEJJ1JSCdiY5xQxRcLDDGa8EPvlLPupJ4DSajbMPAnC0je8jfb9TiUATnxxrHUog==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-find-and-replace": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "license": "MIT", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/minimatch": { - "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" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/mysql2": { - "version": "3.23.1", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.23.1.tgz", - "integrity": "sha512-tTuRnC7qCet2IOfSNMYZ5SwXuBnfvBPAcIA28P0gtruXyZlU1LMxA6uha32kYypoFgyYklMqhLWwt4laYwXR/Q==", - "license": "MIT", - "dependencies": { - "aws-ssl-profiles": "^1.1.2", - "denque": "^2.1.0", - "generate-function": "^2.3.1", - "iconv-lite": "^0.7.2", - "long": "^5.3.2", - "lru.min": "^1.1.4", - "named-placeholders": "^1.1.6", - "sql-escaper": "^1.5.1" - }, - "engines": { - "node": ">= 8.0" - }, - "peerDependencies": { - "@types/node": ">= 8" - } - }, - "node_modules/named-placeholders": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", - "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", - "license": "MIT", - "dependencies": { - "lru.min": "^1.1.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", - "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/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, - "node_modules/parse-srcset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==", - "license": "MIT" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/postcss": { - "version": "8.5.20", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.20.tgz", - "integrity": "sha512-lW616l85ucIQL+FocMmL7pQFPqBmwejrCMg+iPxyImlrANNJG9NHq/RkyCZopDhd8C3LA03PHRJDjkbGu8vvug==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.16", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/property-information": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", - "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/qrcode": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", - "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", - "license": "MIT", - "dependencies": { - "dijkstrajs": "^1.0.1", - "pngjs": "^5.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "qrcode": "bin/qrcode" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "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" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/redis": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/redis/-/redis-5.12.1.tgz", - "integrity": "sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==", - "license": "MIT", - "dependencies": { - "@redis/bloom": "5.12.1", - "@redis/client": "5.12.1", - "@redis/json": "5.12.1", - "@redis/search": "5.12.1", - "@redis/time-series": "5.12.1" - }, - "engines": { - "node": ">= 18.19.0" - } - }, - "node_modules/rehype-dom-parse": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/rehype-dom-parse/-/rehype-dom-parse-5.0.2.tgz", - "integrity": "sha512-8CqP11KaqvtWsMqVEC2yM3cZWZsDNqqpr8nPvogjraLuh45stabgcpXadCAxu1n6JaUNJ/Xr3GIqXP7okbNqLg==", - "license": "ISC", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-from-dom": "^5.0.0", - "unified": "^11.0.0" - } - }, - "node_modules/rehype-dom-stringify": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/rehype-dom-stringify/-/rehype-dom-stringify-4.0.2.tgz", - "integrity": "sha512-2HVFYbtmm5W3C2j8QsV9lcHdIMc2Yn/ytlPKcSC85/tRx2haZbU8V67Wxyh8STT38ZClvKlZ993Me/Hw8g88Aw==", - "license": "ISC", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-to-dom": "^4.0.0", - "unified": "^11.0.0" - } - }, - "node_modules/rehype-minify-whitespace": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/rehype-minify-whitespace/-/rehype-minify-whitespace-6.0.2.tgz", - "integrity": "sha512-Zk0pyQ06A3Lyxhe9vGtOtzz3Z0+qZ5+7icZ/PL/2x1SHPbKao5oB/g/rlc6BCTajqBb33JcOe71Ye1oFsuYbnw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-minify-whitespace": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-remark": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/rehype-remark/-/rehype-remark-10.0.1.tgz", - "integrity": "sha512-EmDndlb5NVwXGfUa4c9GPK+lXeItTilLhE6ADSaQuHr4JUlKw9MidzGzx4HpqZrNCt6vnHmEifXQiiA+CEnjYQ==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "hast-util-to-mdast": "^10.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-breaks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-breaks/-/remark-breaks-4.0.0.tgz", - "integrity": "sha512-IjEjJOkH4FuJvHZVIW0QCDWxcG96kCq7An/KVH2NfJe6rKZU2AsHeB3OEjPNRxi4QC34Xdx7I2KGYn6IpT7gxQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-newline-to-break": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-gfm": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", - "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-gfm": "^3.0.0", - "micromark-extension-gfm": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-rehype": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", - "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-stringify": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-to-markdown": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "license": "ISC" - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/sanitize-html": { - "version": "2.17.6", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.6.tgz", - "integrity": "sha512-M4bo9tfv1yfhQZZKkc6dL07ALrGJtfvNOuhX3hU9AVPR/uPQ+nKOJBqTYc7LfMQblTW04mtSWDJWEyLvygJsLA==", - "license": "MIT", - "dependencies": { - "deepmerge": "^4.2.2", - "escape-string-regexp": "^4.0.0", - "htmlparser2": "^12.0.0", - "is-plain-object": "^5.0.0", - "launder": "^1.7.1", - "parse-srcset": "^1.0.2", - "postcss": "^8.3.11" - }, - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/sanitize-html/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==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC" - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/sql-escaper": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.5.1.tgz", - "integrity": "sha512-4toX5E1fQbBrpfXidaHnF0669nkAdETeIPTs2SUjxxD7RRIs9ICG4gtpmfc68JCEKehsdwLFqBu9VlQqZ1P1gg==", - "license": "MIT", - "engines": { - "bun": ">=1.0.0", - "deno": ">=2.0.0", - "node": ">=12.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/mysqljs/sql-escaper?sponsor=1" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stringify-entities": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", - "license": "MIT", - "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tmp": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", - "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "license": "MIT/X11", - "engines": { - "node": "*" - } - }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trim-trailing-lines": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-2.1.0.tgz", - "integrity": "sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "license": "MIT", - "peer": true - }, - "node_modules/unified": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-find-after": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", - "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-is": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", - "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", - "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unzipper": { - "version": "0.10.14", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", - "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", - "license": "MIT", - "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "node_modules/unzipper/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/unzipper/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/unzipper/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/uuid": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", - "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/esm/bin/uuid" - } - }, - "node_modules/vanilla-colorful": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/vanilla-colorful/-/vanilla-colorful-0.7.2.tgz", - "integrity": "sha512-z2YZusTFC6KnLERx1cgoIRX2CjPRP0W75N+3CC6gbvdX5Ch47rZkEMGO2Xnf+IEmi3RiFLxS18gayMA27iU7Kg==", - "license": "MIT" - }, - "node_modules/vfile": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", - "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/web-namespaces": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "license": "ISC" - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "license": "MIT" - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "license": "ISC" - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "license": "MIT", - "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "license": "MIT", - "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index f305f31..0000000 --- a/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "hengzhun-exam-system", - "version": "1.1.0", - "private": true, - "type": "module", - "scripts": { - "start": "dotnet run --project src/Eis.Web/Eis.Web.csproj", - "test": "dotnet test Eis.slnx", - "test:legacy": "node tests/client-auth.test.mjs && node tests/api-dedup.test.mjs && node tests/cache.test.mjs && node tests/auth-state.test.mjs && node tests/state-cache.test.mjs && node tests/document-verification.test.mjs && node tests/admission.test.mjs && node tests/seed.test.mjs && node tests/system.test.mjs", - "test:cache": "node tests/cache.test.mjs", - "reset-db": "dotnet run --project src/Eis.Tools -- database reset", - "seed-test-data": "dotnet run --project src/Eis.Tools -- database seed", - "seed-test-data:sqlite": "dotnet run --project src/Eis.Tools -- database seed --sqlite", - "seed-test-data:mysql": "dotnet run --project src/Eis.Tools -- database seed --mysql", - "initialize-system": "dotnet run --project src/Eis.Tools -- database reset", - "initialize-system:sqlite": "dotnet run --project src/Eis.Tools -- database reset --sqlite", - "initialize-system:mysql": "dotnet run --project src/Eis.Tools -- database reset --mysql" - }, - "dependencies": { - "ckeditor5": "^48.3.1", - "exceljs": "^4.4.0", - "mysql2": "^3.14.2", - "qrcode": "1.5.4", - "redis": "^5.12.1", - "sanitize-html": "^2.17.6" - }, - "overrides": { - "exceljs": { - "uuid": "^11.1.1" - } - }, - "engines": { - "node": ">=22.5" - } -} diff --git a/scripts/build-regions.mjs b/scripts/build-regions.mjs deleted file mode 100644 index 0df0099..0000000 --- a/scripts/build-regions.mjs +++ /dev/null @@ -1,55 +0,0 @@ -import { readFile, writeFile } from 'node:fs/promises'; -import { resolve } from 'node:path'; - -const input = resolve(process.argv[2] || 'ok_data_level3.csv'); -const output = resolve(process.argv[3] || 'src/data/china-regions.mjs'); - -function parseCsvLine(line) { - const values = []; - let value = ''; - let quoted = false; - for (let index = 0; index < line.length; index += 1) { - const char = line[index]; - if (char === '"') { - if (quoted && line[index + 1] === '"') { value += '"'; index += 1; } - else quoted = !quoted; - } else if (char === ',' && !quoted) { - values.push(value); - value = ''; - } else value += char; - } - values.push(value); - return values; -} - -const source = await readFile(input, 'utf8'); -const rows = source.replace(/^\uFEFF/, '').trim().split(/\r?\n/).slice(1).map(line => { - const [id, pid, deep, , , , extId, extName] = parseCsvLine(line); - return { id, pid, deep: Number(deep), code: extId.slice(0, 6), name: extName }; -}); - -const provinces = rows.filter(item => item.deep === 0 && item.code !== '0').map(province => ({ - code: province.code, - name: province.name, - cities: rows.filter(city => city.deep === 1 && city.pid === province.id).map(city => ({ - code: city.code, - name: city.name, - districts: rows.filter(district => district.deep === 2 && district.pid === city.id).map(district => ({ - code: district.code, - name: district.name - })) - })) -})); - -const hotan = provinces.find(item => item.code === '650000')?.cities.find(item => item.code === '653200'); -for (const district of [ - { code: '653228', name: '和康县' }, - { code: '653229', name: '和安县' } -]) { - if (hotan && !hotan.districts.some(item => item.code === district.code)) hotan.districts.push(district); -} -hotan?.districts.sort((a, b) => a.code.localeCompare(b.code)); - -const banner = `// Generated from AreaCity-JsSpider-StatsGov release 2025.251231.260403.\n// Source snapshot: 国家地名信息库 2025-12-31; generated 2026-07-20.\n// Manual official additions: 和康县 653228, 和安县 653229.\n`; -await writeFile(output, `${banner}export const chinaRegionsVersion = '2025-12-31';\nexport const chinaRegions = ${JSON.stringify(provinces)};\n`, 'utf8'); -console.log(`Generated ${provinces.length} provinces at ${output}`); diff --git a/scripts/export-dotnet-demo-seed.mjs b/scripts/export-dotnet-demo-seed.mjs deleted file mode 100644 index 479aecc..0000000 --- a/scripts/export-dotnet-demo-seed.mjs +++ /dev/null @@ -1,44 +0,0 @@ -import { pbkdf2Sync } from 'node:crypto'; -import { writeFile } from 'node:fs/promises'; -import { fileURLToPath } from 'node:url'; -import { dirname, join, resolve } from 'node:path'; -import { gzipSync } from 'node:zlib'; -import { buildSeedOperations } from '../database.mjs'; -import { createSeedDatabase } from '../src/data/seed.mjs'; - -const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); -const outputPath = join(root, 'src', 'Eis.Infrastructure', 'Data', 'demo-seed-operations.json.gz'); -const generatedAt = '2026-07-23T00:00:00.000Z'; -const deterministicSalt = 'eis-dotnet-demo-seed'; -const hashPassword = password => { - const hash = pbkdf2Sync(password, deterministicSalt, 120000, 32, 'sha256').toString('hex'); - return `${deterministicSalt}:${hash}`; -}; - -const database = createSeedDatabase({ - nowIso: () => generatedAt, - hashPassword -}); -database.meta.version = 20; -const operations = buildSeedOperations(database); -const payload = { - version: 1, - schemaVersion: 20, - generatedAt, - summary: { - schools: database.schools.length, - users: database.users.length, - candidates: database.candidateProfiles.length, - registrations: database.registrations.length, - results: database.results.length, - admissionRecords: database.admissionRecords.length, - firstRoundPreferences: database.admissionRecords.filter( - item => item.kind === 'preference' && Number(item.payload?.round || 1) === 1 - ).length, - operations: operations.length - }, - operations -}; -const compressed = gzipSync(Buffer.from(JSON.stringify(payload)), { level: 9 }); -await writeFile(outputPath, compressed); -console.log(JSON.stringify({ outputPath, compressedBytes: compressed.length, ...payload.summary })); diff --git a/scripts/smoke-dotnet-migration.ps1 b/scripts/smoke-dotnet-migration.ps1 deleted file mode 100644 index 8d161cc..0000000 --- a/scripts/smoke-dotnet-migration.ps1 +++ /dev/null @@ -1,1987 +0,0 @@ -[CmdletBinding()] -param() - -$ErrorActionPreference = 'Stop' -Set-StrictMode -Version Latest - -$repositoryRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..')) -$smokeArtifactRoot = [System.IO.Path]::GetFullPath((Join-Path $repositoryRoot 'artifacts\smoke')) -$testDirectory = Join-Path $smokeArtifactRoot ("eis-migration-smoke-{0}" -f [guid]::NewGuid().ToString('N')) -$nodeProcess = $null -$dotnetProcess = $null -$nativeAuthProcess = $null - -function Get-AvailableTcpPort { - $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) - try { - $listener.Start() - return ([System.Net.IPEndPoint] $listener.LocalEndpoint).Port - } - finally { - $listener.Stop() - } -} - -function Start-TestProcess { - param( - [Parameter(Mandatory)] - [string] $FileName, - - [Parameter(Mandatory)] - [string[]] $ArgumentList, - - [Parameter(Mandatory)] - [hashtable] $Environment - ) - - $startInfo = [System.Diagnostics.ProcessStartInfo]::new() - $startInfo.FileName = $FileName - $startInfo.WorkingDirectory = $repositoryRoot - $startInfo.UseShellExecute = $false - $startInfo.CreateNoWindow = $true - $startInfo.RedirectStandardOutput = $true - $startInfo.RedirectStandardError = $true - foreach ($argument in $ArgumentList) { - $startInfo.ArgumentList.Add($argument) - } - foreach ($entry in $Environment.GetEnumerator()) { - $startInfo.Environment[$entry.Key] = [string] $entry.Value - } - - return [System.Diagnostics.Process]::Start($startInfo) -} - -function Wait-ForUrl { - param( - [Parameter(Mandatory)] - [uri] $Uri, - - [Parameter(Mandatory)] - [System.Diagnostics.Process[]] $Processes - ) - - $deadline = [DateTimeOffset]::UtcNow.AddSeconds(25) - while ([DateTimeOffset]::UtcNow -lt $deadline) { - foreach ($process in $Processes) { - if ($process.HasExited) { - $standardOutput = $process.StandardOutput.ReadToEnd() - $standardError = $process.StandardError.ReadToEnd() - throw "Process $($process.Id) exited with code $($process.ExitCode) before $Uri became ready`n$standardOutput`n$standardError" - } - } - - try { - $response = Invoke-WebRequest -Uri $Uri -TimeoutSec 2 - if ($response.StatusCode -eq 200) { - return - } - } - catch { - Start-Sleep -Milliseconds 250 - } - } - - throw "Timed out waiting for $Uri" -} - -function Assert-JsonEquivalent { - param( - [Parameter(Mandatory)] - [string] $Expected, - - [Parameter(Mandatory)] - [string] $Actual, - - [Parameter(Mandatory)] - [string] $Label - ) - - $expectedNode = [System.Text.Json.Nodes.JsonNode]::Parse($Expected) - $actualNode = [System.Text.Json.Nodes.JsonNode]::Parse($Actual) - if (-not [System.Text.Json.Nodes.JsonNode]::DeepEquals($expectedNode, $actualNode)) { - $difference = Find-JsonDifference -Expected $expectedNode -Actual $actualNode -Path '$' - throw "$Label JSON payload differs from the legacy API at $difference" - } -} - -function Assert-CandidateResultsEquivalent { - param( - [Parameter(Mandatory)] - [string] $Expected, - - [Parameter(Mandatory)] - [string] $Actual - ) - - $expectedNode = [System.Text.Json.Nodes.JsonNode]::Parse($Expected) - $actualNode = [System.Text.Json.Nodes.JsonNode]::Parse($Actual) - foreach ($node in @($expectedNode, $actualNode)) { - foreach ($summary in $node['summaries'].AsArray()) { - $summary.AsObject().Remove('verificationQr') | Out-Null - } - } - if (-not [System.Text.Json.Nodes.JsonNode]::DeepEquals($expectedNode, $actualNode)) { - $difference = Find-JsonDifference -Expected $expectedNode -Actual $actualNode -Path '$' - throw "Candidate route 'results' JSON payload differs from the legacy API at $difference" - } -} - -function Assert-CandidateAdmissionsEquivalent { - param( - [Parameter(Mandatory)] - [string] $Expected, - - [Parameter(Mandatory)] - [string] $Actual - ) - - $expectedNode = [System.Text.Json.Nodes.JsonNode]::Parse($Expected) - $actualNode = [System.Text.Json.Nodes.JsonNode]::Parse($Actual) - foreach ($node in @($expectedNode, $actualNode)) { - foreach ($admission in $node['admissions'].AsArray()) { - $admission.AsObject().Remove('noticeVerificationQr') | Out-Null - } - } - if (-not [System.Text.Json.Nodes.JsonNode]::DeepEquals($expectedNode, $actualNode)) { - $difference = Find-JsonDifference -Expected $expectedNode -Actual $actualNode -Path '$' - throw "Candidate route 'admissions' JSON payload differs from the legacy API at $difference" - } -} - -function Assert-ArrangementPreviewEquivalent { - param( - [Parameter(Mandatory)] - [string] $Expected, - - [Parameter(Mandatory)] - [string] $Actual - ) - - $expectedNode = [System.Text.Json.Nodes.JsonNode]::Parse($Expected) - $actualNode = [System.Text.Json.Nodes.JsonNode]::Parse($Actual) - foreach ($node in @($expectedNode, $actualNode)) { - foreach ($sample in $node['samples'].AsArray()) { - $sample.AsObject().Remove('generatedAt') | Out-Null - } - } - if (-not [System.Text.Json.Nodes.JsonNode]::DeepEquals($expectedNode, $actualNode)) { - $difference = Find-JsonDifference -Expected $expectedNode -Actual $actualNode -Path '$' - throw "Arrangement preview JSON payload differs from the legacy API at $difference" - } -} - -function Find-JsonDifference { - param( - [AllowNull()] - [System.Text.Json.Nodes.JsonNode] $Expected, - - [AllowNull()] - [System.Text.Json.Nodes.JsonNode] $Actual, - - [Parameter(Mandatory)] - [string] $Path - ) - - if ($null -eq $Expected -or $null -eq $Actual) { - return "$Path (expected=$Expected, actual=$Actual)" - } - - if ($Expected -is [System.Text.Json.Nodes.JsonObject] -and $Actual -is [System.Text.Json.Nodes.JsonObject]) { - foreach ($entry in $Expected) { - if (-not $Actual.ContainsKey($entry.Key)) { - return "$Path.$($entry.Key) (missing from actual)" - } - if (-not [System.Text.Json.Nodes.JsonNode]::DeepEquals($entry.Value, $Actual[$entry.Key])) { - return Find-JsonDifference -Expected $entry.Value -Actual $Actual[$entry.Key] -Path "$Path.$($entry.Key)" - } - } - foreach ($entry in $Actual) { - if (-not $Expected.ContainsKey($entry.Key)) { - return "$Path.$($entry.Key) (unexpected in actual)" - } - } - return "$Path (object values differ)" - } - - if ($Expected -is [System.Text.Json.Nodes.JsonArray] -and $Actual -is [System.Text.Json.Nodes.JsonArray]) { - if ($Expected.Count -ne $Actual.Count) { - return "$Path.Count (expected=$($Expected.Count), actual=$($Actual.Count))" - } - for ($index = 0; $index -lt $Expected.Count; $index++) { - if (-not [System.Text.Json.Nodes.JsonNode]::DeepEquals($Expected[$index], $Actual[$index])) { - return Find-JsonDifference -Expected $Expected[$index] -Actual $Actual[$index] -Path "$Path[$index]" - } - } - return "$Path (array values differ)" - } - - return "$Path (expected=$($Expected.ToJsonString()), actual=$($Actual.ToJsonString()))" -} - -try { - New-Item -ItemType Directory -Path $testDirectory | Out-Null - - $legacyPort = Get-AvailableTcpPort - $webPort = Get-AvailableTcpPort - $nativeAuthPort = Get-AvailableTcpPort - $legacyBaseUrl = "http://127.0.0.1:$legacyPort" - $webBaseUrl = "http://127.0.0.1:$webPort" - $nativeAuthBaseUrl = "http://127.0.0.1:$nativeAuthPort" - - $nodeExecutable = (Get-Command node.exe -ErrorAction Stop).Source - $dotnetExecutable = (Get-Command dotnet.exe -ErrorAction Stop).Source - $smokeDatabasePath = Join-Path $testDirectory 'smoke.sqlite' - $nodeEnvironment = @{ - NODE_ENV = 'test' - HOST = '127.0.0.1' - PORT = [string] $legacyPort - DATABASE_CLIENT = 'sqlite' - SQLITE_PATH = $smokeDatabasePath - INITIAL_ADMIN_USERNAME = 'migration_admin' - INITIAL_ADMIN_PASSWORD = 'Migration123!' - INITIAL_ADMIN_DISPLAY_NAME = '迁移测试管理员' - REDIS_URL = '' - REDIS_SESSION_URL = '' - TOTP_ENCRYPTION_KEY = 'migration-smoke-totp-key-32-characters-minimum' - DOCUMENT_VERIFICATION_SECRET = 'migration-smoke-document-key-32-characters-minimum' - } - $seedProcess = Start-TestProcess -FileName $dotnetExecutable -ArgumentList @( - 'run', '--project', 'src/Eis.Tools', '--', - 'database', 'seed', '--sqlite', - '--path', $smokeDatabasePath, - '--confirm-target', $smokeDatabasePath - ) -Environment $nodeEnvironment - if (-not $seedProcess.WaitForExit(30000)) { - $seedProcess.Kill($true) - throw 'Timed out while preparing the migration smoke-test database' - } - $seedOutput = $seedProcess.StandardOutput.ReadToEnd() - $seedError = $seedProcess.StandardError.ReadToEnd() - if ($seedProcess.ExitCode -ne 0) { - throw "Failed to prepare the migration smoke-test database`n$seedOutput`n$seedError" - } - $seedProcess.Dispose() - - $registrationSwitchProcess = Start-TestProcess -FileName $nodeExecutable -ArgumentList @( - 'tests/helpers/enable-self-registration.mjs', $smokeDatabasePath - ) -Environment $nodeEnvironment - if (-not $registrationSwitchProcess.WaitForExit(10000)) { - $registrationSwitchProcess.Kill($true) - throw 'Timed out while enabling self-registration in the smoke-test database' - } - $registrationSwitchOutput = $registrationSwitchProcess.StandardOutput.ReadToEnd() - $registrationSwitchError = $registrationSwitchProcess.StandardError.ReadToEnd() - if ($registrationSwitchProcess.ExitCode -ne 0) { - throw "Could not enable self-registration in the smoke-test database`n$registrationSwitchOutput`n$registrationSwitchError" - } - $registrationSwitchProcess.Dispose() - - $arrangementCapacityProcess = Start-TestProcess -FileName $nodeExecutable -ArgumentList @( - 'tests/helpers/prepare-admin-arrangement-smoke.mjs', $smokeDatabasePath - ) -Environment $nodeEnvironment - if (-not $arrangementCapacityProcess.WaitForExit(10000)) { - $arrangementCapacityProcess.Kill($true) - throw 'Timed out while preparing arrangement capacity in the smoke-test database' - } - $arrangementCapacityOutput = $arrangementCapacityProcess.StandardOutput.ReadToEnd() - $arrangementCapacityError = $arrangementCapacityProcess.StandardError.ReadToEnd() - if ($arrangementCapacityProcess.ExitCode -ne 0) { - throw "Could not prepare arrangement capacity in the smoke-test database`n$arrangementCapacityOutput`n$arrangementCapacityError" - } - $arrangementCapacityProcess.Dispose() - - $projectPath = Join-Path $repositoryRoot 'src\Eis.Web\Eis.Web.csproj' - $buildProcess = Start-TestProcess -FileName $dotnetExecutable -ArgumentList @( - 'build', $projectPath, - '--configuration', 'Release' - ) -Environment @{} - if (-not $buildProcess.WaitForExit(60000)) { - $buildProcess.Kill($true) - throw 'Timed out while building the ASP.NET Core migration host' - } - $buildOutput = $buildProcess.StandardOutput.ReadToEnd() - $buildError = $buildProcess.StandardError.ReadToEnd() - if ($buildProcess.ExitCode -ne 0) { - throw "Failed to build the ASP.NET Core migration host`n$buildOutput`n$buildError" - } - $buildProcess.Dispose() - - $nodeProcess = Start-TestProcess -FileName $nodeExecutable -ArgumentList @('server.mjs') -Environment $nodeEnvironment - $dotnetProcess = Start-TestProcess -FileName $dotnetExecutable -ArgumentList @( - 'run', - '--project', $projectPath, - '--configuration', 'Release', - '--no-build', - '--no-launch-profile', - '--', - '--urls', $webBaseUrl - ) -Environment @{ - ASPNETCORE_ENVIRONMENT = 'Development' - LegacyNode__Enabled = 'true' - LegacyNode__BaseUrl = $legacyBaseUrl - DATABASE_CLIENT = 'sqlite' - SQLITE_PATH = $smokeDatabasePath - DOCUMENT_VERIFICATION_SECRET = 'migration-smoke-document-key-32-characters-minimum' - } - - Wait-ForUrl -Uri "$webBaseUrl/health/live" -Processes @($nodeProcess, $dotnetProcess) - Wait-ForUrl -Uri "$webBaseUrl/health/migration" -Processes @($nodeProcess, $dotnetProcess) - - $index = Invoke-WebRequest -Uri "$webBaseUrl/" - if ($index.Content -notmatch '衡准') { - throw 'ASP.NET Core did not serve the existing index.html' - } - - $clientModule = Invoke-WebRequest -Uri "$webBaseUrl/src/client/api.mjs" - if ($clientModule.Content -notmatch 'export function api') { - throw 'ASP.NET Core did not serve the existing client module' - } - - $homeResponse = Invoke-WebRequest -Uri "$webBaseUrl/api/public/home" - if ($homeResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core') { - throw 'Public home request did not use the native ASP.NET Core endpoint' - } - $homePayload = $homeResponse.Content | ConvertFrom-Json - if ($homePayload.ok -ne $true) { - throw 'Native public API did not return a valid JSON response' - } - $legacyHomePayload = Invoke-RestMethod -Uri "$legacyBaseUrl/api/public/home" - if ($homePayload.stats.candidates -ne $legacyHomePayload.stats.candidates -or - $homePayload.stats.exams -ne $legacyHomePayload.stats.exams -or - $homePayload.stats.registrations -ne $legacyHomePayload.stats.registrations -or - $homePayload.schools.Count -ne $legacyHomePayload.schools.Count -or - $homePayload.classes.Count -ne $legacyHomePayload.classes.Count -or - $homePayload.notices.Count -ne $legacyHomePayload.notices.Count) { - throw 'Native public home aggregates do not match the legacy API' - } - foreach ($legacyExam in $legacyHomePayload.exams) { - $nativeExam = $homePayload.exams | Where-Object id -eq $legacyExam.id | Select-Object -First 1 - if ($null -eq $nativeExam -or $nativeExam.subjects.Count -ne $legacyExam.subjects.Count -or - $nativeExam.totalScore -ne $legacyExam.totalScore -or $nativeExam.registrationCount -ne $legacyExam.registrationCount) { - throw "Native public exam projection does not match the legacy API for $($legacyExam.id)" - } - } - - $announcementResponse = Invoke-WebRequest -Uri "$webBaseUrl/api/public/announcements" - if ($announcementResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core') { - throw 'Public announcements request did not use the native ASP.NET Core endpoint' - } - $nativeAnnouncements = $announcementResponse.Content | ConvertFrom-Json - $legacyAnnouncements = Invoke-RestMethod -Uri "$legacyBaseUrl/api/public/announcements" - foreach ($section in @('plans', 'qualifications', 'admissions', 'cutoffs', 'reports')) { - $nativeIds = @($nativeAnnouncements.$section | ForEach-Object id) - $legacyIds = @($legacyAnnouncements.$section | ForEach-Object id) - if (($nativeIds -join "`0") -ne ($legacyIds -join "`0")) { - throw "Native public announcement section '$section' does not match the legacy API" - } - $nativeSectionJson = $nativeAnnouncements.$section | ConvertTo-Json -Depth 100 -Compress - $legacySectionJson = $legacyAnnouncements.$section | ConvertTo-Json -Depth 100 -Compress - if ($nativeSectionJson -ne $legacySectionJson) { - throw "Native public announcement payload '$section' differs from the legacy API" - } - } - - $session = [Microsoft.PowerShell.Commands.WebRequestSession]::new() - $loginBody = @{ username = 'admin'; password = '12345678' } | ConvertTo-Json -Compress - $login = Invoke-RestMethod -Uri "$webBaseUrl/api/auth/login" -Method Post -ContentType 'application/json' -Body $loginBody -WebSession $session - if ($login.ok -ne $true -or $login.user.username -ne 'admin') { - throw 'Legacy login API proxy did not preserve the response' - } - - $currentUser = Invoke-RestMethod -Uri "$webBaseUrl/api/auth/me" -WebSession $session - if ($currentUser.user.username -ne 'admin') { - throw 'Legacy API proxy did not preserve the session cookie' - } - - $noticeBody = @{ - title = 'ASP.NET Core 迁移冒烟通知' - content = '
原生公开读取验证
' - category = '系统测试' - pinned = $true - status = 'published' - } | ConvertTo-Json -Compress - $createdNotice = Invoke-RestMethod -Uri "$webBaseUrl/api/admin/notices" -Method Post -ContentType 'application/json' -Body $noticeBody -WebSession $session - $noticeResponse = Invoke-WebRequest -Uri "$webBaseUrl/api/public/notices/$($createdNotice.notice.id)" - if ($noticeResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core') { - throw 'Public notice request did not use the native ASP.NET Core endpoint' - } - $noticePayload = $noticeResponse.Content | ConvertFrom-Json - if ($noticePayload.notice.title -ne 'ASP.NET Core 迁移冒烟通知' -or $noticePayload.notice.content -match ' +