From 5b86cdaec2ae81ba4a30972e4f141e887a750a4c Mon Sep 17 00:00:00 2001 From: biss Date: Mon, 20 Jul 2026 19:23:11 +0800 Subject: [PATCH] Expand application functionality --- app.js | 75 +- package-lock.json | 2794 ++++++++++++++++++++++++++++++- package.json | 4 +- server.mjs | 10 +- src/routes/admin.routes.mjs | 24 +- src/routes/candidate.routes.mjs | 4 +- src/routes/public.routes.mjs | 6 +- src/security/notice-content.mjs | 94 ++ styles.css | 21 +- tests/system.test.mjs | 27 +- 10 files changed, 3037 insertions(+), 22 deletions(-) create mode 100644 src/security/notice-content.mjs diff --git a/app.js b/app.js index 9de55ae..80852b5 100644 --- a/app.js +++ b/app.js @@ -9,6 +9,8 @@ import { formatRegionAddress, mountRegionSelects, updateRegionSelects } from './ const app = document.querySelector('#app'); const modalRoot = document.querySelector('#modalRoot'); let toastTimer; +let noticeEditor; +let ckeditorModulePromise; function toast(title, message = '') { const element = document.querySelector('#toast'); element.querySelector('strong').textContent = title; @@ -24,9 +26,27 @@ function setModal(content) { } function closeModal() { + const editor = noticeEditor; + noticeEditor = null; + if (editor) editor.destroy().catch(error => console.error('CKEditor cleanup failed', error)); modalRoot.innerHTML = ''; } +function loadCKEditor() { + if (!document.querySelector('link[data-ckeditor-styles]')) { + const stylesheet = document.createElement('link'); + stylesheet.rel = 'stylesheet'; + stylesheet.href = '/vendor/ckeditor5/ckeditor5.css'; + stylesheet.dataset.ckeditorStyles = ''; + document.head.append(stylesheet); + } + ckeditorModulePromise ||= Promise.all([ + import('/vendor/ckeditor5/ckeditor5.js'), + import('/vendor/ckeditor5/translations/zh-cn.js') + ]); + return ckeditorModulePromise; +} + function emptyState(title, description, route, action) { return `
${icons.ticket}

${h(title)}

${h(description)}

${route ? `` : ''}
`; } @@ -108,7 +128,8 @@ document.addEventListener('click', async event => { } if (action === 'open-notice') { const notice = state.publicData.notices.find(item => item.id === target.dataset.id) || (await api(`/api/public/notices/${target.dataset.id}`)).notice; - setModal(`

