diff --git a/CHANGELOG.md b/CHANGELOG.md index bd572bcbe7f..ae2ce734cb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 2.2.5 + +### Notable enhancements and fixes + +- Fixed timeslider not scrolling when the revision count is a multiple of 100 +- Added new Restful API for version 2 of Etherpad. It is available at /api-docs + + # 2.2.4 ### Notable enhancements and fixes diff --git a/admin/package.json b/admin/package.json index aea97c9fd51..f0d52d2ac3d 100644 --- a/admin/package.json +++ b/admin/package.json @@ -1,7 +1,7 @@ { "name": "admin", "private": true, - "version": "2.2.4", + "version": "2.2.5", "type": "module", "scripts": { "dev": "vite", @@ -16,25 +16,25 @@ "devDependencies": { "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-toast": "^1.2.1", - "@types/react": "^18.3.5", + "@types/react": "^18.3.8", "@types/react-dom": "^18.2.25", - "@typescript-eslint/eslint-plugin": "^8.4.0", - "@typescript-eslint/parser": "^8.4.0", + "@typescript-eslint/eslint-plugin": "^8.6.0", + "@typescript-eslint/parser": "^8.6.0", "@vitejs/plugin-react-swc": "^3.5.0", - "eslint": "^9.9.1", + "eslint": "^9.10.0", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.11", - "i18next": "^23.14.0", + "eslint-plugin-react-refresh": "^0.4.12", + "i18next": "^23.15.1", "i18next-browser-languagedetector": "^8.0.0", - "lucide-react": "^0.439.0", + "lucide-react": "^0.441.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.53.0", - "react-i18next": "^15.0.1", - "react-router-dom": "^6.26.1", + "react-i18next": "^15.0.2", + "react-router-dom": "^6.26.2", "socket.io-client": "^4.7.5", - "typescript": "^5.5.4", - "vite": "^5.4.3", + "typescript": "^5.6.2", + "vite": "^5.4.7", "vite-plugin-static-copy": "^1.0.6", "vite-plugin-svgr": "^4.2.0", "zustand": "^4.5.5" diff --git a/admin/public/ep_admin_pads/de.json b/admin/public/ep_admin_pads/de.json index afb553caf46..67dd73ddf07 100644 --- a/admin/public/ep_admin_pads/de.json +++ b/admin/public/ep_admin_pads/de.json @@ -14,6 +14,7 @@ "ep_adminpads2_autoupdate.title": "Aktiviert oder deaktiviert automatische Aktualisierungen für die aktuelle Abfrage.", "ep_adminpads2_confirm": "Willst du das Pad {{padID}} wirklich löschen?", "ep_adminpads2_delete.value": "Löschen", + "ep_adminpads2_cleanup": "Historie aufräumen", "ep_adminpads2_last-edited": "Zuletzt bearbeitet", "ep_adminpads2_loading": "Lädt...", "ep_adminpads2_manage-pads": "Pads verwalten", diff --git a/admin/public/ep_admin_pads/en.json b/admin/public/ep_admin_pads/en.json index 8a9044b1b84..76354c6403f 100644 --- a/admin/public/ep_admin_pads/en.json +++ b/admin/public/ep_admin_pads/en.json @@ -4,6 +4,7 @@ "ep_adminpads2_autoupdate.title": "Enables or disables automatic updates for the current query.", "ep_adminpads2_confirm": "Do you really want to delete the pad {{padID}}?", "ep_adminpads2_delete.value": "Delete", + "ep_adminpads2_cleanup": "Cleanup revisions", "ep_adminpads2_last-edited": "Last edited", "ep_adminpads2_loading": "Loading…", "ep_adminpads2_manage-pads": "Manage pads", diff --git a/admin/src/App.tsx b/admin/src/App.tsx index b3238ef9a73..708bd1bfd30 100644 --- a/admin/src/App.tsx +++ b/admin/src/App.tsx @@ -1,4 +1,4 @@ -import {useEffect} from 'react' +import {useEffect, useState} from 'react' import './App.css' import {connect} from 'socket.io-client' import {isJSONClean} from './utils/utils.ts' @@ -6,107 +6,113 @@ import {NavLink, Outlet, useNavigate} from "react-router-dom"; import {useStore} from "./store/store.ts"; import {LoadingScreen} from "./utils/LoadingScreen.tsx"; import {Trans, useTranslation} from "react-i18next"; -import {Cable, Construction, Crown, NotepadText, Wrench, PhoneCall} from "lucide-react"; +import {Cable, Construction, Crown, NotepadText, Wrench, PhoneCall, LucideMenu} from "lucide-react"; -const WS_URL = import.meta.env.DEV? 'http://localhost:9001' : '' -export const App = ()=> { - const setSettings = useStore(state => state.setSettings); - const {t} = useTranslation() - const navigate = useNavigate() +const WS_URL = import.meta.env.DEV ? 'http://localhost:9001' : '' +export const App = () => { + const setSettings = useStore(state => state.setSettings); + const {t} = useTranslation() + const navigate = useNavigate() + const [sidebarOpen, setSidebarOpen] = useState(true) - useEffect(() => { - fetch('/admin-auth/', { - method: 'POST' - }).then((value)=>{ - if(!value.ok){ - navigate('/login') - } - }).catch(()=>{ - navigate('/login') - }) - }, []); + useEffect(() => { + fetch('/admin-auth/', { + method: 'POST' + }).then((value) => { + if (!value.ok) { + navigate('/login') + } + }).catch(() => { + navigate('/login') + }) + }, []); - useEffect(() => { - document.title = t('admin.page-title') + useEffect(() => { + document.title = t('admin.page-title') - useStore.getState().setShowLoading(true); - const settingSocket = connect(`${WS_URL}/settings`, { - transports: ['websocket'], - }); + useStore.getState().setShowLoading(true); + const settingSocket = connect(`${WS_URL}/settings`, { + transports: ['websocket'], + }); - const pluginsSocket = connect(`${WS_URL}/pluginfw/installer`, { - transports: ['websocket'], - }) + const pluginsSocket = connect(`${WS_URL}/pluginfw/installer`, { + transports: ['websocket'], + }) - pluginsSocket.on('connect', () => { - useStore.getState().setPluginsSocket(pluginsSocket); - }); + pluginsSocket.on('connect', () => { + useStore.getState().setPluginsSocket(pluginsSocket); + }); - settingSocket.on('connect', () => { - useStore.getState().setSettingsSocket(settingSocket); - useStore.getState().setShowLoading(false) - settingSocket.emit('load'); - console.log('connected'); - }); + settingSocket.on('connect', () => { + useStore.getState().setSettingsSocket(settingSocket); + useStore.getState().setShowLoading(false) + settingSocket.emit('load'); + console.log('connected'); + }); - settingSocket.on('disconnect', (reason) => { - // The settingSocket.io client will automatically try to reconnect for all reasons other than "io - // server disconnect". - useStore.getState().setShowLoading(true) - if (reason === 'io server disconnect') { - settingSocket.connect(); - } - }); + settingSocket.on('disconnect', (reason) => { + // The settingSocket.io client will automatically try to reconnect for all reasons other than "io + // server disconnect". + useStore.getState().setShowLoading(true) + if (reason === 'io server disconnect') { + settingSocket.connect(); + } + }); - settingSocket.on('settings', (settings) => { - /* Check whether the settings.json is authorized to be viewed */ - if (settings.results === 'NOT_ALLOWED') { - console.log('Not allowed to view settings.json') - return; - } + settingSocket.on('settings', (settings) => { + /* Check whether the settings.json is authorized to be viewed */ + if (settings.results === 'NOT_ALLOWED') { + console.log('Not allowed to view settings.json') + return; + } - /* Check to make sure the JSON is clean before proceeding */ - if (isJSONClean(settings.results)) { - setSettings(settings.results); - } else { - alert('Invalid JSON'); - } - useStore.getState().setShowLoading(false); - }); + /* Check to make sure the JSON is clean before proceeding */ + if (isJSONClean(settings.results)) { + setSettings(settings.results); + } else { + alert('Invalid JSON'); + } + useStore.getState().setShowLoading(false); + }); - settingSocket.on('saveprogress', (status)=>{ - console.log(status) - }) + settingSocket.on('saveprogress', (status) => { + console.log(status) + }) - return () => { - settingSocket.disconnect(); - pluginsSocket.disconnect() - } - }, []); + return () => { + settingSocket.disconnect(); + pluginsSocket.disconnect() + } + }, []); - return
- -
-
- + return
+ +
+
+

Etherpad

-
    -
  • -
  • -
  • -
  • -
  • Communication
  • -
-
-
-
- -
+
    { + setSidebarOpen(false) + }}> +
  • +
  • +
  • +
  • +
  • Communication
  • +