${h(notice.content).replace(/\n/g, '

')}

`); return; + const contentHtml = notice.contentHtml || `

${h(notice.content).replace(/\r?\n/g, '

')}

`; + setModal(`
${contentHtml}
`); return; } if (action === 'download-admit') { window.location.href = `/api/candidate/registrations/${target.dataset.id}/admit-card`; return; } if (['batch-admit-download', 'admit-info-export', 'center-materials-export'].includes(action)) { @@ -119,7 +140,7 @@ document.addEventListener('click', async event => { window.location.href = `/api/admin/admission-exports/${type}?examId=${encodeURIComponent(examId)}`; return; } - if (action === 'new-notice') return openNoticeForm(); + if (action === 'new-notice') { await openNoticeForm(); return; } if (action === 'new-exam') return openExamForm(); if (action === 'new-admin') return openAdminForm(); if (action === 'new-school-class') return openSchoolClassForm(); @@ -484,7 +505,9 @@ document.addEventListener('submit', async event => { await api(`/api/admin/workflow-instances/${body.id}/supervise`, { method: 'PATCH', body }); closeModal(); toast('流程已监督调整', '节点与责任人已更新并记录'); renderRoute(); } else if (kind === 'notice-form') { - const body = formObject(form); body.pinned = form.pinned.checked; + const body = formObject(form); + if (noticeEditor) body.content = noticeEditor.getData(); + body.pinned = form.pinned.checked; await api('/api/admin/notices', { method: 'POST', body }); closeModal(); await refreshPublic(); toast(body.status === 'published' ? '通知已发布' : '草稿已保存', '公开首页状态已同步'); renderRoute(); } else if (kind === 'exam-form') { @@ -599,8 +622,50 @@ function openRegistrationReview(id) { setModal(`
报考科目

${reg.subjects.map(subject => `${h(subject.name)}`).join('')}

账户报名号
${h(reg.registrationNumber || reg.candidate?.candidateNumber || '账户号码异常')}
当前步骤
${h(reg.workflow?.currentStepDetail?.name || '流程已结束')}
责任人
${h(reg.workflow?.assignee?.displayName || '—')}
缴费状态
${badge(reg.paymentStatus)}
${canReview ? `` : ''}`); } -function openNoticeForm() { - setModal(``); +async function openNoticeForm() { + setModal(``); + const source = modalRoot.querySelector('[data-notice-editor]'); + try { + const [ckeditor, translation] = await loadCKEditor(); + const { + ClassicEditor, AutoImage, AutoLink, BlockQuote, Bold, Essentials, Heading, + Image, ImageCaption, ImageInsertViaUrl, ImageStyle, ImageTextAlternative, ImageToolbar, + Italic, Link, List, Paragraph, Table, TableCaption, TableToolbar, Underline + } = ckeditor; + if (!source?.isConnected) return; + noticeEditor = await ClassicEditor.create(source, { + licenseKey: 'GPL', + language: 'zh-cn', + translations: [translation.default], + plugins: [ + Essentials, Paragraph, Heading, Bold, Italic, Underline, Link, AutoLink, List, BlockQuote, + Image, ImageCaption, ImageInsertViaUrl, ImageStyle, ImageTextAlternative, ImageToolbar, AutoImage, + Table, TableToolbar, TableCaption + ], + toolbar: { + items: ['heading', '|', 'bold', 'italic', 'underline', '|', 'bulletedList', 'numberedList', 'blockQuote', '|', 'link', 'insertImageViaUrl', 'insertTable', '|', 'undo', 'redo'], + shouldNotGroupWhenFull: true + }, + heading: { + options: [ + { model: 'paragraph', title: '正文', class: 'ck-heading_paragraph' }, + { model: 'heading2', view: 'h2', title: '二级标题', class: 'ck-heading_heading2' }, + { model: 'heading3', view: 'h3', title: '三级标题', class: 'ck-heading_heading3' } + ] + }, + link: { defaultProtocol: 'https://', addTargetToExternalLinks: true }, + image: { + toolbar: ['imageStyle:inline', 'imageStyle:block', 'imageStyle:side', '|', 'toggleImageCaption', 'imageTextAlternative'] + }, + table: { + contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', '|', 'toggleTableCaption'] + }, + placeholder: '请输入完整通知内容;图片使用 URL 插入,文件使用超链接' + }); + } catch (error) { + console.error('CKEditor failed to load', error); + toast('富文本编辑器加载失败', '已保留普通文本输入,可检查网络后重试'); + } } function dateTimeLocal(value) { diff --git a/package-lock.json b/package-lock.json index d436c4d..561379d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,13 +8,857 @@ "name": "hengzhun-exam-system", "version": "1.1.0", "dependencies": { + "ckeditor5": "^48.3.1", "exceljs": "^4.4.0", - "mysql2": "^3.14.2" + "mysql2": "^3.14.2", + "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", @@ -56,6 +900,54 @@ "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", "license": "MIT" }, + "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", @@ -66,6 +958,18 @@ "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/archiver": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", @@ -150,6 +1054,16 @@ "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", @@ -215,6 +1129,12 @@ "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", @@ -275,6 +1195,16 @@ "node": ">=0.2.0" } }, + "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", @@ -287,6 +1217,144 @@ "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/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", @@ -345,6 +1413,45 @@ "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/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", @@ -354,6 +1461,95 @@ "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/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", @@ -402,6 +1598,40 @@ "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": "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/exceljs": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", @@ -422,6 +1652,12 @@ "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", @@ -463,6 +1699,12 @@ "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", @@ -499,6 +1741,263 @@ "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", @@ -558,6 +2057,27 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "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", @@ -612,6 +2132,15 @@ "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", @@ -754,6 +2283,16 @@ "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", @@ -769,6 +2308,815 @@ "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-find-and-replace/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/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", @@ -802,6 +3150,12 @@ "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", @@ -836,6 +3190,24 @@ "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", @@ -860,6 +3232,12 @@ "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-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -869,12 +3247,56 @@ "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/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/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -919,6 +3341,140 @@ "node": ">=10" } }, + "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/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -958,6 +3514,24 @@ "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/saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -976,6 +3550,25 @@ "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", @@ -1000,6 +3593,20 @@ "safe-buffer": "~5.2.0" } }, + "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/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", @@ -1034,6 +3641,36 @@ "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", @@ -1041,6 +3678,107 @@ "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", @@ -1108,6 +3846,50 @@ "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/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1154,6 +3936,16 @@ "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 index e6ece34..e672bfd 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,10 @@ "reset-db": "node scripts/reset-dev-database.mjs" }, "dependencies": { + "ckeditor5": "^48.3.1", "exceljs": "^4.4.0", - "mysql2": "^3.14.2" + "mysql2": "^3.14.2", + "sanitize-html": "^2.17.6" }, "overrides": { "exceljs": { diff --git a/server.mjs b/server.mjs index 3a15df7..ef43abc 100644 --- a/server.mjs +++ b/server.mjs @@ -36,6 +36,11 @@ const staticFiles = new Set([ '/src/client/region-select.mjs', '/src/data/china-regions.mjs' ]); +const vendorStaticFiles = new Map([ + ['/vendor/ckeditor5/ckeditor5.js', join(root, 'node_modules', 'ckeditor5', 'dist', 'browser', 'ckeditor5.js')], + ['/vendor/ckeditor5/ckeditor5.css', join(root, 'node_modules', 'ckeditor5', 'dist', 'browser', 'ckeditor5.css')], + ['/vendor/ckeditor5/translations/zh-cn.js', join(root, 'node_modules', 'ckeditor5', 'dist', 'translations', 'zh-cn.js')] +]); const mimeTypes = { '.html': 'text/html; charset=utf-8', '.css': 'text/css; charset=utf-8', @@ -865,8 +870,9 @@ const handleAdmin = createAdminRoutes(routeContext); async function serveStatic(response, pathname) { const requestPath = pathname === '/' ? '/index.html' : pathname; - if (!staticFiles.has(requestPath)) return false; - const filePath = normalize(join(root, requestPath.replace(/^\/+/, ''))); + const filePath = vendorStaticFiles.get(requestPath) + || (staticFiles.has(requestPath) ? normalize(join(root, requestPath.replace(/^\/+/, ''))) : null); + if (!filePath) return false; const body = await readFile(filePath); response.writeHead(200, { 'Content-Type': mimeTypes[extname(filePath)] || 'application/octet-stream', 'Cache-Control': 'no-cache' }); response.end(body); diff --git a/src/routes/admin.routes.mjs b/src/routes/admin.routes.mjs index a313b68..a9ac7a3 100644 --- a/src/routes/admin.routes.mjs +++ b/src/routes/admin.routes.mjs @@ -1,4 +1,5 @@ import { admissionMixingScopes, buildAdmissionArrangement } from '../services/admission-arrangement.mjs'; +import { noticeForClient, noticePlainText, sanitizeNoticeContent } from '../security/notice-content.mjs'; export function createAdminRoutes(context) { const { @@ -1001,18 +1002,22 @@ export function createAdminRoutes(context) { } if (request.method === 'GET' && pathname === '/api/admin/notices') { if (!requirePermission(user, response, '*')) return true; - return sendJson(response, 200, { ok: true, notices: db.notices.sort((a, b) => new Date(b.publishAt || b.createdAt) - new Date(a.publishAt || a.createdAt)) }); + const notices = db.notices + .sort((a, b) => new Date(b.publishAt || b.createdAt) - new Date(a.publishAt || a.createdAt)) + .map(noticeForClient); + return sendJson(response, 200, { ok: true, notices }); } if (request.method === 'POST' && pathname === '/api/admin/notices') { if (!requirePermission(user, response, '*')) return true; const body = await readJson(request); const title = cleanText(body.title, 120); - const content = cleanText(body.content, 5000); - if (!title || !content) return sendError(response, 400, '通知标题和正文不能为空'); - const notice = { id: uid('notice'), title, summary: cleanText(body.summary, 260) || content.slice(0, 80), content, category: cleanText(body.category, 30) || '通知公告', pinned: Boolean(body.pinned), status: body.status === 'draft' ? 'draft' : 'published', publishAt: body.status === 'draft' ? null : nowIso(), createdAt: nowIso(), author: user.displayName }; + const content = sanitizeNoticeContent(body.content); + const contentText = noticePlainText(content); + if (!title || !contentText) return sendError(response, 400, '通知标题和正文不能为空'); + const notice = { id: uid('notice'), title, summary: cleanText(body.summary, 260) || contentText.slice(0, 80), content, category: cleanText(body.category, 30) || '通知公告', pinned: Boolean(body.pinned), status: body.status === 'draft' ? 'draft' : 'published', publishAt: body.status === 'draft' ? null : nowIso(), createdAt: nowIso(), author: user.displayName }; const log = logAction(db, user, notice.status === 'published' ? '发布通知' : '保存通知草稿', notice.title); await database.createNotice(notice, log); - return sendJson(response, 201, { ok: true, notice }); + return sendJson(response, 201, { ok: true, notice: noticeForClient(notice) }); } const noticeMatch = pathname.match(/^\/api\/admin\/notices\/([^/]+)$/); if (request.method === 'PATCH' && noticeMatch) { @@ -1020,7 +1025,12 @@ export function createAdminRoutes(context) { const body = await readJson(request); const notice = db.notices.find(item => item.id === noticeMatch[1]); if (!notice) return sendError(response, 404, '通知不存在'); - ['title', 'summary', 'content', 'category'].forEach(field => { if (body[field] != null) notice[field] = cleanText(body[field], field === 'content' ? 5000 : 260); }); + ['title', 'summary', 'category'].forEach(field => { if (body[field] != null) notice[field] = cleanText(body[field], 260); }); + if (body.content != null) { + const content = sanitizeNoticeContent(body.content); + if (!noticePlainText(content)) return sendError(response, 400, '通知正文不能为空'); + notice.content = content; + } if (body.pinned != null) notice.pinned = Boolean(body.pinned); if (body.status && ['draft', 'published'].includes(body.status)) { notice.status = body.status; @@ -1028,7 +1038,7 @@ export function createAdminRoutes(context) { } const log = logAction(db, user, '更新通知', `${notice.title} · ${notice.status}`); await database.updateNotice(notice, log); - return sendJson(response, 200, { ok: true, notice }); + return sendJson(response, 200, { ok: true, notice: noticeForClient(notice) }); } if (request.method === 'GET' && pathname === '/api/admin/results') { if (!requirePermission(user, response, 'results.read')) return true; diff --git a/src/routes/candidate.routes.mjs b/src/routes/candidate.routes.mjs index 86e0b64..8adb8ed 100644 --- a/src/routes/candidate.routes.mjs +++ b/src/routes/candidate.routes.mjs @@ -1,3 +1,5 @@ +import { noticeForClient } from '../security/notice-content.mjs'; + export function createCandidateRoutes(context) { const { database, @@ -65,7 +67,7 @@ export function createCandidateRoutes(context) { if (request.method === 'GET' && pathname === '/api/candidate/dashboard') { const registrations = db.registrations.filter(item => item.userId === user.id).map(item => examRegistrationView(db, item)); const results = db.results.filter(result => result.published && registrations.some(reg => reg.id === result.registrationId)); - const notices = db.notices.filter(item => item.status === 'published').sort((a, b) => new Date(b.publishAt) - new Date(a.publishAt)).slice(0, 5); + const notices = db.notices.filter(item => item.status === 'published').sort((a, b) => new Date(b.publishAt) - new Date(a.publishAt)).slice(0, 5).map(noticeForClient); const profileInstance = pendingWorkflow(db, 'profile_change', profile.id) || db.workflowInstances.filter(item => item.businessType === 'profile_change' && item.businessId === profile.id)[0]; return sendJson(response, 200, { ok: true, profile, profileWorkflow: workflowView(db, profileInstance), registrations, results, notices }); diff --git a/src/routes/public.routes.mjs b/src/routes/public.routes.mjs index 6229726..d58d249 100644 --- a/src/routes/public.routes.mjs +++ b/src/routes/public.routes.mjs @@ -1,3 +1,5 @@ +import { noticeForClient } from '../security/notice-content.mjs'; + export function createPublicRoutes(context) { const { database, @@ -50,14 +52,14 @@ export function createPublicRoutes(context) { async function handlePublic(pathname, response) { const db = await readDb(); if (pathname === '/api/public/home') { - const publishedNotices = db.notices.filter(item => item.status === 'published').sort((a, b) => Number(b.pinned) - Number(a.pinned) || new Date(b.publishAt) - new Date(a.publishAt)); + const publishedNotices = db.notices.filter(item => item.status === 'published').sort((a, b) => Number(b.pinned) - Number(a.pinned) || new Date(b.publishAt) - new Date(a.publishAt)).map(noticeForClient); const exams = db.exams.filter(item => item.status === 'published' && !item.archivedAt).map(exam => ({ ...publicExam(exam), registrationCount: db.registrations.filter(reg => reg.examId === exam.id).length })); return sendJson(response, 200, { ok: true, organization: db.organization, schools: db.schools.filter(item => item.active), classes: db.classes.filter(item => item.active), selfRegistrationEnabled: db.settings.selfRegistrationEnabled, notices: publishedNotices, exams, stats: { candidates: db.candidateProfiles.length, exams: exams.length, registrations: db.registrations.length } }); } const noticeMatch = pathname.match(/^\/api\/public\/notices\/([^/]+)$/); if (noticeMatch) { const notice = db.notices.find(item => item.id === noticeMatch[1] && item.status === 'published'); - return notice ? sendJson(response, 200, { ok: true, notice }) : sendError(response, 404, '通知不存在或尚未发布'); + return notice ? sendJson(response, 200, { ok: true, notice: noticeForClient(notice) }) : sendError(response, 404, '通知不存在或尚未发布'); } return false; } diff --git a/src/security/notice-content.mjs b/src/security/notice-content.mjs new file mode 100644 index 0000000..aa7e92b --- /dev/null +++ b/src/security/notice-content.mjs @@ -0,0 +1,94 @@ +import sanitizeHtml from 'sanitize-html'; + +const allowedTags = [ + 'p', 'br', 'h2', 'h3', 'h4', + 'strong', 'em', 'u', 's', + 'ul', 'ol', 'li', 'blockquote', 'a', + 'figure', 'figcaption', 'img', + 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td' +]; + +const blockTags = /<\/?(?:p|h[2-4]|ul|ol|li|blockquote|br|figure|figcaption|table|thead|tbody|tfoot|tr|th|td)\b[^>]*>/gi; + +function escapeHtml(value) { + return String(value) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + +function decodeTextEntities(value) { + const named = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", '#39': "'", nbsp: ' ' }; + const codePoint = (code, radix) => { + const parsed = Number.parseInt(code, radix); + return Number.isInteger(parsed) && parsed >= 0 && parsed <= 0x10ffff && !(parsed >= 0xd800 && parsed <= 0xdfff) + ? String.fromCodePoint(parsed) + : '�'; + }; + return String(value) + .replace(/&#x([0-9a-f]+);/gi, (_, code) => codePoint(code, 16)) + .replace(/&#(\d+);/g, (_, code) => codePoint(code, 10)) + .replace(/&(amp|lt|gt|quot|apos|#39|nbsp);/gi, (_, name) => named[name.toLowerCase()]); +} + +export function sanitizeNoticeContent(value) { + const source = String(value ?? '').trim().slice(0, 20000); + return sanitizeHtml(source, { + allowedTags, + allowedAttributes: { + a: ['href', 'target', 'rel'], + figure: ['class'], + img: ['src', 'alt'], + th: ['colspan', 'rowspan'], + td: ['colspan', 'rowspan'] + }, + allowedClasses: { + figure: [ + 'image', 'table', 'image-style-inline', 'image-style-block', 'image-style-side', + 'image-style-align-left', 'image-style-align-right', + 'image-style-block-align-left', 'image-style-block-align-right' + ] + }, + allowedSchemes: ['http', 'https', 'mailto', 'tel'], + allowProtocolRelative: false, + transformTags: { + a(tagName, attributes) { + const safeAttributes = {}; + if (attributes.href) safeAttributes.href = attributes.href; + if (attributes.target === '_blank') safeAttributes.target = '_blank'; + safeAttributes.rel = 'noopener noreferrer'; + return { tagName, attribs: safeAttributes }; + }, + img(tagName, attributes) { + const safeAttributes = {}; + if (/^https?:\/\//i.test(attributes.src || '')) safeAttributes.src = attributes.src; + if (attributes.alt) safeAttributes.alt = attributes.alt; + return { tagName, attribs: safeAttributes }; + } + } + }); +} + +export function noticePlainText(value) { + const sanitized = sanitizeNoticeContent(value).replace(blockTags, ' '); + const withoutTags = sanitizeHtml(sanitized, { allowedTags: [], allowedAttributes: {} }); + return decodeTextEntities(withoutTags).replace(/\s+/g, ' ').trim(); +} + +export function noticeContentHtml(value) { + const source = String(value ?? '').trim(); + if (!source) return ''; + if (!/<\/?(?:p|h[2-4]|strong|em|u|s|ul|ol|li|blockquote|a|br|figure|figcaption|img|table|thead|tbody|tfoot|tr|th|td)\b/i.test(source)) { + return source + .split(/\r?\n{2,}/) + .map(paragraph => `

${escapeHtml(paragraph).replace(/\r?\n/g, '
')}

`) + .join(''); + } + return sanitizeNoticeContent(source); +} + +export function noticeForClient(notice) { + return { ...notice, content: sanitizeNoticeContent(notice.content), contentHtml: noticeContentHtml(notice.content) }; +} diff --git a/styles.css b/styles.css index cb7659e..9c71c23 100644 --- a/styles.css +++ b/styles.css @@ -265,8 +265,27 @@ button:disabled { cursor: not-allowed; opacity: .5; } .score-rule-hint { margin:0; padding:9px 11px; border-radius:7px; color:#6d7890; background:#f3f6fb; font-size:8px; } /* Modals and feedback */ -.modal-layer { position:fixed; inset:0; z-index:100; display:grid; place-items:center; padding:22px; background:rgba(12,22,48,.55); backdrop-filter:blur(5px); animation:fadeIn .18s ease; }.modal-card { width:min(620px,100%); max-height:90vh; border-radius:16px; background:#fff; box-shadow:0 30px 90px rgba(13,23,51,.3); overflow-y:auto; animation:modalIn .22s ease; }.modal-head { display:flex; align-items:flex-start; justify-content:space-between; gap:20px; padding:22px 24px 18px; border-bottom:1px solid var(--line); }.modal-head span { color:#8b94a8; font-family:Consolas,monospace; font-size:8px; letter-spacing:1.5px; }.modal-head h2 { margin:5px 0; font-family:"STKaiti"; font-size:23px; font-weight:400; }.modal-head p { margin:0; color:#8c94a5; font-size:8px; }.modal-head > button { border:0; color:#8a92a2; background:transparent; font-size:23px; }.notice-content { padding:25px; }.notice-content p { margin:0 0 13px; color:#525d73; font-size:11px; line-height:2; }.modal-form { display:grid; gap:14px; padding:22px 24px 0; }.modal-foot { display:flex; justify-content:flex-end; gap:8px; margin:20px -24px 0; padding:15px 24px; border-top:1px solid var(--line); background:#fafbfc; }.modal-card > .modal-foot { margin:0; }.review-profile,.registration-review,.admit-preview { padding:22px 24px 0; }.review-profile dl { display:grid; grid-template-columns:1fr 1fr; gap:13px; margin:0; }.review-profile dl div,.registration-review dl div,.admit-preview dl div { display:grid; gap:4px; padding:10px; border-radius:7px; background:#f7f8fb; }.review-profile dt,.registration-review dt,.admit-preview dt { color:#969dac; font-size:7px; }.review-profile dd,.registration-review dd,.admit-preview dd { margin:0; color:#525d73; font-size:9px; }.registration-review > div > span { color:#9199a9; font-size:8px; }.registration-review > div p { display:flex; flex-wrap:wrap; gap:5px; }.registration-review > div b { padding:5px 8px; border-radius:5px; color:#54617a; background:#eef1f6; font-size:8px; }.registration-review dl,.admit-preview dl { display:grid; grid-template-columns:repeat(3,1fr); gap:9px; }.admit-preview > strong { display:block; margin:5px 0 18px; color:var(--navy); font-family:Consolas,monospace; font-size:26px; letter-spacing:2px; }.admit-preview > p { margin:16px 0 0; padding:11px; border-radius:7px; color:#7a5a24; background:#fff3dc; font-size:8px; }.toast { position:fixed; right:24px; bottom:24px; z-index:130; min-width:245px; display:flex; align-items:center; gap:11px; padding:13px 15px; border:1px solid #dfe7e3; border-radius:10px; background:#fff; box-shadow:0 17px 50px rgba(18,39,30,.17); opacity:0; transform:translateY(25px); pointer-events:none; transition:.25s; }.toast.show { opacity:1; transform:none; }.toast-icon { width:29px; height:29px; display:grid; place-items:center; border-radius:50%; color:#fff; background:var(--jade); font-size:11px; }.toast div { display:grid; gap:2px; }.toast strong { font-size:9px; }.toast small { color:#858d9e; font-size:8px; }.fatal-error { min-height:100vh; display:grid; place-content:center; justify-items:center; padding:25px; text-align:center; }.fatal-error > span { width:55px; height:55px; display:grid; place-items:center; border-radius:50%; color:#fff; background:var(--red); font-family:Georgia,serif; font-size:28px; }.fatal-error h1 { margin:18px 0 8px; font-family:"STKaiti"; font-size:28px; font-weight:400; }.fatal-error p { margin:0 0 18px; color:#7f8799; font-size:10px; }.empty-state { padding:35px; color:#8b93a4; font-size:9px; text-align:center; } +.modal-layer { position:fixed; inset:0; z-index:100; display:grid; place-items:center; padding:22px; background:rgba(12,22,48,.55); backdrop-filter:blur(5px); animation:fadeIn .18s ease; }.modal-card { width:min(620px,100%); max-height:90vh; border-radius:16px; background:#fff; box-shadow:0 30px 90px rgba(13,23,51,.3); overflow-y:auto; animation:modalIn .22s ease; }.modal-head { display:flex; align-items:flex-start; justify-content:space-between; gap:20px; padding:22px 24px 18px; border-bottom:1px solid var(--line); }.modal-head span { color:#8b94a8; font-family:Consolas,monospace; font-size:8px; letter-spacing:1.5px; }.modal-head h2 { margin:5px 0; font-family:"STKaiti"; font-size:23px; font-weight:400; }.modal-head p { margin:0; color:#8c94a5; font-size:8px; }.modal-head > button { border:0; color:#8a92a2; background:transparent; font-size:23px; }.notice-content { padding:25px; color:#525d73; overflow-wrap:anywhere; }.notice-content p,.notice-content li { color:#525d73; font-size:11px; line-height:2; }.notice-content p { margin:0 0 13px; }.notice-content h2,.notice-content h3,.notice-content h4 { margin:22px 0 10px; color:var(--navy); font-family:"STKaiti"; font-weight:400; }.notice-content h2 { font-size:22px; }.notice-content h3 { font-size:18px; }.notice-content h4 { font-size:15px; }.notice-content ul,.notice-content ol { margin:0 0 14px; padding-left:24px; }.notice-content blockquote { margin:15px 0; padding:10px 14px; border-left:3px solid var(--blue); background:#f4f7fc; }.notice-content blockquote p { margin:0; }.notice-content a { color:var(--blue); text-decoration:underline; text-underline-offset:2px; }.modal-form { display:grid; gap:14px; padding:22px 24px 0; }.modal-foot { display:flex; justify-content:flex-end; gap:8px; margin:20px -24px 0; padding:15px 24px; border-top:1px solid var(--line); background:#fafbfc; }.modal-card > .modal-foot { margin:0; }.review-profile,.registration-review,.admit-preview { padding:22px 24px 0; }.review-profile dl { display:grid; grid-template-columns:1fr 1fr; gap:13px; margin:0; }.review-profile dl div,.registration-review dl div,.admit-preview dl div { display:grid; gap:4px; padding:10px; border-radius:7px; background:#f7f8fb; }.review-profile dt,.registration-review dt,.admit-preview dt { color:#969dac; font-size:7px; }.review-profile dd,.registration-review dd,.admit-preview dd { margin:0; color:#525d73; font-size:9px; }.registration-review > div > span { color:#9199a9; font-size:8px; }.registration-review > div p { display:flex; flex-wrap:wrap; gap:5px; }.registration-review > div b { padding:5px 8px; border-radius:5px; color:#54617a; background:#eef1f6; font-size:8px; }.registration-review dl,.admit-preview dl { display:grid; grid-template-columns:repeat(3,1fr); gap:9px; }.admit-preview > strong { display:block; margin:5px 0 18px; color:var(--navy); font-family:Consolas,monospace; font-size:26px; letter-spacing:2px; }.admit-preview > p { margin:16px 0 0; padding:11px; border-radius:7px; color:#7a5a24; background:#fff3dc; font-size:8px; }.toast { position:fixed; right:24px; bottom:24px; z-index:130; min-width:245px; display:flex; align-items:center; gap:11px; padding:13px 15px; border:1px solid #dfe7e3; border-radius:10px; background:#fff; box-shadow:0 17px 50px rgba(18,39,30,.17); opacity:0; transform:translateY(25px); pointer-events:none; transition:.25s; }.toast.show { opacity:1; transform:none; }.toast-icon { width:29px; height:29px; display:grid; place-items:center; border-radius:50%; color:#fff; background:var(--jade); font-size:11px; }.toast div { display:grid; gap:2px; }.toast strong { font-size:9px; }.toast small { color:#858d9e; font-size:8px; }.fatal-error { min-height:100vh; display:grid; place-content:center; justify-items:center; padding:25px; text-align:center; }.fatal-error > span { width:55px; height:55px; display:grid; place-items:center; border-radius:50%; color:#fff; background:var(--red); font-family:Georgia,serif; font-size:28px; }.fatal-error h1 { margin:18px 0 8px; font-family:"STKaiti"; font-size:28px; font-weight:400; }.fatal-error p { margin:0 0 18px; color:#7f8799; font-size:10px; }.empty-state { padding:35px; color:#8b93a4; font-size:9px; text-align:center; } .modal-card:has(.exam-config-form) { width:min(980px,100%); } +.modal-card:has(.notice-editor-form) { width:min(820px,100%); } +.notice-editor-field { display:grid; gap:7px; } +.notice-editor-field > span { color:#555f75; font-size:10px; font-weight:700; } +.notice-editor-field > small { color:#8b94a5; font-size:8px; font-weight:400; } +.notice-editor-form .ck.ck-editor { width:100%; } +.notice-editor-form .ck-editor__editable_inline { min-height:280px; max-height:430px; color:#333d52; font-size:13px; line-height:1.75; } +.notice-editor-form .ck.ck-toolbar { border-color:#dce1ea; border-radius:8px 8px 0 0; background:#f8f9fc; } +.notice-editor-form .ck.ck-editor__main > .ck-editor__editable { border-color:#dce1ea; border-radius:0 0 8px 8px; } +.notice-content figure.image { margin:20px auto; text-align:center; } +.notice-content figure.image img { display:block; width:auto; max-width:100%; height:auto; margin:auto; border-radius:7px; } +.notice-content figure.image.image-style-side { max-width:50%; margin-left:auto; } +.notice-content figure.image.image-style-align-left,.notice-content figure.image.image-style-block-align-left { margin-right:auto; margin-left:0; } +.notice-content figure.image.image-style-align-right,.notice-content figure.image.image-style-block-align-right { margin-right:0; margin-left:auto; } +.notice-content figcaption { margin-top:7px; color:#8a93a5; font-size:9px; line-height:1.6; text-align:center; } +.notice-content figure.table { margin:18px 0; overflow-x:auto; } +.notice-content table { width:100%; border-collapse:collapse; background:#fff; font-size:10px; } +.notice-content th,.notice-content td { min-width:70px; padding:9px 11px; border:1px solid #d8dfeb; color:#525d73; line-height:1.7; text-align:left; vertical-align:top; } +.notice-content th { color:var(--navy); background:#f1f4f9; font-weight:700; } +.notice-content td p,.notice-content th p { margin:0; font-size:inherit; line-height:inherit; } .exam-config-form { gap:18px; } .exam-form-section { display:grid; gap:14px; padding:17px; border:1px solid var(--line); border-radius:11px; background:#fbfcfe; } .exam-form-section > header { display:flex; align-items:center; gap:11px; } diff --git a/tests/system.test.mjs b/tests/system.test.mjs index 8c34591..fab4e51 100644 --- a/tests/system.test.mjs +++ b/tests/system.test.mjs @@ -144,6 +144,11 @@ try { assert.ok(publicHome.data.notices.length >= 3, '公开首页应返回通知'); assert.ok(publicHome.data.exams.some(exam => exam.subjects.length > 1), '公开考试应包含多个科目'); assert.equal(publicHome.data.selfRegistrationEnabled, false, '自主注册默认应关闭'); + const ckeditorAsset = await anonymous.request('/vendor/ckeditor5/ckeditor5.js'); + assert.equal(ckeditorAsset.response.status, 200, '服务端应提供自托管 CKEditor 浏览器包'); + assert.match(ckeditorAsset.data, /ImageInsertViaUrl/, '自托管 CKEditor 应包含图片 URL 插件'); + const ckeditorStyles = await anonymous.request('/vendor/ckeditor5/ckeditor5.css'); + assert.equal(ckeditorStyles.response.status, 200, '服务端应提供自托管 CKEditor 样式'); const closedRegister = await candidate.request('/api/auth/register', { method: 'POST', @@ -605,10 +610,28 @@ try { const earlyDownload = await candidate.request(`/api/candidate/registrations/${futureRegistrationId}/admit-card`); assert.equal(earlyDownload.response.status, 403, '准考证下载窗口开放前必须拒绝下载'); - const publishNotice = await admin.request('/api/admin/notices', { method: 'POST', body: { title: '系统测试成绩发布通知', summary: '测试通知将同步到首页', content: '系统测试考试成绩现已发布。', category: '成绩通知', pinned: true, status: 'published' } }); + const publishNotice = await admin.request('/api/admin/notices', { method: 'POST', body: { + title: '系统测试成绩发布通知', + summary: '', + content: '

成绩发布

系统测试考试成绩现已发布。下载说明

成绩发布横幅
成绩发布说明
科目状态
语文已发布
', + category: '成绩通知', + pinned: true, + status: 'published' + } }); assert.equal(publishNotice.response.status, 201); + assert.match(publishNotice.data.notice.contentHtml, /

成绩发布<\/h2>/, '通知接口应保留 CKEditor 标题格式'); + assert.match(publishNotice.data.notice.contentHtml, /href="https:\/\/files\.example\.com\/results\.pdf"/, '通知接口应保留安全超链接'); + assert.match(publishNotice.data.notice.contentHtml, /rel="noopener noreferrer"/, '外部链接应带安全关系属性'); + assert.match(publishNotice.data.notice.contentHtml, /成绩发布横幅/, '通知接口应保留专用服务器图片链接'); + assert.match(publishNotice.data.notice.contentHtml, /.*
科目<\/th>.*语文<\/td>.*<\/table>/s, '通知接口应保留表格结构'); + assert.doesNotMatch(publishNotice.data.notice.contentHtml, /script|onclick|onerror/i, '通知富文本必须移除脚本和事件属性'); + assert.match(publishNotice.data.notice.summary, /成绩发布/, '首页摘要留空时应从富文本正文提取纯文本'); + const emptyRichNotice = await admin.request('/api/admin/notices', { method: 'POST', body: { title: '空富文本', content: '', status: 'draft' } }); + assert.equal(emptyRichNotice.response.status, 400, '清洗后没有正文的通知必须拒绝保存'); const refreshedHome = await anonymous.request('/api/public/home'); - assert.ok(refreshedHome.data.notices.some(item => item.title === '系统测试成绩发布通知'), '管理员发布通知后首页应可见'); + const publicRichNotice = refreshedHome.data.notices.find(item => item.title === '系统测试成绩发布通知'); + assert.ok(publicRichNotice, '管理员发布通知后首页应可见'); + assert.equal(publicRichNotice.contentHtml, publishNotice.data.notice.contentHtml, '公开接口应返回已清洗的富文本正文'); const stagedResultFile = Buffer.from(await buildWorkbook('results', [{ candidateNumber, examCode: exam.code, subjectName: exam.subjects[0].name, score: 125, grade: 'A', published: '不发布' }])); const stagedPreview = await admin.request('/api/admin/excel/results', { method: 'POST', headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }, body: stagedResultFile });