+
+ +
+ +
+
} export default App diff --git a/admin/src/index.css b/admin/src/index.css index 99a406ee70d..acc0d2e970a 100644 --- a/admin/src/index.css +++ b/admin/src/index.css @@ -1,282 +1,298 @@ :root { - --etherpad-color: #0f775b; - --etherpad-comp: #9C8840; - --etherpad-light: #99FF99; + --etherpad-color: #0f775b; + --etherpad-comp: #9C8840; + --etherpad-light: #99FF99; + --sidebar-width: 20em; } @font-face { - font-family: Karla; - src: url(/Karla-Regular.ttf); + font-family: Karla; + src: url(/Karla-Regular.ttf); } html, body, #root { - box-sizing: border-box; - height: 100%; - font-family: "Karla", sans-serif; + box-sizing: border-box; + height: 100%; + font-family: "Karla", sans-serif; } *, *:before, *:after { - box-sizing: inherit; - font-size: 16px; + box-sizing: inherit; + font-size: 16px; } body { - margin: 0; - color: #333; - font: 14px helvetica, sans-serif; - background: #eee; + margin: 0; + color: #333; + font: 14px helvetica, sans-serif; + background: #eee; } div.menu { - height: 100vh; - font-size: 16px; - font-weight: bolder; - display: flex; - align-items: center; - justify-content: center; - max-width: 20%; - min-width: 20%; -} - -.icon-button{ - display: flex; - gap: 10px; - background-color: var(--etherpad-color); - color: white; - border: none; - padding: 10px 20px; - border-radius: 5px; - cursor: pointer; + left: 0; + transition: left .3s; + height: 100vh; + font-size: 16px; + font-weight: bolder; + display: flex; + align-items: center; + justify-content: center; + width: var(--sidebar-width); + z-index: 99; + position: fixed; +} + + +.icon-button { + display: flex; + gap: 10px; + background-color: var(--etherpad-color); + color: white; + border: none; + padding: 10px 20px; + border-radius: 5px; + cursor: pointer; } .icon-button svg { - align-self: center; + align-self: center; } .icon-button span { - align-self: center; + align-self: center; } div.menu span:first-child { - display: flex; - justify-content: center; + display: flex; + justify-content: center; } div.menu span:first-child svg { - margin-right: 10px; - align-self: center; + margin-right: 10px; + align-self: center; } div.menu h1 { - font-size: 50px; - text-align: center; + font-size: 50px; + text-align: center; } .inner-menu { - border-radius: 0 20px 20px 0; - padding: 10px; - flex-grow: 100; - background-color: var(--etherpad-comp); - color: white; - height: 100vh; + border-radius: 0 20px 20px 0; + padding: 10px; + flex-grow: 100; + background-color: var(--etherpad-comp); + color: white; + height: 100vh; } div.menu ul { - color: white; - padding: 0; + color: white; + padding: 0; } div.menu li a { - display: flex; - gap: 10px; - margin-bottom: 20px; + display: flex; + gap: 10px; + margin-bottom: 20px; } div.menu svg { - align-self: center; + align-self: center; } div.menu li { - padding: 10px; - color: white; - list-style: none; - margin-left: 3px; - line-height: 3; + padding: 10px; + color: white; + list-style: none; + margin-left: 3px; + line-height: 3; } div.menu li:has(.active) { - background-color: #9C885C ; + background-color: #9C885C; } div.menu li a { - color: lightgray; + color: lightgray; } - div.innerwrapper { - background-color: #F0F0F0; - overflow: auto; - height: 100vh; - flex-grow: 100; - padding: 20px; + transition: margin-left .3s; + isolation: isolate; + background-color: #F0F0F0; + overflow: auto; + height: 100vh; + flex-grow: 100; + margin-left: var(--sidebar-width); + padding: 20px 20px 20px; } div.innerwrapper-err { - display: none; + display: none; } #wrapper { - display: flex; - background: none repeat scroll 0px 0px #FFFFFF; - box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.2); - min-height: 100%;/*always display a scrollbar*/ - + background: none repeat scroll 0px 0px #FFFFFF; + box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.2); + min-height: 100%; /*always display a scrollbar*/ } h1 { - font-size: 29px; + font-size: 29px; } h2 { - font-size: 24px; + font-size: 24px; } .separator { - margin: 10px 0; - height: 1px; - background: #aaa; - background: -webkit-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff); - background: -moz-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff); - background: -ms-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff); - background: -o-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff); + margin: 10px 0; + height: 1px; + background: #aaa; + background: -webkit-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff); + background: -moz-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff); + background: -ms-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff); + background: -o-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff); } form { - margin-bottom: 0; + margin-bottom: 0; } #inner { - width: 300px; - margin: 0 auto; + width: 300px; + margin: 0 auto; } input { - font-weight: bold; - font-size: 15px; + font-weight: bold; + font-size: 15px; } .sort { - cursor: pointer; + cursor: pointer; } + .sort:after { - content: '▲▼' + content: '▲▼' } + .sort.up:after { - content:'▲' + content: '▲' } + .sort.down:after { - content:'▼' + content: '▼' } #installed-plugins thead tr th:nth-child(3) { - width: 15%; + width: 15%; } table { - border: 1px solid #ddd; - border-radius: 3px; - border-spacing: 0; - width: 100%; - margin: 20px 0; + border: 1px solid #ddd; + border-radius: 3px; + border-spacing: 0; + width: 100%; + margin: 20px 0; } +.table-container { + width: 100%; + overflow: auto; + max-height: 90vh; +} - - -#available-plugins th:first-child, #available-plugins th:nth-child(2){ - text-align: center; +#available-plugins th:first-child, #available-plugins th:nth-child(2) { + text-align: center; } td, th { - padding: 5px; + padding: 5px; } .template { - display: none; + display: none; } -#installed-plugins td>div { - position: relative;/* Allows us to position the loading indicator relative to this row */ - display: inline-block; /*make this fill the whole cell*/ - width:100%; +#installed-plugins td > div { + position: relative; /* Allows us to position the loading indicator relative to this row */ + display: inline-block; /*make this fill the whole cell*/ + width: 100%; } .messages { - height: 5em; + height: 5em; } + .messages * { - display: none; - text-align: center; + display: none; + text-align: center; } + .messages .fetching { - display: block; + display: block; } .progress { - position: absolute; - top: 0; left: 0; bottom:0; right:0; - padding: auto; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + padding: auto; - background: rgb(255,255,255); - display: none; + background: rgb(255, 255, 255); + display: none; } #search-progress.progress { - padding-top: 20%; - background: rgba(255,255,255,0.3); + padding-top: 20%; + background: rgba(255, 255, 255, 0.3); } .progress * { - display: block; - margin: 0 auto; - text-align: center; - color: #666; + display: block; + margin: 0 auto; + text-align: center; + color: #666; } .settings-page { - display: flex; - flex-direction: column; - gap: 20px; - height: 100%; + display: flex; + flex-direction: column; + gap: 20px; + height: 100%; } .settings { - flex-grow: max(1, 1); - outline: none; - width: 100%; - resize: none; - font-family: monospace; + flex-grow: max(1, 1); + outline: none; + width: 100%; + resize: none; + font-family: monospace; } #response { - display: inline; + display: inline; } a:link, a:visited, a:hover, a:focus { - color: #333333; - text-decoration: none; + color: #333333; + text-decoration: none; } a:focus, a:hover { - text-decoration: underline; + text-decoration: underline; } .installed-results a:link, @@ -286,524 +302,565 @@ a:focus, a:hover { .installed-results a:hover, .search-results a:hover, .installed-results a:focus, -.search-results a:focus { - text-decoration: underline; +.search-results a:focus { + text-decoration: underline; } .installed-results a:focus, .search-results a:focus, .installed-results a:hover, .search-results a:hover { - text-decoration: none; + text-decoration: none; } pre { - white-space: pre-wrap; - word-wrap: break-word; + white-space: pre-wrap; + word-wrap: break-word; +} + + +#icon-button { + color: var(--etherpad-color); + top: 10px; + background-color: transparent; + border: none; + z-index: 99; + position: absolute; + left: 10px; +} + + +.inner-menu span:nth-child(2) { + display: flex; + margin-top: 30px; +} + +#wrapper.closed .menu { + left: calc(-1 * var(--sidebar-width)); +} + +#wrapper.closed .innerwrapper { + margin-left: 0; } @media (max-width: 800px) { - div.innerwrapper { - padding: 0 15px 15px 15px; - } - - div.menu { - padding: 1px 15px 0 15px; - position: static; - height: auto; - border-right: none; - width: auto; - float: left; - } - - table { - border: none; - } - - table, thead, tbody, td, tr { - display: block; - } - - thead tr { - display: none; - } - - tr { - border: 1px solid #ccc; - margin-bottom: 5px; - border-radius: 3px; - } - - td { - border: none; - border-bottom: 1px solid #eee; - position: relative; - padding-left: 50%; - white-space: normal; - text-align: left; - } - - td.name { - word-wrap: break-word; - } - - td:before { - position: absolute; - top: 6px; - left: 6px; - text-align: left; - padding-right: 10px; - white-space: nowrap; - font-weight: bold; - content: attr(data-label); - } - - td:last-child { - border-bottom: none; - } - - table input[type="button"] { - float: none; - } + + div.innerwrapper { + margin-left: 0; + } + + .inner-menu { + border-radius: 0; + } + + div.menu { + height: auto; + border-right: none; + --sidebar-width: 100%; + float: left; + } + + table { + border: none; + } + + table, thead, tbody, td, tr { + display: block; + } + + thead tr { + display: none; + } + + tr { + border: 1px solid #ccc; + margin-bottom: 5px; + border-radius: 3px; + } + + td { + border: none; + border-bottom: 1px solid #eee; + position: relative; + padding-left: 50%; + white-space: normal; + text-align: left; + } + + td.name { + word-wrap: break-word; + } + + td:before { + position: absolute; + top: 6px; + left: 6px; + text-align: left; + padding-right: 10px; + white-space: nowrap; + font-weight: bold; + content: attr(data-label); + } + + td:last-child { + border-bottom: none; + } + + table input[type="button"] { + float: none; + } } .settings-button-bar { - margin-top: 10px; - display: flex; - gap: 10px; + margin-top: 10px; + display: flex; + gap: 10px; } .login-background { - background-image: url("/fond.jpg"); - background-repeat: no-repeat; - background-size: cover; - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - background-color: #f0f0f0; + background-image: url("/fond.jpg"); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background-color: #f0f0f0; } .login-inner-box div { - margin-top: 1rem; + margin-top: 1rem; } -.login-inner-box [type=submit]{ - margin-top: 2rem; +.login-inner-box [type=submit] { + margin-top: 2rem; } - .login-textinput { - width: 100%; - padding: 10px; - background-color: #fffacc; - border-radius: 5px; - border: 1px solid #ccc; - margin-bottom: 10px; + width: 100%; + padding: 10px; + background-color: #fffacc; + border-radius: 5px; + border: 1px solid #ccc; + margin-bottom: 10px; } .login-box { - width: 20%; - padding: 20px; - border-radius: 40px; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - background-color: #fff; + padding: 20px; + border-radius: 40px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + background-color: #fff; } -.login-inner-box{ - position: relative; - padding: 20px; + +@media (max-width: 900px) { + .login-box { + width: 90% + } +} + +.login-inner-box { + position: relative; + padding: 20px; } .login-title { - padding: 0; - margin: 0; - text-align: center; - color: var(--etherpad-color); - font-size: 4rem; - font-weight: 1000; + padding: 0; + margin: 0; + text-align: center; + color: var(--etherpad-color); + font-size: 4rem; + font-weight: 1000; } .login-button { - padding: 10px; - background-color: var(--etherpad-color); - color: white; - border: none; - border-radius: 5px; - cursor: pointer; - width: 100%; - height: 40px; + padding: 10px; + background-color: var(--etherpad-color); + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + width: 100%; + height: 40px; } .dialog-overlay { - position: fixed; - inset: 0; - background-color: white; - z-index: 100; + position: fixed; + inset: 0; + background-color: white; + z-index: 100; } .dialog-confirm-overlay { - position: fixed; - inset: 0; - background-color: rgba(0, 0, 0, 0.5); - z-index: 100; + position: fixed; + inset: 0; + background-color: rgba(0, 0, 0, 0.5); + z-index: 100; } .dialog-confirm-content { - position: fixed; - top: 50%; - left: 50%; - background-color: white; - transform: translate(-50%, -50%); - padding: 20px; - z-index: 101; + position: fixed; + top: 50%; + left: 50%; + background-color: white; + transform: translate(-50%, -50%); + padding: 20px; + z-index: 101; } .dialog-content { - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - padding: 20px; - z-index: 101; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + padding: 20px; + z-index: 101; } .dialog-title { - color: var(--etherpad-color); - font-size: 2em; - margin-bottom: 20px; + color: var(--etherpad-color); + font-size: 2em; + margin-bottom: 20px; } - .ToastViewport { - position: fixed; - top: 10px; - right: 20px; - display: flex; - flex-direction: column; - gap: 10px; - width: 390px; - max-width: 100vw; - margin: 0; - list-style: none; - z-index: 2147483647; - outline: none; + position: fixed; + top: 10px; + right: 20px; + display: flex; + flex-direction: column; + gap: 10px; + width: 390px; + max-width: 100vw; + margin: 0; + list-style: none; + z-index: 2147483647; + outline: none; } .ToastRootSuccess { - background-color: lawngreen; + background-color: lawngreen; } .ToastRootFailure { - background-color: red; + background-color: red; } .ToastRootFailure > .ToastTitle { - color: white; + color: white; } .ToastRoot { - border-radius: 20px; - box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px; - padding: 15px; - display: grid; - grid-template-areas: 'title action' 'description action'; - grid-template-columns: auto max-content; - column-gap: 15px; - align-items: center; + border-radius: 20px; + box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px; + padding: 15px; + display: grid; + grid-template-areas: 'title action' 'description action'; + grid-template-columns: auto max-content; + column-gap: 15px; + align-items: center; } + .ToastRoot[data-state='open'] { - animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1); + animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1); } + .ToastRoot[data-state='closed'] { - animation: hide 100ms ease-in; + animation: hide 100ms ease-in; } + .ToastRoot[data-swipe='move'] { - transform: translateX(var(--radix-toast-swipe-move-x)); + transform: translateX(var(--radix-toast-swipe-move-x)); } + .ToastRoot[data-swipe='cancel'] { - transform: translateX(0); - transition: transform 200ms ease-out; + transform: translateX(0); + transition: transform 200ms ease-out; } + .ToastRoot[data-swipe='end'] { - animation: swipeOut 100ms ease-out; + animation: swipeOut 100ms ease-out; } @keyframes hide { - from { - opacity: 1; - } - to { - opacity: 0; - } + from { + opacity: 1; + } + to { + opacity: 0; + } } @keyframes slideIn { - from { - transform: translateX(calc(100% + var(--viewport-padding))); - } - to { - transform: translateX(0); - } + from { + transform: translateX(calc(100% + var(--viewport-padding))); + } + to { + transform: translateX(0); + } } @keyframes swipeOut { - from { - transform: translateX(var(--radix-toast-swipe-end-x)); - } - to { - transform: translateX(calc(100% + var(--viewport-padding))); - } + from { + transform: translateX(var(--radix-toast-swipe-end-x)); + } + to { + transform: translateX(calc(100% + var(--viewport-padding))); + } } .ToastTitle { - grid-area: title; - margin-bottom: 5px; - font-weight: 500; - color: var(--slate-12); - padding: 10px; - font-size: 15px; + grid-area: title; + margin-bottom: 5px; + font-weight: 500; + color: var(--slate-12); + padding: 10px; + font-size: 15px; } .ToastDescription { - grid-area: description; - margin: 0; - color: var(--slate-11); - font-size: 13px; - line-height: 1.3; + grid-area: description; + margin: 0; + color: var(--slate-11); + font-size: 13px; + line-height: 1.3; } .ToastAction { - grid-area: action; + grid-area: action; } .help-block { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 20px + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 20px } .search-field { - position: relative; + position: relative; } .search-field input { - border-color: transparent; - border-radius: 20px; - height: 2.5rem; - width: 100vh; - padding: 5px 5px 5px 30px; + border-color: transparent; + border-radius: 20px; + height: 2.5rem; + width: 100%; + padding: 5px 5px 5px 30px; } .search-field input:focus { - outline: none; + outline: none; } .send-message { - position: relative; + position: relative; } .send-message input { - width: auto; + width: auto; } .send-message { } .send-message svg { - position: absolute; - right: 3px; - bottom: -3px; - left: auto !important; + position: absolute; + right: 3px; + bottom: -3px; + left: auto !important; } .search-field svg { - position: absolute; - left: 3px; - bottom: -3px; + position: absolute; + left: 3px; + bottom: -3px; } .search-field svg { - color: gray + color: gray } table { - margin: 25px 0; - font-size: 0.9em; - font-family: sans-serif; - min-width: 400px; - box-shadow: 0 0 20px rgba(0, 0, 0, 0.15); + margin: 25px 0; + font-size: 0.9em; + font-family: sans-serif; + min-width: 400px; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.15); } th:first-child { - border-top-left-radius: 10px; + border-top-left-radius: 10px; } th:last-child { - border-top-right-radius: 10px; + border-top-right-radius: 10px; } table thead tr { - font-size: 25px; - background-color: var(--etherpad-color); - color: #ffffff; - text-align: left; + font-size: 25px; + background-color: var(--etherpad-color); + color: #ffffff; + text-align: left; } table tbody tr { - border-bottom: 1px solid #dddddd; + border-bottom: 1px solid #dddddd; } table tr:nth-child(even) td { - background-color: lightgray; + background-color: lightgray; } table tr td { - padding: 12px 15px; + padding: 12px 15px; } table tbody tr:nth-of-type(even) { - background-color: #f3f3f3; + background-color: #f3f3f3; } table tbody tr:last-of-type { - border-bottom: 2px solid #009879; + border-bottom: 2px solid #009879; } table tbody tr.active-row { - font-weight: bold; - color: #009879; + font-weight: bold; + color: #009879; } -.pad-pagination{ - display: flex; - justify-content: center; - gap: 10px; - margin-top: 20px; +.pad-pagination { + display: flex; + justify-content: center; + gap: 10px; + margin-top: 20px; } .pad-pagination button { - display: flex; - padding: 10px 20px; - border-radius: 5px; - border: none; - color: black; - cursor: pointer; + display: flex; + padding: 10px 20px; + border-radius: 5px; + border: none; + color: black; + cursor: pointer; } .pad-pagination button:disabled { - background: transparent; - color: lightgrey; - cursor: not-allowed; + background: transparent; + color: lightgrey; + cursor: not-allowed; } .pad-pagination span { - align-self: center; + align-self: center; } -.pad-pagination >span { - font-size: 20px; +.pad-pagination > span { + font-size: 20px; } .login-page .login-form .input-control input[type=text], .login-page .login-form .input-control input[type=email], .login-page .login-form .input-control input[type=password], .login-page .signup-form .input-control input[type=text], .login-page .signup-form .input-control input[type=email], .login-page .signup-form .input-control input[type=password], .login-page .forgot-form .input-control input[type=text], .login-page .forgot-form .input-control input[type=email], .login-page .forgot-form .input-control input[type=password] { - width: 100%; - padding: 12px 20px; - margin: 8px 0; - display: inline-block; - border-bottom: 2px solid #ccc; - border-top: 0; - border-left: 0; - border-right: 0; - -webkit-box-sizing: border-box; - box-sizing: border-box; - border-radius: 5px; - font-size: 14px; - color: #666; - background-color: #f8f8f8; - -webkit-transition: all 0.3s ease-in-out; - transition: all 0.3s ease-in-out; + width: 100%; + padding: 12px 20px; + margin: 8px 0; + display: inline-block; + border-bottom: 2px solid #ccc; + border-top: 0; + border-left: 0; + border-right: 0; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border-radius: 5px; + font-size: 14px; + color: #666; + background-color: #f8f8f8; + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; } input, button, select, optgroup, textarea { - margin: 0; - font-family: inherit; - font-size: inherit; - line-height: inherit; + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; } .icon-input { - position: relative; + position: relative; } .icon-input svg { - position: absolute; - top: 50%; - transform: translateY(-50%); - right: 10px; - color: #666; + position: absolute; + top: 50%; + transform: translateY(-50%); + right: 10px; + color: #666; } .SwitchRoot { - align-self: center; - width: 60px; - height: 30px; - background-color: black; - border-radius: 9999px; - position: relative; - box-shadow: 0 2px 10px var(--black-a7); - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + align-self: center; + width: 60px; + height: 30px; + background-color: black; + border-radius: 9999px; + position: relative; + box-shadow: 0 2px 10px var(--black-a7); + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } + .SwitchRoot:focus { - box-shadow: 0 0 0 2px black; + box-shadow: 0 0 0 2px black; } + .SwitchRoot[data-state='checked'] { - background-color: var(--etherpad-color); + background-color: var(--etherpad-color); } .SwitchThumb { - display: block; - width: 20px; - height: 20px; - background-color: white; - border-radius: 9999px; - box-shadow: 0 2px 2px var(--black-a7); - transition: transform 100ms; - transform: translateX(2px); - will-change: transform; + display: block; + width: 20px; + height: 20px; + background-color: white; + border-radius: 9999px; + box-shadow: 0 2px 2px var(--black-a7); + transition: transform 100ms; + transform: translateX(2px); + will-change: transform; } + .SwitchThumb[data-state='checked'] { - transform: translateX(25px); + transform: translateX(25px); } .Label { - color: white; - font-size: 15px; - line-height: 1; + color: white; + font-size: 15px; + line-height: 1; } .message { - position: relative; - padding: 10px; - border: 1px solid #e0e0e0; - margin: 10px 20px 10px 10px; - border-radius: 10px 0 10px 10px; - background-color: var(--etherpad-color); - color: white + position: relative; + padding: 10px; + border: 1px solid #e0e0e0; + margin: 10px 20px 10px 10px; + border-radius: 10px 0 10px 10px; + background-color: var(--etherpad-color); + color: white } -.search-pads{ +.search-pads { text-align: center; } diff --git a/admin/src/pages/HomePage.tsx b/admin/src/pages/HomePage.tsx index c0d5913eefa..589e40e5e65 100644 --- a/admin/src/pages/HomePage.tsx +++ b/admin/src/pages/HomePage.tsx @@ -193,6 +193,7 @@ export const HomePage = () => {

{setSearchTerm(v.target.value)}} placeholder={t('admin_plugins.available_search.placeholder')} value={searchTerm}/> +
@@ -240,5 +241,6 @@ export const HomePage = () => { }
+
} diff --git a/admin/src/pages/PadPage.tsx b/admin/src/pages/PadPage.tsx index e663603cdd9..b5db854f567 100644 --- a/admin/src/pages/PadPage.tsx +++ b/admin/src/pages/PadPage.tsx @@ -6,7 +6,7 @@ import {useDebounce} from "../utils/useDebounce.ts"; import {determineSorting} from "../utils/sorting.ts"; import * as Dialog from "@radix-ui/react-dialog"; import {IconButton} from "../components/IconButton.tsx"; -import {ChevronLeft, ChevronRight, Eye, Trash2} from "lucide-react"; +import {ChevronLeft, ChevronRight, Eye, Trash2, FileStack} from "lucide-react"; import {SearchField} from "../components/SearchField.tsx"; export const PadPage = ()=>{ @@ -23,6 +23,7 @@ export const PadPage = ()=>{ const pads = useStore(state=>state.pads) const [currentPage, setCurrentPage] = useState(0) const [deleteDialog, setDeleteDialog] = useState(false) + const [errorText, setErrorText] = useState(null) const [padToDelete, setPadToDelete] = useState('') const pages = useMemo(()=>{ if(!pads){ @@ -68,12 +69,35 @@ export const PadPage = ()=>{ results: newPads }) }) + + settingsSocket.on('results:cleanupPadRevisions', (data)=>{ + let newPads = useStore.getState().pads?.results ?? [] + + if (data.error) { + setErrorText(data.error) + return + } + + newPads.forEach((pad)=>{ + if (pad.padName === data.padId) { + pad.revisionNumber = data.keepRevisions + } + }) + + useStore.getState().setPads({ + results: newPads, + total: useStore.getState().pads!.total + }) + }) }, [settingsSocket, pads]); const deletePad = (padID: string)=>{ settingsSocket?.emit('deletePad', padID) } + const cleanupPad = (padID: string)=>{ + settingsSocket?.emit('cleanupPadRevisions', padID) + } return
@@ -100,6 +124,21 @@ export const PadPage = ()=>{ + + + + +
+
Error occured: {errorText}
+
+ +
+
+
+
+

setSearchTerm(v.target.value)} placeholder={t('ep_admin_pads:ep_adminpads2_search-heading')}/> @@ -150,6 +189,9 @@ export const PadPage = ()=>{ setPadToDelete(pad.padName) setDeleteDialog(true) }}/> + } title={} onClick={()=>{ + cleanupPad(pad.padName) + }}/> } title="view" onClick={()=>window.open(`/p/${pad.padName}`, '_blank')}/> diff --git a/bin/make_docs.ts b/bin/make_docs.ts index d414822dd6f..d4abfc97df5 100644 --- a/bin/make_docs.ts +++ b/bin/make_docs.ts @@ -57,7 +57,7 @@ createDirIfNotExists('../out/doc/api') -exec(`asciidoctor -D ../out/doc ../doc/index.adoc */**.adoc -a VERSION=${VERSION}`) +exec(`asciidoctor -D ../out/doc ../doc/index.adoc ../*/**.adoc -a VERSION=${VERSION}`) exec(`asciidoctor -D ../out/doc/api ../doc/api/*.adoc -a VERSION=${VERSION}`) copyFolderSync('../doc/public/', '../out/doc/') diff --git a/bin/package.json b/bin/package.json index acea680ffea..347901819a5 100644 --- a/bin/package.json +++ b/bin/package.json @@ -1,6 +1,6 @@ { "name": "bin", - "version": "2.2.4", + "version": "2.2.5", "description": "", "main": "checkAllPads.js", "directories": { @@ -11,13 +11,13 @@ "ep_etherpad-lite": "workspace:../src", "log4js": "^6.9.1", "semver": "^7.6.3", - "tsx": "^4.19.0", - "ueberdb2": "^4.2.103" + "tsx": "^4.19.1", + "ueberdb2": "^5.0.2" }, "devDependencies": { - "@types/node": "^22.5.4", + "@types/node": "^22.5.5", "@types/semver": "^7.5.8", - "typescript": "^5.5.4" + "typescript": "^5.6.2" }, "scripts": { "makeDocs": "node --import tsx make_docs.ts", diff --git a/doc/.vitepress/config.mts b/doc/.vitepress/config.mts index 170f2189832..c96fa3bd363 100644 --- a/doc/.vitepress/config.mts +++ b/doc/.vitepress/config.mts @@ -32,6 +32,7 @@ export default defineConfig({ { text: 'Stats', link: '/stats.md' }, {text: 'Skins', link: '/skins.md' }, {text: 'Demo', link: '/demo.md' }, + {text: 'CLI', link: '/cli.md'}, ] }, { diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 62b9bc56366..b8c01f26325 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -58,7 +58,7 @@ services: # ports: # - "5432:5432" volumes: - - postgres_data:/var/lib/postgresql/data/pgdata + - postgres_data:/var/lib/postgresql/data volumes: - postgres_data: \ No newline at end of file + postgres_data: diff --git a/docker-compose.yml b/docker-compose.yml index 24a726164b0..f0620918cf5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,7 +42,7 @@ services: # ports: # - "5432:5432" volumes: - - postgres_data:/var/lib/postgresql/data/pgdata + - postgres_data:/var/lib/postgresql/data volumes: postgres_data: diff --git a/package.json b/package.json index d46816f0bb7..d4e94f017f5 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,6 @@ "type": "git", "url": "https://github.com/ether/etherpad-lite.git" }, - "version": "2.2.4", + "version": "2.2.5", "license": "Apache-2.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 17eff3bd8e9..421cb977ab5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,47 +26,47 @@ importers: dependencies: '@radix-ui/react-switch': specifier: ^1.1.0 - version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) devDependencies: '@radix-ui/react-dialog': specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-toast': specifier: ^1.2.1 - version: 1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/react': - specifier: ^18.3.5 - version: 18.3.5 + specifier: ^18.3.8 + version: 18.3.8 '@types/react-dom': specifier: ^18.2.25 version: 18.3.0 '@typescript-eslint/eslint-plugin': - specifier: ^8.4.0 - version: 8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4) + specifier: ^8.6.0 + version: 8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2) '@typescript-eslint/parser': - specifier: ^8.4.0 - version: 8.4.0(eslint@9.9.1)(typescript@5.5.4) + specifier: ^8.6.0 + version: 8.6.0(eslint@9.10.0)(typescript@5.6.2) '@vitejs/plugin-react-swc': specifier: ^3.5.0 - version: 3.7.0(vite@5.4.3(@types/node@22.5.4)) + version: 3.7.0(vite@5.4.7(@types/node@22.5.5)) eslint: - specifier: ^9.9.1 - version: 9.9.1 + specifier: ^9.10.0 + version: 9.10.0 eslint-plugin-react-hooks: specifier: ^4.6.0 - version: 4.6.2(eslint@9.9.1) + version: 4.6.2(eslint@9.10.0) eslint-plugin-react-refresh: - specifier: ^0.4.11 - version: 0.4.11(eslint@9.9.1) + specifier: ^0.4.12 + version: 0.4.12(eslint@9.10.0) i18next: - specifier: ^23.14.0 - version: 23.14.0 + specifier: ^23.15.1 + version: 23.15.1 i18next-browser-languagedetector: specifier: ^8.0.0 version: 8.0.0 lucide-react: - specifier: ^0.439.0 - version: 0.439.0(react@18.3.1) + specifier: ^0.441.0 + version: 0.441.0(react@18.3.1) react: specifier: ^18.2.0 version: 18.3.1 @@ -77,29 +77,29 @@ importers: specifier: ^7.53.0 version: 7.53.0(react@18.3.1) react-i18next: - specifier: ^15.0.1 - version: 15.0.1(i18next@23.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^15.0.2 + version: 15.0.2(i18next@23.15.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-router-dom: - specifier: ^6.26.1 - version: 6.26.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^6.26.2 + version: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) socket.io-client: specifier: ^4.7.5 version: 4.7.5 typescript: - specifier: ^5.5.4 - version: 5.5.4 + specifier: ^5.6.2 + version: 5.6.2 vite: - specifier: ^5.4.3 - version: 5.4.3(@types/node@22.5.4) + specifier: ^5.4.7 + version: 5.4.7(@types/node@22.5.5) vite-plugin-static-copy: specifier: ^1.0.6 - version: 1.0.6(vite@5.4.3(@types/node@22.5.4)) + version: 1.0.6(vite@5.4.7(@types/node@22.5.5)) vite-plugin-svgr: specifier: ^4.2.0 - version: 4.2.0(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.3(@types/node@22.5.4)) + version: 4.2.0(rollup@4.21.0)(typescript@5.6.2)(vite@5.4.7(@types/node@22.5.5)) zustand: specifier: ^4.5.5 - version: 4.5.5(@types/react@18.3.5)(react@18.3.1) + version: 4.5.5(@types/react@18.3.8)(react@18.3.1) bin: dependencies: @@ -116,27 +116,27 @@ importers: specifier: ^7.6.3 version: 7.6.3 tsx: - specifier: ^4.19.0 - version: 4.19.0 + specifier: ^4.19.1 + version: 4.19.1 ueberdb2: - specifier: ^4.2.103 - version: 4.2.103 + specifier: ^5.0.2 + version: 5.0.2 devDependencies: '@types/node': - specifier: ^22.5.4 - version: 22.5.4 + specifier: ^22.5.5 + version: 22.5.5 '@types/semver': specifier: ^7.5.8 version: 7.5.8 typescript: - specifier: ^5.5.4 - version: 5.5.4 + specifier: ^5.6.2 + version: 5.6.2 doc: devDependencies: vitepress: specifier: ^1.3.4 - version: 1.3.4(@algolia/client-search@4.23.3)(@types/node@22.5.4)(@types/react@18.3.5)(axios@1.7.7)(postcss@8.4.45)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) + version: 1.3.4(@algolia/client-search@4.23.3)(@types/node@22.5.5)(@types/react@18.3.8)(axios@1.7.7)(postcss@8.4.45)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) src: dependencies: @@ -165,11 +165,11 @@ importers: specifier: ^0.23.1 version: 0.23.1 express: - specifier: 4.19.2 - version: 4.19.2 + specifier: 4.21.0 + version: 4.21.0 express-rate-limit: specifier: ^7.4.0 - version: 7.4.0(express@4.19.2) + version: 7.4.0(express@4.21.0) fast-deep-equal: specifier: ^3.1.3 version: 3.1.3 @@ -183,8 +183,8 @@ importers: specifier: ^2.0.0 version: 2.0.0 jose: - specifier: ^5.8.0 - version: 5.8.0 + specifier: ^5.9.2 + version: 5.9.2 js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -222,8 +222,8 @@ importers: specifier: ^8.5.1 version: 8.5.1 openapi-backend: - specifier: ^5.10.6 - version: 5.10.6 + specifier: ^5.11.0 + version: 5.11.0 proxy-addr: specifier: ^2.0.7 version: 2.0.7 @@ -234,14 +234,14 @@ importers: specifier: ^13.0.1 version: 13.0.1 rehype-minify-whitespace: - specifier: ^6.0.0 - version: 6.0.0 + specifier: ^6.0.1 + version: 6.0.1 resolve: specifier: 1.22.8 version: 1.22.8 rusty-store-kv: - specifier: ^1.2.0 - version: 1.2.0 + specifier: ^1.3.1 + version: 1.3.1 security: specifier: 1.0.0 version: 1.0.0 @@ -257,15 +257,18 @@ importers: superagent: specifier: 10.1.0 version: 10.1.0 + swagger-ui-express: + specifier: ^5.0.1 + version: 5.0.1(express@4.21.0) tinycon: specifier: 0.6.8 version: 0.6.8 tsx: - specifier: 4.19.0 - version: 4.19.0 + specifier: 4.19.1 + version: 4.19.1 ueberdb2: - specifier: ^4.2.103 - version: 4.2.103 + specifier: ^5.0.2 + version: 5.0.2 underscore: specifier: 1.13.7 version: 1.13.7 @@ -277,8 +280,8 @@ importers: version: 0.9.3 devDependencies: '@playwright/test': - specifier: ^1.47.0 - version: 1.47.0 + specifier: ^1.47.1 + version: 1.47.1 '@types/async': specifier: ^3.2.24 version: 3.2.24 @@ -301,17 +304,17 @@ importers: specifier: ^21.1.7 version: 21.1.7 '@types/jsonwebtoken': - specifier: ^9.0.6 - version: 9.0.6 + specifier: ^9.0.7 + version: 9.0.7 '@types/mime-types': specifier: ^2.1.4 version: 2.1.4 '@types/mocha': - specifier: ^10.0.7 - version: 10.0.7 + specifier: ^10.0.8 + version: 10.0.8 '@types/node': - specifier: ^22.5.4 - version: 22.5.4 + specifier: ^22.5.5 + version: 22.5.5 '@types/oidc-provider': specifier: ^8.5.2 version: 8.5.2 @@ -324,18 +327,24 @@ importers: '@types/supertest': specifier: ^6.0.2 version: 6.0.2 + '@types/swagger-ui-express': + specifier: ^4.1.6 + version: 4.1.6 '@types/underscore': specifier: ^1.11.15 version: 1.11.15 + '@types/whatwg-mimetype': + specifier: ^3.0.2 + version: 3.0.2 chokidar: - specifier: ^3.6.0 - version: 3.6.0 + specifier: ^4.0.0 + version: 4.0.0 eslint: - specifier: ^9.9.1 - version: 9.9.1 + specifier: ^9.10.0 + version: 9.10.0 eslint-config-etherpad: specifier: ^4.0.4 - version: 4.0.4(eslint@9.9.1)(typescript@5.5.4) + version: 4.0.4(eslint@9.10.0)(typescript@5.6.2) etherpad-cli-client: specifier: ^3.0.2 version: 3.0.2 @@ -355,8 +364,8 @@ importers: specifier: ^2.7.0 version: 2.7.0 sinon: - specifier: ^18.0.0 - version: 18.0.0 + specifier: ^19.0.2 + version: 19.0.2 split-grid: specifier: ^1.0.11 version: 1.0.11 @@ -364,11 +373,11 @@ importers: specifier: ^7.0.0 version: 7.0.0 typescript: - specifier: ^5.5.4 - version: 5.5.4 + specifier: ^5.6.2 + version: 5.6.2 vitest: - specifier: ^2.0.5 - version: 2.0.5(@types/node@22.5.4)(jsdom@25.0.0) + specifier: ^2.1.1 + version: 2.1.1(@types/node@22.5.5)(jsdom@25.0.0) ui: devDependencies: @@ -376,11 +385,11 @@ importers: specifier: workspace:../src version: link:../src typescript: - specifier: ^5.5.4 - version: 5.5.4 + specifier: ^5.6.2 + version: 5.6.2 vite: - specifier: ^5.4.3 - version: 5.4.3(@types/node@22.5.4) + specifier: ^5.4.7 + version: 5.4.7(@types/node@22.5.5) packages: @@ -540,6 +549,10 @@ packages: resolution: {integrity: sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.25.6': + resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==} + engines: {node: '>=6.9.0'} + '@babel/template@7.24.7': resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} engines: {node: '>=6.9.0'} @@ -875,14 +888,18 @@ packages: resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.9.1': - resolution: {integrity: sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==} + '@eslint/js@9.10.0': + resolution: {integrity: sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.4': resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/plugin-kit@0.1.0': + resolution: {integrity: sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@etherpad/express-session@1.18.4': resolution: {integrity: sha512-uiUtcfv0hyEA+Lur00V6yINaa/qe09HiFqmc+DzSXYChILFLgOV3G4p4XJkIRrUOGmqaJRiliB1BoQIiY3Tnjw==} engines: {node: '>= 0.8.0'} @@ -907,8 +924,8 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -923,6 +940,7 @@ packages: '@koa/router@12.0.1': resolution: {integrity: sha512-ribfPYfHb+Uw3b27Eiw6NPqjhIhTpVFzEWLwyc/1Xp+DCdwRRyIlAUODX+9bPARF6aQtUu1+/PHzdNvRzcs/+Q==} engines: {node: '>= 12'} + deprecated: Use v12.0.2 or higher to fix the vulnerability issue '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -936,8 +954,8 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@playwright/test@1.47.0': - resolution: {integrity: sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA==} + '@playwright/test@1.47.1': + resolution: {integrity: sha512-dbWpcNQZ5nj16m+A5UNScYx7HX5trIy7g4phrcitn+Nk83S32EBX/CLU4hiF4RGKX/yRc93AAqtfaXB7JWBd4Q==} engines: {node: '>=18'} hasBin: true @@ -1173,8 +1191,8 @@ packages: '@types/react-dom': optional: true - '@remix-run/router@1.19.1': - resolution: {integrity: sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==} + '@remix-run/router@1.19.2': + resolution: {integrity: sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==} engines: {node: '>=14.0.0'} '@rollup/pluginutils@5.1.0': @@ -1279,20 +1297,17 @@ packages: resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} engines: {node: '>=14.16'} - '@sinonjs/commons@2.0.0': - resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} - '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - '@sinonjs/fake-timers@11.2.2': - resolution: {integrity: sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==} + '@sinonjs/fake-timers@13.0.2': + resolution: {integrity: sha512-4Bb+oqXZTSTZ1q27Izly9lv8B9dlV61CROxPiVtywwzv5SnytJqhvYe6FclHYuXml4cd1VHPo1zd5PmTeJozvA==} - '@sinonjs/samsam@8.0.0': - resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==} + '@sinonjs/samsam@8.0.2': + resolution: {integrity: sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==} - '@sinonjs/text-encoding@0.7.2': - resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==} + '@sinonjs/text-encoding@0.7.3': + resolution: {integrity: sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==} '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} @@ -1519,8 +1534,8 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/jsonwebtoken@9.0.6': - resolution: {integrity: sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==} + '@types/jsonwebtoken@9.0.7': + resolution: {integrity: sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==} '@types/keygrip@1.0.6': resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} @@ -1555,8 +1570,8 @@ packages: '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - '@types/mocha@10.0.7': - resolution: {integrity: sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==} + '@types/mocha@10.0.8': + resolution: {integrity: sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw==} '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} @@ -1564,8 +1579,8 @@ packages: '@types/node-fetch@2.6.11': resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} - '@types/node@22.5.4': - resolution: {integrity: sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==} + '@types/node@22.5.5': + resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==} '@types/oidc-provider@8.5.2': resolution: {integrity: sha512-NiD3VG49+cRCAAe8+uZLM4onOcX8y9+cwaml8JG1qlgc98rWoCRgsnOB4Ypx+ysays5jiwzfUgT0nWyXPB/9uQ==} @@ -1582,8 +1597,8 @@ packages: '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} - '@types/react@18.3.5': - resolution: {integrity: sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==} + '@types/react@18.3.8': + resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -1609,6 +1624,9 @@ packages: '@types/supertest@6.0.2': resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==} + '@types/swagger-ui-express@4.1.6': + resolution: {integrity: sha512-UVSiGYXa5IzdJJG3hrc86e8KdZWLYxyEsVoUI4iPXc7CO4VZ3AfNP8d/8+hrDRIqz+HAaSMtZSqAsF3Nq2X/Dg==} + '@types/tar@6.1.13': resolution: {integrity: sha512-IznnlmU5f4WcGTh2ltRu/Ijpmk8wiWXfF0VA4s+HPjHZgvFggk1YaIkbo5krX/zUCzWF8N/l4+W/LNxnvAJ8nw==} @@ -1627,6 +1645,9 @@ packages: '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + '@typescript-eslint/eslint-plugin@7.17.0': resolution: {integrity: sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==} engines: {node: ^18.18.0 || >=20.0.0} @@ -1638,8 +1659,8 @@ packages: typescript: optional: true - '@typescript-eslint/eslint-plugin@8.4.0': - resolution: {integrity: sha512-rg8LGdv7ri3oAlenMACk9e+AR4wUV0yrrG+XKsGKOK0EVgeEDqurkXMPILG2836fW4ibokTB5v4b6Z9+GYQDEw==} + '@typescript-eslint/eslint-plugin@8.6.0': + resolution: {integrity: sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -1659,8 +1680,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@8.4.0': - resolution: {integrity: sha512-NHgWmKSgJk5K9N16GIhQ4jSobBoJwrmURaLErad0qlLjrpP5bECYg+wxVTGlGZmJbU03jj/dfnb6V9bw+5icsA==} + '@typescript-eslint/parser@8.6.0': + resolution: {integrity: sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1673,8 +1694,8 @@ packages: resolution: {integrity: sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/scope-manager@8.4.0': - resolution: {integrity: sha512-n2jFxLeY0JmKfUqy3P70rs6vdoPjHK8P/w+zJcV3fk0b0BwRXC/zxRTEnAsgYT7MwdQDt/ZEbtdzdVC+hcpF0A==} + '@typescript-eslint/scope-manager@8.6.0': + resolution: {integrity: sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/type-utils@7.17.0': @@ -1687,8 +1708,8 @@ packages: typescript: optional: true - '@typescript-eslint/type-utils@8.4.0': - resolution: {integrity: sha512-pu2PAmNrl9KX6TtirVOrbLPLwDmASpZhK/XU7WvoKoCUkdtq9zF7qQ7gna0GBZFN0hci0vHaSusiL2WpsQk37A==} + '@typescript-eslint/type-utils@8.6.0': + resolution: {integrity: sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -1700,8 +1721,8 @@ packages: resolution: {integrity: sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/types@8.4.0': - resolution: {integrity: sha512-T1RB3KQdskh9t3v/qv7niK6P8yvn7ja1mS7QK7XfRVL6wtZ8/mFs/FHf4fKvTA0rKnqnYxl/uHFNbnEt0phgbw==} + '@typescript-eslint/types@8.6.0': + resolution: {integrity: sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@7.17.0': @@ -1713,8 +1734,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@8.4.0': - resolution: {integrity: sha512-kJ2OIP4dQw5gdI4uXsaxUZHRwWAGpREJ9Zq6D5L0BweyOrWsL6Sz0YcAZGWhvKnH7fm1J5YFE1JrQL0c9dd53A==} + '@typescript-eslint/typescript-estree@8.6.0': + resolution: {integrity: sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -1728,8 +1749,8 @@ packages: peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/utils@8.4.0': - resolution: {integrity: sha512-swULW8n1IKLjRAgciCkTCafyTHHfwVQFt8DovmaF69sKbOxTSFMmIZaSHjqO9i/RV0wIblaawhzvtva8Nmm7lQ==} + '@typescript-eslint/utils@8.6.0': + resolution: {integrity: sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1738,8 +1759,8 @@ packages: resolution: {integrity: sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/visitor-keys@8.4.0': - resolution: {integrity: sha512-zTQD6WLNTre1hj5wp09nBIDiOc2U5r/qmzo7wxPn4ZgAjHql09EofqhF9WF+fZHzL5aCyaIpPcT2hyxl73kr9A==} + '@typescript-eslint/visitor-keys@8.6.0': + resolution: {integrity: sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.2.0': @@ -1757,23 +1778,34 @@ packages: vite: ^5.0.0 vue: ^3.2.25 - '@vitest/expect@2.0.5': - resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==} + '@vitest/expect@2.1.1': + resolution: {integrity: sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==} - '@vitest/pretty-format@2.0.5': - resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==} + '@vitest/mocker@2.1.1': + resolution: {integrity: sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==} + peerDependencies: + msw: ^2.3.5 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.1': + resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==} - '@vitest/runner@2.0.5': - resolution: {integrity: sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==} + '@vitest/runner@2.1.1': + resolution: {integrity: sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==} - '@vitest/snapshot@2.0.5': - resolution: {integrity: sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==} + '@vitest/snapshot@2.1.1': + resolution: {integrity: sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==} - '@vitest/spy@2.0.5': - resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} + '@vitest/spy@2.1.1': + resolution: {integrity: sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==} - '@vitest/utils@2.0.5': - resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} + '@vitest/utils@2.1.1': + resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==} '@vue/compiler-core@3.4.38': resolution: {integrity: sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==} @@ -2007,8 +2039,8 @@ packages: birpc@0.2.17: resolution: {integrity: sha512-+hkTxhot+dWsLpp3gia5AkVHIsKlZybNT5gIYiDlNzJrmYPcTM9k5/w2uaj3IPpd7LlEYpmCj4Jj1nC41VhDFg==} - body-parser@1.20.2: - resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} brace-expansion@1.1.11: @@ -2103,6 +2135,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.0: + resolution: {integrity: sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA==} + engines: {node: '>= 14.16.0'} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -2263,6 +2299,15 @@ packages: supports-color: optional: true + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize@4.0.0: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} engines: {node: '>=10'} @@ -2339,6 +2384,10 @@ packages: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} + diff@7.0.0: + resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2371,6 +2420,10 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + engine.io-client@6.5.4: resolution: {integrity: sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==} @@ -2547,8 +2600,8 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - eslint-plugin-react-refresh@0.4.11: - resolution: {integrity: sha512-wrAKxMbVr8qhXTtIKfXqAn5SAtRZt0aXxe5P23Fh4pUAdC6XEsybGLB8P0PI4j1yYqOgUEUlzKAGDfo7rJOjcw==} + eslint-plugin-react-refresh@0.4.12: + resolution: {integrity: sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg==} peerDependencies: eslint: '>=7' @@ -2578,8 +2631,8 @@ packages: resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.9.1: - resolution: {integrity: sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==} + eslint@9.10.0: + resolution: {integrity: sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -2632,18 +2685,14 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - express-rate-limit@7.4.0: resolution: {integrity: sha512-v1204w3cXu5gCDmAvgvzI6qjzZzoMWKnyVDk3ACgfswTQLYiGen+r8w0VnXnGMmzEN/g8fwIQ4JrFFd4ZP6ssg==} engines: {node: '>= 16'} peerDependencies: express: 4 || 5 || ^5.0.0-beta.1 - express@4.19.2: - resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} + express@4.21.0: + resolution: {integrity: sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==} engines: {node: '>= 0.10.0'} extend@3.0.2: @@ -2690,8 +2739,8 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.2.0: - resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} find-root@1.1.0: @@ -2815,10 +2864,6 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} @@ -2918,6 +2963,9 @@ packages: hast-util-is-element@3.0.0: resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + hast-util-minify-whitespace@1.0.0: + resolution: {integrity: sha512-gD1m4YJSIk62ij32TlhFNqsC3dOQvpA4QAhyZOZFAT4u8LfEfB6N+F0V9oXQGBWXoqrs0h9wQRKa8RCeo8j61g==} + hast-util-parse-selector@4.0.0: resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} @@ -2984,15 +3032,11 @@ packages: resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} engines: {node: '>= 14'} - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - i18next-browser-languagedetector@8.0.0: resolution: {integrity: sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==} - i18next@23.14.0: - resolution: {integrity: sha512-Y5GL4OdA8IU2geRrt2+Uc1iIhsjICdHZzT9tNwQ3TVqdNzgxHToGCKf/TPRP80vTCAP6svg2WbbJL+Gx5MFQVA==} + i18next@23.15.1: + resolution: {integrity: sha512-wB4abZ3uK7EWodYisHl/asf8UYEhrI/vj/8aoSsrj/ZDxj4/UXPOa1KvFt1Fq5hkUHquNqwFlDprmjZ8iySgYA==} iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} @@ -3128,10 +3172,6 @@ packages: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} @@ -3166,8 +3206,8 @@ packages: engines: {node: '>=10'} hasBin: true - jose@5.8.0: - resolution: {integrity: sha512-E7CqYpL/t7MMnfGnK/eg416OsFCVUrU/Y3Vwe7QjKhu/BkS1Ms455+2xsqZQVN57/U2MHMBvEb5SrmAZWAIntA==} + jose@5.9.2: + resolution: {integrity: sha512-ILI2xx/I57b20sd7rHZvgiiQrmp2mcotwsAH+5ajbpFQbrYVQdNHYlQhoA5cFb78CgtBOxtC05TeA+mcgkuCqQ==} js-cookie@3.0.5: resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} @@ -3362,13 +3402,13 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} - lucide-react@0.439.0: - resolution: {integrity: sha512-PafSWvDTpxdtNEndS2HIHxcNAbd54OaqSYJO90/b63rab2HWYqDbH194j0i82ZFdWOAcf0AHinRykXRRK2PJbw==} + lucide-react@0.441.0: + resolution: {integrity: sha512-0vfExYtvSDhkC2lqg0zYVW1Uu9GsI4knuV9GP9by5z0Xhc4Zi5RejTxfz9LsjRmCyWVzHCJvxGKZWcRyvQCWVg==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc - magic-string@0.30.10: - resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} mark.js@8.11.1: resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} @@ -3384,11 +3424,8 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} - merge-descriptors@1.0.1: - resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} @@ -3435,10 +3472,6 @@ packages: engines: {node: '>=4.0.0'} hasBin: true - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} @@ -3529,8 +3562,8 @@ packages: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} engines: {node: '>= 0.4.0'} - nise@6.0.0: - resolution: {integrity: sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==} + nise@6.1.1: + resolution: {integrity: sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==} no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -3557,10 +3590,6 @@ packages: resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} engines: {node: '>=14.16'} - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - nwsapi@2.2.12: resolution: {integrity: sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==} @@ -3614,15 +3643,11 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - only@0.0.2: resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==} - openapi-backend@5.10.6: - resolution: {integrity: sha512-vTjBRys/O4JIHdlRHUKZ7pxS+gwIJreAAU9dvYRFrImtPzQ5qxm5a6B8BTVT9m6I8RGGsShJv35MAc3Tu2/y/A==} + openapi-backend@5.11.0: + resolution: {integrity: sha512-c2p93u0NHUc4Fk2kw4rlReakxNnBw4wMMybOTh0LC/BU0Qp7YIphWwJOfNfq2f9nGe/FeCRxGG6VmtCDgkIjdA==} engines: {node: '>=12.0.0'} openapi-schema-validation@0.4.2: @@ -3684,19 +3709,19 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-to-regexp@0.1.7: - resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + path-to-regexp@0.1.10: + resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} path-to-regexp@6.2.2: resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} + path-to-regexp@8.1.0: + resolution: {integrity: sha512-Bqn3vc8CMHty6zuD+tG23s6v2kwxslHEhTj4eYaVKGIEB+YX/2wd0/rgXLFD9G9id9KCtbVy/3ZgmvZjpa0UdQ==} + engines: {node: '>=16'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -3718,13 +3743,13 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - playwright-core@1.47.0: - resolution: {integrity: sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==} + playwright-core@1.47.1: + resolution: {integrity: sha512-i1iyJdLftqtt51mEk6AhYFaAJCDx0xQ/O5NU8EKaWFgMjItPVma542Nh/Aq8aLCjIJSzjaiEQGW/nyqLkGF1OQ==} engines: {node: '>=18'} hasBin: true - playwright@1.47.0: - resolution: {integrity: sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==} + playwright@1.47.1: + resolution: {integrity: sha512-SUEKi6947IqYbKxRiqnbUobVZY4bF1uu+ZnZNJX9DfU1tlf2UhWfvVjLf01pQx9URsOr18bFVUKXmanYWhbfkw==} engines: {node: '>=18'} hasBin: true @@ -3767,14 +3792,14 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.11.0: - resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} - engines: {node: '>=0.6'} - qs@6.12.3: resolution: {integrity: sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==} engines: {node: '>=0.6'} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -3821,8 +3846,8 @@ packages: peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 - react-i18next@15.0.1: - resolution: {integrity: sha512-NwxLqNM6CLbeGA9xPsjits0EnXdKgCRSS6cgkgOdNcPXqL+1fYNl8fBg1wmnnHvFy812Bt4IWTPE9zjoPmFj3w==} + react-i18next@15.0.2: + resolution: {integrity: sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==} peerDependencies: i18next: '>= 23.2.3' react: '>= 16.8.0' @@ -3854,15 +3879,15 @@ packages: '@types/react': optional: true - react-router-dom@6.26.1: - resolution: {integrity: sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==} + react-router-dom@6.26.2: + resolution: {integrity: sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' - react-router@6.26.1: - resolution: {integrity: sha512-kIwJveZNwp7teQRI5QmwWo39A5bXRyqpH0COKKmPnyD2vBvDwgFXSqDUYtt1h+FEyfnE8eXr7oe0MxRzVwCcvQ==} + react-router@6.26.2: + resolution: {integrity: sha512-tvN1iuT03kHgOFnLPfLJ8V95eijteveqdOSk+srqfePtQvqCExB8eHOYnlilbOcyJyKnYkr1vJvf7YqotAJu1A==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' @@ -3885,6 +3910,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.0.1: + resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==} + engines: {node: '>= 14.16.0'} + regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -3892,8 +3921,8 @@ packages: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} engines: {node: '>= 0.4'} - rehype-minify-whitespace@6.0.0: - resolution: {integrity: sha512-i9It4YHR0Sf3GsnlR5jFUKXRr9oayvEk9GKQUkwZv6hs70OH9q3OCZrq9PpLvIGKt3W+JxBOxCidNVpH/6rWdA==} + rehype-minify-whitespace@6.0.1: + resolution: {integrity: sha512-3oJZ3O8ukn6cNJ8elg8dU/tMCH4CDk7elE9x5G+dKL1qQYXeVnsDkSz17sAiUKIoDOXUUkOyC/VMNGEHbPmCew==} rehype-parse@9.0.0: resolution: {integrity: sha512-WG7nfvmWWkCR++KEkZevZb/uw41E8TsH4DsY9UxsTbIXCVGbAs4S+r8FrQ+OtH5EEQAs+5UxKC42VinkmpA1Yw==} @@ -3954,68 +3983,68 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rusty-store-kv-darwin-arm64@1.2.0: - resolution: {integrity: sha512-3kj/Sgs1WH+6edE8l7Db5+gpROpelYFX8PNloX0y6KzvUQgO1ZDs0Wa8kYG8MEDWIJlmw+7UcwpMmskMleU3Vw==} + rusty-store-kv-darwin-arm64@1.3.1: + resolution: {integrity: sha512-xJ4kZh22AcNkbl5yIxUFPEZ5xtgOfAn9fH1rcLf0pUHJKTh3FsdrggBqNBlBlJRQ9RWw92MYBSC318mn8mH14Q==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - rusty-store-kv-darwin-x64@1.2.0: - resolution: {integrity: sha512-svSiGraZRukY6m330epEnJdu2D54JPzQfMjPRg8LT6f70MELGNxWRirnM/ACIBpWUfh1Ojm9jyK8OoY5IeI4UA==} + rusty-store-kv-darwin-x64@1.3.1: + resolution: {integrity: sha512-glm0uEKaetb6QBtfe5G7tsXA+tnkBCMDaxb3XCe9oCx3Pr7gR/we6OS9lPJHplaQPp10hGxOn7kjAqLVDlcT3w==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - rusty-store-kv-freebsd-x64@1.2.0: - resolution: {integrity: sha512-h2/r4PKrRY92z2Ku5I5ACc8yaKdCma0rqak1l5ue/LsR6Zl2oXmzYKXJnzwrqCSIWDRrs5RG2TXMKuPO4telfw==} + rusty-store-kv-freebsd-x64@1.3.1: + resolution: {integrity: sha512-LWUD+JFvrUlo34XfEsTf29EPsktxqqbGlUHAN/6q5DUjg/s5sBFB2W+C1xlwkD+BumyIkN60ZCRVIoXS2UgJjg==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - rusty-store-kv-linux-arm-gnueabihf@1.2.0: - resolution: {integrity: sha512-ivrCOriUYOc/nedCszyPHFATtnLaSaMfNM8h6Cjv4S0gzScpd9rOKVg2hrPh+zApzV/O3dvf6haDtLL1WViKUg==} + rusty-store-kv-linux-arm-gnueabihf@1.3.1: + resolution: {integrity: sha512-Stpor+kqRZg9ykYLjAJn0YrXfgH96WmTcS1AKeHs6gBhVMJ2RZmn1CyF06g5wVQ7sQGrZWMm8Hp3PGjhM5Z2Ew==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - rusty-store-kv-linux-arm64-gnu@1.2.0: - resolution: {integrity: sha512-dZ3ZWsltagzP3U1J6WqWBRoIakqBP7i7y9MDBnKIFFYALVkvY2q2AhrN5cTBxZHaZTbrjyZyhE/rNbyqLZjXLg==} + rusty-store-kv-linux-arm64-gnu@1.3.1: + resolution: {integrity: sha512-ZorAn0AumVbL/6kqswhB/vnLEwlSBMvnhDF6LApHhFTRIygq63dyRrwtM8hgEqL/cjOMotGft6INn429V0RWcw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - rusty-store-kv-linux-arm64-musl@1.2.0: - resolution: {integrity: sha512-J0Zg+wYzy+03DTFZgMPiTaRTk8dfFJv7zQGpeGgeyma3k7SUmUYT2P1b+0NNjbVxr5xNdFJURyJVglUMP3SJRA==} + rusty-store-kv-linux-arm64-musl@1.3.1: + resolution: {integrity: sha512-QMNbq7G1Zr2Yk82XqGbs7z2X2gs9mO5lxnHXeHLSy++56EUBTW/zj4JSjdYdetnFBkGwlPSQLAs1s0MXefxc0g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - rusty-store-kv-linux-x64-gnu@1.2.0: - resolution: {integrity: sha512-8EK6nzC4o13v7zOtLucoQcSOPSsJe9Rw1cAWk7F5qYg/lfFAQNzOpp68rkCBnrHix8yswcafzcSktJHTKuO4yA==} + rusty-store-kv-linux-x64-gnu@1.3.1: + resolution: {integrity: sha512-aD6Oj3PlRzLLcIMytTdzkh/mIu0pJjsug2tA8Gfd5lH2SdB6NFVrF/cjrFWgx5LSLcmI+vVpstqjLOIuc3tZ7g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - rusty-store-kv-linux-x64-musl@1.2.0: - resolution: {integrity: sha512-8Z6xAYWBFKfspSJ1XrRs8P5qYE/aDl6LGhX/5IXg/9mr54quH+pH6YXx88SD0lTgRh+mAD3brCNfr15fOKZftA==} + rusty-store-kv-linux-x64-musl@1.3.1: + resolution: {integrity: sha512-oSkE6X96muX0cbhE754s7shfzEzUTDQi5d3xrNlA/VskWRjDwKmrqiLHLsxO9lamNcDi5wvK8O6byI9qBXigRg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - rusty-store-kv-win32-arm64-msvc@1.2.0: - resolution: {integrity: sha512-YmhUBOzJc6yj1Im/WXcD20iuaZ2GWANG/heTk09enzwgza8i68sSlA39TPTyLE0tOZFdbT76GEuIXPHB0peRRg==} + rusty-store-kv-win32-arm64-msvc@1.3.1: + resolution: {integrity: sha512-HIJ2uJt5LzI/Flx73gnZX/tUfOH2EKS1UKMEzzMF8kqor3iSeGyr0NkLxdl0sZ31dZzRkW63bKxTESmIYjTgiQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - rusty-store-kv-win32-x64-msvc@1.2.0: - resolution: {integrity: sha512-z0/Snn9bZwsT9YnnG18Ol+pkLQpBHkAISq99NhbVdYj5lAYED/n2qIJpP1ROLJlFMJQ4PvftjCmAHUHy0tnkxA==} + rusty-store-kv-win32-x64-msvc@1.3.1: + resolution: {integrity: sha512-CY1pmACrPg1mgfWPk7/dtB24TGc0RWv34+8Eg2lXbD6V7ePSMOVeVcIH7ra/JIjxbJJV2ljWvhkgUnEnp1FSKA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - rusty-store-kv@1.2.0: - resolution: {integrity: sha512-XlzClGSiIfOrpCUEh/eAAktFbsF4IPpDDeOEIP+cWmLkbVzWuqXVLIBouBH4ybKBlw+bQCyjOnZwBdyM9UVpUg==} + rusty-store-kv@1.3.1: + resolution: {integrity: sha512-Kk+55VwQ5qLWcSD6R0RrxFOEF70SH7BjYj60MCskJvRkuY7MFlAPEn3hY4WzRodWXj5cCOJ4AsDr+4OvtaW/SQ==} engines: {node: '>= 10'} safe-array-concat@1.1.2: @@ -4051,15 +4080,15 @@ packages: engines: {node: '>=10'} hasBin: true - send@0.18.0: - resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - serve-static@1.15.0: - resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} set-cookie-parser@2.7.0: @@ -4097,12 +4126,8 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - sinon@18.0.0: - resolution: {integrity: sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==} + sinon@19.0.2: + resolution: {integrity: sha512-euuToqM+PjO4UgXeLETsfQiuoyPXlqFezr6YZDFwHR3t4qaX0fZUe1MfPMznTL5f8BWrVS89KduLdMUsxFCO6g==} slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -4203,10 +4228,6 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4254,6 +4275,15 @@ packages: swagger-schema-official@2.0.0-bab6bed: resolution: {integrity: sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA==} + swagger-ui-dist@5.17.14: + resolution: {integrity: sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==} + + swagger-ui-express@5.0.1: + resolution: {integrity: sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==} + engines: {node: '>= v0.10.32'} + peerDependencies: + express: '>=4.0.0 || >=5.0.0-beta' + symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -4277,6 +4307,9 @@ packages: tinycon@0.6.8: resolution: {integrity: sha512-bF8Lxm4JUXF6Cw0XlZdugJ44GV575OinZ0Pt8vQPr8ooNqd2yyNkoFdCHzmdpHlgoqfSLfcyk4HDP1EyllT+ug==} + tinyexec@0.3.0: + resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} + tinypool@1.0.0: resolution: {integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -4331,8 +4364,8 @@ packages: resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} engines: {node: '>=0.6.x'} - tsx@4.19.0: - resolution: {integrity: sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==} + tsx@4.19.1: + resolution: {integrity: sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==} engines: {node: '>=18.0.0'} hasBin: true @@ -4344,6 +4377,10 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} @@ -4368,13 +4405,13 @@ packages: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} - typescript@5.5.4: - resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + typescript@5.6.2: + resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} engines: {node: '>=14.17'} hasBin: true - ueberdb2@4.2.103: - resolution: {integrity: sha512-jp+G38Za9vCKGRIGNEr28b7HOE0Et9J/txNSUrGnCGwpkkPLvqkX4tbx8sO3AVOynRuNMYfGy4cS0aoYt/2ePw==} + ueberdb2@5.0.2: + resolution: {integrity: sha512-dgrmxTxc/gkWuGK4UArTGwM6zBfG9hANBbhAxK+OUmZs3GatguyoBCp7LgNqenDMp3ElM/KyL6RBZ3OWpqTFKg==} engines: {node: '>=16.20.1'} uid-safe@2.1.5: @@ -4485,8 +4522,8 @@ packages: vfile@6.0.2: resolution: {integrity: sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==} - vite-node@2.0.5: - resolution: {integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==} + vite-node@2.1.1: + resolution: {integrity: sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -4501,8 +4538,8 @@ packages: peerDependencies: vite: ^2.6.0 || 3 || 4 || 5 - vite@5.4.3: - resolution: {integrity: sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==} + vite@5.4.7: + resolution: {integrity: sha512-5l2zxqMEPVENgvzTuBpHer2awaetimj2BGkhBPdnwKbPNOlHsODU+oiazEZzLK7KhAnOrO+XGYJYn4ZlUhDtDQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -4544,15 +4581,15 @@ packages: postcss: optional: true - vitest@2.0.5: - resolution: {integrity: sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==} + vitest@2.1.1: + resolution: {integrity: sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.0.5 - '@vitest/ui': 2.0.5 + '@vitest/browser': 2.1.1 + '@vitest/ui': 2.1.1 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -4873,7 +4910,7 @@ snapshots: '@babel/traverse': 7.24.7 '@babel/types': 7.24.7 convert-source-map: 2.0.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -4967,6 +5004,10 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@babel/runtime@7.25.6': + dependencies: + regenerator-runtime: 0.14.1 + '@babel/template@7.24.7': dependencies: '@babel/code-frame': 7.24.7 @@ -4983,7 +5024,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.24.7 '@babel/parser': 7.24.7 '@babel/types': 7.24.7 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -4996,9 +5037,9 @@ snapshots: '@docsearch/css@3.6.1': {} - '@docsearch/js@3.6.1(@algolia/client-search@4.23.3)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docsearch/js@3.6.1(@algolia/client-search@4.23.3)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@docsearch/react': 3.6.1(@algolia/client-search@4.23.3)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docsearch/react': 3.6.1(@algolia/client-search@4.23.3)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) preact: 10.22.0 transitivePeerDependencies: - '@algolia/client-search' @@ -5007,14 +5048,14 @@ snapshots: - react-dom - search-insights - '@docsearch/react@3.6.1(@algolia/client-search@4.23.3)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docsearch/react@3.6.1(@algolia/client-search@4.23.3)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3) '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3) '@docsearch/css': 3.6.1 algoliasearch: 4.23.3 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: @@ -5161,9 +5202,9 @@ snapshots: '@esbuild/win32-x64@0.23.1': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.9.1)': + '@eslint-community/eslint-utils@4.4.0(eslint@9.10.0)': dependencies: - eslint: 9.9.1 + eslint: 9.10.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.11.0': {} @@ -5171,7 +5212,7 @@ snapshots: '@eslint/config-array@0.18.0': dependencies: '@eslint/object-schema': 2.1.4 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -5179,7 +5220,7 @@ snapshots: '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 espree: 10.1.0 globals: 14.0.0 ignore: 5.3.1 @@ -5190,10 +5231,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.9.1': {} + '@eslint/js@9.10.0': {} '@eslint/object-schema@2.1.4': {} + '@eslint/plugin-kit@0.1.0': + dependencies: + levn: 0.4.1 + '@etherpad/express-session@1.18.4': dependencies: cookie: 0.4.2 @@ -5214,19 +5259,19 @@ snapshots: '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.2.1': {} - '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.0': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jsdevtools/ono@7.1.3': {} @@ -5236,7 +5281,7 @@ snapshots: '@koa/router@12.0.1': dependencies: - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 http-errors: 2.0.0 koa-compose: 4.1.0 methods: 1.1.2 @@ -5256,215 +5301,215 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@playwright/test@1.47.0': + '@playwright/test@1.47.1': dependencies: - playwright: 1.47.0 + playwright: 1.47.1 '@radix-ui/primitive@1.1.0': {} - '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-context@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-context@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-dialog@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dialog@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.8)(react@18.3.1) aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.5.7(@types/react@18.3.5)(react@18.3.1) + react-remove-scroll: 2.5.7(@types/react@18.3.8)(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@radix-ui/react-focus-guards@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-focus-guards@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@radix-ui/react-id@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-id@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-portal@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-portal@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@radix-ui/react-presence@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-presence@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@radix-ui/react-slot@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-slot@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-switch@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-switch@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@radix-ui/react-toast@1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-toast@1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.8)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-use-previous@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-use-previous@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-use-size@1.1.0(@types/react@18.3.5)(react@18.3.1)': + '@radix-ui/react-use-size@1.1.0(@types/react@18.3.8)(react@18.3.1)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.8)(react@18.3.1) react: 18.3.1 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 '@types/react-dom': 18.3.0 - '@remix-run/router@1.19.1': {} + '@remix-run/router@1.19.2': {} '@rollup/pluginutils@5.1.0(rollup@4.21.0)': dependencies: @@ -5534,25 +5579,21 @@ snapshots: '@sindresorhus/is@5.6.0': {} - '@sinonjs/commons@2.0.0': - dependencies: - type-detect: 4.0.8 - '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 - '@sinonjs/fake-timers@11.2.2': + '@sinonjs/fake-timers@13.0.2': dependencies: '@sinonjs/commons': 3.0.1 - '@sinonjs/samsam@8.0.0': + '@sinonjs/samsam@8.0.2': dependencies: - '@sinonjs/commons': 2.0.0 + '@sinonjs/commons': 3.0.1 lodash.get: 4.4.2 - type-detect: 4.0.8 + type-detect: 4.1.0 - '@sinonjs/text-encoding@0.7.2': {} + '@sinonjs/text-encoding@0.7.3': {} '@socket.io/component-emitter@3.1.2': {} @@ -5600,12 +5641,12 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.24.7) '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.24.7) - '@svgr/core@8.1.0(typescript@5.5.4)': + '@svgr/core@8.1.0(typescript@5.6.2)': dependencies: '@babel/core': 7.24.7 '@svgr/babel-preset': 8.1.0(@babel/core@7.24.7) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.5.4) + cosmiconfig: 8.3.6(typescript@5.6.2) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -5616,11 +5657,11 @@ snapshots: '@babel/types': 7.24.7 entities: 4.5.0 - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.5.4))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.6.2))': dependencies: '@babel/core': 7.24.7 '@svgr/babel-preset': 8.1.0(@babel/core@7.24.7) - '@svgr/core': 8.1.0(typescript@5.5.4) + '@svgr/core': 8.1.0(typescript@5.6.2) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: @@ -5686,18 +5727,18 @@ snapshots: '@types/accepts@1.3.7': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/async@3.2.24': {} '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/connect@3.4.38': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/content-disposition@0.5.8': {} @@ -5710,11 +5751,11 @@ snapshots: '@types/connect': 3.4.38 '@types/express': 4.17.21 '@types/keygrip': 1.0.6 - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/cors@2.8.17': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/debug@4.1.12': dependencies: @@ -5724,7 +5765,7 @@ snapshots: '@types/express-serve-static-core@4.19.5': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -5738,11 +5779,11 @@ snapshots: '@types/formidable@3.4.5': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/fs-extra@9.0.13': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/hast@3.0.4': dependencies: @@ -5762,7 +5803,7 @@ snapshots: '@types/jsdom@21.1.7': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/tough-cookie': 4.0.5 parse5: 7.1.2 @@ -5770,9 +5811,9 @@ snapshots: '@types/json5@0.0.29': {} - '@types/jsonwebtoken@9.0.6': + '@types/jsonwebtoken@9.0.7': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/keygrip@1.0.6': {} @@ -5789,7 +5830,7 @@ snapshots: '@types/http-errors': 2.0.4 '@types/keygrip': 1.0.6 '@types/koa-compose': 3.2.8 - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/linkify-it@5.0.0': {} @@ -5812,23 +5853,23 @@ snapshots: '@types/mime@1.3.5': {} - '@types/mocha@10.0.7': {} + '@types/mocha@10.0.8': {} '@types/ms@0.7.34': {} '@types/node-fetch@2.6.11': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 form-data: 4.0.0 - '@types/node@22.5.4': + '@types/node@22.5.5': dependencies: undici-types: 6.19.6 '@types/oidc-provider@8.5.2': dependencies: '@types/koa': 2.15.0 - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/prop-types@15.7.12': {} @@ -5838,9 +5879,9 @@ snapshots: '@types/react-dom@18.3.0': dependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - '@types/react@18.3.5': + '@types/react@18.3.8': dependencies: '@types/prop-types': 15.7.12 csstype: 3.1.3 @@ -5850,12 +5891,12 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/send': 0.17.4 '@types/sinon@17.0.3': @@ -5870,16 +5911,21 @@ snapshots: dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 - '@types/node': 22.5.4 + '@types/node': 22.5.5 '@types/supertest@6.0.2': dependencies: '@types/methods': 1.1.4 '@types/superagent': 8.1.7 + '@types/swagger-ui-express@4.1.6': + dependencies: + '@types/express': 4.17.21 + '@types/serve-static': 1.15.7 + '@types/tar@6.1.13': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 minipass: 4.2.8 '@types/tough-cookie@4.0.5': {} @@ -5892,65 +5938,67 @@ snapshots: '@types/web-bluetooth@0.0.20': {} - '@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4)': + '@types/whatwg-mimetype@3.0.2': {} + + '@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 7.17.0(eslint@9.9.1)(typescript@5.5.4) + '@typescript-eslint/parser': 7.17.0(eslint@9.10.0)(typescript@5.6.2) '@typescript-eslint/scope-manager': 7.17.0 - '@typescript-eslint/type-utils': 7.17.0(eslint@9.9.1)(typescript@5.5.4) - '@typescript-eslint/utils': 7.17.0(eslint@9.9.1)(typescript@5.5.4) + '@typescript-eslint/type-utils': 7.17.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/utils': 7.17.0(eslint@9.10.0)(typescript@5.6.2) '@typescript-eslint/visitor-keys': 7.17.0 - eslint: 9.9.1 + eslint: 9.10.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.5.4) + ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4)': + '@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 8.4.0(eslint@9.9.1)(typescript@5.5.4) - '@typescript-eslint/scope-manager': 8.4.0 - '@typescript-eslint/type-utils': 8.4.0(eslint@9.9.1)(typescript@5.5.4) - '@typescript-eslint/utils': 8.4.0(eslint@9.9.1)(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 8.4.0 - eslint: 9.9.1 + '@typescript-eslint/parser': 8.6.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/scope-manager': 8.6.0 + '@typescript-eslint/type-utils': 8.6.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/utils': 8.6.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/visitor-keys': 8.6.0 + eslint: 9.10.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.5.4) + ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4)': + '@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2)': dependencies: '@typescript-eslint/scope-manager': 7.17.0 '@typescript-eslint/types': 7.17.0 - '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@8.1.1) - eslint: 9.9.1 + debug: 4.3.7 + eslint: 9.10.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.4.0(eslint@9.9.1)(typescript@5.5.4)': + '@typescript-eslint/parser@8.6.0(eslint@9.10.0)(typescript@5.6.2)': dependencies: - '@typescript-eslint/scope-manager': 8.4.0 - '@typescript-eslint/types': 8.4.0 - '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 8.4.0 - debug: 4.3.5(supports-color@8.1.1) - eslint: 9.9.1 + '@typescript-eslint/scope-manager': 8.6.0 + '@typescript-eslint/types': 8.6.0 + '@typescript-eslint/typescript-estree': 8.6.0(typescript@5.6.2) + '@typescript-eslint/visitor-keys': 8.6.0 + debug: 4.3.7 + eslint: 9.10.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color @@ -5959,87 +6007,87 @@ snapshots: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/visitor-keys': 7.17.0 - '@typescript-eslint/scope-manager@8.4.0': + '@typescript-eslint/scope-manager@8.6.0': dependencies: - '@typescript-eslint/types': 8.4.0 - '@typescript-eslint/visitor-keys': 8.4.0 + '@typescript-eslint/types': 8.6.0 + '@typescript-eslint/visitor-keys': 8.6.0 - '@typescript-eslint/type-utils@7.17.0(eslint@9.9.1)(typescript@5.5.4)': + '@typescript-eslint/type-utils@7.17.0(eslint@9.10.0)(typescript@5.6.2)': dependencies: - '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4) - '@typescript-eslint/utils': 7.17.0(eslint@9.9.1)(typescript@5.5.4) - debug: 4.3.5(supports-color@8.1.1) - eslint: 9.9.1 - ts-api-utils: 1.3.0(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) + '@typescript-eslint/utils': 7.17.0(eslint@9.10.0)(typescript@5.6.2) + debug: 4.3.7 + eslint: 9.10.0 + ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.4.0(eslint@9.9.1)(typescript@5.5.4)': + '@typescript-eslint/type-utils@8.6.0(eslint@9.10.0)(typescript@5.6.2)': dependencies: - '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.5.4) - '@typescript-eslint/utils': 8.4.0(eslint@9.9.1)(typescript@5.5.4) - debug: 4.3.5(supports-color@8.1.1) - ts-api-utils: 1.3.0(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 8.6.0(typescript@5.6.2) + '@typescript-eslint/utils': 8.6.0(eslint@9.10.0)(typescript@5.6.2) + debug: 4.3.7 + ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - eslint - supports-color '@typescript-eslint/types@7.17.0': {} - '@typescript-eslint/types@8.4.0': {} + '@typescript-eslint/types@8.6.0': {} - '@typescript-eslint/typescript-estree@7.17.0(typescript@5.5.4)': + '@typescript-eslint/typescript-estree@7.17.0(typescript@5.6.2)': dependencies: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.5.4) + ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.4.0(typescript@5.5.4)': + '@typescript-eslint/typescript-estree@8.6.0(typescript@5.6.2)': dependencies: - '@typescript-eslint/types': 8.4.0 - '@typescript-eslint/visitor-keys': 8.4.0 - debug: 4.3.5(supports-color@8.1.1) + '@typescript-eslint/types': 8.6.0 + '@typescript-eslint/visitor-keys': 8.6.0 + debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.5.4) + ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.17.0(eslint@9.9.1)(typescript@5.5.4)': + '@typescript-eslint/utils@7.17.0(eslint@9.10.0)(typescript@5.6.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) '@typescript-eslint/scope-manager': 7.17.0 '@typescript-eslint/types': 7.17.0 - '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4) - eslint: 9.9.1 + '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) + eslint: 9.10.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@8.4.0(eslint@9.9.1)(typescript@5.5.4)': + '@typescript-eslint/utils@8.6.0(eslint@9.10.0)(typescript@5.6.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) - '@typescript-eslint/scope-manager': 8.4.0 - '@typescript-eslint/types': 8.4.0 - '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.5.4) - eslint: 9.9.1 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) + '@typescript-eslint/scope-manager': 8.6.0 + '@typescript-eslint/types': 8.6.0 + '@typescript-eslint/typescript-estree': 8.6.0(typescript@5.6.2) + eslint: 9.10.0 transitivePeerDependencies: - supports-color - typescript @@ -6049,55 +6097,62 @@ snapshots: '@typescript-eslint/types': 7.17.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.4.0': + '@typescript-eslint/visitor-keys@8.6.0': dependencies: - '@typescript-eslint/types': 8.4.0 + '@typescript-eslint/types': 8.6.0 eslint-visitor-keys: 3.4.3 '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react-swc@3.7.0(vite@5.4.3(@types/node@22.5.4))': + '@vitejs/plugin-react-swc@3.7.0(vite@5.4.7(@types/node@22.5.5))': dependencies: '@swc/core': 1.5.28 - vite: 5.4.3(@types/node@22.5.4) + vite: 5.4.7(@types/node@22.5.5) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-vue@5.1.2(vite@5.4.3(@types/node@22.5.4))(vue@3.4.38(typescript@5.5.4))': + '@vitejs/plugin-vue@5.1.2(vite@5.4.7(@types/node@22.5.5))(vue@3.4.38(typescript@5.6.2))': dependencies: - vite: 5.4.3(@types/node@22.5.4) - vue: 3.4.38(typescript@5.5.4) + vite: 5.4.7(@types/node@22.5.5) + vue: 3.4.38(typescript@5.6.2) - '@vitest/expect@2.0.5': + '@vitest/expect@2.1.1': dependencies: - '@vitest/spy': 2.0.5 - '@vitest/utils': 2.0.5 + '@vitest/spy': 2.1.1 + '@vitest/utils': 2.1.1 chai: 5.1.1 tinyrainbow: 1.2.0 - '@vitest/pretty-format@2.0.5': + '@vitest/mocker@2.1.1(vite@5.4.7(@types/node@22.5.5))': + dependencies: + '@vitest/spy': 2.1.1 + estree-walker: 3.0.3 + magic-string: 0.30.11 + optionalDependencies: + vite: 5.4.7(@types/node@22.5.5) + + '@vitest/pretty-format@2.1.1': dependencies: tinyrainbow: 1.2.0 - '@vitest/runner@2.0.5': + '@vitest/runner@2.1.1': dependencies: - '@vitest/utils': 2.0.5 + '@vitest/utils': 2.1.1 pathe: 1.1.2 - '@vitest/snapshot@2.0.5': + '@vitest/snapshot@2.1.1': dependencies: - '@vitest/pretty-format': 2.0.5 - magic-string: 0.30.10 + '@vitest/pretty-format': 2.1.1 + magic-string: 0.30.11 pathe: 1.1.2 - '@vitest/spy@2.0.5': + '@vitest/spy@2.1.1': dependencies: tinyspy: 3.0.0 - '@vitest/utils@2.0.5': + '@vitest/utils@2.1.1': dependencies: - '@vitest/pretty-format': 2.0.5 - estree-walker: 3.0.3 + '@vitest/pretty-format': 2.1.1 loupe: 3.1.1 tinyrainbow: 1.2.0 @@ -6122,7 +6177,7 @@ snapshots: '@vue/compiler-ssr': 3.4.38 '@vue/shared': 3.4.38 estree-walker: 2.0.2 - magic-string: 0.30.10 + magic-string: 0.30.11 postcss: 8.4.45 source-map-js: 1.2.0 @@ -6165,29 +6220,29 @@ snapshots: '@vue/shared': 3.4.38 csstype: 3.1.3 - '@vue/server-renderer@3.4.38(vue@3.4.38(typescript@5.5.4))': + '@vue/server-renderer@3.4.38(vue@3.4.38(typescript@5.6.2))': dependencies: '@vue/compiler-ssr': 3.4.38 '@vue/shared': 3.4.38 - vue: 3.4.38(typescript@5.5.4) + vue: 3.4.38(typescript@5.6.2) '@vue/shared@3.4.38': {} - '@vueuse/core@11.0.1(vue@3.4.38(typescript@5.5.4))': + '@vueuse/core@11.0.1(vue@3.4.38(typescript@5.6.2))': dependencies: '@types/web-bluetooth': 0.0.20 '@vueuse/metadata': 11.0.1 - '@vueuse/shared': 11.0.1(vue@3.4.38(typescript@5.5.4)) - vue-demi: 0.14.10(vue@3.4.38(typescript@5.5.4)) + '@vueuse/shared': 11.0.1(vue@3.4.38(typescript@5.6.2)) + vue-demi: 0.14.10(vue@3.4.38(typescript@5.6.2)) transitivePeerDependencies: - '@vue/composition-api' - vue - '@vueuse/integrations@11.0.1(axios@1.7.7)(focus-trap@7.5.4)(vue@3.4.38(typescript@5.5.4))': + '@vueuse/integrations@11.0.1(axios@1.7.7)(focus-trap@7.5.4)(vue@3.4.38(typescript@5.6.2))': dependencies: - '@vueuse/core': 11.0.1(vue@3.4.38(typescript@5.5.4)) - '@vueuse/shared': 11.0.1(vue@3.4.38(typescript@5.5.4)) - vue-demi: 0.14.10(vue@3.4.38(typescript@5.5.4)) + '@vueuse/core': 11.0.1(vue@3.4.38(typescript@5.6.2)) + '@vueuse/shared': 11.0.1(vue@3.4.38(typescript@5.6.2)) + vue-demi: 0.14.10(vue@3.4.38(typescript@5.6.2)) optionalDependencies: axios: 1.7.7 focus-trap: 7.5.4 @@ -6197,9 +6252,9 @@ snapshots: '@vueuse/metadata@11.0.1': {} - '@vueuse/shared@11.0.1(vue@3.4.38(typescript@5.5.4))': + '@vueuse/shared@11.0.1(vue@3.4.38(typescript@5.6.2))': dependencies: - vue-demi: 0.14.10(vue@3.4.38(typescript@5.5.4)) + vue-demi: 0.14.10(vue@3.4.38(typescript@5.6.2)) transitivePeerDependencies: - '@vue/composition-api' - vue @@ -6217,7 +6272,7 @@ snapshots: agent-base@7.1.1: dependencies: - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -6372,7 +6427,7 @@ snapshots: birpc@0.2.17: {} - body-parser@1.20.2: + body-parser@1.20.3: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -6382,7 +6437,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.11.0 + qs: 6.13.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 @@ -6493,6 +6548,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.0: + dependencies: + readdirp: 4.0.1 + chownr@2.0.0: {} cliui@7.0.4: @@ -6564,14 +6623,14 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig@8.3.6(typescript@5.5.4): + cosmiconfig@8.3.6(typescript@5.6.2): dependencies: import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 cross-env@7.0.3: dependencies: @@ -6630,6 +6689,10 @@ snapshots: optionalDependencies: supports-color: 8.1.1 + debug@4.3.7: + dependencies: + ms: 2.1.3 + decamelize@4.0.0: {} decimal.js@10.4.3: {} @@ -6691,6 +6754,8 @@ snapshots: diff@5.2.0: {} + diff@7.0.0: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -6720,10 +6785,12 @@ snapshots: encodeurl@1.0.2: {} + encodeurl@2.0.0: {} + engine.io-client@6.5.4: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 engine.io-parser: 5.2.3 ws: 8.17.1 xmlhttprequest-ssl: 2.0.0 @@ -6738,12 +6805,12 @@ snapshots: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 - '@types/node': 22.5.4 + '@types/node': 22.5.5 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.4.2 cors: 2.8.5 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 engine.io-parser: 5.2.3 ws: 8.17.1 transitivePeerDependencies: @@ -6906,24 +6973,24 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-compat-utils@0.5.1(eslint@9.9.1): + eslint-compat-utils@0.5.1(eslint@9.10.0): dependencies: - eslint: 9.9.1 + eslint: 9.10.0 semver: 7.6.3 - eslint-config-etherpad@4.0.4(eslint@9.9.1)(typescript@5.5.4): + eslint-config-etherpad@4.0.4(eslint@9.10.0)(typescript@5.6.2): dependencies: '@rushstack/eslint-patch': 1.10.3 - '@typescript-eslint/eslint-plugin': 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4) - '@typescript-eslint/parser': 7.17.0(eslint@9.9.1)(typescript@5.5.4) - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@9.9.1) - eslint-plugin-cypress: 2.15.2(eslint@9.9.1) - eslint-plugin-eslint-comments: 3.2.0(eslint@9.9.1) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@9.9.1) - eslint-plugin-mocha: 10.4.3(eslint@9.9.1) - eslint-plugin-n: 16.6.2(eslint@9.9.1) - eslint-plugin-prefer-arrow: 1.2.3(eslint@9.9.1) - eslint-plugin-promise: 6.6.0(eslint@9.9.1) + '@typescript-eslint/eslint-plugin': 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/parser': 7.17.0(eslint@9.10.0)(typescript@5.6.2) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-plugin-import@2.29.1)(eslint@9.10.0) + eslint-plugin-cypress: 2.15.2(eslint@9.10.0) + eslint-plugin-eslint-comments: 3.2.0(eslint@9.10.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.1)(eslint@9.10.0) + eslint-plugin-mocha: 10.4.3(eslint@9.10.0) + eslint-plugin-n: 16.6.2(eslint@9.10.0) + eslint-plugin-prefer-arrow: 1.2.3(eslint@9.10.0) + eslint-plugin-promise: 6.6.0(eslint@9.10.0) eslint-plugin-you-dont-need-lodash-underscore: 6.14.0 transitivePeerDependencies: - eslint @@ -6940,13 +7007,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@9.9.1): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-plugin-import@2.29.1)(eslint@9.10.0): dependencies: - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 enhanced-resolve: 5.17.0 - eslint: 9.9.1 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@9.9.1))(eslint@9.9.1) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@9.9.1) + eslint: 9.10.0 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-plugin-import@2.29.1)(eslint@9.10.0))(eslint@9.10.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.1)(eslint@9.10.0) fast-glob: 3.3.2 get-tsconfig: 4.7.6 is-core-module: 2.15.0 @@ -6957,36 +7024,36 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@9.9.1))(eslint@9.9.1): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-plugin-import@2.29.1)(eslint@9.10.0))(eslint@9.10.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.17.0(eslint@9.9.1)(typescript@5.5.4) - eslint: 9.9.1 + '@typescript-eslint/parser': 7.17.0(eslint@9.10.0)(typescript@5.6.2) + eslint: 9.10.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@9.9.1) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-plugin-import@2.29.1)(eslint@9.10.0) transitivePeerDependencies: - supports-color - eslint-plugin-cypress@2.15.2(eslint@9.9.1): + eslint-plugin-cypress@2.15.2(eslint@9.10.0): dependencies: - eslint: 9.9.1 + eslint: 9.10.0 globals: 13.24.0 - eslint-plugin-es-x@7.8.0(eslint@9.9.1): + eslint-plugin-es-x@7.8.0(eslint@9.10.0): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) '@eslint-community/regexpp': 4.11.0 - eslint: 9.9.1 - eslint-compat-utils: 0.5.1(eslint@9.9.1) + eslint: 9.10.0 + eslint-compat-utils: 0.5.1(eslint@9.10.0) - eslint-plugin-eslint-comments@3.2.0(eslint@9.9.1): + eslint-plugin-eslint-comments@3.2.0(eslint@9.10.0): dependencies: escape-string-regexp: 1.0.5 - eslint: 9.9.1 + eslint: 9.10.0 ignore: 5.3.1 - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@9.9.1): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.1)(eslint@9.10.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -6994,9 +7061,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.9.1 + eslint: 9.10.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.9.1)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@9.9.1))(eslint@9.9.1) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@9.10.0)(typescript@5.6.2))(eslint-plugin-import@2.29.1)(eslint@9.10.0))(eslint@9.10.0) hasown: 2.0.2 is-core-module: 2.15.0 is-glob: 4.0.3 @@ -7007,25 +7074,25 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.17.0(eslint@9.9.1)(typescript@5.5.4) + '@typescript-eslint/parser': 7.17.0(eslint@9.10.0)(typescript@5.6.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-mocha@10.4.3(eslint@9.9.1): + eslint-plugin-mocha@10.4.3(eslint@9.10.0): dependencies: - eslint: 9.9.1 - eslint-utils: 3.0.0(eslint@9.9.1) + eslint: 9.10.0 + eslint-utils: 3.0.0(eslint@9.10.0) globals: 13.24.0 rambda: 7.5.0 - eslint-plugin-n@16.6.2(eslint@9.9.1): + eslint-plugin-n@16.6.2(eslint@9.10.0): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) builtins: 5.1.0 - eslint: 9.9.1 - eslint-plugin-es-x: 7.8.0(eslint@9.9.1) + eslint: 9.10.0 + eslint-plugin-es-x: 7.8.0(eslint@9.10.0) get-tsconfig: 4.7.6 globals: 13.24.0 ignore: 5.3.1 @@ -7035,21 +7102,21 @@ snapshots: resolve: 1.22.8 semver: 7.6.3 - eslint-plugin-prefer-arrow@1.2.3(eslint@9.9.1): + eslint-plugin-prefer-arrow@1.2.3(eslint@9.10.0): dependencies: - eslint: 9.9.1 + eslint: 9.10.0 - eslint-plugin-promise@6.6.0(eslint@9.9.1): + eslint-plugin-promise@6.6.0(eslint@9.10.0): dependencies: - eslint: 9.9.1 + eslint: 9.10.0 - eslint-plugin-react-hooks@4.6.2(eslint@9.9.1): + eslint-plugin-react-hooks@4.6.2(eslint@9.10.0): dependencies: - eslint: 9.9.1 + eslint: 9.10.0 - eslint-plugin-react-refresh@0.4.11(eslint@9.9.1): + eslint-plugin-react-refresh@0.4.12(eslint@9.10.0): dependencies: - eslint: 9.9.1 + eslint: 9.10.0 eslint-plugin-you-dont-need-lodash-underscore@6.14.0: dependencies: @@ -7060,9 +7127,9 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 - eslint-utils@3.0.0(eslint@9.9.1): + eslint-utils@3.0.0(eslint@9.10.0): dependencies: - eslint: 9.9.1 + eslint: 9.10.0 eslint-visitor-keys: 2.1.0 eslint-visitor-keys@2.1.0: {} @@ -7071,13 +7138,14 @@ snapshots: eslint-visitor-keys@4.0.0: {} - eslint@9.9.1: + eslint@9.10.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) '@eslint-community/regexpp': 4.11.0 '@eslint/config-array': 0.18.0 '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.9.1 + '@eslint/js': 9.10.0 + '@eslint/plugin-kit': 0.1.0 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.3.0 '@nodelib/fs.walk': 1.2.8 @@ -7100,7 +7168,6 @@ snapshots: is-glob: 4.0.3 is-path-inside: 3.0.3 json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 @@ -7150,50 +7217,38 @@ snapshots: - supports-color - utf-8-validate - execa@8.0.1: + express-rate-limit@7.4.0(express@4.21.0): dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 + express: 4.21.0 - express-rate-limit@7.4.0(express@4.19.2): - dependencies: - express: 4.19.2 - - express@4.19.2: + express@4.21.0: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.2 + body-parser: 1.20.3 content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.6.0 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.2.0 + finalhandler: 1.3.1 fresh: 0.5.2 http-errors: 2.0.0 - merge-descriptors: 1.0.1 + merge-descriptors: 1.0.3 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.7 + path-to-regexp: 0.1.10 proxy-addr: 2.0.7 - qs: 6.11.0 + qs: 6.13.0 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 + send: 0.19.0 + serve-static: 1.16.2 setprototypeof: 1.2.0 statuses: 2.0.1 type-is: 1.6.18 @@ -7247,10 +7302,10 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.2.0: + finalhandler@1.3.1: dependencies: debug: 2.6.9 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 @@ -7302,7 +7357,7 @@ snapshots: dezalgo: 1.0.4 hexoid: 1.0.0 once: 1.4.0 - qs: 6.12.3 + qs: 6.13.0 formidable@3.5.1: dependencies: @@ -7373,8 +7428,6 @@ snapshots: get-stream@6.0.1: {} - get-stream@8.0.1: {} - get-symbol-description@1.0.2: dependencies: call-bind: 1.0.7 @@ -7389,7 +7442,7 @@ snapshots: dependencies: basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 fs-extra: 11.2.0 transitivePeerDependencies: - supports-color @@ -7505,6 +7558,14 @@ snapshots: dependencies: '@types/hast': 3.0.4 + hast-util-minify-whitespace@1.0.0: + dependencies: + '@types/hast': 3.0.4 + 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 + hast-util-parse-selector@4.0.0: dependencies: '@types/hast': 3.0.4 @@ -7604,7 +7665,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.1 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -7616,17 +7677,15 @@ snapshots: https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.1 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 transitivePeerDependencies: - supports-color - human-signals@5.0.0: {} - i18next-browser-languagedetector@8.0.0: dependencies: '@babel/runtime': 7.24.7 - i18next@23.14.0: + i18next@23.15.1: dependencies: '@babel/runtime': 7.24.8 @@ -7748,8 +7807,6 @@ snapshots: dependencies: call-bind: 1.0.7 - is-stream@3.0.0: {} - is-string@1.0.7: dependencies: has-tostringtag: 1.0.2 @@ -7781,7 +7838,7 @@ snapshots: filelist: 1.0.4 minimatch: 3.1.2 - jose@5.8.0: {} + jose@5.9.2: {} js-cookie@3.0.5: {} @@ -7907,7 +7964,7 @@ snapshots: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.9.1 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -8026,13 +8083,13 @@ snapshots: lru-cache@7.18.3: {} - lucide-react@0.439.0(react@18.3.1): + lucide-react@0.441.0(react@18.3.1): dependencies: react: 18.3.1 - magic-string@0.30.10: + magic-string@0.30.11: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 mark.js@8.11.1: {} @@ -8055,9 +8112,7 @@ snapshots: media-typer@0.3.0: {} - merge-descriptors@1.0.1: {} - - merge-stream@2.0.0: {} + merge-descriptors@1.0.3: {} merge2@1.4.1: {} @@ -8095,8 +8150,6 @@ snapshots: mime@2.6.0: {} - mimic-fn@4.0.0: {} - mimic-response@3.1.0: {} mimic-response@4.0.0: {} @@ -8179,13 +8232,13 @@ snapshots: netmask@2.0.2: {} - nise@6.0.0: + nise@6.1.1: dependencies: '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers': 11.2.2 - '@sinonjs/text-encoding': 0.7.2 + '@sinonjs/fake-timers': 13.0.2 + '@sinonjs/text-encoding': 0.7.3 just-extend: 6.2.0 - path-to-regexp: 6.2.2 + path-to-regexp: 8.1.0 no-case@3.0.4: dependencies: @@ -8210,10 +8263,6 @@ snapshots: normalize-url@8.0.1: {} - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - nwsapi@2.2.12: {} object-assign@4.1.1: {} @@ -8257,7 +8306,7 @@ snapshots: debug: 4.3.5(supports-color@8.1.1) eta: 3.4.0 got: 13.0.0 - jose: 5.8.0 + jose: 5.9.2 jsesc: 3.0.2 koa: 2.15.3 nanoid: 5.0.7 @@ -8280,13 +8329,9 @@ snapshots: dependencies: wrappy: 1.0.2 - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - only@0.0.2: {} - openapi-backend@5.10.6: + openapi-backend@5.11.0: dependencies: '@apidevtools/json-schema-ref-parser': 11.6.4 ajv: 8.17.1 @@ -8339,7 +8384,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.1 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 get-uri: 6.0.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 @@ -8374,14 +8419,14 @@ snapshots: path-key@3.1.1: {} - path-key@4.0.0: {} - path-parse@1.0.7: {} - path-to-regexp@0.1.7: {} + path-to-regexp@0.1.10: {} path-to-regexp@6.2.2: {} + path-to-regexp@8.1.0: {} + path-type@4.0.0: {} pathe@1.1.2: {} @@ -8394,11 +8439,11 @@ snapshots: picomatch@2.3.1: {} - playwright-core@1.47.0: {} + playwright-core@1.47.1: {} - playwright@1.47.0: + playwright@1.47.1: dependencies: - playwright-core: 1.47.0 + playwright-core: 1.47.1 optionalDependencies: fsevents: 2.3.2 @@ -8428,7 +8473,7 @@ snapshots: proxy-agent@6.4.0: dependencies: agent-base: 7.1.1 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 lru-cache: 7.18.3 @@ -8444,11 +8489,11 @@ snapshots: punycode@2.3.1: {} - qs@6.11.0: + qs@6.12.3: dependencies: side-channel: 1.0.6 - qs@6.12.3: + qs@6.13.0: dependencies: side-channel: 1.0.6 @@ -8489,54 +8534,54 @@ snapshots: dependencies: react: 18.3.1 - react-i18next@15.0.1(i18next@23.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-i18next@15.0.2(i18next@23.15.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@babel/runtime': 7.24.8 + '@babel/runtime': 7.25.6 html-parse-stringify: 3.0.1 - i18next: 23.14.0 + i18next: 23.15.1 react: 18.3.1 optionalDependencies: react-dom: 18.3.1(react@18.3.1) - react-remove-scroll-bar@2.3.6(@types/react@18.3.5)(react@18.3.1): + react-remove-scroll-bar@2.3.6(@types/react@18.3.8)(react@18.3.1): dependencies: react: 18.3.1 - react-style-singleton: 2.2.1(@types/react@18.3.5)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.8)(react@18.3.1) tslib: 2.6.3 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - react-remove-scroll@2.5.7(@types/react@18.3.5)(react@18.3.1): + react-remove-scroll@2.5.7(@types/react@18.3.8)(react@18.3.1): dependencies: react: 18.3.1 - react-remove-scroll-bar: 2.3.6(@types/react@18.3.5)(react@18.3.1) - react-style-singleton: 2.2.1(@types/react@18.3.5)(react@18.3.1) + react-remove-scroll-bar: 2.3.6(@types/react@18.3.8)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.8)(react@18.3.1) tslib: 2.6.3 - use-callback-ref: 1.3.2(@types/react@18.3.5)(react@18.3.1) - use-sidecar: 1.1.2(@types/react@18.3.5)(react@18.3.1) + use-callback-ref: 1.3.2(@types/react@18.3.8)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.8)(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - react-router-dom@6.26.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-router-dom@6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@remix-run/router': 1.19.1 + '@remix-run/router': 1.19.2 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-router: 6.26.1(react@18.3.1) + react-router: 6.26.2(react@18.3.1) - react-router@6.26.1(react@18.3.1): + react-router@6.26.2(react@18.3.1): dependencies: - '@remix-run/router': 1.19.1 + '@remix-run/router': 1.19.2 react: 18.3.1 - react-style-singleton@2.2.1(@types/react@18.3.5)(react@18.3.1): + react-style-singleton@2.2.1(@types/react@18.3.8)(react@18.3.1): dependencies: get-nonce: 1.0.1 invariant: 2.2.4 react: 18.3.1 tslib: 2.6.3 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 react@18.3.1: dependencies: @@ -8546,6 +8591,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.0.1: {} + regenerator-runtime@0.14.1: {} regexp.prototype.flags@1.5.2: @@ -8555,13 +8602,10 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 - rehype-minify-whitespace@6.0.0: + rehype-minify-whitespace@6.0.1: dependencies: '@types/hast': 3.0.4 - 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 + hast-util-minify-whitespace: 1.0.0 rehype-parse@9.0.0: dependencies: @@ -8638,48 +8682,48 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rusty-store-kv-darwin-arm64@1.2.0: + rusty-store-kv-darwin-arm64@1.3.1: optional: true - rusty-store-kv-darwin-x64@1.2.0: + rusty-store-kv-darwin-x64@1.3.1: optional: true - rusty-store-kv-freebsd-x64@1.2.0: + rusty-store-kv-freebsd-x64@1.3.1: optional: true - rusty-store-kv-linux-arm-gnueabihf@1.2.0: + rusty-store-kv-linux-arm-gnueabihf@1.3.1: optional: true - rusty-store-kv-linux-arm64-gnu@1.2.0: + rusty-store-kv-linux-arm64-gnu@1.3.1: optional: true - rusty-store-kv-linux-arm64-musl@1.2.0: + rusty-store-kv-linux-arm64-musl@1.3.1: optional: true - rusty-store-kv-linux-x64-gnu@1.2.0: + rusty-store-kv-linux-x64-gnu@1.3.1: optional: true - rusty-store-kv-linux-x64-musl@1.2.0: + rusty-store-kv-linux-x64-musl@1.3.1: optional: true - rusty-store-kv-win32-arm64-msvc@1.2.0: + rusty-store-kv-win32-arm64-msvc@1.3.1: optional: true - rusty-store-kv-win32-x64-msvc@1.2.0: + rusty-store-kv-win32-x64-msvc@1.3.1: optional: true - rusty-store-kv@1.2.0: + rusty-store-kv@1.3.1: optionalDependencies: - rusty-store-kv-darwin-arm64: 1.2.0 - rusty-store-kv-darwin-x64: 1.2.0 - rusty-store-kv-freebsd-x64: 1.2.0 - rusty-store-kv-linux-arm-gnueabihf: 1.2.0 - rusty-store-kv-linux-arm64-gnu: 1.2.0 - rusty-store-kv-linux-arm64-musl: 1.2.0 - rusty-store-kv-linux-x64-gnu: 1.2.0 - rusty-store-kv-linux-x64-musl: 1.2.0 - rusty-store-kv-win32-arm64-msvc: 1.2.0 - rusty-store-kv-win32-x64-msvc: 1.2.0 + rusty-store-kv-darwin-arm64: 1.3.1 + rusty-store-kv-darwin-x64: 1.3.1 + rusty-store-kv-freebsd-x64: 1.3.1 + rusty-store-kv-linux-arm-gnueabihf: 1.3.1 + rusty-store-kv-linux-arm64-gnu: 1.3.1 + rusty-store-kv-linux-arm64-musl: 1.3.1 + rusty-store-kv-linux-x64-gnu: 1.3.1 + rusty-store-kv-linux-x64-musl: 1.3.1 + rusty-store-kv-win32-arm64-msvc: 1.3.1 + rusty-store-kv-win32-x64-msvc: 1.3.1 safe-array-concat@1.1.2: dependencies: @@ -8712,7 +8756,7 @@ snapshots: semver@7.6.3: {} - send@0.18.0: + send@0.19.0: dependencies: debug: 2.6.9 depd: 2.0.0 @@ -8734,12 +8778,12 @@ snapshots: dependencies: randombytes: 2.1.0 - serve-static@1.15.0: + serve-static@1.16.2: dependencies: - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.18.0 + send: 0.19.0 transitivePeerDependencies: - supports-color @@ -8785,15 +8829,13 @@ snapshots: signal-exit@3.0.7: {} - signal-exit@4.1.0: {} - - sinon@18.0.0: + sinon@19.0.2: dependencies: '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers': 11.2.2 - '@sinonjs/samsam': 8.0.0 - diff: 5.2.0 - nise: 6.0.0 + '@sinonjs/fake-timers': 13.0.2 + '@sinonjs/samsam': 8.0.2 + diff: 7.0.0 + nise: 6.1.1 supports-color: 7.2.0 slash@3.0.0: {} @@ -8807,7 +8849,7 @@ snapshots: socket.io-adapter@2.5.5: dependencies: - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 ws: 8.17.1 transitivePeerDependencies: - bufferutil @@ -8828,7 +8870,7 @@ snapshots: socket.io-parser@4.2.4: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -8849,7 +8891,7 @@ snapshots: socks-proxy-agent@8.0.4: dependencies: agent-base: 7.1.1 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -8883,7 +8925,7 @@ snapshots: streamroller@3.1.5: dependencies: date-format: 4.0.14 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 fs-extra: 8.1.0 transitivePeerDependencies: - supports-color @@ -8924,8 +8966,6 @@ snapshots: strip-bom@3.0.0: {} - strip-final-newline@3.0.0: {} - strip-json-comments@3.1.1: {} superagent@10.1.0: @@ -8946,13 +8986,13 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 fast-safe-stringify: 2.1.1 form-data: 4.0.0 formidable: 2.1.2 methods: 1.1.2 mime: 2.6.0 - qs: 6.12.3 + qs: 6.13.0 semver: 7.6.3 transitivePeerDependencies: - supports-color @@ -8961,13 +9001,13 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 fast-safe-stringify: 2.1.1 form-data: 4.0.0 formidable: 3.5.1 methods: 1.1.2 mime: 2.6.0 - qs: 6.12.3 + qs: 6.13.0 transitivePeerDependencies: - supports-color @@ -9000,6 +9040,13 @@ snapshots: swagger-schema-official@2.0.0-bab6bed: {} + swagger-ui-dist@5.17.14: {} + + swagger-ui-express@5.0.1(express@4.21.0): + dependencies: + express: 4.21.0 + swagger-ui-dist: 5.17.14 + symbol-tree@3.2.4: {} tabbable@6.2.0: {} @@ -9021,6 +9068,8 @@ snapshots: tinycon@0.6.8: {} + tinyexec@0.3.0: {} + tinypool@1.0.0: {} tinyrainbow@1.2.0: {} @@ -9050,9 +9099,9 @@ snapshots: trough@2.2.0: {} - ts-api-utils@1.3.0(typescript@5.5.4): + ts-api-utils@1.3.0(typescript@5.6.2): dependencies: - typescript: 5.5.4 + typescript: 5.6.2 tsconfig-paths@3.15.0: dependencies: @@ -9065,7 +9114,7 @@ snapshots: tsscmp@1.0.6: {} - tsx@4.19.0: + tsx@4.19.1: dependencies: esbuild: 0.23.1 get-tsconfig: 4.7.6 @@ -9078,6 +9127,8 @@ snapshots: type-detect@4.0.8: {} + type-detect@4.1.0: {} + type-fest@0.20.2: {} type-is@1.6.18: @@ -9117,9 +9168,9 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - typescript@5.5.4: {} + typescript@5.6.2: {} - ueberdb2@4.2.103: {} + ueberdb2@5.0.2: {} uid-safe@2.1.5: dependencies: @@ -9196,20 +9247,20 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - use-callback-ref@1.3.2(@types/react@18.3.5)(react@18.3.1): + use-callback-ref@1.3.2(@types/react@18.3.8)(react@18.3.1): dependencies: react: 18.3.1 tslib: 2.6.3 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 - use-sidecar@1.1.2(@types/react@18.3.5)(react@18.3.1): + use-sidecar@1.1.2(@types/react@18.3.8)(react@18.3.1): dependencies: detect-node-es: 1.1.0 react: 18.3.1 tslib: 2.6.3 optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 use-sync-external-store@1.2.2(react@18.3.1): dependencies: @@ -9235,13 +9286,12 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - vite-node@2.0.5(@types/node@22.5.4): + vite-node@2.1.1(@types/node@22.5.5): dependencies: cac: 6.7.14 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7 pathe: 1.1.2 - tinyrainbow: 1.2.0 - vite: 5.4.3(@types/node@22.5.4) + vite: 5.4.7(@types/node@22.5.5) transitivePeerDependencies: - '@types/node' - less @@ -9253,52 +9303,52 @@ snapshots: - supports-color - terser - vite-plugin-static-copy@1.0.6(vite@5.4.3(@types/node@22.5.4)): + vite-plugin-static-copy@1.0.6(vite@5.4.7(@types/node@22.5.5)): dependencies: chokidar: 3.6.0 fast-glob: 3.3.2 fs-extra: 11.2.0 picocolors: 1.0.1 - vite: 5.4.3(@types/node@22.5.4) + vite: 5.4.7(@types/node@22.5.5) - vite-plugin-svgr@4.2.0(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.3(@types/node@22.5.4)): + vite-plugin-svgr@4.2.0(rollup@4.21.0)(typescript@5.6.2)(vite@5.4.7(@types/node@22.5.5)): dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.21.0) - '@svgr/core': 8.1.0(typescript@5.5.4) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.5.4)) - vite: 5.4.3(@types/node@22.5.4) + '@svgr/core': 8.1.0(typescript@5.6.2) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.6.2)) + vite: 5.4.7(@types/node@22.5.5) transitivePeerDependencies: - rollup - supports-color - typescript - vite@5.4.3(@types/node@22.5.4): + vite@5.4.7(@types/node@22.5.5): dependencies: esbuild: 0.21.5 postcss: 8.4.45 rollup: 4.21.0 optionalDependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 fsevents: 2.3.3 - vitepress@1.3.4(@algolia/client-search@4.23.3)(@types/node@22.5.4)(@types/react@18.3.5)(axios@1.7.7)(postcss@8.4.45)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4): + vitepress@1.3.4(@algolia/client-search@4.23.3)(@types/node@22.5.5)(@types/react@18.3.8)(axios@1.7.7)(postcss@8.4.45)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2): dependencies: '@docsearch/css': 3.6.1 - '@docsearch/js': 3.6.1(@algolia/client-search@4.23.3)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docsearch/js': 3.6.1(@algolia/client-search@4.23.3)(@types/react@18.3.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@shikijs/core': 1.14.1 '@shikijs/transformers': 1.14.1 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 5.1.2(vite@5.4.3(@types/node@22.5.4))(vue@3.4.38(typescript@5.5.4)) + '@vitejs/plugin-vue': 5.1.2(vite@5.4.7(@types/node@22.5.5))(vue@3.4.38(typescript@5.6.2)) '@vue/devtools-api': 7.3.8 '@vue/shared': 3.4.38 - '@vueuse/core': 11.0.1(vue@3.4.38(typescript@5.5.4)) - '@vueuse/integrations': 11.0.1(axios@1.7.7)(focus-trap@7.5.4)(vue@3.4.38(typescript@5.5.4)) + '@vueuse/core': 11.0.1(vue@3.4.38(typescript@5.6.2)) + '@vueuse/integrations': 11.0.1(axios@1.7.7)(focus-trap@7.5.4)(vue@3.4.38(typescript@5.6.2)) focus-trap: 7.5.4 mark.js: 8.11.1 minisearch: 7.1.0 shiki: 1.14.1 - vite: 5.4.3(@types/node@22.5.4) - vue: 3.4.38(typescript@5.5.4) + vite: 5.4.7(@types/node@22.5.5) + vue: 3.4.38(typescript@5.6.2) optionalDependencies: postcss: 8.4.45 transitivePeerDependencies: @@ -9329,33 +9379,34 @@ snapshots: - typescript - universal-cookie - vitest@2.0.5(@types/node@22.5.4)(jsdom@25.0.0): + vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.0): dependencies: - '@ampproject/remapping': 2.3.0 - '@vitest/expect': 2.0.5 - '@vitest/pretty-format': 2.0.5 - '@vitest/runner': 2.0.5 - '@vitest/snapshot': 2.0.5 - '@vitest/spy': 2.0.5 - '@vitest/utils': 2.0.5 + '@vitest/expect': 2.1.1 + '@vitest/mocker': 2.1.1(vite@5.4.7(@types/node@22.5.5)) + '@vitest/pretty-format': 2.1.1 + '@vitest/runner': 2.1.1 + '@vitest/snapshot': 2.1.1 + '@vitest/spy': 2.1.1 + '@vitest/utils': 2.1.1 chai: 5.1.1 - debug: 4.3.5(supports-color@8.1.1) - execa: 8.0.1 - magic-string: 0.30.10 + debug: 4.3.7 + magic-string: 0.30.11 pathe: 1.1.2 std-env: 3.7.0 tinybench: 2.9.0 + tinyexec: 0.3.0 tinypool: 1.0.0 tinyrainbow: 1.2.0 - vite: 5.4.3(@types/node@22.5.4) - vite-node: 2.0.5(@types/node@22.5.4) + vite: 5.4.7(@types/node@22.5.5) + vite-node: 2.1.1(@types/node@22.5.5) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.5.4 + '@types/node': 22.5.5 jsdom: 25.0.0 transitivePeerDependencies: - less - lightningcss + - msw - sass - sass-embedded - stylus @@ -9365,19 +9416,19 @@ snapshots: void-elements@3.1.0: {} - vue-demi@0.14.10(vue@3.4.38(typescript@5.5.4)): + vue-demi@0.14.10(vue@3.4.38(typescript@5.6.2)): dependencies: - vue: 3.4.38(typescript@5.5.4) + vue: 3.4.38(typescript@5.6.2) - vue@3.4.38(typescript@5.5.4): + vue@3.4.38(typescript@5.6.2): dependencies: '@vue/compiler-dom': 3.4.38 '@vue/compiler-sfc': 3.4.38 '@vue/runtime-dom': 3.4.38 - '@vue/server-renderer': 3.4.38(vue@3.4.38(typescript@5.5.4)) + '@vue/server-renderer': 3.4.38(vue@3.4.38(typescript@5.6.2)) '@vue/shared': 3.4.38 optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 w3c-xmlserializer@5.0.0: dependencies: @@ -9478,11 +9529,11 @@ snapshots: yocto-queue@0.1.0: {} - zustand@4.5.5(@types/react@18.3.5)(react@18.3.1): + zustand@4.5.5(@types/react@18.3.8)(react@18.3.1): dependencies: use-sync-external-store: 1.2.2(react@18.3.1) optionalDependencies: - '@types/react': 18.3.5 + '@types/react': 18.3.8 react: 18.3.1 zwitch@2.0.4: {} diff --git a/settings.json.docker b/settings.json.docker index bbe96fc5194..da1d51c13a8 100644 --- a/settings.json.docker +++ b/settings.json.docker @@ -171,6 +171,14 @@ */ "showSettingsInAdminPage": "${SHOW_SETTINGS_IN_ADMIN_PAGE:true}", + /* + * Settings for cleanup of pads + */ + "cleanup": { + "enabled": false, + "keepRevisions": 5 + }, + /* The authentication method used by the server. The default value is sso @@ -194,6 +202,15 @@ }, */ + + /* + * Enables the use of a different server. We have a different one that syncs changes from the original server. + * It is hosted on GitHub and should not be blocked by many firewalls. + * https://etherpad.org/ep_infos + */ + + "updateServer": "https://etherpad.org/ep_infos", + /* * The type of the database. * diff --git a/settings.json.template b/settings.json.template index 66c9a7df2fd..2d856f42e4c 100644 --- a/settings.json.template +++ b/settings.json.template @@ -162,6 +162,14 @@ */ "showSettingsInAdminPage": true, + /* + * Settings for cleanup of pads + */ + "cleanup": { + "enabled": false, + "keepRevisions": 5 + }, + /* * Node native SSL support * @@ -271,6 +279,14 @@ "pageDown": true }, + /* + * Enables the use of a different server. We have a different one that syncs changes from the original server. + * It is hosted on GitHub and should not be blocked by many firewalls. + * https://etherpad.org/ep_infos + */ + + "updateServer": "https://etherpad.org/ep_infos", + /* * Should we suppress errors from being visible in the default Pad Text? */ diff --git a/src/ep.json b/src/ep.json index c9b26c175aa..83dfc509db8 100644 --- a/src/ep.json +++ b/src/ep.json @@ -82,6 +82,12 @@ "expressCreateServer": "ep_etherpad-lite/node/hooks/express/errorhandling" } }, + { + "name": "restApi", + "hooks": { + "expressCreateServer": "ep_etherpad-lite/node/handler/RestAPI" + } + }, { "name": "socketio", "hooks": { diff --git a/src/node/handler/APIHandler.ts b/src/node/handler/APIHandler.ts index 5feb74eb965..b108f50f0a0 100644 --- a/src/node/handler/APIHandler.ts +++ b/src/node/handler/APIHandler.ts @@ -24,10 +24,10 @@ import {MapArrayType} from "../types/MapType"; const api = require('../db/API'); const padManager = require('../db/PadManager'); import createHTTPError from 'http-errors'; -import {Http2ServerRequest, Http2ServerResponse} from "node:http2"; +import {Http2ServerRequest} from "node:http2"; import {publicKeyExported} from "../security/OAuth2Provider"; import {jwtVerify} from "jose"; -import {apikey} from './APIKeyHandler' +import {APIFields, apikey} from './APIKeyHandler' // a list of all functions const version:MapArrayType = {}; @@ -141,6 +141,7 @@ version['1.3.0'] = { setText: ['padID', 'text', 'authorId'], }; + // set the latest available API version here exports.latestApiVersion = '1.3.0'; @@ -148,13 +149,6 @@ exports.latestApiVersion = '1.3.0'; exports.version = version; -type APIFields = { - apikey: string; - api_key: string; - padID: string; - padName: string; - authorization: string; -} /** * Handles an HTTP API call diff --git a/src/node/handler/APIKeyHandler.ts b/src/node/handler/APIKeyHandler.ts index b4e70f6e4b0..5a00453b14d 100644 --- a/src/node/handler/APIKeyHandler.ts +++ b/src/node/handler/APIKeyHandler.ts @@ -7,6 +7,16 @@ const settings = require('../utils/Settings'); const apiHandlerLogger = log4js.getLogger('APIHandler'); + + +export type APIFields = { + apikey: string; + api_key: string; + padID: string; + padName: string; + authorization: string; +} + // ensure we have an apikey export let apikey:string|null = null; const apikeyFilename = absolutePaths.makeAbsolute(argv.apikey || './APIKEY.txt'); diff --git a/src/node/handler/PadMessageHandler.ts b/src/node/handler/PadMessageHandler.ts index 6d2ee0d5785..9f1c9e86bc0 100644 --- a/src/node/handler/PadMessageHandler.ts +++ b/src/node/handler/PadMessageHandler.ts @@ -1147,13 +1147,13 @@ const getChangesetInfo = async (pad: PadType, startNum: number, endNum:number, g getPadLines(pad, startNum - 1), // Get all needed composite Changesets. ...compositesChangesetNeeded.map(async (item) => { - const changeset = await composePadChangesets(pad, item.start, item.end); + const changeset = await exports.composePadChangesets(pad, item.start, item.end); composedChangesets[`${item.start}/${item.end}`] = changeset; }), // Get all needed revision Dates. ...revTimesNeeded.map(async (revNum) => { const revDate = await pad.getRevisionDate(revNum); - revisionDate[revNum] = Math.floor(revDate / 1000); + revisionDate[revNum] = revDate; }), ]); @@ -1213,7 +1213,7 @@ const getPadLines = async (pad: PadType, revNum: number) => { * Tries to rebuild the composePadChangeset function of the original Etherpad * https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L241 */ -const composePadChangesets = async (pad: PadType, startNum: number, endNum: number) => { +exports.composePadChangesets = async (pad: PadType, startNum: number, endNum: number) => { // fetch all changesets we need const headNum = pad.getHeadRevisionNumber(); endNum = Math.min(endNum, headNum + 1); diff --git a/src/node/handler/RestAPI.ts b/src/node/handler/RestAPI.ts new file mode 100644 index 00000000000..7b1b82309d7 --- /dev/null +++ b/src/node/handler/RestAPI.ts @@ -0,0 +1,1527 @@ +import {ArgsExpressType} from "../types/ArgsExpressType"; +import {MapArrayType} from "../types/MapType"; +import {IncomingForm} from "formidable"; +import {ErrorCaused} from "../types/ErrorCaused"; +import createHTTPError from "http-errors"; + +const apiHandler = require('./APIHandler') +import {serve, setup} from 'swagger-ui-express' +import express from "express"; + +const settings = require('../utils/Settings') + + +type RestAPIMapping = { + apiVersion: string; + functionName: string, + summary?: string, + operationId?: string, + requestBody?: any, + responses?: any, + tags?: string[], +} + + +const mapping = new Map> + + +const GET = "GET" +const POST = "POST" +const PUT = "PUT" +const DELETE = "DELETE" +const PATCH = "PATCH" + + +const defaultResponses = { + "200": { + "description": "ok (code 0)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "example": 0 + }, + "message": { + "type": "string", + "example": "ok" + }, + "data": { + "type": "object", + "properties": { + "groupID": { + "type": "string" + } + } + } + } + } + } + } + }, + "400": { + "description": "generic api error (code 1)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "example": 1 + }, + "message": { + "type": "string", + "example": "error message" + }, + "data": { + "type": "object", + "example": null + } + } + } + } + } + }, + "401": { + "description": "no or wrong API key (code 4)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "example": 4 + }, + "message": { + "type": "string", + "example": "no or wrong API key" + }, + "data": { + "type": "object", + "example": null + } + } + } + } + } + }, + "500": { + "description": "internal api error (code 2)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "example": 2 + }, + "message": { + "type": "string", + "example": "internal error" + }, + "data": { + "type": "object", + "example": null + } + } + } + } + } + }, + "tags": [ + "group" + ], + "parameters": [] +} + +const prepareResponses = (data: { + type: string, + properties: Record, + properties?: Record, + }>, +}) => { + return { + ...defaultResponses, + 200: { + ...defaultResponses["200"], + content: { + ...defaultResponses["200"].content, + "application/json": { + schema: { + type: "object", + properties: { + ...defaultResponses["200"].content["application/json"].schema.properties, + data: data + } + } + } + } + } + } +} + + +const prepareDefinition = (mapping: Map>, address: string) => { + const authenticationMethod = settings.authenticationMethod + + + const definitions: { + "openapi": string, + "info": { + "title": string, + "description": string, + "termsOfService": string, + "contact": { + "name": string, + "url": string, + "email": string, + }, + }, + "components": { + "securitySchemes": { + "apiKey": { + "type": string, + "name": string, + "in": string + + }, + "sso"?: { + "type": string, + "flows": { + "authorizationCode": { + "authorizationUrl": string, + "tokenUrl": string, + "scopes": { + "openid": string, + "profile": string, + "email": string, + "admin": string + } + } + } + } + }, + }, + "servers": [ + { + "url": string + } + ], + "paths": Record, + }>>, + "security": any[] + } = { + "openapi": "3.0.2", + "info": { + "title": "Etherpad API", + "description": "Etherpad is a real-time collaborative editor scalable to thousands of simultaneous real time users. It provides full data export capabilities, and runs on your server, under your control.", + "termsOfService": "https://etherpad.org/", + "contact": { + "name": "The Etherpad Foundation", + "url": "https://etherpad.org/", + "email": "", + }, + }, + "components": { + "securitySchemes": { + "apiKey": { + "type": "apiKey", + "name": "apikey", + "in": "query" + + }, + }, + }, + "servers": [ + { + "url": `${address}/api/2` + } + ], + "paths": {}, + "security": [] + } + + if (authenticationMethod === "apikey") { + definitions.security = [ + { + "apiKey": [] + } + ] + } else if (authenticationMethod === "sso") { + definitions.components.securitySchemes.sso = { + type: "oauth2", + flows: { + authorizationCode: { + authorizationUrl: settings.sso.issuer + "/oidc/auth", + tokenUrl: settings.sso.issuer + "/oidc/token", + scopes: { + openid: "openid", + profile: "profile", + email: "email", + admin: "admin" + } + } + }, + } + + definitions.security = [ + { + "sso": [] + } + ] + } + + + for (const [method, value] of mapping) { + for (const [path, mapping] of Object.entries(value)) { + const {apiVersion, functionName, summary, operationId, requestBody, responses, tags} = mapping + if (!definitions.paths[path]) { + definitions.paths[path] = {} + } + + const methodLowercased = method.toLowerCase() + + definitions.paths[path][methodLowercased] = { + summary: summary!, + operationId: operationId!, + responses, + tags: tags! + } + + if (method === GET) { + definitions.paths[path][methodLowercased].parameters = requestBody + } else { + definitions.paths[path][methodLowercased].requestBody = requestBody + } + } + } + return definitions +} + + +export const expressCreateServer = async (hookName: string, {app}: ArgsExpressType) => { + mapping.set(GET, {}) + mapping.set(POST, {}) + mapping.set(PUT, {}) + mapping.set(DELETE, {}) + mapping.set(PATCH, {}) + + // Version 1 + mapping.get(POST)!["/groups"] = { + apiVersion: '1', + functionName: 'createGroup', summary: 'Creates a new group', + operationId: 'createGroup', tags: ['group'], responses: prepareResponses({type: "object", properties: {groupID: {type: "string"}}}) + + } + mapping.get(POST)!["/groups/createIfNotExistsFor"] = { + apiVersion: '1', functionName: 'createGroupIfNotExistsFor', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + groupMapper: { + type: "string" + } + }, + required: ["groupMapper"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {groupID: {type: "string"}}}), + summary: "Creates a new group if it doesn't exist", operationId: 'createGroupIfNotExistsFor', tags: ['group'] + }; + mapping.get(GET)!["/groups/pads"] = { + apiVersion: '1', functionName: 'listPads', + summary: "Lists all pads in a group", tags: ['group'], + operationId: 'listPads', responses: prepareResponses({type: "object", properties: {padIDs: {type: "string"}}}), + requestBody: [ + { + "name": "groupID", + "in": "query", + "schema": { + "type": "string" + } + } + ] + } + mapping.get(DELETE)!["/groups"] = { + apiVersion: '1', functionName: 'deleteGroup', responses: prepareResponses({type: "object", properties: {}}), requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + groupID: { + type: "string" + } + }, + required: ["groupID"] + } + } + } + }, summary: "Deletes a group", operationId: 'deleteGroup', tags: ['group'] + } + + mapping.get(POST)!["/authors"] = { + apiVersion: '1', functionName: 'createAuthor', requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + name: { + type: "string" + } + }, + required: ["name"] + } + } + } + }, tags: ["author"] + } + + + mapping.get(POST)!["/authors/createIfNotExistsFor"] = { + apiVersion: '1', functionName: 'createAuthorIfNotExistsFor', + responses: prepareResponses({type: "object", properties: {authorID: {type: "string"}}}), + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + authorMapper: { + type: "string" + }, + name: { + type: "string" + } + }, + required: ["authorMapper", "name"] + } + } + } + }, + tags: ["author"], + } + + + mapping.get(GET)!["/authors/pads"] = { + apiVersion: '1', functionName: 'listPadsOfAuthor', + requestBody: [ + { + "name": "authorID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + responses: prepareResponses({type: "object", properties: {padIDs: {type: "array", items: {type: "string"}}}}), + tags: ["author"] + } + mapping.get(POST)!["/sessions"] = { + apiVersion: '1', functionName: 'createSession', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + groupID: { + type: "string" + }, + authorID: { + type: "string" + }, + validUntil: { + type: "string" + } + }, + required: ["groupID", "authorID", "validUntil"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {sessionID: {type: "string"}}}), + tags: ['session'] + } + + mapping.get(DELETE)!["/sessions"] = { + apiVersion: '1', functionName: 'deleteSession', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + sessionID: { + type: "string" + } + }, + required: ["sessionID"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + tags: ['session'] + } + + + mapping.get(GET)!["/sessions/info"] = { + apiVersion: '1', functionName: 'getSessionInfo', + requestBody: [ + { + "name": "sessionID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + responses: prepareResponses({ + "type": "object", + "properties": { + id: { + type: "string" + }, + "groupID": { + "type": "string" + }, + "authorID": { + "type": "string" + }, + "validUntil": { + "type": "string" + } + } + }), + tags: ['session'] + } + + + mapping.get(GET)!["/sessions/group"] = { + apiVersion: '1', functionName: 'listSessionsOfGroup', summary: 'Lists all sessions in a group', + operationId: 'listSessionsOfGroup', tags: ['session'], + responses: prepareResponses({ + type: "object", "properties": { + "sessions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "authorID": { + "type": "string" + }, + "groupID": { + "type": "string" + }, + "validUntil": { + "type": "integer" + } + } + } + } + } + }), + requestBody: [ + { + "name": "groupID", + "in": "query", + "schema": { + "type": "string" + } + } + ] + } + mapping.get(GET)!["/sessions/author"] = { + apiVersion: '1', functionName: 'listSessionsOfAuthor', + summary: 'Lists all sessions of an author', operationId: 'listSessionsOfAuthor', tags: ['session'], + responses: prepareResponses({ + type: "object", "properties": { + "sessions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "authorID": { + "type": "string" + }, + "groupID": { + "type": "string" + }, + "validUntil": { + "type": "integer" + } + } + } + } + } + }), + requestBody: [ + { + "name": "authorID", + "in": "query", + "schema": { + "type": "string" + } + } + ] + } + + + mapping.get(GET)!["/pads/text"] = { + apiVersion: '1', functionName: 'getText', + responses: prepareResponses({type: "object", properties: {text: {type: "string"}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + tags: ['pad'] + } + + + mapping.get(GET)!["/pads/html"] = { + apiVersion: '1', functionName: 'getHTML', + responses: prepareResponses({type: "object", properties: {html: {type: "string"}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the HTML of a pad', + tags: ['pad'] + } + mapping.get(GET)!["/pads/revisions"] = { + apiVersion: '1', functionName: 'getRevisionsCount', + responses: prepareResponses({type: "object", properties: {revisions: {type: "integer"}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the number of revisions of a pad', + tags: ['pad'] + } + + mapping.get(GET)!["/pads/lastEdited"] = { + apiVersion: '1', functionName: 'getLastEdited', + responses: prepareResponses({type: "object", properties: {lastEdited: {type: "integer"}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the timestamp of the last revision of a pad', + tags: ['pad'] + } + + + mapping.get(DELETE)!["/pads"] = { + apiVersion: '1', functionName: 'deletePad', + responses: prepareResponses({type: "object", properties: {}}), + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + } + }, + required: ["padID"] + } + } + } + }, + summary: 'Deletes a pad', + tags: ['pad'] + } + mapping.get(GET)!["/pads/readonly"] = { + apiVersion: '1', functionName: 'getReadOnlyID', + responses: prepareResponses({type: "object", properties: {readOnlyID: {type: "string"}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the read only id of a pad', + tags: ['pad'] + } + + mapping.get(POST)!["/pads/publicStatus"] = { + apiVersion: '1', functionName: 'setPublicStatus', + responses: prepareResponses({type: "object", properties: {}}), + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + publicStatus: { + type: "boolean" + } + }, + required: ["padID", "publicStatus"] + } + } + } + }, + summary: 'Set the public status of a pad', + tags: ['pad'] + + } + mapping.get(GET)!["/pads/publicStatus"] = { + apiVersion: '1', functionName: 'getPublicStatus', + responses: prepareResponses({type: "object", properties: {publicStatus: {type: "boolean"}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the public status of a pad', + tags: ['pad'] + } + mapping.get(GET)!["/pads/authors"] = { + apiVersion: '1', functionName: 'listAuthorsOfPad', + responses: prepareResponses({type: "object", properties: {authorIDs: {type: "array", items: {type: "string"}}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the authors of a pad', + tags: ['pad'] + } + mapping.get(GET)!["/pads/usersCount"] = { + apiVersion: '1', functionName: 'padUsersCount', + responses: prepareResponses({type: "object", properties: {padUsersCount: {type: "integer"}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the number of users currently editing a pad', + tags: ['pad'] + } + + + // Version 1.1 + mapping.get(GET)!["/authors/name"] = { + apiVersion: '1.1', functionName: 'getAuthorName', + responses: prepareResponses({type: "object", properties: {authorName: {type: "string"}}}), + requestBody: [ + { + "name": "authorID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the name of an author', + tags: ['author'] + } + mapping.get(GET)!["/pads/users"] = { + apiVersion: '1.1', functionName: 'padUsers', + responses: prepareResponses({ + type: "object", properties: { + padUsers: { + type: "array", "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "colorId": { + "type": "string" + }, + "name": { + "type": "string" + }, + "timestamp": { + "type": "integer" + } + } + } + } + } + }), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the users currently editing a pad', + tags: ['pad'] + } + + + mapping.get(POST)!["/pads/clientsMessage"] = { + apiVersion: '1.1', functionName: 'sendClientsMessage', + responses: prepareResponses({type: "object", properties: {}}), + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + msg: { + type: "string" + } + }, + required: ["padID", "msg"] + } + } + } + }, + summary: 'Send a message to all clients of a pad', + tags: ['pad'] + } + + + mapping.get(GET)!["/groups"] = { + apiVersion: '1.1', functionName: 'listAllGroups', + responses: prepareResponses({type: "object", properties: {groupIDs: {type: "array", items: {type: "string"}}}}), + summary: 'Lists all groups', + tags: ['group'] + } + + + // Version 1.2 + mapping.get(GET)!["/checkToken"] = { + apiVersion: '1.2', functionName: 'checkToken', + responses: prepareResponses({type: "object", properties: {}}), + requestBody: [ + { + "name": "token", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Check if a token is valid', + tags: ['token'] + + } + + // Version 1.2.1 + mapping.get(GET)!["/pads"] = { + apiVersion: '1.2.1', functionName: 'listAllPads', + summary: 'Lists all pads', + tags: ['pad'], + requestBody: [ + { + "name": "groupID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + responses: prepareResponses({type: "object", properties: {padIDs: {type: "array", items: {type: "string"}}}}) + } + + // Version 1.2.7 + mapping.get(POST)!["/pads/diff"] = { + apiVersion: '1.2.7', functionName: 'createDiffHTML', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + startRev: { + type: "integer" + }, + endRev: { + type: "integer" + } + }, + required: ["padID", "startRev", "endRev"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Creates a diff of a pad', + tags: ['pad'] + } + mapping.get(GET)!["/pads/chatHistory"] = { + apiVersion: '1.2.7', functionName: 'getChatHistory', + responses: prepareResponses({ + type: "object", properties: { + messages: { + type: "array", items: { + type: "object", properties: { + "text": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "userName": { + "type": "string" + }, + "time": { + "type": "integer" + } + } + } + } + } + }), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the chat history of a pad', + tags: ['pad'] + } + mapping.get(GET)!["/pads/chatHead"] = { + apiVersion: '1.2.7', functionName: 'getChatHead', + responses: prepareResponses({ + type: "object", properties: { + chatHead: { + type: "object", + properties: { + "text": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "userName": { + "type": "string" + }, + "time": { + "type": "integer" + } + } + } + + } + }), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the chat head of a pad', + tags: ['pad'] + + } + + // Version 1.2.8 + mapping.get(GET)!["/pads/attributePool"] = { + apiVersion: '1.2.8', functionName: 'getAttributePool', + responses: prepareResponses({type: "object", properties: {}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the attribute pool of a pad', + tags: ['pad'] + } + mapping.get(GET)!["/pads/revisionChangeset"] = { + apiVersion: '1.2.8', functionName: 'getRevisionChangeset', + responses: prepareResponses({type: "object", properties: {}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "rev", + "in": "query", + "schema": { + "type": "integer" + } + } + ], + summary: 'Get the changeset of a revision of a pad', + tags: ['pad'] + } + + // Version 1.2.9 + mapping.get(POST)!["/pads/copypad"] = { + apiVersion: '1.2.9', functionName: 'copyPad', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + sourceID: { + type: "string" + }, + destinationID: { + type: "string" + }, + force: { + type: "boolean" + } + }, + required: ["sourceID", "destinationID"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Copies a pad', + tags: ['pad'] + } + + + mapping.get(POST)!["/pads/movePad"] = { + apiVersion: '1.2.9', functionName: 'movePad', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + sourceID: { + type: "string" + }, + destinationID: { + type: "string" + }, + force: { + type: "boolean" + } + }, + required: ["sourceID", "destinationID"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Moves a pad', + tags: ['pad'] + } + + // Version 1.2.10 + mapping.get(POST)!["/pads/padId"] = { + apiVersion: '1.2.10', functionName: 'getPadID', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + roID: { + type: "string" + } + }, + required: ["roID"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Get the pad id of a pad', + tags: ['pad'] + } + + // Version 1.2.11 + mapping.get(GET)!["/savedRevisions"] = { + apiVersion: '1.2.11', functionName: 'listSavedRevisions', + responses: prepareResponses({type: "object", properties: {savedRevisions: {type: "array", items: {type: "object"}}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Lists all saved revisions of a pad', + tags: ['pad'] + } + + + mapping.get(POST)!["/savedRevisions"] = { + apiVersion: '1.2.11', functionName: 'saveRevision', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + rev: { + type: "integer" + } + }, + required: ["padID", "rev"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Saves a revision of a pad', + tags: ['pad'] + } + + mapping.get(GET)!["/savedRevisions/revisionsCount"] = { + apiVersion: '1.2.11', functionName: 'getSavedRevisionsCount', + responses: prepareResponses({type: "object", properties: {revisionsCount: {type: "integer"}}}), + requestBody: [ + { + "name": "padID", + "in": "query", + "schema": { + "type": "string" + } + } + ], + summary: 'Get the number of saved revisions of a pad', + tags: ['pad'] + } + + // Version 1.2.12 + mapping.get(PATCH)!["/chats/messages"] = { + apiVersion: '1.2.12', functionName: 'appendChatMessage', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + text: { + type: "string" + }, + authorID: { + type: "string" + }, + time: { + type: "string" + } + }, + required: ["padID", "text"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Appends a chat message to a pad', + tags: ['pad'] + } + + // Version 1.2.13 + + // Version 1.2.14 + mapping.get(GET)!["/stats"] = { + apiVersion: '1.2.14', functionName: 'getStats', + responses: prepareResponses({type: "object", properties: {stats: {type: "object"}}}), + summary: 'Get stats', + tags: ['stats'] + } + + // Version 1.2.15 + + // Version 1.3.0 + mapping.get(PATCH)!["/pads/text"] = { + apiVersion: '1.3.0', functionName: 'appendText', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + text: { + type: "string" + }, + authorID: { + type: "string" + }, + }, + required: ["padID", "text", "authorID"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Appends text to a pad', + tags: ['pad'] + } + mapping.get(POST)!["/pads/copyWithoutHistory"] = { + apiVersion: '1.3.0', functionName: 'copyPadWithoutHistory', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + sourceID: { + type: "string" + }, + destinationID: { + type: "string" + }, + force: { + type: "string" + }, + authorID: { + type: "string" + } + }, + required: ["sourceID", "destinationID", "force", "authorID"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Copies a pad without its history', + tags: ['pad'] + } + mapping.get(POST)!["/pads/group"] = { + apiVersion: '1.3.0', functionName: 'createGroupPad', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + groupID: { + type: "string" + }, + padName: { + type: "string" + }, + text: { + type: "string" + }, + authorID: { + type: "string" + } + }, + required: ["groupID", "padName"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Creates a new pad in a group', + tags: ['pad'] + + } + mapping.get(POST)!["/pads"] = { + apiVersion: '1.3.0', functionName: 'createPad', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + text: { + type: "string" + }, + authorId: { + type: "string" + } + }, + required: ["padName"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Creates a new pad', + tags: ['pad'] + } + mapping.get(PATCH)!["/savedRevisions"] = { + apiVersion: '1.3.0', functionName: 'restoreRevision', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + rev: { + type: "integer" + }, + authorId: { + type: "string" + } + }, + required: ["padID", "rev", "authorId"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Restores a revision of a pad', + tags: ['pad'] + } + + + mapping.get(POST)!["/pads/html"] = { + apiVersion: '1.3.0', functionName: 'setHTML', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + html: { + type: "string" + }, + authorId: { + type: "string" + } + }, + required: ["padID", "html", "authorId"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Sets the HTML of a pad', + tags: ['pad'] + } + + mapping.get(POST)!["/pads/text"] = { + apiVersion: '1.3.0', functionName: 'setText', + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + padID: { + type: "string" + }, + text: { + type: "string" + }, + authorId: { + type: "string" + } + }, + required: ["padID", "text", "authorId"] + } + } + } + }, + responses: prepareResponses({type: "object", properties: {}}), + summary: 'Sets the text of a pad', + tags: ['pad'] + } + + + app.use('/api-docs', serve); + app.get('/api-docs', setup(undefined, { + swaggerOptions: { + url: '/api-docs.json', + }, + })); + + app.use(express.json()); + + app.get('/api-docs.json', (req, res) => { + const fullUrl = req.protocol + '://' + req.get('host'); + const generatedDefinition = prepareDefinition(mapping, fullUrl) + res.json(generatedDefinition) + }) + app.use('/api/2', async (req, res, next) => { + const method = req.method + const pathToFunction = req.path + // parse fields from request + const {headers, params, query} = req; + + // read form data if method was POST + let formData: MapArrayType = {}; + if (method.toLowerCase() === 'post' || method.toLowerCase() === "delete") { + if (!req.headers['content-type'] || req.headers['content-type']!.startsWith('application/json')) { + // parse json + formData = req.body; + } else { + const form = new IncomingForm(); + formData = (await form.parse(req))[0]; + for (const k of Object.keys(formData)) { + if (formData[k] instanceof Array) { + formData[k] = formData[k][0]; + } + } + } + } + + const fields = Object.assign({}, headers, params, query, formData); + + if (mapping.has(method) && pathToFunction in mapping.get(method)!) { + const {apiVersion, functionName} = mapping.get(method)![pathToFunction]! + // pass to api handler + let response; + try { + try { + let data = await apiHandler.handle(apiVersion, functionName, fields, req, res); + + // return in common format + response = {code: 0, message: 'ok', data: data || null}; + } catch (err) { + const errCaused = err as ErrorCaused + // convert all errors to http errors + if (createHTTPError.isHttpError(err)) { + // pass http errors thrown by handler forward + throw err; + } else if (errCaused.name === 'apierror') { + // parameters were wrong and the api stopped execution, pass the error + // convert to http error + throw new createHTTPError.BadRequest(errCaused.message); + } else { + // an unknown error happened + // log it and throw internal error + console.error(errCaused.stack || errCaused.toString()); + throw new createHTTPError.InternalServerError('internal error'); + } + } + } catch (err) { + const errCaused = err as ErrorCaused + // handle http errors + // @ts-ignore + res.statusCode = errCaused.statusCode || 500; + + // convert to our json response format + // https://github.com/ether/etherpad-lite/tree/master/doc/api/http_api.md#response-format + switch (res.statusCode) { + case 403: // forbidden + response = {code: 4, message: errCaused.message, data: null}; + break; + case 401: // unauthorized (no or wrong api key) + response = {code: 4, message: errCaused.message, data: null}; + break; + case 404: // not found (no such function) + response = {code: 3, message: errCaused.message, data: null}; + break; + case 500: // server error (internal error) + response = {code: 2, message: errCaused.message, data: null}; + break; + case 400: // bad request (wrong parameters) + // respond with 200 OK to keep old behavior and pass tests + res.statusCode = 200; // @TODO: this is bad api design + response = {code: 1, message: errCaused.message, data: null}; + break; + default: + response = {code: 1, message: errCaused.message, data: null}; + break; + } + } + + + console.debug(`RESPONSE, ${functionName}, ${JSON.stringify(response)}`); + + // return the response data + res.json(response); + } else { + res.json({code: 1, message: 'not found'}); + } + }) +} diff --git a/src/node/hooks/express/adminsettings.ts b/src/node/hooks/express/adminsettings.ts index 63d901f2126..4c60a05ad20 100644 --- a/src/node/hooks/express/adminsettings.ts +++ b/src/node/hooks/express/adminsettings.ts @@ -13,6 +13,7 @@ const settings = require('../../utils/Settings'); const UpdateCheck = require('../../utils/UpdateCheck'); const padManager = require('../../db/PadManager'); const api = require('../../db/API'); +const cleanup = require('../../utils/Cleanup'); const queryPadLimit = 12; @@ -252,6 +253,40 @@ exports.socketio = (hookName: string, {io}: any) => { } }) + socket.on('cleanupPadRevisions', async (padId: string) => { + if (!settings.cleanup.enabled) { + socket.emit('results:cleanupPadRevisions', { + error: 'Cleanup disabled. Enable cleanup in settings.json: cleanup.enabled => true', + }); + return; + } + + const padExists = await padManager.doesPadExists(padId); + if (padExists) { + logger.info(`Cleanup pad revisions: ${padId}`); + try { + const result = await cleanup.deleteRevisions(padId, settings.cleanup.keepRevisions) + if (result) { + socket.emit('results:cleanupPadRevisions', { + padId: padId, + keepRevisions: settings.cleanup.keepRevisions, + }); + logger.info('successful cleaned up pad: ', padId) + } else { + socket.emit('results:cleanupPadRevisions', { + error: 'Error cleaning up pad', + }); + } + } catch (err: any) { + logger.error(`Error in pad ${padId}: ${err.stack || err}`); + socket.emit('results:cleanupPadRevisions', { + error: err.toString(), + }); + return; + } + } + }) + socket.on('restartServer', async () => { logger.info('Admin request to restart server through a socket on /admin/settings'); settings.reloadSettings(); diff --git a/src/node/hooks/express/specialpages.ts b/src/node/hooks/express/specialpages.ts index b2ea3614e8f..ef5914e9573 100644 --- a/src/node/hooks/express/specialpages.ts +++ b/src/node/hooks/express/specialpages.ts @@ -12,6 +12,7 @@ const webaccess = require('./webaccess'); const plugins = require('../../../static/js/pluginfw/plugin_defs'); import {build, buildSync} from 'esbuild' +import {ArgsExpressType} from "../../types/ArgsExpressType"; let ioI: { sockets: { sockets: any[]; }; } | null = null exports.socketio = (hookName: string, {io}: any) => { @@ -19,7 +20,7 @@ exports.socketio = (hookName: string, {io}: any) => { } -exports.expressPreSession = async (hookName:string, {app}:any) => { +exports.expressPreSession = async (hookName:string, {app}:ArgsExpressType) => { // This endpoint is intended to conform to: // https://www.ietf.org/archive/id/draft-inadarei-api-health-check-06.html app.get('/health', (req:any, res:any) => { @@ -113,7 +114,7 @@ const convertTypescript = (content: string) => { const handleLiveReload = async (args: any, padString: string, timeSliderString: string, indexString: any) => { const chokidar = await import('chokidar') - const watcher = chokidar.watch(path.join(settings.root, 'src', 'static', 'js')); + const watcher = chokidar.watch(path.join(settings.root, 'src', 'static', 'js'), {}); let routeHandlers: { [key: string]: Function } = {}; const setRouteHandler = (path: string, newHandler: Function) => { @@ -243,7 +244,7 @@ const convertTypescriptWatched = (content: string, cb: (output:string, hash: str }) } -exports.expressCreateServer = async (hookName: string, args: any, cb: Function) => { +exports.expressCreateServer = async (hookName: string, args: ArgsExpressType, cb: Function) => { const padString = eejs.require('ep_etherpad-lite/templates/padBootstrap.js', { pluginModules: (() => { const pluginModules = new Set(); diff --git a/src/node/security/OAuth2Provider.ts b/src/node/security/OAuth2Provider.ts index e212113504b..76e7ed4b894 100644 --- a/src/node/security/OAuth2Provider.ts +++ b/src/node/security/OAuth2Provider.ts @@ -153,7 +153,7 @@ export const expressCreateServer = async (hookName: string, args: ArgsExpressTyp }); - args.app.post('/interaction/:uid', async (req: Http2ServerRequest, res: Http2ServerResponse, next:Function) => { + args.app.post('/interaction/:uid', async (req, res, next) => { const formid = new IncomingForm(); try { // @ts-ignore @@ -226,7 +226,7 @@ export const expressCreateServer = async (hookName: string, args: ArgsExpressTyp }) - args.app.get('/interaction/:uid', async (req: Request, res: Response, next: Function) => { + args.app.get('/interaction/:uid', async (req, res, next) => { try { const { uid, prompt, params, session, diff --git a/src/node/types/ArgsExpressType.ts b/src/node/types/ArgsExpressType.ts index 5c0675b9730..d8dc700be1c 100644 --- a/src/node/types/ArgsExpressType.ts +++ b/src/node/types/ArgsExpressType.ts @@ -1,5 +1,7 @@ +import {Express} from "express"; + export type ArgsExpressType = { - app:any, + app:Express, io: any, server:any -} \ No newline at end of file +} diff --git a/src/node/types/Revision.ts b/src/node/types/Revision.ts new file mode 100644 index 00000000000..8a9d65e29cf --- /dev/null +++ b/src/node/types/Revision.ts @@ -0,0 +1,9 @@ +import {AChangeSet} from "./PadType"; + +export type Revision = { + changeset: AChangeSet, + meta: { + author: string, + timestamp: number, + } +} diff --git a/src/node/utils/Cleanup.ts b/src/node/utils/Cleanup.ts new file mode 100644 index 00000000000..7e480020dda --- /dev/null +++ b/src/node/utils/Cleanup.ts @@ -0,0 +1,168 @@ +'use strict' + +import {AChangeSet} from "../types/PadType"; +import {Revision} from "../types/Revision"; + +const promises = require('./promises'); +const padManager = require('ep_etherpad-lite/node/db/PadManager'); +const db = require('ep_etherpad-lite/node/db/DB'); +const Changeset = require('ep_etherpad-lite/static/js/Changeset'); +const padMessageHandler = require('ep_etherpad-lite/node/handler/PadMessageHandler'); +const log4js = require('log4js'); +const logger = log4js.getLogger('cleanup'); + +exports.deleteAllRevisions = async (padID: string): Promise => { + + const randomPadId = padID + 'aertdfdf' + Math.random().toString(10) + + let pad = await padManager.getPad(padID); + await pad.copyPadWithoutHistory(randomPadId, false); + pad = await padManager.getPad(randomPadId); + await pad.copyPadWithoutHistory(padID, true); + await pad.remove(); +} + +const createRevision = async (aChangeset: AChangeSet, timestamp: number, isKeyRev: boolean, authorId: string, atext: any, pool: any) => { + + if (authorId !== '') pool.putAttrib(['author', authorId]); + + return { + changeset: aChangeset, + meta: { + author: authorId, + timestamp: timestamp, + ...isKeyRev ? { + pool: pool, + atext: atext, + } : {}, + }, + }; +} + +exports.deleteRevisions = async (padId: string, keepRevisions: number): Promise => { + + logger.debug('Start cleanup revisions', padId) + + let pad = await padManager.getPad(padId); + await pad.check() + + logger.debug('Initial pad is valid') + + if (pad.head <= keepRevisions) { + logger.debug('Pad has not enough revisions') + return false + } + + padMessageHandler.kickSessionsFromPad(padId) + + const cleanupUntilRevision = pad.head - keepRevisions + logger.debug('Composing changesets: ', cleanupUntilRevision) + const changeset = await padMessageHandler.composePadChangesets(pad, 0, cleanupUntilRevision + 1) + + const revisions: Revision[] = []; + + await promises.timesLimit(keepRevisions + 1, 500, async (i: number) => { + const rev = i + cleanupUntilRevision + revisions[rev] = await pad.getRevision(rev) + }); + + logger.debug('Loaded revisions: ', revisions.length) + + await promises.timesLimit(pad.head + 1, 500, async (i: string) => { + await db.remove(`pad:${padId}:revs:${i}`, null); + }); + + let padContent = await db.get(`pad:${padId}`) + padContent.head = keepRevisions + if (padContent.savedRevisions) { + let newSavedRevisions = [] + + for (let i = 0; i < padContent.savedRevisions.length; i++) { + if (padContent.savedRevisions[i].revNum > cleanupUntilRevision) { + padContent.savedRevisions[i].revNum = padContent.savedRevisions[i].revNum - cleanupUntilRevision + newSavedRevisions.push(padContent.savedRevisions[i]) + } + } + padContent.savedRevisions = newSavedRevisions + } + await db.set(`pad:${padId}`, padContent); + + let newAText = Changeset.makeAText('\n'); + let pool = pad.apool() + + newAText = Changeset.applyToAText(changeset, newAText, pool); + + const revision = await createRevision( + changeset, + revisions[cleanupUntilRevision].meta.timestamp, + 0 === pad.getKeyRevisionNumber(0), + '', + newAText, + pool + ); + + const p: Promise[] = []; + + p.push(db.set(`pad:${padId}:revs:0`, revision)) + + p.push(promises.timesLimit(keepRevisions, 500, async (i: number) => { + const rev = i + cleanupUntilRevision + 1 + const newRev = rev - cleanupUntilRevision; + + newAText = Changeset.applyToAText(revisions[rev].changeset, newAText, pool); + + const revision = await createRevision( + revisions[rev].changeset, + revisions[rev].meta.timestamp, + newRev === pad.getKeyRevisionNumber(newRev), + revisions[rev].meta.author, + newAText, + pool + ); + + await db.set(`pad:${padId}:revs:${newRev}`, revision); + })); + + await Promise.all(p) + + logger.debug('Finished migration. Checking pad now') + + padManager.unloadPad(padId); + + let newPad = await padManager.getPad(padId); + await newPad.check(); + + return true +} + +exports.checkTodos = async () => { + await new Promise(resolve => setTimeout(resolve, 5000)); + + // TODO: Move to settings + const settings = { + minHead: 100, + keepRevisions: 100, + minAge: 1,//1000 * 60 * 60 * 24, + } + + await Promise.all((await padManager.listAllPads()).padIDs.map(async (padId: string) => { + // TODO: Handle concurrency + const pad = await padManager.getPad(padId); + + const revisionDate = await pad.getRevisionDate(pad.getHeadRevisionNumber()) + + if (pad.head < settings.minHead || padMessageHandler.padUsersCount(padId) > 0 || Date.now() < revisionDate + settings.minAge) { + return + } + + try { + const result = await exports.deleteRevisions(padId, settings.keepRevisions) + if (result) { + logger.info('successful cleaned up pad: ', padId) + } + } catch (err: any) { + logger.error(`Error in pad ${padId}: ${err.stack || err}`); + return; + } + })); +} diff --git a/src/node/utils/Settings.ts b/src/node/utils/Settings.ts index 00b9c2981f9..4d7b421e1c8 100644 --- a/src/node/utils/Settings.ts +++ b/src/node/utils/Settings.ts @@ -107,6 +107,7 @@ exports.ttl = { RefreshToken: 1 * 24 * 60 * 60, // 1 day in seconds } +exports.updateServer = "https://static.etherpad.org" /* @@ -379,6 +380,14 @@ exports.sso = { */ exports.showSettingsInAdminPage = true; +/* + * Settings for cleanup of pads + */ +exports.cleanup = { + enabled: false, + keepRevisions: 100, +} + /* * By default, when caret is moved out of viewport, it scrolls the minimum * height needed to make this line visible. diff --git a/src/node/utils/UpdateCheck.ts b/src/node/utils/UpdateCheck.ts index 534c5c640fa..de7d2eea62f 100644 --- a/src/node/utils/UpdateCheck.ts +++ b/src/node/utils/UpdateCheck.ts @@ -20,7 +20,7 @@ const loadEtherpadInformations = () => { return infos; } - return axios.get('https://static.etherpad.org/info.json', {headers: headers}) + return axios.get(`${settings.updateServer}/info.json`, {headers: headers}) .then(async (resp: any) => { infos = await resp.data; if (infos === undefined || infos === null) { diff --git a/src/package.json b/src/package.json index 3a6d232a010..4ebb80a297f 100644 --- a/src/package.json +++ b/src/package.json @@ -38,13 +38,13 @@ "cross-spawn": "^7.0.3", "ejs": "^3.1.10", "esbuild": "^0.23.1", - "express": "4.19.2", + "express": "4.21.0", "express-rate-limit": "^7.4.0", "fast-deep-equal": "^3.1.3", "find-root": "1.1.0", "formidable": "^3.5.1", "http-errors": "^2.0.0", - "jose": "^5.8.0", + "jose": "^5.9.2", "js-cookie": "^3.0.5", "jsdom": "^25.0.0", "jsonminify": "0.4.2", @@ -57,31 +57,32 @@ "measured-core": "^2.0.0", "mime-types": "^2.1.35", "oidc-provider": "^8.5.1", - "openapi-backend": "^5.10.6", + "openapi-backend": "^5.11.0", "proxy-addr": "^2.0.7", "rate-limiter-flexible": "^5.0.3", "rehype": "^13.0.1", - "rehype-minify-whitespace": "^6.0.0", + "rehype-minify-whitespace": "^6.0.1", "resolve": "1.22.8", + "rusty-store-kv": "^1.3.1", "security": "1.0.0", "semver": "^7.6.3", "socket.io": "^4.7.5", "socket.io-client": "^4.7.5", "superagent": "10.1.0", + "swagger-ui-express": "^5.0.1", "tinycon": "0.6.8", - "tsx": "4.19.0", - "ueberdb2": "^4.2.103", + "tsx": "4.19.1", + "ueberdb2": "^5.0.2", "underscore": "1.13.7", "unorm": "1.6.0", - "wtfnode": "^0.9.3", - "rusty-store-kv": "^1.2.0" + "wtfnode": "^0.9.3" }, "bin": { "etherpad-healthcheck": "../bin/etherpad-healthcheck", "etherpad-lite": "node/server.ts" }, "devDependencies": { - "@playwright/test": "^1.47.0", + "@playwright/test": "^1.47.1", "@types/async": "^3.2.24", "@types/express": "^4.17.21", "@types/formidable": "^3.4.5", @@ -89,17 +90,19 @@ "@types/jquery": "^3.5.30", "@types/js-cookie": "^3.0.6", "@types/jsdom": "^21.1.7", - "@types/jsonwebtoken": "^9.0.6", + "@types/jsonwebtoken": "^9.0.7", "@types/mime-types": "^2.1.4", - "@types/mocha": "^10.0.7", - "@types/node": "^22.5.4", + "@types/mocha": "^10.0.8", + "@types/node": "^22.5.5", "@types/oidc-provider": "^8.5.2", "@types/semver": "^7.5.8", "@types/sinon": "^17.0.3", "@types/supertest": "^6.0.2", + "@types/swagger-ui-express": "^4.1.6", "@types/underscore": "^1.11.15", - "chokidar": "^3.6.0", - "eslint": "^9.9.1", + "@types/whatwg-mimetype": "^3.0.2", + "chokidar": "^4.0.0", + "eslint": "^9.10.0", "eslint-config-etherpad": "^4.0.4", "etherpad-cli-client": "^3.0.2", "mocha": "^10.7.3", @@ -107,11 +110,11 @@ "nodeify": "^1.0.1", "openapi-schema-validation": "^0.4.2", "set-cookie-parser": "^2.7.0", - "sinon": "^18.0.0", + "sinon": "^19.0.2", "split-grid": "^1.0.11", "supertest": "^7.0.0", - "typescript": "^5.5.4", - "vitest": "^2.0.5" + "typescript": "^5.6.2", + "vitest": "^2.1.1" }, "engines": { "node": ">=18.18.2", @@ -138,6 +141,6 @@ "debug:socketio": "cross-env DEBUG=socket.io* node --require tsx/cjs node/server.ts", "test:vitest": "vitest" }, - "version": "2.2.4", + "version": "2.2.5", "license": "Apache-2.0" } diff --git a/src/static/js/ace2_inner.ts b/src/static/js/ace2_inner.ts index 0dce038a89c..15db776e1a3 100644 --- a/src/static/js/ace2_inner.ts +++ b/src/static/js/ace2_inner.ts @@ -167,7 +167,7 @@ function Ace2Inner(editorInfo, cssManagers) { for (const name of names) console[name] = noop; } - const scheduler = parent; // hack for opera required + const scheduler = window; // hack for opera required const performDocumentReplaceRange = (start, end, newText) => { if (start === undefined) start = rep.selStart; @@ -240,7 +240,7 @@ function Ace2Inner(editorInfo, cssManagers) { bgcolor = fadeColor(bgcolor, info.fade); } const textColor = - colorutils.textColorFromBackgroundColor(bgcolor, parent.parent.clientVars.skinName); + colorutils.textColorFromBackgroundColor(bgcolor, window.clientVars.skinName); const styles = [ cssManagers.inner.selectorStyle(authorSelector), cssManagers.parent.selectorStyle(authorSelector), @@ -1270,7 +1270,7 @@ function Ace2Inner(editorInfo, cssManagers) { const prevLine = rep.lines.prev(thisLine); const prevLineText = prevLine.text; let theIndent = /^ *(?:)/.exec(prevLineText)[0]; - const shouldIndent = parent.parent.clientVars.indentationOnNewLine; + const shouldIndent = window.clientVars.indentationOnNewLine; if (shouldIndent && /[[(:{]\s*$/.exec(prevLineText)) { theIndent += THE_TAB; } @@ -2023,7 +2023,7 @@ function Ace2Inner(editorInfo, cssManagers) { const isPadLoading = (t) => t === 'setup' || t === 'setBaseText' || t === 'importText'; const updateStyleButtonState = (attribName, hasStyleOnRepSelection) => { - const $formattingButton = parent.parent.$(`[data-key="${attribName}"]`).find('a'); + const $formattingButton = window.$(`[data-key="${attribName}"]`).find('a'); $formattingButton.toggleClass(SELECT_BUTTON_CLASS, hasStyleOnRepSelection); }; @@ -2277,7 +2277,7 @@ function Ace2Inner(editorInfo, cssManagers) { }; const hideEditBarDropdowns = () => { - window.parent.parent.padeditbar.toggleDropDown('none'); + window.padeditbar.toggleDropDown('none'); }; const renumberList = (lineNum) => { @@ -2582,7 +2582,7 @@ function Ace2Inner(editorInfo, cssManagers) { specialHandled = specialHandledInHook.indexOf(true) !== -1; } - const padShortcutEnabled = parent.parent.clientVars.padShortcutEnabled; + const padShortcutEnabled = window.clientVars.padShortcutEnabled; if (!specialHandled && isTypeForSpecialKey && altKey && keyCode === 120 && padShortcutEnabled.altF9) { @@ -2591,7 +2591,7 @@ function Ace2Inner(editorInfo, cssManagers) { // As ubuntu cannot use Alt F10.... // Focus on the editbar. // -- TODO: Move Focus back to previous state (we know it so we can use it) - const firstEditbarElement = parent.parent.$('#editbar') + const firstEditbarElement = window.$('#editbar') .children('ul').first().children().first() .children().first().children().first(); $(this).trigger('blur'); @@ -2603,8 +2603,8 @@ function Ace2Inner(editorInfo, cssManagers) { padShortcutEnabled.altC) { // Alt c focuses on the Chat window $(this).trigger('blur'); - parent.parent.chat.show(); - parent.parent.$('#chatinput').trigger('focus'); + window.chat.show(); + window.$('#chatinput').trigger('focus'); evt.preventDefault(); } if (!specialHandled && type === 'keydown' && @@ -2626,12 +2626,12 @@ function Ace2Inner(editorInfo, cssManagers) { if (authorId) authorIds.add(authorId); } } - const idToName = new Map(parent.parent.pad.userList().map((a) => [a.userId, a.name])); - const myId = parent.parent.clientVars.userId; + const idToName = new Map(window.pad.userList().map((a) => [a.userId, a.name])); + const myId = window.clientVars.userId; const authors = [...authorIds].map((id) => id === myId ? 'me' : idToName.get(id) || 'unknown'); - parent.parent.$.gritter.add({ + window.$.gritter.add({ title: 'Line Authors', text: authors.length === 0 ? 'No author information is available' @@ -2680,7 +2680,7 @@ function Ace2Inner(editorInfo, cssManagers) { specialHandled = true; // close all gritters when the user hits escape key - parent.parent.$.gritter.removeAll(); + window.$.gritter.removeAll(); } if (!specialHandled && isTypeForCmdKey && /* Do a saved revision on ctrl S */ @@ -2688,13 +2688,13 @@ function Ace2Inner(editorInfo, cssManagers) { !evt.altKey && padShortcutEnabled.cmdS) { evt.preventDefault(); - const originalBackground = parent.parent.$('#revisionlink').css('background'); - parent.parent.$('#revisionlink').css({background: 'lightyellow'}); + const originalBackground = window.$('#revisionlink').css('background'); + window.$('#revisionlink').css({background: 'lightyellow'}); scheduler.setTimeout(() => { - parent.parent.$('#revisionlink').css({background: originalBackground}); + window.$('#revisionlink').css({background: originalBackground}); }, 1000); - /* The parent.parent part of this is BAD and I feel bad.. It may break something */ - parent.parent.pad.collabClient.sendMessage({type: 'SAVE_REVISION'}); + + window.pad.collabClient.sendMessage({type: 'SAVE_REVISION'}); specialHandled = true; } if (!specialHandled && isTypeForSpecialKey && diff --git a/src/static/js/broadcast.ts b/src/static/js/broadcast.ts index 85ccdb0ff6d..347cf29e29e 100644 --- a/src/static/js/broadcast.ts +++ b/src/static/js/broadcast.ts @@ -186,7 +186,7 @@ const loadBroadcastJS = (socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro mutateTextLines(changeset, padContents); padContents.currentRevision = revision; - padContents.currentTime += timeDelta * 1000; + padContents.currentTime += timeDelta; updateTimer(); @@ -299,7 +299,7 @@ const loadBroadcastJS = (socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro // Loading changeset history for new revision loadChangesetsForRevision(newRevision, update); // Loading changeset history for old revision (to make diff between old and new revision) - loadChangesetsForRevision(padContents.currentRevision - 1); + loadChangesetsForRevision(padContents.currentRevision); } const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]); diff --git a/src/static/js/changesettracker.ts b/src/static/js/changesettracker.ts index 41d5c266891..a8d19945d23 100644 --- a/src/static/js/changesettracker.ts +++ b/src/static/js/changesettracker.ts @@ -140,7 +140,7 @@ const makeChangesetTracker = (scheduler, apool, aceCallbacksProvider) => { toSubmit = compose(submittedChangeset, userChangeset, apool); } else { // Get my authorID - const authorId = parent.parent.pad.myUserInfo.userId; + const authorId = window.pad.myUserInfo.userId; // Sanitize authorship: Replace all author attributes with this user's author ID in case the // text was copied from another author. diff --git a/src/static/js/pluginfw/installer.ts b/src/static/js/pluginfw/installer.ts index effed768a80..c605378e1bd 100644 --- a/src/static/js/pluginfw/installer.ts +++ b/src/static/js/pluginfw/installer.ts @@ -171,7 +171,7 @@ export const getAvailablePlugins = (maxCacheAge: number|false) => { return resolve(availablePlugins); } - await axios.get('https://static.etherpad.org/plugins.json', {headers}) + await axios.get(`${settings.updateServer}/plugins.json`, {headers}) .then((pluginsLoaded:AxiosResponse>) => { availablePlugins = pluginsLoaded.data; cacheTimestamp = nowTimestamp; diff --git a/src/static/js/scroll.ts b/src/static/js/scroll.ts index 95075d8078d..74c2462434e 100644 --- a/src/static/js/scroll.ts +++ b/src/static/js/scroll.ts @@ -15,7 +15,8 @@ class Scroll { // DOM reference this.outerWin = outerWin; this.doc = this.outerWin.contentDocument!; - this.rootDocument = parent.parent.document; + this.rootDocument = document; + console.log(this.rootDocument) } scrollWhenCaretIsInTheLastLineOfViewportWhenNecessary(rep: RepModel, isScrollableEvent: boolean, innerHeight: number) { @@ -112,7 +113,7 @@ class Scroll { }; _getEditorPositionTop() { - const editor = parent.document.getElementsByTagName('iframe'); + const editor = document.getElementsByTagName('iframe'); const editorPositionTop = editor[0].offsetTop; return editorPositionTop; }; diff --git a/ui/package.json b/ui/package.json index f39e405251d..d10a992e69a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -11,7 +11,7 @@ }, "devDependencies": { "ep_etherpad-lite": "workspace:../src", - "typescript": "^5.5.4", - "vite": "^5.4.3" + "typescript": "^5.6.2", + "vite": "^5.4.7" } }