diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2204679a6..8915c39dd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -66,10 +66,6 @@ updates: - dependency-name: "@babel/preset-react" versions: - 7.13.13 - - dependency-name: codemirror - versions: - - 5.59.3 - - 5.60.0 - dependency-name: classnames versions: - 2.3.0 diff --git a/changelog.md b/changelog.md index 1e1ac70e2..136f6346a 100644 --- a/changelog.md +++ b/changelog.md @@ -85,14 +85,52 @@ pre { } .page .df { - font-size: 2em; - vertical-align: middle; + font-size: 2em; + vertical-align: middle; } ``` ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). +### Saturday 4/20/2026 - v3.22.0 + +{{taskList +##### 5e-Cleric +* [x] Major update to editor framework (Codemirror 6) +Fixes issues [#3511](https://github.com/naturalcrit/homebrewery/issues/3511), [#4590](https://github.com/naturalcrit/homebrewery/issues/4590), [#4563](https://github.com/naturalcrit/homebrewery/issues/4653), [#4655](https://github.com/naturalcrit/homebrewery/issues/4655) +* [x] Fix to Admin page tab names + +##### G-Ambatte +* [x] Fix white page crash on certain browsers +}} + +### Saturday 4/04/2026 - v3.21.0 + +{{taskList +##### Gazook89 +* [x] Allow custom {{openSans **:fas_table_list: SNIPPETS**}} to be inserted mid-line + +##### abquintic +* [x] Move example snippet images out of imgur (for folks without imgur access) + +##### 5e-Cleric +* [x] Add auto-suggest to tag entry input box +* [x] Replace all example artwork with +* [x] Added tooltips to the {{openSans :fas_circle_info: **Properties**}} menu +* [x] Removed {{openSans **SYSTEMS**}} checkboxes from {{openSans :fas_circle_info: **Properties**}} menu; instead {{openSans **TAGS**}} should be used for this purpose +* [x] Replace all AI-generated art with public domain art +* [x] Major backend refactor to use Vite + +##### A1Asriel (new contributor!) +* [x] Add fix for column breaks on Firefox + +Fixes issues [#543](https://github.com/naturalcrit/homebrewery/issues/543), [#2473](https://github.com/naturalcrit/homebrewery/issues/2473), [#3712](https://github.com/naturalcrit/homebrewery/issues/3712) + +##### G-Ambatte, abquintic, 5e-Cleric +* [x] Multiple other backend fixes and refactors +}} + ### Friday 1/11/2026 - v3.20.1 {{taskList @@ -2358,4 +2396,4 @@ Massive changelog incoming: * Added `phb.standalone.css` plus a build system for creating it * Added page numbers and footer text -* Page accent now flips each page +* Page accent now flips each page \ No newline at end of file diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index cc6eb72ca..a8ee10562 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -49,4 +49,4 @@ const Admin = ()=>{ ); }; -module.exports = Admin; +export default Admin; diff --git a/client/admin/admin.less b/client/admin/admin.less index 0fc353194..432f92e8b 100644 --- a/client/admin/admin.less +++ b/client/admin/admin.less @@ -1,11 +1,9 @@ -@import 'naturalcrit/styles/reset.less'; -@import 'naturalcrit/styles/elements.less'; -@import 'naturalcrit/styles/animations.less'; -@import 'naturalcrit/styles/colors.less'; -@import 'naturalcrit/styles/tooltip.less'; -@import './themes/fonts/iconFonts/fontAwesome.less'; - -@import 'font-awesome/css/font-awesome.css'; +@import '@sharedStyles/reset.less'; +@import '@sharedStyles/elements.less'; +@import '@sharedStyles/animations.less'; +@import '@sharedStyles/colors.less'; +@import '@sharedStyles/tooltip.less'; +@import '@themes/fonts/iconFonts/fontAwesome.less'; html,body, #reactContainer, .naturalCrit { min-height : 100%; } diff --git a/client/admin/brewUtils/brewCleanup/brewCleanup.jsx b/client/admin/brewUtils/brewCleanup/brewCleanup.jsx index 6cec01178..721ec1e00 100644 --- a/client/admin/brewUtils/brewCleanup/brewCleanup.jsx +++ b/client/admin/brewUtils/brewCleanup/brewCleanup.jsx @@ -1,71 +1,72 @@ -import React from 'react'; -import createReactClass from 'create-react-class'; +import React, { useState } from 'react'; import request from 'superagent'; -const BrewCleanup = createReactClass({ - displayName : 'BrewCleanup', - getDefaultProps(){ - return {}; - }, - getInitialState() { - return { - count : 0, +const BrewCleanup = ({})=>{ + const [count, setCount] = useState(0); + const [pending, setPending] = useState(false); + const [primed, setPrimed] = useState(false); + const [error, setError] = useState(null); - pending : false, - primed : false, - err : null - }; - }, - prime(){ - this.setState({ pending: true }); + const prime = async ()=>{ + setPending(true); - request.get('/admin/cleanup') - .then((res)=>this.setState({ count: res.body.count, primed: true })) - .catch((err)=>this.setState({ error: err })) - .finally(()=>this.setState({ pending: false })); - }, - cleanup(){ - this.setState({ pending: true }); + try { + const res = await request.get('/admin/cleanup'); - request.post('/admin/cleanup') - .then((res)=>this.setState({ count: res.body.count })) - .catch((err)=>this.setState({ error: err })) - .finally(()=>this.setState({ pending: false, primed: false })); - }, - renderPrimed(){ - if(!this.state.primed) return; - - if(!this.state.count){ - return
No Matching Brews found.
; + setCount(res.body.count); + setPrimed(true); + } catch (err) { + setError(err); + } finally { + setPending(false); } + }; + + const cleanup = async ()=>{ + setPending(true); + + try { + const res = await request.post('/admin/cleanup'); + + setCount(res.body.count); + } catch (err) { + setError(err); + } finally { + setPending(false); + setPrimed(false); + } + }; + const renderPrimed = ()=>{ + if(!primed) return; + + if(!count) return
No Matching Brews found.
; + return
- - Found {this.state.count} Brews that could be removed. + Found {count} Brews that could be removed.
; - }, - render(){ - return
-

Brew Cleanup

-

Removes very short brews to tidy up the database

+ }; - - {this.renderPrimed()} + return
+

Brew Cleanup

+

Removes very short brews to tidy up the database

- {this.state.error - &&
{this.state.error.toString()}
+
; - } -}); + + {renderPrimed()} + + {error &&
{error.toString()}
} +
; + +}; export default BrewCleanup; diff --git a/client/admin/brewUtils/brewUtils.less b/client/admin/brewUtils/brewUtils.less index 5bbbc3f69..cfa7dbbdf 100644 --- a/client/admin/brewUtils/brewUtils.less +++ b/client/admin/brewUtils/brewUtils.less @@ -1,3 +1,5 @@ +@import '@sharedStyles/colors.less'; + .brewUtil { .result { margin-top : 20px; diff --git a/client/admin/main.jsx b/client/admin/main.jsx new file mode 100644 index 000000000..a5b7c84ad --- /dev/null +++ b/client/admin/main.jsx @@ -0,0 +1,6 @@ +import { createRoot } from 'react-dom/client'; +import Admin from './admin.jsx'; + +const props = window.__INITIAL_PROPS__ || {}; + +createRoot(document.getElementById('reactRoot')).render(); diff --git a/client/components/codeEditor/autocompleteEmoji.js b/client/components/codeEditor/autocompleteEmoji.js deleted file mode 100644 index d5a3a71aa..000000000 --- a/client/components/codeEditor/autocompleteEmoji.js +++ /dev/null @@ -1,84 +0,0 @@ -import diceFont from 'themes/fonts/iconFonts/diceFont.js'; -import elderberryInn from 'themes/fonts/iconFonts/elderberryInn.js'; -import fontAwesome from 'themes/fonts/iconFonts/fontAwesome.js'; -import gameIcons from 'themes/fonts/iconFonts/gameIcons.js'; - -const emojis = { - ...diceFont, - ...elderberryInn, - ...fontAwesome, - ...gameIcons -}; - -const showAutocompleteEmoji = function(CodeMirror, editor) { - CodeMirror.commands.autocomplete = function(editor) { - editor.showHint({ - completeSingle : false, - hint : function(editor) { - const cursor = editor.getCursor(); - const line = cursor.line; - const lineContent = editor.getLine(line); - const start = lineContent.lastIndexOf(':', cursor.ch - 1) + 1; - const end = cursor.ch; - const currentWord = lineContent.slice(start, end); - - - const list = Object.keys(emojis).filter(function(emoji) { - return emoji.toLowerCase().indexOf(currentWord.toLowerCase()) >= 0; - }).sort((a, b)=>{ - const lowerA = a.replace(/\d+/g, function(match) { // Temporarily convert any numbers in emoji string - return match.padStart(4, '0'); // to 4-digits, left-padded with 0's, to aid in - }).toLowerCase(); // sorting numbers, i.e., "d6, d10, d20", not "d10, d20, d6" - const lowerB = b.replace(/\d+/g, function(match) { // Also make lowercase for case-insensitive alpha sorting - return match.padStart(4, '0'); - }).toLowerCase(); - - if(lowerA < lowerB) - return -1; - return 1; - }).map(function(emoji) { - return { - text : `${emoji}:`, // Text to output to editor when option is selected - render : function(element, self, data) { // How to display the option in the dropdown - const div = document.createElement('div'); - div.innerHTML = ` ${emoji}`; - element.appendChild(div); - } - }; - }); - - return { - list : list.length ? list : [], - from : CodeMirror.Pos(line, start), - to : CodeMirror.Pos(line, end) - }; - } - }); - }; - - editor.on('inputRead', function(instance, change) { - const cursor = editor.getCursor(); - const line = editor.getLine(cursor.line); - - // Get the text from the start of the line to the cursor - const textToCursor = line.slice(0, cursor.ch); - - // Do not autosuggest emojis in curly span/div/injector properties - if(line.includes('{')) { - const curlyToCursor = textToCursor.slice(textToCursor.indexOf(`{`)); - const curlySpanRegex = /{(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\1$/g; - - if(curlySpanRegex.test(curlyToCursor)) - return; - } - - // Check if the text ends with ':xyz' - if(/:[^\s:]+$/.test(textToCursor)) { - CodeMirror.commands.autocomplete(editor); - } - }); -}; - -export default { - showAutocompleteEmoji -}; \ No newline at end of file diff --git a/client/components/codeEditor/close-tag.js b/client/components/codeEditor/close-tag.js deleted file mode 100644 index 84cf62169..000000000 --- a/client/components/codeEditor/close-tag.js +++ /dev/null @@ -1,48 +0,0 @@ -const autoCloseCurlyBraces = function(CodeMirror, cm, typingClosingBrace) { - const ranges = cm.listSelections(), replacements = []; - for (let i = 0; i < ranges.length; i++) { - if(!ranges[i].empty()) return CodeMirror.Pass; - const pos = ranges[i].head, line = cm.getLine(pos.line), tok = cm.getTokenAt(pos); - if(!typingClosingBrace && (tok.type == 'string' || tok.string.charAt(0) != '{' || tok.start != pos.ch - 1)) - return CodeMirror.Pass; - else if(typingClosingBrace) { - let hasUnclosedBraces = false, index = -1; - do { - index = line.indexOf('{{', index + 1); - if(index !== -1 && line.indexOf('}}', index + 1) === -1) { - hasUnclosedBraces = true; - break; - } - } while (index !== -1); - if(!hasUnclosedBraces) return CodeMirror.Pass; - } - - replacements[i] = typingClosingBrace ? { - text : '}}', - newPos : CodeMirror.Pos(pos.line, pos.ch + 2) - } : { - text : '{}}', - newPos : CodeMirror.Pos(pos.line, pos.ch + 1) - }; - } - - for (let i = ranges.length - 1; i >= 0; i--) { - const info = replacements[i]; - cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, '+insert'); - const sel = cm.listSelections().slice(0); - sel[i] = { - head : info.newPos, - anchor : info.newPos - }; - cm.setSelections(sel); - } -}; - -export default { - autoCloseCurlyBraces : function(CodeMirror, codeMirror) { - const map = { name: 'autoCloseCurlyBraces' }; - map[`'{'`] = function(cm) { return autoCloseCurlyBraces(CodeMirror, cm); }; - map[`'}'`] = function(cm) { return autoCloseCurlyBraces(CodeMirror, cm, true); }; - codeMirror?.addKeyMap(map); - } -}; \ No newline at end of file diff --git a/client/components/codeEditor/codeEditor.jsx b/client/components/codeEditor/codeEditor.jsx index cd140ad07..c5cf669bd 100644 --- a/client/components/codeEditor/codeEditor.jsx +++ b/client/components/codeEditor/codeEditor.jsx @@ -1,490 +1,402 @@ -/* eslint-disable max-lines */ +/* eslint max-lines: ["error", { "max": 405 }] */ import './codeEditor.less'; -import React from 'react'; -import createReactClass from 'create-react-class'; -import _ from 'lodash'; -import closeTag from './close-tag'; -import autoCompleteEmoji from './autocompleteEmoji'; -let CodeMirror; +import React, { useEffect, useRef, forwardRef, useImperativeHandle } from 'react'; -const CodeEditor = createReactClass({ - displayName : 'CodeEditor', - getDefaultProps : function() { - return { - language : '', - tab : 'brewText', - value : '', - wrap : true, - onChange : ()=>{}, - enableFolding : true, - editorTheme : 'default' - }; +import { + EditorView, + keymap, + lineNumbers, + highlightActiveLineGutter, + highlightActiveLine, + scrollPastEnd, + Decoration, + drawSelection, + dropCursor, + rectangularSelection, + crosshairCursor, +} from '@codemirror/view'; +import { EditorState, Compartment, StateEffect, StateField } from '@codemirror/state'; +import { + unfoldAll as unfoldAllCmd, + foldGutter, + foldKeymap, + foldEffect, + foldState, + syntaxHighlighting, +} from '@codemirror/language'; +import { defaultKeymap, history, undo, redo, undoDepth, redoDepth } from '@codemirror/commands'; +import { languages } from '@codemirror/language-data'; +import { css } from '@codemirror/lang-css'; +import { markdown, markdownLanguage } from '@codemirror/lang-markdown'; +import { html } from '@codemirror/lang-html'; +import { autocompleteEmoji } from './extensions/autocompleteEmoji.js'; +import { searchKeymap, search } from '@codemirror/search'; +import { closeBrackets } from '@codemirror/autocomplete'; + +const autoCloseBrackets = closeBrackets({ brackets: ['()', '[]', '{{}}'] }); + +import defaultCM5Theme from '@themes/codeMirror/default.js'; +import darkbrewery from '@themes/codeMirror/darkbrewery.js'; +import cm5Themes from 'codemirror-5-themes'; + +const themes = { default: defaultCM5Theme, ...cm5Themes, darkbrewery }; +const themeCompartment = new Compartment(); +const highlightCompartment = new Compartment(); + +import { generalKeymap, markdownKeymap } from './extensions/customKeyMaps.js'; +import foldOnPages from './extensions/customFolding.js'; +import { customHighlightPlugin, customHighlightStyle } from './extensions/customHighlight.js'; +import { legacyCustomHighlightStyle } from './extensions/legacyCustomHighlight.js'; + +const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m; + +const setProgrammaticCursorLine = StateEffect.define(); + +const programmaticCursorLineField = StateField.define({ + create() { + return Decoration.none; }, + update(decorations, transitionState) { + //deco is the decoratiions object + //tr is the transition state object, tr.effects is an array of stateEffects + //seems to be the easiest way of setting a class programatically only when called + for (const effects of transitionState.effects) { + if(effects.is(setProgrammaticCursorLine)) { + const pos = effects.value; + if(pos == null) return Decoration.none; + const line = transitionState.state.doc.lineAt(pos); - getInitialState : function() { - return { - docs : {} - }; - }, - - editor : React.createRef(null), - - async componentDidMount() { - CodeMirror = (await import('codemirror')).default; - this.CodeMirror = CodeMirror; - - await import('codemirror/mode/gfm/gfm.js'); - await import('codemirror/mode/css/css.js'); - await import('codemirror/mode/javascript/javascript.js'); - - // addons - await import('codemirror/addon/fold/foldcode.js'); - await import('codemirror/addon/fold/foldgutter.js'); - await import('codemirror/addon/fold/xml-fold.js'); - await import('codemirror/addon/search/search.js'); - await import('codemirror/addon/search/searchcursor.js'); - await import('codemirror/addon/search/jump-to-line.js'); - await import('codemirror/addon/search/match-highlighter.js'); - await import('codemirror/addon/search/matchesonscrollbar.js'); - await import('codemirror/addon/dialog/dialog.js'); - await import('codemirror/addon/scroll/scrollpastend.js'); - await import('codemirror/addon/edit/closetag.js'); - await import('codemirror/addon/hint/show-hint.js'); - // import 'codemirror/addon/selection/active-line.js'; - // import 'codemirror/addon/edit/trailingspace.js'; - - - // register helpers dynamically as well - const foldPagesCode = (await import('./fold-pages')).default; - const foldCSSCode = (await import('./fold-css')).default; - foldPagesCode.registerHomebreweryHelper(CodeMirror); - foldCSSCode.registerHomebreweryHelper(CodeMirror); - - this.buildEditor(); - const newDoc = CodeMirror?.Doc(this.props.value, this.props.language); - this.codeMirror?.swapDoc(newDoc); - }, - - - componentDidUpdate : function(prevProps) { - if(prevProps.view !== this.props.view){ //view changed; swap documents - let newDoc; - - if(!this.state.docs[this.props.view]) { - newDoc = CodeMirror?.Doc(this.props.value, this.props.language); - } else { - newDoc = this.state.docs[this.props.view]; + return Decoration.set([ + Decoration.line({ + class : 'sourceMoveFlash' + }).range(line.from) + ]); } - - const oldDoc = { [prevProps.view]: this.codeMirror?.swapDoc(newDoc) }; - - this.setState((prevState)=>({ - docs : _.merge({}, prevState.docs, oldDoc) - })); - - this.props.rerenderParent(); - } else if(this.codeMirror?.getValue() != this.props.value) { //update editor contents if brew.text is changed from outside - this.codeMirror?.setValue(this.props.value); - } - - if(this.props.enableFolding) { - this.codeMirror?.setOption('foldOptions', this.foldOptions(this.codeMirror)); - } else { - this.codeMirror?.setOption('foldOptions', false); - } - - if(prevProps.editorTheme !== this.props.editorTheme){ - this.codeMirror?.setOption('theme', this.props.editorTheme); } + return decorations; }, - - buildEditor : function() { - this.codeMirror = CodeMirror(this.editor.current, { - lineNumbers : true, - lineWrapping : this.props.wrap, - indentWithTabs : false, - tabSize : 2, - smartIndent : false, - historyEventDelay : 250, - scrollPastEnd : true, - extraKeys : { - 'Tab' : this.indent, - 'Shift-Tab' : this.dedent, - 'Ctrl-B' : this.makeBold, - 'Cmd-B' : this.makeBold, - 'Shift-Ctrl-=' : this.makeSuper, - 'Shift-Cmd-=' : this.makeSuper, - 'Ctrl-=' : this.makeSub, - 'Cmd-=' : this.makeSub, - 'Ctrl-I' : this.makeItalic, - 'Cmd-I' : this.makeItalic, - 'Ctrl-U' : this.makeUnderline, - 'Cmd-U' : this.makeUnderline, - 'Ctrl-.' : this.makeNbsp, - 'Cmd-.' : this.makeNbsp, - 'Shift-Ctrl-.' : this.makeSpace, - 'Shift-Cmd-.' : this.makeSpace, - 'Shift-Ctrl-,' : this.removeSpace, - 'Shift-Cmd-,' : this.removeSpace, - 'Ctrl-M' : this.makeSpan, - 'Cmd-M' : this.makeSpan, - 'Shift-Ctrl-M' : this.makeDiv, - 'Shift-Cmd-M' : this.makeDiv, - 'Ctrl-/' : this.makeComment, - 'Cmd-/' : this.makeComment, - 'Ctrl-K' : this.makeLink, - 'Cmd-K' : this.makeLink, - 'Ctrl-L' : ()=>this.makeList('UL'), - 'Cmd-L' : ()=>this.makeList('UL'), - 'Shift-Ctrl-L' : ()=>this.makeList('OL'), - 'Shift-Cmd-L' : ()=>this.makeList('OL'), - 'Shift-Ctrl-1' : ()=>this.makeHeader(1), - 'Shift-Ctrl-2' : ()=>this.makeHeader(2), - 'Shift-Ctrl-3' : ()=>this.makeHeader(3), - 'Shift-Ctrl-4' : ()=>this.makeHeader(4), - 'Shift-Ctrl-5' : ()=>this.makeHeader(5), - 'Shift-Ctrl-6' : ()=>this.makeHeader(6), - 'Shift-Cmd-1' : ()=>this.makeHeader(1), - 'Shift-Cmd-2' : ()=>this.makeHeader(2), - 'Shift-Cmd-3' : ()=>this.makeHeader(3), - 'Shift-Cmd-4' : ()=>this.makeHeader(4), - 'Shift-Cmd-5' : ()=>this.makeHeader(5), - 'Shift-Cmd-6' : ()=>this.makeHeader(6), - 'Shift-Ctrl-Enter' : this.newColumn, - 'Shift-Cmd-Enter' : this.newColumn, - 'Ctrl-Enter' : this.newPage, - 'Cmd-Enter' : this.newPage, - 'Ctrl-F' : 'findPersistent', - 'Cmd-F' : 'findPersistent', - 'Shift-Enter' : 'findPersistentPrevious', - 'Ctrl-[' : this.foldAllCode, - 'Cmd-[' : this.foldAllCode, - 'Ctrl-]' : this.unfoldAllCode, - 'Cmd-]' : this.unfoldAllCode - }, - foldGutter : true, - foldOptions : this.foldOptions(this.codeMirror), - gutters : ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], - autoCloseTags : true, - styleActiveLine : true, - showTrailingSpace : false, - theme : this.props.editorTheme - // specialChars : / /, - // specialCharPlaceholder : function(char) { - // const el = document.createElement('span'); - // el.className = 'cm-space'; - // el.innerHTML = ' '; - // return el; - // } - }); - - // Add custom behaviors (auto-close curlies and auto-complete emojis) - closeTag.autoCloseCurlyBraces(CodeMirror, this.codeMirror); - autoCompleteEmoji.showAutocompleteEmoji(CodeMirror, this.codeMirror); - - // Note: codeMirror passes a copy of itself in this callback. cm === this.codeMirror?. Either one works. - this.codeMirror?.on('change', (cm)=>{this.props.onChange(cm.getValue());}); - this.updateSize(); - }, - - // Use for GFM tabs that use common hot-keys - isGFM : function() { - if((this.isGFM()) || (this.props.tab === 'brewSnippets')) return true; - return false; - }, - - isBrewText : function() { - if(this.isGFM()) return true; - return false; - }, - - isBrewSnippets : function() { - if(this.props.tab === 'brewSnippets') return true; - return false; - }, - - indent : function () { - const cm = this.codeMirror; - if(cm.somethingSelected()) { - cm.execCommand('indentMore'); - } else { - cm.execCommand('insertSoftTab'); - } - }, - - dedent : function () { - this.codeMirror?.execCommand('indentLess'); - }, - - makeHeader : function (number) { - if(!this.isGFM()) return; - const selection = this.codeMirror?.getSelection(); - const header = Array(number).fill('#').join(''); - this.codeMirror?.replaceSelection(`${header} ${selection}`, 'around'); - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setCursor({ line: cursor.line, ch: cursor.ch + selection.length + number + 1 }); - }, - - makeBold : function() { - if(!this.isGFM()) return; - const selection = this.codeMirror?.getSelection(), t = selection.slice(0, 2) === '**' && selection.slice(-2) === '**'; - this.codeMirror?.replaceSelection(t ? selection.slice(2, -2) : `**${selection}**`, 'around'); - if(selection.length === 0){ - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setCursor({ line: cursor.line, ch: cursor.ch - 2 }); - } - }, - - makeItalic : function() { - if(!this.isGFM()) return; - const selection = this.codeMirror.getSelection(), t = selection.slice(0, 1) === '*' && selection.slice(-1) === '*'; - this.codeMirror?.replaceSelection(t ? selection.slice(1, -1) : `*${selection}*`, 'around'); - if(selection.length === 0){ - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setCursor({ line: cursor.line, ch: cursor.ch - 1 }); - } - }, - - makeSuper : function() { - if(!this.isGFM()) return; - const selection = this.codeMirror.getSelection(), t = selection.slice(0, 1) === '^' && selection.slice(-1) === '^'; - this.codeMirror?.replaceSelection(t ? selection.slice(1, -1) : `^${selection}^`, 'around'); - if(selection.length === 0){ - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setCursor({ line: cursor.line, ch: cursor.ch - 1 }); - } - }, - - makeSub : function() { - if(!this.isGFM()) return; - const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '^^' && selection.slice(-2) === '^^'; - this.codeMirror?.replaceSelection(t ? selection.slice(2, -2) : `^^${selection}^^`, 'around'); - if(selection.length === 0){ - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setCursor({ line: cursor.line, ch: cursor.ch - 2 }); - } - }, - - - makeNbsp : function() { - if(!this.isGFM()) return; - this.codeMirror?.replaceSelection(' ', 'end'); - }, - - makeSpace : function() { - if(!this.isGFM()) return; - const selection = this.codeMirror?.getSelection(); - const t = selection.slice(0, 8) === '{{width:' && selection.slice(0 -4) === '% }}'; - if(t){ - const percent = parseInt(selection.slice(8, -4)) + 10; - this.codeMirror?.replaceSelection(percent < 90 ? `{{width:${percent}% }}` : '{{width:100% }}', 'around'); - } else { - this.codeMirror?.replaceSelection(`{{width:10% }}`, 'around'); - } - }, - - removeSpace : function() { - if(!this.isGFM()) return; - const selection = this.codeMirror?.getSelection(); - const t = selection.slice(0, 8) === '{{width:' && selection.slice(0 -4) === '% }}'; - if(t){ - const percent = parseInt(selection.slice(8, -4)) - 10; - this.codeMirror?.replaceSelection(percent > 10 ? `{{width:${percent}% }}` : '', 'around'); - } - }, - - newColumn : function() { - if(!this.isGFM()) return; - this.codeMirror?.replaceSelection('\n\\column\n\n', 'end'); - }, - - newPage : function() { - if(!this.isGFM()) return; - this.codeMirror?.replaceSelection('\n\\page\n\n', 'end'); - }, - - injectText : function(injectText, overwrite=true) { - const cm = this.codeMirror; - if(!overwrite) { - cm.setCursor(cm.getCursor('from')); - } - cm.replaceSelection(injectText, 'end'); - cm.focus(); - }, - - makeUnderline : function() { - if(!this.isGFM()) return; - const selection = this.codeMirror.getSelection(), t = selection.slice(0, 3) === '' && selection.slice(-4) === ''; - this.codeMirror?.replaceSelection(t ? selection.slice(3, -4) : `${selection}`, 'around'); - if(selection.length === 0){ - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setCursor({ line: cursor.line, ch: cursor.ch - 4 }); - } - }, - - makeSpan : function() { - if(!this.isGFM()) return; - const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '{{' && selection.slice(-2) === '}}'; - this.codeMirror?.replaceSelection(t ? selection.slice(2, -2) : `{{ ${selection}}}`, 'around'); - if(selection.length === 0){ - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setCursor({ line: cursor.line, ch: cursor.ch - 2 }); - } - }, - - makeDiv : function() { - if(!this.isGFM()) return; - const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '{{' && selection.slice(-2) === '}}'; - this.codeMirror?.replaceSelection(t ? selection.slice(2, -2) : `{{\n${selection}\n}}`, 'around'); - if(selection.length === 0){ - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setCursor({ line: cursor.line - 1, ch: cursor.ch }); // set to -2? if wanting to enter classes etc. if so, get rid of first \n when replacing selection - } - }, - - makeComment : function() { - let regex; - let cursorPos; - let newComment; - const selection = this.codeMirror?.getSelection(); - if(this.isGFM()){ - regex = /^\s*()\s*$/gs; - cursorPos = 4; - newComment = ``; - } else { - regex = /^\s*(\/\*\s?)(.*?)(\s?\*\/)\s*$/gs; - cursorPos = 3; - newComment = `/* ${selection} */`; - } - this.codeMirror?.replaceSelection(regex.test(selection) == true ? selection.replace(regex, '$2') : newComment, 'around'); - if(selection.length === 0){ - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setCursor({ line: cursor.line, ch: cursor.ch - cursorPos }); - }; - }, - - makeLink : function() { - if(!this.isGFM()) return; - const isLink = /^\[(.*)\]\((.*)\)$/; - const selection = this.codeMirror?.getSelection().trim(); - let match; - if(match = isLink.exec(selection)){ - const altText = match[1]; - const url = match[2]; - this.codeMirror?.replaceSelection(`${altText} ${url}`); - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setSelection({ line: cursor.line, ch: cursor.ch - url.length }, { line: cursor.line, ch: cursor.ch }); - } else { - this.codeMirror?.replaceSelection(`[${selection || 'alt text'}](url)`); - const cursor = this.codeMirror?.getCursor(); - this.codeMirror?.setSelection({ line: cursor.line, ch: cursor.ch - 4 }, { line: cursor.line, ch: cursor.ch - 1 }); - } - }, - - makeList : function(listType) { - if(!this.isGFM()) return; - const selectionStart = this.codeMirror.getCursor('from'), selectionEnd = this.codeMirror.getCursor('to'); - this.codeMirror?.setSelection( - { line: selectionStart.line, ch: 0 }, - { line: selectionEnd.line, ch: this.codeMirror?.getLine(selectionEnd.line).length } - ); - const newSelection = this.codeMirror?.getSelection(); - - const regex = /^\d+\.\s|^-\s/gm; - if(newSelection.match(regex) != null){ // if selection IS A LIST - this.codeMirror?.replaceSelection(newSelection.replace(regex, ''), 'around'); - } else { // if selection IS NOT A LIST - listType == 'UL' ? this.codeMirror?.replaceSelection(newSelection.replace(/^/gm, `- `), 'around') : - this.codeMirror?.replaceSelection(newSelection.replace(/^/gm, (()=>{ - let n = 1; - return ()=>{ - return `${n++}. `; - }; - })()), 'around'); - } - }, - - foldAllCode : function() { - this.codeMirror?.execCommand('foldAll'); - }, - - unfoldAllCode : function() { - this.codeMirror?.execCommand('unfoldAll'); - }, - - //=-- Externally used -==// - setCursorPosition : function(line, char){ - setTimeout(()=>{ - this.codeMirror?.focus(); - this.codeMirror?.doc.setCursor(line, char); - }, 10); - }, - getCursorPosition : function(){ - return this.codeMirror?.getCursor(); - }, - getTopVisibleLine : function(){ - const rect = this.codeMirror?.getWrapperElement().getBoundingClientRect(); - const topVisibleLine = this.codeMirror?.lineAtHeight(rect.top, 'window'); - return topVisibleLine; - }, - updateSize : function(){ - this.codeMirror?.refresh(); - }, - redo : function(){ - return this.codeMirror?.redo(); - }, - undo : function(){ - return this.codeMirror?.undo(); - }, - historySize : function(){ - return this.codeMirror?.doc.historySize(); - }, - - foldOptions : function(cm){ - return { - scanUp : true, - rangeFinder : this.props.language === 'css' ? CodeMirror.fold.homebrewerycss : CodeMirror.fold.homebrewery, - widget : (from, to)=>{ - let text = ''; - let currentLine = from.line; - let maxLength = 50; - - let foldPreviewText = ''; - while (currentLine <= to.line && text.length <= maxLength) { - const currentText = this.codeMirror?.getLine(currentLine); - currentLine++; - if(currentText[0] == '#'){ - foldPreviewText = currentText; - break; - } - if(!foldPreviewText && currentText != '\n') { - foldPreviewText = currentText; - } - } - text = foldPreviewText || `Lines ${from.line+1}-${to.line+1}`; - text = text.replace('{', '').trim(); - - // Truncate data URLs at `data:` - const startOfData = text.indexOf('data:'); - if(startOfData > 0) - maxLength = Math.min(startOfData + 5, maxLength); - - if(text.length > maxLength) - text = `${text.slice(0, maxLength)}...`; - - return `\u21A4 ${text} \u21A6`; - } - }; - }, - //----------------------// - - render : function(){ - return <> - -
- ; - } + provide : (decorationSet)=>EditorView.decorations.from(decorationSet) }); -export default CodeEditor; +const CodeEditor = forwardRef( + ( + { + language = '', + tab = 'brewText', + view, + value = '', + onChange = ()=>{}, + onCursorChange = ()=>{}, + onViewChange = ()=>{}, + editorTheme = 'default', + style, + renderer, + ...props + }, + ref, + )=>{ + const editorRef = useRef(null); + const viewRef = useRef(null); + const docsRef = useRef({}); + const tabRef = useRef(tab); + const prevTabRef = useRef(tab); + const scrollRef = useRef({}); + const foldsRef = useRef({}); + const pageMap = useRef([]); + const recomputePages = (doc)=>{ + if(tab !== 'brewText') return; + const pages = [0]; + const text = doc.toString(); + let offset = 0; + + for (const line of text.split('\n')) { + if(PAGEBREAK_REGEX_V3.test(line)) { + pages.push(offset); + } + offset += line.length + 1; + } + + pageMap.current = pages; + }; + + const findPageFromPos = (pos)=>{ + const pages = pageMap.current; + let page = 1; + + for (let i = 1; i < pages.length; i++) { + if(pos >= pages[i]) page = i + 1; + } + + return page; + }; + + const getFoldRanges = (state)=>{ + const folds = []; + state.field(foldState, false)?.between(0, state.doc.length, (from, to)=>{ + folds.push({ from, to }); + }); + return folds; + }; + + const createExtensions = ({ onChange, language, editorTheme })=>{ + const setEventListeners = EditorView.updateListener.of((update)=>{ + if(update.docChanged) { + recomputePages(update.state.doc); + onChange(update.state.doc.toString()); + } + if(update.selectionSet) { + const pos = update.state.selection.main.head; + const page = findPageFromPos(pos); + onCursorChange(page); + } + }); + + const highlightExtension = renderer === 'V3' + ? syntaxHighlighting(customHighlightStyle) + : syntaxHighlighting(legacyCustomHighlightStyle); + + const languageExtension = language === 'css' ? css() : [markdown({ base: markdownLanguage, codeLanguages: languages }), html({ autoCloseTags: true })]; + const themeExtension = Array.isArray(themes[editorTheme]) ? themes[editorTheme] : themes[editorTheme] || themes['default']; + + return [ + EditorView.lineWrapping, + setEventListeners, + languageExtension, + autoCloseBrackets, + lineNumbers(), + scrollPastEnd(), + search(), + history(), //allows for undo and redo + ...(tab !== 'brewStyles' ? [autocompleteEmoji] : []), + + //folding + foldOnPages, + foldGutter({ + openText : '▾', + closedText : '▸' + }), + + //highlights + highlightCompartment.of([customHighlightPlugin(renderer, tab), highlightExtension]), + themeCompartment.of(themeExtension), + highlightActiveLine(), + highlightActiveLineGutter(), + + //keyboard shortcut + keymap.of([...defaultKeymap, foldKeymap, ...searchKeymap]), + generalKeymap, + ...(tab !== 'brewStyles' ? [markdownKeymap] : []), + + //multiple cursors and selections + drawSelection(), + rectangularSelection(), + crosshairCursor(), + EditorState.allowMultipleSelections.of(true), + dropCursor(), + programmaticCursorLineField, + ]; + }; + + useEffect(()=>{ + if(!editorRef.current) return; + + const state = EditorState.create({ + doc : value, + extensions : createExtensions({ onChange, language, editorTheme }), + }); + + recomputePages(state.doc); + + viewRef.current = new EditorView({ + state, + parent : editorRef.current, + }); + + const view = viewRef.current; + + let ticking = false; + + const handleScroll = ()=>{ + if(ticking) return; + + ticking = true; + requestAnimationFrame(()=>{ + const top = view.scrollDOM.scrollTop; + scrollRef.current[tabRef.current] = top; + const block = view.lineBlockAtHeight(top); + const page = findPageFromPos(block.from); + onViewChange(page); + ticking = false; + }); + }; + + view.scrollDOM.addEventListener('scroll', handleScroll); + + docsRef.current[tab] = state; + + return ()=>{ + view.scrollDOM.removeEventListener('scroll', handleScroll); + viewRef.current?.destroy(); + }; + }, []); + + const restoreFolds = (view, folds)=>{ + if(!folds?.length) return; + + view.dispatch({ + effects : folds.map((f)=>foldEffect.of(f)) + }); + }; + + useEffect(()=>{ + const view = viewRef.current; + if(!view) return; + + tabRef.current = tab; + const prevTab = prevTabRef.current; + + foldsRef.current[prevTab] = getFoldRanges(view.state); + + if(prevTab !== tab) { + docsRef.current[prevTab] = view.state; + + let nextState = docsRef.current[tab]; + + if(!nextState) { + nextState = EditorState.create({ + doc : value, + extensions : createExtensions({ onChange, language, editorTheme }), + }); + } + + view.setState(nextState); + restoreFolds(view, foldsRef.current[tab]); + + const savedScroll = scrollRef.current[tab]; + + if(savedScroll != null) { + requestAnimationFrame(()=>{ + view.scrollDOM.scrollTop = savedScroll; + }); + } + + prevTabRef.current = tab; + } + view.focus(); + }, [tab]); + + useEffect(()=>{ + const view = viewRef.current; + if(!view) return; + + const current = view.state.doc.toString(); + if(value !== current) { + view.dispatch({ + changes : { from: 0, to: current.length, insert: value }, + }); + } + }, [value]); + + useEffect(()=>{ + //rebuild theme extension on theme change + const view = viewRef.current; + if(!view) return; + + const themeExtension = Array.isArray(themes[editorTheme])? themes[editorTheme]: themes[editorTheme] || themes['default']; + + view.dispatch({ + effects : themeCompartment.reconfigure(themeExtension), + }); + }, [editorTheme]); + + useEffect(()=>{ + //rebuild syntax highlight when changing tab or renderer + const view = viewRef.current; + if(!view) return; + + const highlightExtension =renderer === 'V3' + ? syntaxHighlighting(customHighlightStyle) + : syntaxHighlighting(legacyCustomHighlightStyle); + + view.dispatch({ + effects : highlightCompartment.reconfigure([customHighlightPlugin(renderer, tab), highlightExtension]), + }); + }, [renderer, tab]); + + useImperativeHandle(ref, ()=>({ + + injectText : (text)=>{ + const view = viewRef.current; + + view.dispatch( + view.state.replaceSelection(text) + ); + view.focus(); + }, + getCursorPosition : ()=>viewRef.current.state.selection.main.head, + + scrollToPage : (pageNumber, smooth = true)=>{ + const view = viewRef.current; + if(!view) return; + + const pos = pageMap.current[pageNumber - 1] ?? 0; + + view.dispatch({ + selection : { anchor: pos }, + effects : [setProgrammaticCursorLine.of(pos), EditorView.scrollIntoView(pos, { y: 'start' })], + }); + + view.focus(); + + setTimeout(()=>{ + view.dispatch({ + effects : setProgrammaticCursorLine.of(null) + }); + }, 400); + }, + + undo : ()=>undo(viewRef.current), + redo : ()=>redo(viewRef.current), + + historySize : ()=>{ + const view = viewRef.current; + if(!view) return { done: 0, undone: 0 }; + + return { + done : undoDepth(view.state), + undone : redoDepth(view.state), + }; + }, + + foldAll : ()=>{ + const view = viewRef.current; + if(!view) return; + + const doc = view.state.doc; + const pages = pageMap.current; + + const effects = pages.map((start, i)=>{ + const next = pages[i + 1] || doc.length; + const from = i ? doc.line(doc.lineAt(start).number + 1).from : 0; + const to = doc.line(doc.lineAt(next).number).from - 1; + + return to > from ? foldEffect.of({ from, to }) : null; + }).filter(Boolean); + + view.dispatch({ effects }); + }, + unfoldAll : ()=>{ + const view = viewRef.current; + if(!view) return; + view.dispatch(unfoldAllCmd(view)); + }, + + focus : ()=>viewRef.current.focus(), + })); + + return
; + }, +); + +export default CodeEditor; diff --git a/client/components/codeEditor/codeEditor.less b/client/components/codeEditor/codeEditor.less index c8e60974b..ca77f29a8 100644 --- a/client/components/codeEditor/codeEditor.less +++ b/client/components/codeEditor/codeEditor.less @@ -1,60 +1,207 @@ -@import (less) 'codemirror/lib/codemirror.css'; -@import (less) 'codemirror/addon/fold/foldgutter.css'; -@import (less) 'codemirror/addon/search/matchesonscrollbar.css'; -@import (less) 'codemirror/addon/dialog/dialog.css'; -@import (less) 'codemirror/addon/hint/show-hint.css'; - -//Icon fonts included so they can appear in emoji autosuggest dropdown -@import (less) './themes/fonts/iconFonts/diceFont.less'; -@import (less) './themes/fonts/iconFonts/elderberryInn.less'; -@import (less) './themes/fonts/iconFonts/gameIcons.less'; -@import (less) './themes/fonts/iconFonts/fontAwesome.less'; +// Icon fonts for emoji/autocomplete +@import (less) '@themes/fonts/iconFonts/diceFont.less'; +@import (less) '@themes/fonts/iconFonts/elderberryInn.less'; +@import (less) '@themes/fonts/iconFonts/gameIcons.less'; +@import (less) '@themes/fonts/iconFonts/fontAwesome.less'; @keyframes sourceMoveAnimation { - 50% { color : white;background-color : red;} - 100% { color : unset;background-color : unset;} + 50% { + color : white; + background-color : red; + } + 100% { + color : unset; + background-color : unset; + } } -.codeEditor { +:where(.codeEditor) { + width : 100%; + height : calc(100% - 25px); + font-family : monospace; + + .cm-editor { + height : 100%; + outline : none !important; + } + + &.brewSnippets .cm-snippetLine, + :where(&.brewText) .cm-pageLine { + background : #33333328; + border-top : #333399 solid 1px; + } + + &.brewSnippets { + .cm-pageLine { + color : #777777; + background : #3E4E3E1B; + border-top : #3399423B solid 1px; + } + } + + &:where(.brewText), &.brewSnippets { + + + .cm-pageLine[data-page-number]::after { + float : right; + color : grey; + content : attr(data-page-number); + } + .cm-columnSplit { + font-style : italic; + color : grey; + background-color : fade(#229999, 15%); + border-bottom : #229999 solid 1px; + } + .cm-define { + &:not(.term):not(.definition) { + font-weight : bold; + color : #949494; + background : #E5E5E5; + border-radius : 3px; + } + &.term { color : rgb(96, 117, 143); } + &.definition { color : rgb(97, 57, 178); } + } + .cm-block:not(.cm-comment), + .cm-block:not(.cm-comment) * { + font-weight : bold; + color : purple; + } + .cm-inline-block, + .cm-define .cm-inline-block { + font-weight : bold; + color : red; + span:not(.cm-comment) { color : inherit; } + } + .cm-injection:not(.cm-comment) { + font-weight : bold; + color : green; + span { color : inherit; } + } + .cm-emoji:not(.cm-comment) { + padding-bottom : 1px; + margin-left : 2px; + font-weight : bold; + color : #360034; + outline : solid 2px #FF96FC; + outline-offset : -2px; + background : #FFC8FF; + border-radius : 6px; + } + .cm-superscript:not(.cm-comment) { + font-size : 0.9em; + font-weight : bold; + vertical-align : super; + color : goldenrod; + } + .cm-subscript:not(.cm-comment) { + font-size : 0.9em; + font-weight : bold; + vertical-align : sub; + color : rgb(123, 123, 15); + } + .cm-strikethrough { + text-decoration: line-through; + } + + .cm-definitionList { + .cm-definitionTerm { color : rgb(96, 117, 143); } + .cm-definitionColon:not(:has(.cm-comment)) { + font-weight : bold; + color : #949494; + background : #E5E5E5; + border-radius : 3px; + } + .cm-definitionDesc { color : rgb(97, 57, 178); } + } + + .cm-tooltip-autocomplete { + + li { + display : flex; + gap : 10px; + align-items : center; + justify-content : flex-start; + + .cm-completionIcon { display : none; } + .cm-tooltip-autocomplete .cm-completionLabel { translate : 0 -2px; } + } + } + } + + .cm-content { tab-size : 2 !important; } + @media screen and (pointer : coarse) { font-size : 16px; } - .CodeMirror-foldmarker { + + .cm-gutterElement span { font-family : inherit; font-weight : 600; color : grey; text-shadow : none; } - .CodeMirror-foldgutter { + .cm-foldGutter { cursor : pointer; border-left : 1px solid #EEEEEE; transition : background 0.1s; &:hover { background : #DDDDDD; } } - .sourceMoveFlash .CodeMirror-line { + /* Flash animation for source moves */ + .cm-line.sourceMoveFlash { animation-name : sourceMoveAnimation; animation-duration : 0.4s; } - .CodeMirror-search-field { - width:25em !important; - outline:1px inset #00000055 !important; + /* Search input */ + .cm-searchField { + width : 25em !important; + outline : 1px inset #00000055 !important; } + .cm-image { + position:relative; + + .cm-preview { + object-fit: contain; + position:absolute; + bottom:0; + left:0; + height:200px; + width:200px; + height:200px; + padding:5px; + background-color: #fff; + border-radius:10px; + border:3px solid grey; + pointer-events: none; + opacity:0; + transition:0.2s opacity 0.5s; + translate:0 100%; + z-index:1000; + } + + &:hover .cm-preview { + opacity:1; + } + } + + /* Tab character visualization (optional) */ //.cm-tab { - // background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right; + // background: url(...) no-repeat right; //} - //.cm-trailingspace { - // .cm-space { - // background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) no-repeat right; - // } + /* Trailing space visualization (optional) */ + //.cm-trailingSpace .cm-space { + // background: url(...) no-repeat right; //} } +/* Emoji preview styling */ .emojiPreview { font-size : 1.5em; line-height : 1.2em; -} \ No newline at end of file +} diff --git a/client/components/codeEditor/extensions/autocompleteEmoji.js b/client/components/codeEditor/extensions/autocompleteEmoji.js new file mode 100644 index 000000000..309668884 --- /dev/null +++ b/client/components/codeEditor/extensions/autocompleteEmoji.js @@ -0,0 +1,76 @@ +import { autocompletion } from '@codemirror/autocomplete'; + +import diceFont from '@themes/fonts/iconFonts/diceFont.js'; +import elderberryInn from '@themes/fonts/iconFonts/elderberryInn.js'; +import fontAwesome from '@themes/fonts/iconFonts/fontAwesome.js'; +import gameIcons from '@themes/fonts/iconFonts/gameIcons.js'; + +const emojis = { + ...diceFont, + ...elderberryInn, + ...fontAwesome, + ...gameIcons +}; + +const emojiCompletionList = (context)=>{ + const word = context.matchBefore(/:[^\s:]+/); + if(!word) return null; + + const line = context.state.doc.lineAt(context.pos); + const textToCursor = line.text.slice(0, context.pos - line.from); + + if(textToCursor.includes('{')) { + const curlyToCursor = textToCursor.slice(textToCursor.indexOf('{')); + const curlySpanRegex = /{(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\1$/g; + if(curlySpanRegex.test(curlyToCursor)) return null; + } + + const currentWord = word.text.slice(1); // remove ':' + + const options = Object.keys(emojis) + .filter((e)=>e.toLowerCase().includes(currentWord.toLowerCase())) + .sort((a, b)=>{ + const normalize = (str)=>str.replace(/\d+/g, (m)=>m.padStart(4, '0')).toLowerCase(); + return normalize(a) < normalize(b) ? -1 : 1; + }) + .map((e)=>({ + label : e, + apply : `${e}:`, + type : 'text', + info : ()=>{ + const div = document.createElement('div'); + div.innerHTML = ` ${e}`; + return div; + } + })); + //Label is the text in the list, comes with an icon that just + //renders example text "abc", hid that with css because i didn't see other choice + //Apply is the text that is set when the choice is selected + //Info is the tooltip + + return { + from : word.from + 1, + options, + filter : false, + }; +}; + +export const autocompleteEmoji = autocompletion({ + override : [emojiCompletionList], + activateOnTyping : true, + addToOptions : [ + { + render(completion) { + const e = completion.label; + + const icon = document.createElement('i'); + icon.className = `emojiPreview ${emojis[e]}`; + + const fragment = document.createDocumentFragment(); + fragment.appendChild(icon); + + return fragment; + } + } + ] +}); \ No newline at end of file diff --git a/client/components/codeEditor/extensions/customFolding.js b/client/components/codeEditor/extensions/customFolding.js new file mode 100644 index 000000000..49cb449e7 --- /dev/null +++ b/client/components/codeEditor/extensions/customFolding.js @@ -0,0 +1,46 @@ +import { foldService, codeFolding } from '@codemirror/language'; + +const foldOnPages = [ + foldService.of((state, lineStart)=>{ //tells where to fold + const doc = state.doc; + const matcher = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m; + + const startLine = doc.lineAt(lineStart); + const prevLineText = startLine.number > 1 ? doc.line(startLine.number - 1).text : ''; + + if(!matcher.test(prevLineText)) return null; + + let endLine = startLine.number; + while (endLine < doc.lines && !matcher.test(doc.line(endLine + 1).text)) { + endLine++; + } + + if(endLine === startLine.number) return null; + + return { from: startLine.from, to: doc.line(endLine).to }; + }), + codeFolding({ + preparePlaceholder : (state, range)=>{ + const doc = state.doc; + const start = doc.lineAt(range.from).number; + const end = doc.lineAt(range.to).number; + + if(doc.line(start).text.trim()) return ` ↤ Lines ${start}-${end} ↦`; + + const preview = Array.from({ length: end - start }, (_, i)=>doc.line(start + 1 + i).text.trim() + ).find(Boolean) || `Lines ${start}-${end}`; + + return ` ↤ ${preview.replace('{', '').slice(0, 50).trim()}${preview.length > 50 ? '...' : ''} ↦`; + }, + placeholderDOM(view, onclick, prepared) { + const span = document.createElement('span'); + span.className = 'cm-fold-placeholder'; + span.textContent = prepared; + span.onclick = onclick; + span.style.color = '#989898'; + return span; + }, + }), +]; + +export default foldOnPages; \ No newline at end of file diff --git a/client/components/codeEditor/extensions/customHighlight.js b/client/components/codeEditor/extensions/customHighlight.js new file mode 100644 index 000000000..33c68da7a --- /dev/null +++ b/client/components/codeEditor/extensions/customHighlight.js @@ -0,0 +1,472 @@ +/* eslint max-lines: ["error", { "max": 500 }] */ +import { HighlightStyle } from '@codemirror/language'; +import { tags } from '@lezer/highlight'; +import { legacyTokenizeCustomMarkdown } from './legacyCustomHighlight'; +import { + Decoration, + ViewPlugin, +} from '@codemirror/view'; +import { + syntaxTree, + ensureSyntaxTree +} from '@codemirror/language'; + +// Making the tokens +const customTags = { + pageLine : 'pageLine', // .cm-pageLine + snippetLine : 'snippetLine', // .cm-snippetLine + columnSplit : 'columnSplit', // .cm-columnSplit + block : 'block', // .cm-block + inlineBlock : 'inline-block', // .cm-inline-block + injection : 'injection', // .cm-injection + emoji : 'emoji', // .cm-emoji + superscript : 'superscript', // .cm-superscript + subscript : 'subscript', // .cm-subscript + definitionList : 'definitionList', // .cm-definitionList + definitionTerm : 'definitionTerm', // .cm-definitionTerm + definitionDesc : 'definitionDesc', // .cm-definitionDesc + definitionColon : 'definitionColon', // .cm-definitionColon + strikethrough : 'strikethrough', // .cm-strikethrough + + //CSS + + variable : 'variable', +}; + +function tokenizeCustomMarkdown(text) { + const tokens = []; + const lines = text.split('\n'); + + //tokens without a `from` or `to` are interpreted by the custom plugin as line tokens + + lines.forEach((lineText, lineNumber)=>{ + // --- Page / snippet lines --- + if(/^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m.test(lineText)) tokens.push({ line: lineNumber, type: customTags.pageLine }); + if(/^\\snippet\ .*$/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.snippetLine }); + if(/^\\column(?:break)?$/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.columnSplit }); + + // --- Emoji --- + if(/:.\w+?:/.test(lineText)) { + const emojiRegex = /(:\w+?:)/g; + let match; + while ((match = emojiRegex.exec(lineText)) !== null) { + tokens.push({ + line : lineNumber, + type : customTags.emoji, + from : match.index, + to : match.index + match[0].length, + }); + } + } + + // --- Superscript / Subscript --- + if(/\^/.test(lineText)) { + let startIndex = lineText.indexOf('^'); + const superRegex = /\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^/gy; + const subRegex = /\^\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^\^/gy; + + while (startIndex >= 0) { + superRegex.lastIndex = subRegex.lastIndex = startIndex; + + let match = subRegex.exec(lineText); + let type = customTags.subscript; + + if(!match) { + match = superRegex.exec(lineText); + type = customTags.superscript; + } + + if(match) { + tokens.push({ + line : lineNumber, + type, + from : match.index, + to : match.index + match[0].length, + }); + } + + startIndex = lineText.indexOf( + '^', + Math.max(startIndex + 1, superRegex.lastIndex || 0, subRegex.lastIndex || 0), + ); + } + } + + // --- Strikethrough --- + if(/\~/.test(lineText)) { + const strikethroughRegex = /~(?!\s)(.+?)(? 0 && lineText.trim().length > 0) { + tokens.push({ + line : startLine, + type : customTags.definitionList, + }); + + // term + tokens.push({ + line : startLine, + type : customTags.definitionTerm, + from : 0, + to : lineText.length, + }); + + // definitions + defs.forEach((d)=>{ + tokens.push({ + line : d.line, + type : customTags.definitionList, + }); + + tokens.push({ + line : d.line, + type : customTags.definitionColon, + from : 0, + to : d.colons.length, + }); + tokens.push({ + line : d.line, + type : customTags.definitionDesc, + from : d.colons.length, + to : d.colons.length + d.desc?.length, + }); + }); + } + } + + if(lineText.includes('{') && lineText.includes('}')) { + const injectionRegex = /(?:^|[^{\n])({(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\2})/gmd; + let match; + + while ((match = injectionRegex.exec(lineText)) !== null) { + tokens.push({ + line : lineNumber, + from : match.indices[1][0], + to : match.indices[1][1], + type : customTags.injection, + }); + } + } + if(lineText.includes('{{') && lineText.includes('}}')) { + // Inline blocks: single-line {{…}} + const spanRegex = /{{(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\1 *|}}/g; + let match; + let blockCount = 0; + while ((match = spanRegex.exec(lineText)) !== null) { + if(match[0].startsWith('{{')) { + blockCount += 1; + } else { + blockCount -= 1; + } + if(blockCount < 0) { + blockCount = 0; + continue; + } + tokens.push({ + line : lineNumber, + from : match.index, + to : match.index + match[0].length, + type : customTags.inlineBlock, + }); + } + } else if(lineText.trimLeft().startsWith('{{') || lineText.trimLeft().startsWith('}}')) { + // Highlight block divs {{\n Content \n}} + let endCh = lineText.length + 1; + + const match = lineText.match( + /^ *{{(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\1 *$|^ *}}$/, + ); + if(match) endCh = match.index + match[0].length; + const closingMatch = lineText.match(/ *(}})/d); + + if(closingMatch) { + tokens.push({ line: lineNumber, from: closingMatch.indices[1][0], to: closingMatch.indices[1][1], type: customTags.block }); + } else { + tokens.push({ line: lineNumber, type: customTags.block }); + } + + } + }); + + return tokens; +} + +function tokenizeCustomCSS(text) { + const tokens = []; + const lines = text.split('\n'); + + lines.forEach((lineText, lineNumber)=>{ + + if(/--[a-zA-Z0-9-_]+/gm.test(lineText)) { + const varRegex =/--[a-zA-Z0-9-_]+/gm; + let match; + while ((match = varRegex.exec(lineText)) !== null) { + tokens.push({ + line : lineNumber, + from : match.index +1, + to : match.index + match.length[1] +1, + type : customTags.varProperty, + }); + } + } + }); + + return tokens; +} + +//assign classes to tags provided by lezer, not unlike the function above +export const customHighlightStyle = HighlightStyle.define([ + { tag: tags.heading, class: 'cm-header' }, + { tag: tags.heading1, class: 'cm-header cm-header-1' }, + { tag: tags.heading2, class: 'cm-header cm-header-2' }, + { tag: tags.heading3, class: 'cm-header cm-header-3' }, + { tag: tags.heading4, class: 'cm-header cm-header-4' }, + { tag: tags.heading5, class: 'cm-header cm-header-5' }, + { tag: tags.heading6, class: 'cm-header cm-header-6' }, + { tag: tags.link, class: 'cm-link' }, + { tag: tags.string, class: 'cm-string' }, + { tag: tags.url, class: 'cm-string cm-url' }, + { tag: tags.list, class: 'cm-list' }, + { tag: tags.strong, class: 'cm-strong' }, + { tag: tags.emphasis, class: 'cm-em' }, + { tag: tags.quote, class: 'cm-quote' }, + { tag: tags.comment, class: 'cm-comment' }, + { tag: tags.monospace, class: 'cm-comment' }, + + //css tags + + { tag: tags.tagName, class: 'cm-tag' }, + { tag: tags.className, class: 'cm-class' }, + { tag: tags.propertyName, class: 'cm-property' }, + { tag: tags.attributeValue, class: 'cm-value' }, + { tag: tags.keyword, class: 'cm-keyword' }, + { tag: tags.atom, class: 'cm-atom' }, + { tag: tags.integer, class: 'cm-integer' }, + { tag: tags.unit, class: 'cm-unit' }, + { tag: tags.color, class: 'cm-color' }, + { tag: tags.paren, class: 'cm-paren' }, + { tag: tags.variableName, class: 'cm-variable' }, + { tag: tags.invalid, class: 'cm-error' }, + +]); + +function getUrl(node, doc) { + let url = null; + + const cursor = node.node.cursor(); + + if(cursor.firstChild()) { + do { + if(cursor.name === 'URL') { + url = doc.sliceString(cursor.from, cursor.to); + break; + } + } while (cursor.nextSibling()); + } + + return url; +} + +import { WidgetType } from '@codemirror/view'; + +class ImageWidget extends WidgetType { + constructor(url) { + super(); + this.url = url; + } + + toDOM() { + const img = document.createElement('img'); + img.loading = "lazy"; + img.className = 'cm-preview'; + img.src = this.url; + + + img.onerror = ()=>{ + img.src = 'client/icons/broken-image.jpg'; + }; + + return img; + } + + eq(other) { + return other.url === this.url; + } +} + +export function customHighlightPlugin(renderer, tab) { + //this function takes the custom tokens created in the tokenize function in customhighlight files + //takes the tokens defined by that function and assigns classes to them + //it also creates page number and snippet number widgets + + let tokenize; + + if(tab === 'brewStyles') { + tokenize = tokenizeCustomCSS; + } else { + tokenize = renderer === 'V3' ? tokenizeCustomMarkdown : legacyTokenizeCustomMarkdown; + } + + return ViewPlugin.fromClass( + class { + constructor(view) { + this.decorations = this.buildDecorations(view); + } + update(update) { + if(update.docChanged) { + this.decorations = this.buildDecorations(update.view); + } + } + buildDecorations(view) { + const decos = []; + const tokens = tokenize(view.state.doc.toString()); + let pageCount = 1; + let snippetCount = 0; + + const tree = ensureSyntaxTree(view.state, view.state.doc.length, 50) || syntaxTree(view.state); + tree.iterate({ + enter : (node)=>{ + if(node.name === 'Image') { + const url = getUrl(node, view.state.doc); + + const widgetPosition = node.node.lastChild.from; + //this is not exactly standard, but should hold, + //and is the shortest way i could find of positioning + //the image inside the cm-image node + + if(!url) return; + + decos.push( + Decoration.mark({ + class : 'cm-image' + }).range(node.from, node.to) + ); + decos.push( + Decoration.widget({ + widget : new ImageWidget(url), + side : 1 + }).range(widgetPosition) + ); + } + } + }); + + tokens.forEach((token)=>{ + const line = view.state.doc.line(token.line + 1); + + if(token.from != null && token.to != null && token.from < token.to) { + const from = line.from + token.from; + const to = line.from + token.to; + + const attrs = {}; + if(token.type === 'Image' && token.url) { + + attrs['data-url'] = token.url; + } + + decos.push( + Decoration.mark({ + class : `cm-${token.type}`, + ...(Object.keys(attrs).length + ? { attributes: attrs } + : {}) + }).range(from, to) + ); + } else { + decos.push( + Decoration.line({ + class : `cm-${token.type}` + }).range(line.from) + ); + if(token.type === 'pageLine' && tab === 'brewText') { + pageCount++; + if(line.from === 0) pageCount--; + decos.push(Decoration.line({ attributes: { 'data-page-number': pageCount } }).range(line.from)); + } + if(token.type === 'snippetLine' && tab === 'brewSnippets') { + snippetCount++; + decos.push(Decoration.line({ attributes: { 'data-page-number': snippetCount } }).range(line.from)); + } + } + }); + + decos.sort((a, b)=>a.from - b.from || a.to - b.to); + return Decoration.set(decos); + } + }, + { decorations: (v)=>v.decorations } + ); +}; \ No newline at end of file diff --git a/client/components/codeEditor/extensions/customKeyMaps.js b/client/components/codeEditor/extensions/customKeyMaps.js new file mode 100644 index 000000000..db3edf47f --- /dev/null +++ b/client/components/codeEditor/extensions/customKeyMaps.js @@ -0,0 +1,204 @@ +/* eslint max-lines: ["error", { "max": 300 }] */ +import { keymap } from '@codemirror/view'; +import { undo, redo, indentMore, deleteLine } from '@codemirror/commands'; +import { Prec } from '@codemirror/state'; + +const insertTab = (view)=>{ + const { from, to } = view.state.selection.main; + + view.dispatch({ + changes : { from, to, insert: ' ' }, + selection : { anchor: from + 2 } + }); + + return true; +}; + +const indentLess = (view)=>{ + const { from, to } = view.state.selection.main; + const lines = []; + for (let l = view.state.doc.lineAt(from).number; l <= view.state.doc.lineAt(to).number; l++) { + const line = view.state.doc.line(l); + const match = line.text.match(/^ {1,2}/); // match up to 2 spaces + if(match) { + lines.push({ from: line.from, to: line.from + match[0].length, insert: '' }); + } + } + if(lines.length > 0) view.dispatch({ changes: lines }); + return true; +}; + +const wrapSelection = (prefix, suffix)=>(view)=>{ + const changes = []; + + for (const range of view.state.selection.ranges) { + const { from, to } = range; + const selected = view.state.doc.sliceString(from, to); + + let text; + + if(from === to) { text = prefix + suffix; } else if(selected.startsWith(prefix) && selected.endsWith(suffix)) { + text = selected.slice(prefix.length, -suffix.length); + } else {text = `${prefix}${selected}${suffix}`;} + + changes.push({ from, to, insert: text }); + } + + view.dispatch({ + changes + }); + + return true; +}; + +const makeNbsp = (view)=>{ + const { from } = view.state.selection.main; + + const prev2 = from >= 2 + ? view.state.doc.sliceString(from - 2, from) + : ''; + + const insert = (prev2 === ':>' || prev2 === '>>') ? '>' : ':>'; + + view.dispatch({ + changes : { from, to: from, insert }, + selection : { anchor: from + insert.length }, + }); + + return true; +}; + +const makeSpace = (view)=>{ + const { from, to } = view.state.selection.main; + const selected = view.state.doc.sliceString(from, to); + const match = selected.match(/^{{width:(\d+)% }}$/); + let newText = '{{width:10% }}'; + if(match) { + const percent = Math.min(parseInt(match[1], 10) + 10, 100); + newText = `{{width:${percent}% }}`; + } + view.dispatch({ changes: { from, to, insert: newText } }); + return true; +}; + +const removeSpace = (view)=>{ + const { from, to } = view.state.selection.main; + const selected = view.state.doc.sliceString(from, to); + const match = selected.match(/^{{width:(\d+)% }}$/); + if(match) { + const percent = parseInt(match[1], 10) - 10; + const newText = percent > 0 ? `{{width:${percent}% }}` : ''; + view.dispatch({ changes: { from, to, insert: newText } }); + } + return true; +}; + +const makeSpan = (view)=>{ + const { from, to } = view.state.selection.main; + const selected = view.state.doc.sliceString(from, to); + const text = selected.startsWith('{{') && selected.endsWith('}}') + ? selected.slice(2, -2) + : `{{${selected}}}`; + view.dispatch({ changes: { from, to, insert: text } }); + return true; +}; + +const makeDiv = (view)=>{ + const { from, to } = view.state.selection.main; + const selected = view.state.doc.sliceString(from, to); + const text = selected.startsWith('{{') && selected.endsWith('}}') + ? selected.slice(2, -2) + : `{{\n${selected}\n}}`; + view.dispatch({ changes: { from, to, insert: text } }); + return true; +}; + +const makeComment = (view)=>{ + const { from, to } = view.state.selection.main; + const selected = view.state.doc.sliceString(from, to); + const isHtmlComment = selected.startsWith(''); + const text = isHtmlComment + ? selected.slice(4, -3) + : ``; + view.dispatch({ changes: { from, to, insert: text } }); + return true; +}; + +const makeLink = (view)=>{ + const { from, to } = view.state.selection.main; + const selected = view.state.doc.sliceString(from, to).trim(); + const isLink = /^\[(.*)\]\((.*)\)$/.exec(selected); + const text = isLink ? `${isLink[1]} ${isLink[2]}` : `[${selected || 'alt text'}](url)`; + view.dispatch({ changes: { from, to, insert: text } }); + return true; +}; + +const makeList = (type)=>(view)=>{ + const { from, to } = view.state.selection.main; + const lines = []; + for (let l = from; l <= to; l++) { + const lineText = view.state.doc.line(l + 1).text; + lines.push(lineText); + } + const joined = lines.join('\n'); + let newText; + if(type === 'UL') newText = joined.replace(/^/gm, '- '); + else newText = joined.replace(/^/gm, (m, i)=>`${i + 1}. `); + view.dispatch({ changes: { from, to, insert: newText } }); + return true; +}; + +const makeHeader = (level)=>(view)=>{ + const { from, to } = view.state.selection.main; + const selected = view.state.doc.sliceString(from, to); + const text = `${'#'.repeat(level)} ${selected}`; + view.dispatch({ changes: { from, to, insert: text } }); + return true; +}; + +const newColumn = (view)=>{ + const { from, to } = view.state.selection.main; + view.dispatch({ changes: { from, to, insert: '\n\\column\n\n' } }); + return true; +}; + +const newPage = (view)=>{ + const { from, to } = view.state.selection.main; + view.dispatch({ changes: { from, to, insert: '\n\\page\n\n' } }); + return true; +}; + +export const generalKeymap = Prec.high(keymap.of([ + { key: 'Tab', run: insertTab }, + { key: 'Mod-z', run: undo }, //i think it may be unnecessary + { key: 'Mod-Shift-z', run: redo }, + { key: 'Mod-y', run: redo }, + { key: 'Mod-d', run: deleteLine }, +])); + +export const markdownKeymap = Prec.highest(keymap.of([ + //{ key: 'Shift-Tab', run: indentMore }, + { key: 'Shift-Tab', run: indentLess }, + { key: 'Mod-b', run: wrapSelection('**', '**') }, // makeBold + { key: 'Mod-i', run: wrapSelection('*', '*') }, // makeItalic + { key: 'Mod-u', run: wrapSelection('', '') }, // makeUnderline + { key: 'Shift-Mod-=', run: wrapSelection('^', '^') }, // makeSuper + { key: 'Mod-=', run: wrapSelection('^^', '^^') }, // makeSub + { key: 'Mod-.', run: makeNbsp }, + { key: 'Shift-Mod-.', run: makeSpace }, + { key: 'Shift-Mod-,', run: removeSpace }, + { key: 'Mod-m', run: makeSpan }, + { key: 'Shift-Mod-m', run: makeDiv }, + { key: 'Mod-/', run: makeComment }, + { key: 'Mod-k', run: makeLink }, + { key: 'Mod-l', run: makeList('UL') }, + { key: 'Shift-Mod-l', run: makeList('OL') }, + { key: 'Shift-Mod-1', run: makeHeader(1) }, + { key: 'Shift-Mod-2', run: makeHeader(2) }, + { key: 'Shift-Mod-3', run: makeHeader(3) }, + { key: 'Shift-Mod-4', run: makeHeader(4) }, + { key: 'Shift-Mod-5', run: makeHeader(5) }, + { key: 'Shift-Mod-6', run: makeHeader(6) }, + { key: 'Mod-Enter', run: newPage }, + { key: 'Shift-Mod-Enter', run: newColumn }, +])); diff --git a/client/components/codeEditor/extensions/legacyCustomHighlight.js b/client/components/codeEditor/extensions/legacyCustomHighlight.js new file mode 100644 index 000000000..cccb6647b --- /dev/null +++ b/client/components/codeEditor/extensions/legacyCustomHighlight.js @@ -0,0 +1,54 @@ +import { HighlightStyle } from '@codemirror/language'; +import { tags } from '@lezer/highlight'; + +const customTags = { + pageLine : 'pageLine', // .cm-pageLine + snippetLine : 'snippetLine', // .cm-snippetLine +}; + +export function legacyTokenizeCustomMarkdown(text) { + const tokens = []; + const lines = text.split('\n'); + + lines.forEach((lineText, lineNumber)=>{ + // --- Page / snippet lines --- + if(/^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m.test(lineText)) tokens.push({ line: lineNumber, type: customTags.pageLine }); + if(/^\\snippet\ .*$/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.snippetLine }); + }); + + return tokens; +} + +export const legacyCustomHighlightStyle = HighlightStyle.define([ + { tag: tags.heading, class: 'cm-header' }, + { tag: tags.heading1, class: 'cm-header cm-header-1' }, + { tag: tags.heading2, class: 'cm-header cm-header-2' }, + { tag: tags.heading3, class: 'cm-header cm-header-3' }, + { tag: tags.heading4, class: 'cm-header cm-header-4' }, + { tag: tags.heading5, class: 'cm-header cm-header-5' }, + { tag: tags.heading6, class: 'cm-header cm-header-6' }, + { tag: tags.link, class: 'cm-link' }, + { tag: tags.string, class: 'cm-string' }, + { tag: tags.url, class: 'cm-string cm-url' }, + { tag: tags.list, class: 'cm-list' }, + { tag: tags.strong, class: 'cm-strong' }, + { tag: tags.emphasis, class: 'cm-em' }, + { tag: tags.quote, class: 'cm-quote' }, + + //css tags + + { tag: tags.tagName, class: 'cm-tag' }, + { tag: tags.className, class: 'cm-class' }, + { tag: tags.propertyName, class: 'cm-property' }, + { tag: tags.attributeValue, class: 'cm-value' }, + { tag: tags.keyword, class: 'cm-keyword' }, + { tag: tags.atom, class: 'cm-atom' }, + { tag: tags.integer, class: 'cm-integer' }, + { tag: tags.unit, class: 'cm-unit' }, + { tag: tags.color, class: 'cm-color' }, + { tag: tags.paren, class: 'cm-paren' }, + { tag: tags.variableName, class: 'cm-variable' }, + { tag: tags.invalid, class: 'cm-error' }, + { tag: tags.comment, class: 'cm-comment' }, +]); + diff --git a/client/components/codeEditor/fold-css.js b/client/components/codeEditor/fold-css.js deleted file mode 100644 index 06bfd96a4..000000000 --- a/client/components/codeEditor/fold-css.js +++ /dev/null @@ -1,44 +0,0 @@ -export default { - registerHomebreweryHelper : function(CodeMirror) { - CodeMirror.registerHelper('fold', 'homebrewerycss', function(cm, start) { - - // BRACE FOLDING - const startMatcher = /\{[ \t]*$/; - const endMatcher = /\}[ \t]*$/; - const activeLine = cm.getLine(start.line); - - - if(activeLine.match(startMatcher)) { - const lastLineNo = cm.lastLine(); - let end = start.line + 1; - let braceCount = 1; - - while (end < lastLineNo) { - const curLine = cm.getLine(end); - if(curLine.match(startMatcher)) braceCount++; - if(curLine.match(endMatcher)) braceCount--; - if(braceCount == 0) break; - ++end; - } - - return { - from : CodeMirror.Pos(start.line, 0), - to : CodeMirror.Pos(end, cm.getLine(end).length) - }; - } - - // @import and data-url folding - const importMatcher = /^@import.*?;/; - const dataURLMatcher = /url\(.*?data\:.*\)/; - - if(activeLine.match(importMatcher) || activeLine.match(dataURLMatcher)) { - return { - from : CodeMirror.Pos(start.line, 0), - to : CodeMirror.Pos(start.line, activeLine.length) - }; - } - - return null; - }); - } -}; diff --git a/client/components/codeEditor/fold-pages.js b/client/components/codeEditor/fold-pages.js deleted file mode 100644 index 1d8d19f6b..000000000 --- a/client/components/codeEditor/fold-pages.js +++ /dev/null @@ -1,26 +0,0 @@ -export default { - registerHomebreweryHelper : function(CodeMirror) { - CodeMirror.registerHelper('fold', 'homebrewery', function(cm, start) { - const matcher = /^\\page.*/; - const prevLine = cm.getLine(start.line - 1); - - if(start.line === cm.firstLine() || prevLine.match(matcher)) { - const lastLineNo = cm.lastLine(); - let end = start.line; - - while (end < lastLineNo) { - if(cm.getLine(end + 1).match(matcher)) - break; - ++end; - } - - return { - from : CodeMirror.Pos(start.line, 0), - to : CodeMirror.Pos(end, cm.getLine(end).length) - }; - } - - return null; - }); - } -}; diff --git a/client/components/combobox.jsx b/client/components/combobox.jsx index 5060b8ecf..7c015d3d6 100644 --- a/client/components/combobox.jsx +++ b/client/components/combobox.jsx @@ -11,16 +11,17 @@ const Combobox = createReactClass({ trigger : 'hover', default : '', placeholder : '', - tooltip: '', + tooltip : '', autoSuggest : { clearAutoSuggestOnClick : true, suggestMethod : 'includes', filterOn : [] // should allow as array to filter on multiple attributes, or even custom filter }, - valuePatterns: /.+/ + valuePatterns : /.+/ }; }, getInitialState : function() { + this.dropdownRef = React.createRef(); return { showDropdown : false, value : '', @@ -41,7 +42,7 @@ const Combobox = createReactClass({ }, handleClickOutside : function(e){ // Close dropdown when clicked outside - if(this.refs.dropdown && !this.refs.dropdown.contains(e.target)) { + if(this.dropdownRef.current && !this.dropdownRef.current.contains(e.target)) { this.handleDropdown(false); } }, @@ -88,7 +89,7 @@ const Combobox = createReactClass({ } }} onKeyDown={(e)=>{ - if (e.key === "Enter") { + if(e.key === 'Enter') { e.preventDefault(); this.props.onEntry(e); } @@ -128,7 +129,7 @@ const Combobox = createReactClass({ }); return (
{this.handleDropdown(false);} : undefined}> {this.renderTextInput()} {this.renderDropdown(dropdownChildren)} diff --git a/client/components/renderWarnings/renderWarnings.less b/client/components/renderWarnings/renderWarnings.less index 70799092a..a1413709b 100644 --- a/client/components/renderWarnings/renderWarnings.less +++ b/client/components/renderWarnings/renderWarnings.less @@ -1,3 +1,5 @@ +@import '@sharedStyles/colors.less'; + .renderWarnings { position : relative; float : right; diff --git a/client/components/splitPane/splitPane.less b/client/components/splitPane/splitPane.less index 80a8695af..779d0c222 100644 --- a/client/components/splitPane/splitPane.less +++ b/client/components/splitPane/splitPane.less @@ -1,3 +1,4 @@ +@import '@sharedStyles/core.less'; .splitPane { position : relative; diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index a1eebab31..24cf9306f 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -1,10 +1,12 @@ /*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/ +import brewRendererStylesUrl from './brewRenderer.less?url'; +import headerNavStylesUrl from './headerNav/headerNav.less?url'; import './brewRenderer.less'; import React, { useState, useRef, useMemo, useEffect } from 'react'; import _ from 'lodash'; -import MarkdownLegacy from '../../../shared/markdownLegacy.js'; -import Markdown from '../../../shared/markdown.js'; +import MarkdownLegacy from '@shared/markdownLegacy.js'; +import Markdown from '@shared/markdown.js'; import ErrorBar from './errorBar/errorBar.jsx'; import ToolBar from './toolBar/toolBar.jsx'; @@ -13,10 +15,10 @@ import RenderWarnings from '../../components/renderWarnings/renderWarnings.jsx'; import NotificationPopup from './notificationPopup/notificationPopup.jsx'; import Frame from 'react-frame-component'; import dedent from 'dedent'; -import { printCurrentBrew } from '../../../shared/helpers.js'; +import { printCurrentBrew } from '@shared/helpers.js'; import HeaderNav from './headerNav/headerNav.jsx'; -import { safeHTML } from './safeHTML.js'; +import safeHTML from './safeHTML.js'; const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m; const PAGEBREAK_REGEX_LEGACY = /\\page(?:break)?/m; @@ -27,9 +29,10 @@ const TOOLBAR_STATE_KEY = 'HB_renderer_toolbarState'; const INITIAL_CONTENT = dedent` - - + + +
`; @@ -38,6 +41,7 @@ const BrewPage = (props)=>{ props = { contents : '', index : 0, + hoisted : false, ...props }; const pageRef = useRef(null); @@ -132,6 +136,7 @@ const BrewRenderer = (props)=>{ const mainRef = useRef(null); const pagesRef = useRef(null); + const urlRef = useRef(''); if(props.renderer == 'legacy') { rawPages = props.text.split(PAGEBREAK_REGEX_LEGACY); @@ -204,13 +209,13 @@ const BrewRenderer = (props)=>{ styles = _.mapKeys(styles, (v, k)=>k.startsWith('--') ? k : _.camelCase(k)); // Convert CSS to camelCase for React classes = [classes, injectedTags.classes].join(' ').trim(); attributes = injectedTags.attributes; - if(global.enable_v4) { + if(global.enablev4) { if (attributes && Object.hasOwn(attributes, 'hbtemplate')) { pageTemplates[index] = attributes['hbtemplate']; } } } - if(global.enable_v4) { + if(global.enablev4) { // If we don't have a template for this page, look backwards until one is found or the first page. if(!pageTemplates[index]) { for (let i=index;i>=0; i--) { @@ -231,7 +236,8 @@ const BrewRenderer = (props)=>{ } }; - const renderPages = ()=>{ + const renderPages = (checkHoists = false)=>{ + if(props.errors && props.errors.length) return renderedPages; @@ -245,10 +251,16 @@ const BrewRenderer = (props)=>{ renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1); _.forEach(rawPages, (page, index)=>{ - if((isInView(index) || !renderedPages[index]) && typeof window !== 'undefined'){ + const varsOnPageRegex = /([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]/g; // Find out if there are any vars on the page. + const forceRender = checkHoists && + !props.hoisted && + (page.match(varsOnPageRegex)); // forceRender forces pages outside of the PPR range to render if true. + // This is necessary on the first load to fully populate the variable table. + if((isInView(index) || !renderedPages[index] || forceRender) && typeof window !== 'undefined'){ renderedPages[index] = renderPage(page, index); // Render any page not yet rendered, but only re-render those in PPR range } }); + if(!props.hoisted) { props.hoisted = true; } // Only fully hoist once. return renderedPages; }; @@ -285,8 +297,10 @@ const BrewRenderer = (props)=>{ const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount" scrollToHash(window.location.hash); + window.addEventListener('hashchange', ()=>scrollToHash(window.location.hash)); + setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame - renderPages(); //Make sure page is renderable before showing + renderPages(true); //Make sure page is renderable before showing setState((prevState)=>({ ...prevState, isMounted : true, diff --git a/client/homebrew/brewRenderer/brewRenderer.less b/client/homebrew/brewRenderer/brewRenderer.less index 5769a13df..ea9b43d75 100644 --- a/client/homebrew/brewRenderer/brewRenderer.less +++ b/client/homebrew/brewRenderer/brewRenderer.less @@ -1,4 +1,4 @@ -@import (multiple, less) 'shared/naturalcrit/styles/reset.less'; +@import '@sharedStyles/core.less'; .brewRenderer { height : 100vh; diff --git a/client/homebrew/brewRenderer/errorBar/errorBar.less b/client/homebrew/brewRenderer/errorBar/errorBar.less index 163648533..528521a07 100644 --- a/client/homebrew/brewRenderer/errorBar/errorBar.less +++ b/client/homebrew/brewRenderer/errorBar/errorBar.less @@ -1,3 +1,4 @@ +@import '@sharedStyles/colors.less'; .errorBar { position : absolute; diff --git a/client/homebrew/brewRenderer/headerNav/headerNav.jsx b/client/homebrew/brewRenderer/headerNav/headerNav.jsx index 3b184aff0..080ce5ad5 100644 --- a/client/homebrew/brewRenderer/headerNav/headerNav.jsx +++ b/client/homebrew/brewRenderer/headerNav/headerNav.jsx @@ -104,7 +104,7 @@ const HeaderNavItem = ({ link, text, depth, className })=>{ if(!link || !text) return; return
  • - + {trimString(text, depth)}
  • ; diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx index dd05391f0..5f4fc5608 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx @@ -1,7 +1,7 @@ import './notificationPopup.less'; import React, { useEffect, useState } from 'react'; import request from '../../utils/request-middleware.js'; -import Markdown from 'markdown.js'; +import Markdown from '@shared/markdown.js'; import Dialog from '../../../components/dialog.jsx'; diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less index 85d4c8365..4f34bad8d 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less @@ -1,3 +1,5 @@ +@import './client/homebrew/navbar/navbar.less'; + .popups { position : fixed; top : calc(@navbarHeight + @viewerToolsHeight); diff --git a/client/homebrew/brewRenderer/safeHTML.js b/client/homebrew/brewRenderer/safeHTML.js index 2574f4cfe..d9438b663 100644 --- a/client/homebrew/brewRenderer/safeHTML.js +++ b/client/homebrew/brewRenderer/safeHTML.js @@ -43,4 +43,4 @@ function safeHTML(htmlString) { return div.innerHTML; }; -module.exports.safeHTML = safeHTML; \ No newline at end of file +export default safeHTML; \ No newline at end of file diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 9707fe84f..017cb7933 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -4,7 +4,6 @@ import React from 'react'; import createReactClass from 'create-react-class'; import _ from 'lodash'; import dedent from 'dedent'; -import Markdown from '../../../shared/markdown.js'; import CodeEditor from '../../components/codeEditor/codeEditor.jsx'; import SnippetBar from './snippetbar/snippetbar.jsx'; @@ -12,8 +11,22 @@ import MetadataEditor from './metadataEditor/metadataEditor.jsx'; const EDITOR_THEME_KEY = 'HB_editor_theme'; -const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m; -const SNIPPETBREAK_REGEX_V3 = /^\\snippet\ .*$/; +import defaultCM5Theme from '@themes/codeMirror/default.js'; +import darkbrewery from '@themes/codeMirror/darkbrewery.js'; +import cm5Themes from 'codemirror-5-themes'; + +const themes = { default: defaultCM5Theme, ...cm5Themes, darkbrewery }; + +const EditorThemes = Object.entries(themes) + .filter(([name, value])=>Array.isArray(value) && + !name.endsWith('Init') && + !name.endsWith('Style') + ) + .map(([name])=>name); + + +//const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m; +//const SNIPPETBREAK_REGEX_V3 = /^\\snippet\ .*$/; const DEFAULT_STYLE_TEXT = dedent` /*=======--- Example CSS styling ---=======*/ /* Any CSS here will apply to your document! */ @@ -30,6 +43,7 @@ const DEFAULT_SNIPPET_TEXT = dedent` This snippet is accessible in the brew tab, and will be inherited if the brew is used as a theme. `; let isJumping = false; +let jumpSource = null; const Editor = createReactClass({ displayName : 'Editor', @@ -72,23 +86,20 @@ const Editor = createReactClass({ componentDidMount : function() { - this.highlightCustomMarkdown(); - document.getElementById('BrewRenderer').addEventListener('keydown', this.handleControlKeys); + const brewRenderer = document.getElementById('BrewRenderer'); + brewRenderer.onload = ()=>brewRenderer.contentDocument?.addEventListener('keydown', this.handleControlKeys); document.addEventListener('keydown', this.handleControlKeys); - this.codeEditor.current.codeMirror?.on('cursorActivity', (cm)=>{this.updateCurrentCursorPage(cm.getCursor());}); - this.codeEditor.current.codeMirror?.on('scroll', _.throttle(()=>{this.updateCurrentViewPage(this.codeEditor.current.getTopVisibleLine());}, 200)); - const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY); - if(editorTheme) { - this.setState({ - editorTheme : editorTheme - }); + if(editorTheme && EditorThemes.includes(editorTheme)) { + this.setState({ editorTheme }); + } else { + this.setState({ editorTheme: 'default' }); } const snippetBar = document.querySelector('.editor > .snippetBar'); if(!snippetBar) return; - this.resizeObserver = new ResizeObserver(entries=>{ + this.resizeObserver = new ResizeObserver((entries)=>{ const height = document.querySelector('.editor > .snippetBar').offsetHeight; this.setState({ snippetBarHeight: height }); }); @@ -98,7 +109,6 @@ const Editor = createReactClass({ componentDidUpdate : function(prevProps, prevState, snapshot) { - this.highlightCustomMarkdown(); if(prevProps.moveBrew !== this.props.moveBrew) this.brewJump(); @@ -132,22 +142,16 @@ const Editor = createReactClass({ } }, - updateCurrentCursorPage : function(cursor) { - const lines = this.props.brew.text.split('\n').slice(1, cursor.line + 1); - const pageRegex = this.props.brew.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/; - const currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1); - this.props.onCursorPageChange(currentPage); + updateCurrentCursorPage : function(pageNumber) { + this.props.onCursorPageChange(pageNumber); }, - updateCurrentViewPage : function(topScrollLine) { - const lines = this.props.brew.text.split('\n').slice(1, topScrollLine + 1); - const pageRegex = this.props.brew.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/; - const currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1); - this.props.onViewPageChange(currentPage); + updateCurrentViewPage : function(pageNumber) { + this.props.onViewPageChange(pageNumber); }, handleInject : function(injectText){ - this.codeEditor.current?.injectText(injectText, false); + this.codeEditor.current?.injectText(injectText); }, handleViewChange : function(newView){ @@ -156,181 +160,12 @@ const Editor = createReactClass({ this.setState({ view : newView }, ()=>{ - this.codeEditor.current?.codeMirror?.focus(); + this.codeEditor.current?.focus(); }); }, - highlightCustomMarkdown : function(){ - if(!this.codeEditor.current?.codeMirror) return; - if((this.state.view === 'text') ||(this.state.view === 'snippet')) { - const codeMirror = this.codeEditor.current.codeMirror; - - codeMirror?.operation(()=>{ // Batch CodeMirror styling - - const foldLines = []; - - //reset custom text styles - const customHighlights = codeMirror?.getAllMarks().filter((mark)=>{ - // Record details of folded sections - if(mark.__isFold) { - const fold = mark.find(); - foldLines.push({ from: fold.from?.line, to: fold.to?.line }); - } - return !mark.__isFold; - }); //Don't undo code folding - - for (let i=customHighlights.length - 1;i>=0;i--) customHighlights[i].clear(); - - let userSnippetCount = 1; // start snippet count from snippet 1 - let editorPageCount = 1; // start page count from page 1 - - const whichSource = this.state.view === 'text' ? this.props.brew.text : this.props.brew.snippets; - _.forEach(whichSource?.split('\n'), (line, lineNumber)=>{ - - const tabHighlight = this.state.view === 'text' ? 'pageLine' : 'snippetLine'; - const textOrSnip = this.state.view === 'text'; - - //reset custom line styles - codeMirror?.removeLineClass(lineNumber, 'background', 'pageLine'); - codeMirror?.removeLineClass(lineNumber, 'background', 'snippetLine'); - codeMirror?.removeLineClass(lineNumber, 'text'); - codeMirror?.removeLineClass(lineNumber, 'wrap', 'sourceMoveFlash'); - - // Don't process lines inside folded text - // If the current lineNumber is inside any folded marks, skip line styling - if(foldLines.some((fold)=>lineNumber >= fold.from && lineNumber <= fold.to)) - return; - - // Styling for \page breaks - if((this.props.renderer == 'legacy' && line.includes('\\page')) || - (this.props.renderer == 'V3' && line.match(textOrSnip ? PAGEBREAK_REGEX_V3 : SNIPPETBREAK_REGEX_V3))) { - - if((lineNumber > 0) && (textOrSnip)) // Since \page is optional on first line of document, - editorPageCount += 1; // don't use it to increment page count; stay at 1 - else if(this.state.view !== 'text') userSnippetCount += 1; - - // add back the original class 'background' but also add the new class '.pageline' - codeMirror?.addLineClass(lineNumber, 'background', tabHighlight); - const pageCountElement = Object.assign(document.createElement('span'), { - className : 'editor-page-count', - textContent : textOrSnip ? editorPageCount : userSnippetCount - }); - codeMirror?.setBookmark({ line: lineNumber, ch: line.length }, pageCountElement); - }; - - - // New CodeMirror styling for V3 renderer - if(this.props.renderer === 'V3') { - if(line.match(/^\\column(?:break)?$/)){ - codeMirror?.addLineClass(lineNumber, 'text', 'columnSplit'); - } - - // definition lists - if(line.includes('::')){ - if(/^:*$/.test(line) == true){ return; }; - const regex = /^([^\n]*?:?\s?)(::[^\n]*)(?:\n|$)/ymd; // the `d` flag, for match indices, throws an ESLint error. - let match; - while ((match = regex.exec(line)) != null){ - codeMirror?.markText({ line: lineNumber, ch: match.indices[0][0] }, { line: lineNumber, ch: match.indices[0][1] }, { className: 'dl-highlight' }); - codeMirror?.markText({ line: lineNumber, ch: match.indices[1][0] }, { line: lineNumber, ch: match.indices[1][1] }, { className: 'dt-highlight' }); - codeMirror?.markText({ line: lineNumber, ch: match.indices[2][0] }, { line: lineNumber, ch: match.indices[2][1] }, { className: 'dd-highlight' }); - const ddIndex = match.indices[2][0]; - const colons = /::/g; - const colonMatches = colons.exec(match[2]); - if(colonMatches !== null){ - codeMirror?.markText({ line: lineNumber, ch: colonMatches.index + ddIndex }, { line: lineNumber, ch: colonMatches.index + colonMatches[0].length + ddIndex }, { className: 'dl-colon-highlight' }); - } - } - } - - // Subscript & Superscript - if(line.includes('^')) { - let startIndex = line.indexOf('^'); - const superRegex = /\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^/gy; - const subRegex = /\^\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^\^/gy; - - while (startIndex >= 0) { - superRegex.lastIndex = subRegex.lastIndex = startIndex; - let isSuper = false; - const match = subRegex.exec(line) || superRegex.exec(line); - if(match) { - isSuper = !subRegex.lastIndex; - codeMirror?.markText({ line: lineNumber, ch: match.index }, { line: lineNumber, ch: match.index + match[0].length }, { className: isSuper ? 'superscript' : 'subscript' }); - } - startIndex = line.indexOf('^', Math.max(startIndex + 1, subRegex.lastIndex, superRegex.lastIndex)); - } - } - - // Highlight injectors {style} - if(line.includes('{') && line.includes('}')){ - const regex = /(?:^|[^{\n])({(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\2})/gm; - let match; - while ((match = regex.exec(line)) != null) { - codeMirror?.markText({ line: lineNumber, ch: line.indexOf(match[1]) }, { line: lineNumber, ch: line.indexOf(match[1]) + match[1].length }, { className: 'injection' }); - } - } - // Highlight inline spans {{content}} - if(line.includes('{{') && line.includes('}}')){ - const regex = /{{(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\1 *|}}/g; - let match; - let blockCount = 0; - while ((match = regex.exec(line)) != null) { - if(match[0].startsWith('{')) { - blockCount += 1; - } else { - blockCount -= 1; - } - if(blockCount < 0) { - blockCount = 0; - continue; - } - codeMirror?.markText({ line: lineNumber, ch: match.index }, { line: lineNumber, ch: match.index + match[0].length }, { className: 'inline-block' }); - } - } else if(line.trimLeft().startsWith('{{') || line.trimLeft().startsWith('}}')){ - // Highlight block divs {{\n Content \n}} - let endCh = line.length+1; - - const match = line.match(/^ *{{(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\1 *$|^ *}}$/); - if(match) - endCh = match.index+match[0].length; - codeMirror?.markText({ line: lineNumber, ch: 0 }, { line: lineNumber, ch: endCh }, { className: 'block' }); - } - - // Emojis - if(line.match(/:[^\s:]+:/g)) { - let startIndex = line.indexOf(':'); - const emojiRegex = /:[^\s:]+:/gy; - - while (startIndex >= 0) { - emojiRegex.lastIndex = startIndex; - const match = emojiRegex.exec(line); - if(match) { - let tokens = Markdown.marked.lexer(match[0]); - tokens = tokens[0].tokens.filter((t)=>t.type == 'emoji'); - if(!tokens.length) - return; - - const startPos = { line: lineNumber, ch: match.index }; - const endPos = { line: lineNumber, ch: match.index + match[0].length }; - - // Iterate over conflicting marks and clear them - const marks = codeMirror?.findMarks(startPos, endPos); - marks.forEach(function(marker) { - if(!marker.__isFold) marker.clear(); - }); - codeMirror?.markText(startPos, endPos, { className: 'emoji' }); - } - startIndex = line.indexOf(':', Math.max(startIndex + 1, emojiRegex.lastIndex)); - } - } - } - }); - }); - } - }, - brewJump : function(targetPage=this.props.currentEditorCursorPageNum, smooth=true){ - if(!window || !this.isText() || isJumping) + if(!window || !this.isText() || isJumping || jumpSource === 'source') return; // Get current brewRenderer scroll position and calculate target position @@ -343,11 +178,13 @@ const Editor = createReactClass({ clearTimeout(scrollingTimeout); // Reset the timer every time a scroll event occurs scrollingTimeout = setTimeout(()=>{ isJumping = false; + jumpSource = null; brewRenderer.removeEventListener('scroll', checkIfScrollComplete); }, 150); // If 150 ms pass without a brewRenderer scroll event, assume scrolling is done }; isJumping = true; + jumpSource = 'brew'; checkIfScrollComplete(); brewRenderer.addEventListener('scroll', checkIfScrollComplete); @@ -371,54 +208,17 @@ const Editor = createReactClass({ }, sourceJump : function(targetPage=this.props.currentBrewRendererPageNum, smooth=true){ - if(!this.isText() || isJumping) + if(!this.isText() || isJumping || jumpSource === 'brew') return; - const textSplit = this.props.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/; - const textString = this.props.brew.text.split(textSplit).slice(0, targetPage-1).join(textSplit); - const targetLine = textString.match('\n') ? textString.split('\n').length - 1 : -1; + const editor = this.codeEditor.current; + if(!editor) return; + jumpSource = 'source'; - let currentY = this.codeEditor.current.codeMirror?.getScrollInfo().top; - let targetY = this.codeEditor.current.codeMirror?.heightAtLine(targetLine, 'local', true); - - let scrollingTimeout; - const checkIfScrollComplete = ()=>{ // Prevent interrupting a scroll in progress if user clicks multiple times - clearTimeout(scrollingTimeout); // Reset the timer every time a scroll event occurs - scrollingTimeout = setTimeout(()=>{ - isJumping = false; - this.codeEditor.current.codeMirror?.off('scroll', checkIfScrollComplete); - }, 150); // If 150 ms pass without a scroll event, assume scrolling is done - }; - - isJumping = true; - checkIfScrollComplete(); - if(this.codeEditor.current?.codeMirror) { - this.codeEditor.current.codeMirror?.on('scroll', checkIfScrollComplete); - } - - if(smooth) { - //Scroll 1/10 of the way every 10ms until 1px off. - const incrementalScroll = setInterval(()=>{ - currentY += (targetY - currentY) / 10; - this.codeEditor.current.codeMirror?.scrollTo(null, currentY); - - // Update target: target height is not accurate until within +-10 lines of the visible window - if(Math.abs(targetY - currentY > 100)) - targetY = this.codeEditor.current.codeMirror?.heightAtLine(targetLine, 'local', true); - - // End when close enough - if(Math.abs(targetY - currentY) < 1) { - this.codeEditor.current.codeMirror?.scrollTo(null, targetY); // Scroll any remaining difference - this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 }); - this.codeEditor.current.codeMirror?.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash'); - clearInterval(incrementalScroll); - } - }, 10); - } else { - this.codeEditor.current.codeMirror?.scrollTo(null, targetY); // Scroll any remaining difference - this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 }); - this.codeEditor.current.codeMirror?.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash'); - } + editor.scrollToPage(targetPage); + setTimeout(()=>{ + jumpSource = null; + }, 200); }, //Called when there are changes to the editor's dimensions @@ -446,9 +246,11 @@ const Editor = createReactClass({ view={this.state.view} value={this.props.brew.text} onChange={this.props.onBrewChange('text')} + onCursorChange={(page)=>this.updateCurrentCursorPage(page)} + onViewChange={(page)=>this.updateCurrentViewPage(page)} editorTheme={this.state.editorTheme} - rerenderParent={this.rerenderParent} - style={{ height: `calc(100% - ${this.state.snippetBarHeight}px)` }} /> + renderer={this.props.brew.renderer} + style={{ height: `calc(100% - ${this.state.snippetBarHeight}px)` }}/> ; } if(this.isStyle()){ @@ -460,18 +262,16 @@ const Editor = createReactClass({ view={this.state.view} value={this.props.brew.style ?? DEFAULT_STYLE_TEXT} onChange={this.props.onBrewChange('style')} - enableFolding={true} editorTheme={this.state.editorTheme} - rerenderParent={this.rerenderParent} - style={{ height: `calc(100% - ${this.state.snippetBarHeight}px)` }} /> + renderer={this.props.brew.renderer} + style={{ height: `calc(100% - ${this.state.snippetBarHeight}px)` }}/> ; } if(this.isMeta()){ return <> + style={{ display: 'none' }}/> + style={{ height: `calc(100% - 25px)` }}/> ; } }, @@ -510,14 +311,13 @@ const Editor = createReactClass({ return this.codeEditor.current?.undo(); }, - foldCode : function(){ - return this.codeEditor.current?.foldAllCode(); + foldCode : function() { + return this.codeEditor.current?.foldAll(); }, - unfoldCode : function(){ - return this.codeEditor.current?.unfoldAllCode(); + unfoldCode : function() { + return this.codeEditor.current?.unfoldAll(); }, - render : function(){ return (
    @@ -547,4 +347,4 @@ const Editor = createReactClass({ } }); -export default Editor; +export default Editor; \ No newline at end of file diff --git a/client/homebrew/editor/editor.less b/client/homebrew/editor/editor.less index d7b51a428..a55fad852 100644 --- a/client/homebrew/editor/editor.less +++ b/client/homebrew/editor/editor.less @@ -1,88 +1,11 @@ -@import 'themes/codeMirror/customEditorStyles.less'; -.editor { - position : relative; - width : 100%; - height : 100%; - container : editor / inline-size; - background:white; - .codeEditor { - height : calc(100% - 25px); - .CodeMirror { height : 100%; } - .pageLine, .snippetLine { - background : #33333328; - border-top : #333399 solid 1px; - } - .editor-page-count { - float : right; - color : grey; - } - .editor-snippet-count { - float : right; - color : grey; - } - .columnSplit { - font-style : italic; - color : grey; - background-color : fade(#229999, 15%); - border-bottom : #229999 solid 1px; - } - .define { - &:not(.term):not(.definition) { - font-weight : bold; - color : #949494; - background : #E5E5E5; - border-radius : 3px; - } - &.term { color : rgb(96, 117, 143); } - &.definition { color : rgb(97, 57, 178); } - } - .block:not(.cm-comment) { - font-weight : bold; - color : purple; - //font-style: italic; - } - .inline-block:not(.cm-comment) { - font-weight : bold; - color : red; - //font-style: italic; - } - .injection:not(.cm-comment) { - font-weight : bold; - color : green; - } - .emoji:not(.cm-comment) { - padding-bottom : 1px; - margin-left : 2px; - font-weight : bold; - color : #360034; - outline : solid 2px #FF96FC; - outline-offset : -2px; - background : #FFC8FF; - border-radius : 6px; - } - .superscript:not(.cm-comment) { - font-size : 0.9em; - font-weight : bold; - vertical-align : super; - color : goldenrod; - } - .subscript:not(.cm-comment) { - font-size : 0.9em; - font-weight : bold; - vertical-align : sub; - color : rgb(123, 123, 15); - } - .dl-highlight { - &.dl-colon-highlight { - font-weight : bold; - color : #949494; - background : #E5E5E5; - border-radius : 3px; - } - &.dt-highlight { color : rgb(96, 117, 143); } - &.dd-highlight { color : rgb(97, 57, 178); } - } - } +@import '@sharedStyles/core.less'; + +:where(.editor) { + position : relative; + width : 100%; + height : 100%; + container : editor / inline-size; + background : white; .brewJump { position : absolute; diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 281d62c93..8d6ccb890 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -7,7 +7,8 @@ import request from '../../utils/request-middleware.js'; import Combobox from '../../../components/combobox.jsx'; import TagInput from '../tagInput/tagInput.jsx'; -import Themes from 'themes/themes.json'; + +import Themes from '@themes/themes.json'; import validations from './validations.js'; import homebreweryThumbnail from '../../thumbnail.png'; @@ -337,9 +338,9 @@ const MetadataEditor = createReactClass({ {this.renderThumbnail()}
    -
    +
    -
    +
    - + {this.renderLanguageDropdown()} @@ -362,9 +363,9 @@ const MetadataEditor = createReactClass({ {this.renderAuthors()} -
    +
    -
    +
    - +

    Privacy

    diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index e684037e2..6a4df1c46 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -1,4 +1,4 @@ -@import 'naturalcrit/styles/colors.less'; +@import '@sharedStyles/core.less'; .userThemeName { padding-right : 10px; diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index b6e977ea2..ac9c7943a 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -7,13 +7,13 @@ import _ from 'lodash'; import cx from 'classnames'; import { loadHistory } from '../../utils/versionHistory.js'; -import { brewSnippetsToJSON } from '../../../../shared/helpers.js'; +import { brewSnippetsToJSON } from '@shared/helpers.js'; -import Legacy5ePHB from 'themes/Legacy/5ePHB/snippets.js'; -import V3_5ePHB from 'themes/V3/5ePHB/snippets.js'; -import V3_5eDMG from 'themes/V3/5eDMG/snippets.js'; -import V3_Journal from 'themes/V3/Journal/snippets.js'; -import V3_Blank from 'themes/V3/Blank/snippets.js'; +import Legacy5ePHB from '@themes/Legacy/5ePHB/snippets.js'; +import V3_5ePHB from '@themes/V3/5ePHB/snippets.js'; +import V3_5eDMG from '@themes/V3/5eDMG/snippets.js'; +import V3_Journal from '@themes/V3/Journal/snippets.js'; +import V3_Blank from '@themes/V3/Blank/snippets.js'; const ThemeSnippets = { Legacy_5ePHB : Legacy5ePHB, @@ -23,7 +23,25 @@ const ThemeSnippets = { V3_Blank : V3_Blank, }; -import EditorThemes from 'build/homebrew/codeMirror/editorThemes.json'; +import defaultCM5Theme from '@themes/codeMirror/default.js'; +import darkbrewery from '@themes/codeMirror/darkbrewery.js'; +import cm5Themes from 'codemirror-5-themes'; + +const themes = { default: defaultCM5Theme, ...cm5Themes, darkbrewery }; + +const themeNames = Object.entries(themes) + .filter(([name, value])=>Array.isArray(value) && + !name.endsWith('Init') && + !name.endsWith('Style') + ) + .map(([name])=>name); + +const EditorThemes = [ + 'default', + ...themeNames + .filter((name)=>name !== 'default') + .sort((a, b)=>a.localeCompare(b)) +]; const execute = function(val, props){ if(_.isFunction(val)) return val(props); @@ -151,7 +169,7 @@ const Snippetbar = createReactClass({ this.props.updateEditorTheme(e.target.value); this.setState({ - showThemeSelector : false, + themeSelector : false, }); }, @@ -232,11 +250,11 @@ const Snippetbar = createReactClass({ { this.state.showHistory && this.renderHistoryItems() }
    -
    -
    diff --git a/client/homebrew/editor/snippetbar/snippetbar.less b/client/homebrew/editor/snippetbar/snippetbar.less index 8e50aa764..37853ca75 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.less +++ b/client/homebrew/editor/snippetbar/snippetbar.less @@ -1,5 +1,6 @@ +@import '@sharedStyles/core.less'; @import (less) './client/icons/customIcons.less'; -@import (less) '././././themes/fonts/5e/fonts.less'; +@import (less) '@themes/fonts/5e/fonts.less'; .snippetBar { @menuHeight : 25px; diff --git a/client/homebrew/editor/tagInput/curatedTagSuggestionList.js b/client/homebrew/editor/tagInput/curatedTagSuggestionList.js index d433175ef..7d692ecb0 100644 --- a/client/homebrew/editor/tagInput/curatedTagSuggestionList.js +++ b/client/homebrew/editor/tagInput/curatedTagSuggestionList.js @@ -1,210 +1,219 @@ -export default [ +export const tagSuggestionList = [ // ############################## Systems // D&D - "system:D&D Original", - "system:D&D Basic", - "system:AD&D 1e", - "system:AD&D 2e", - "system:D&D 3e", - "system:D&D 3.5e", - "system:D&D 4e", - "system:D&D 5e", - "system:D&D 5e 2024", - "system:BD&D (B/X)", - "system:D&D Essentials", + 'system:D&D Original', + 'system:D&D Basic', + 'system:AD&D 1e', + 'system:AD&D 2e', + 'system:D&D 3e', + 'system:D&D 3.5e', + 'system:D&D 4e', + 'system:D&D 5e', + 'system:D&D 5e 2024', + 'system:BD&D (B/X)', + 'system:D&D Essentials', // Other Famous RPGs - "system:Pathfinder 1e", - "system:Pathfinder 2e", - "system:Vampire: The Masquerade", - "system:Werewolf: The Apocalypse", - "system:Mage: The Ascension", - "system:Call of Cthulhu", - "system:Shadowrun", - "system:Star Wars RPG (D6/D20/Edge of the Empire)", - "system:Warhammer Fantasy Roleplay", - "system:Cyberpunk 2020", - "system:Blades in the Dark", - "system:Daggerheart", - "system:Draw Steel", - "system:Mutants and Masterminds", + 'system:Pathfinder 1e', + 'system:Pathfinder 2e', + 'system:Vampire: The Masquerade', + 'system:Werewolf: The Apocalypse', + 'system:Mage: The Ascension', + 'system:Call of Cthulhu', + 'system:Shadowrun', + 'system:Star Wars RPG (D6/D20/Edge of the Empire)', + 'system:Warhammer Fantasy Roleplay', + 'system:Cyberpunk 2020', + 'system:Blades in the Dark', + 'system:Daggerheart', + 'system:Draw Steel', + 'system:Mutants and Masterminds', // Meta - "meta:V3", - "meta:Legacy", - "meta:Template", - "meta:Theme", - "meta:free", - "meta:Character Sheet", - "meta:Documentation", - "meta:NPC", - "meta:Guide", - "meta:Resource", - "meta:Notes", - "meta:Example", + 'meta:V3', + 'meta:Legacy', + 'meta:Template', + 'meta:Theme', + 'meta:free', + 'meta:Character Sheet', + 'meta:Documentation', + 'meta:NPC', + 'meta:Guide', + 'meta:Resource', + 'meta:Notes', + 'meta:Example', // Book type - "type:Campaign", - "type:Campaign Setting", - "type:Adventure", - "type:One-Shot", - "type:Setting", - "type:World", - "type:Lore", - "type:History", - "type:Dungeon Master", - "type:Encounter Pack", - "type:Encounter", - "type:Session Notes", - "type:reference", - "type:Handbook", - "type:Manual", - "type:Manuals", - "type:Compendium", - "type:Bestiary", + 'type:Campaign', + 'type:Campaign Setting', + 'type:Adventure', + 'type:One-Shot', + 'type:Setting', + 'type:World', + 'type:Lore', + 'type:History', + 'type:Dungeon Master', + 'type:Encounter Pack', + 'type:Encounter', + 'type:Session Notes', + 'type:reference', + 'type:Handbook', + 'type:Manual', + 'type:Manuals', + 'type:Compendium', + 'type:Bestiary', // ###################################### RPG Keywords // Classes / Subclasses / Archetypes - "Class", - "Subclass", - "Archetype", - "Martial", - "Half-Caster", - "Full Caster", - "Artificer", - "Barbarian", - "Bard", - "Cleric", - "Druid", - "Fighter", - "Monk", - "Paladin", - "Rogue", - "Sorcerer", - "Warlock", - "Wizard", + 'Class', + 'Subclass', + 'Archetype', + 'Martial', + 'Half-Caster', + 'Full Caster', + 'Artificer', + 'Barbarian', + 'Bard', + 'Cleric', + 'Druid', + 'Fighter', + 'Monk', + 'Paladin', + 'Rogue', + 'Sorcerer', + 'Warlock', + 'Wizard', // Races / Species / Lineages - "Race", - "Ancestry", - "Lineage", - "Aasimar", - "Beastfolk", - "Dragonborn", - "Dwarf", - "Elf", - "Goblin", - "Half-Elf", - "Half-Orc", - "Human", - "Kobold", - "Lizardfolk", - "Lycan", - "Orc", - "Tiefling", - "Vampire", - "Yuan-Ti", + 'Race', + 'Ancestry', + 'Lineage', + 'Aasimar', + 'Beastfolk', + 'Dragonborn', + 'Dwarf', + 'Elf', + 'Goblin', + 'Half-Elf', + 'Half-Orc', + 'Human', + 'Kobold', + 'Lizardfolk', + 'Lycan', + 'Orc', + 'Tiefling', + 'Vampire', + 'Yuan-Ti', // Magic / Spells / Items - "Magic", - "Magic Item", - "Magic Items", - "Wondrous Item", - "Magic Weapon", - "Artifact", - "Spell", - "Spells", - "Cantrip", - "Cantrips", - "Eldritch", - "Eldritch Invocation", - "Invocation", - "Invocations", - "Pact boon", - "Pact Boon", - "Spellcaster", - "Spellblade", - "Magical Tattoos", - "Enchantment", - "Enchanted", - "Attunement", - "Requires Attunement", - "Rune", - "Runes", - "Wand", - "Rod", - "Scroll", - "Potion", - "Potions", - "Item", - "Items", - "Bag of Holding", + 'Magic', + 'Magic Item', + 'Magic Items', + 'Wondrous Item', + 'Magic Weapon', + 'Artifact', + 'Spell', + 'Spells', + 'Cantrip', + 'Cantrips', + 'Eldritch', + 'Eldritch Invocation', + 'Invocation', + 'Invocations', + 'Pact boon', + 'Pact Boon', + 'Spellcaster', + 'Spellblade', + 'Magical Tattoos', + 'Enchantment', + 'Enchanted', + 'Attunement', + 'Requires Attunement', + 'Rune', + 'Runes', + 'Wand', + 'Rod', + 'Scroll', + 'Potion', + 'Potions', + 'Item', + 'Items', + 'Bag of Holding', // Monsters / Creatures / Enemies - "Monster", - "Creatures", - "Creature", - "Beast", - "Beasts", - "Humanoid", - "Undead", - "Fiend", - "Aberration", - "Ooze", - "Giant", - "Dragon", - "Monstrosity", - "Demon", - "Devil", - "Elemental", - "Construct", - "Constructs", - "Boss", - "BBEG", + 'Monster', + 'Creatures', + 'Creature', + 'Beast', + 'Beasts', + 'Humanoid', + 'Undead', + 'Fiend', + 'Aberration', + 'Ooze', + 'Giant', + 'Dragon', + 'Monstrosity', + 'Demon', + 'Devil', + 'Elemental', + 'Construct', + 'Constructs', + 'Boss', + 'BBEG', // ############################# Media / Pop Culture - "One Piece", - "Dragon Ball", - "Dragon Ball Z", - "Naruto", - "Jujutsu Kaisen", - "Fairy Tail", - "Final Fantasy", - "Kingdom Hearts", - "Elder Scrolls", - "Skyrim", - "WoW", - "World of Warcraft", - "Marvel Comics", - "DC Comics", - "Pokemon", - "League of Legends", - "Runeterra", - "Arcane", - "Yu-Gi-Oh", - "Minecraft", - "Don't Starve", - "Witcher", - "Witcher 3", - "Cyberpunk", - "Cyberpunk 2077", - "Fallout", - "Divinity Original Sin 2", - "Fullmetal Alchemist", - "Fullmetal Alchemist Brotherhood", - "Lobotomy Corporation", - "Bloodborne", - "Dragonlance", - "Shackled City Adventure Path", - "Baldurs Gate 3", - "Library of Ruina", - "Radiant Citadel", - "Ravenloft", - "Forgotten Realms", - "Exandria", - "Critical Role", - "Star Wars", - "SW5e", - "Star Wars 5e", + 'One Piece', + 'Dragon Ball', + 'Dragon Ball Z', + 'Naruto', + 'Jujutsu Kaisen', + 'Fairy Tail', + 'Final Fantasy', + 'Kingdom Hearts', + 'Elder Scrolls', + 'Skyrim', + 'WoW', + 'World of Warcraft', + 'Marvel Comics', + 'DC Comics', + 'Pokemon', + 'League of Legends', + 'Runeterra', + 'Arcane', + 'Yu-Gi-Oh', + 'Minecraft', + 'Don\'t Starve', + 'Witcher', + 'Witcher 3', + 'Cyberpunk', + 'Cyberpunk 2077', + 'Fallout', + 'Divinity Original Sin 2', + 'Fullmetal Alchemist', + 'Fullmetal Alchemist Brotherhood', + 'Lobotomy Corporation', + 'Bloodborne', + 'Dragonlance', + 'Shackled City Adventure Path', + 'Baldurs Gate 3', + 'Library of Ruina', + 'Radiant Citadel', + 'Ravenloft', + 'Forgotten Realms', + 'Exandria', + 'Critical Role', + 'Star Wars', + 'SW5e', + 'Star Wars 5e', ]; + +// substrings to be normalized to the first value on the array +export const canonizationList = [ + ['5e 2024', '5.5e', '5e\'24', '5.24', '5e24', '5.5'], + ['5e', '5th Edition'], + ['Dungeons & Dragons', 'Dungeons and Dragons', 'Dungeons n dragons'], + ['D&D', 'DnD', 'dnd', 'Dnd', 'dnD', 'd&d', 'd&D', 'D&d'], + ['P2e', 'p2e', 'P2E', 'Pathfinder 2e'], +]; \ No newline at end of file diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 7f4a3a77f..b43797424 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -1,71 +1,62 @@ -import "./tagInput.less"; -import React, { useState, useEffect } from "react"; -import Combobox from "../../../components/combobox.jsx"; +import './tagInput.less'; +import React, { useState, useEffect } from 'react'; +import Combobox from '../../../components/combobox.jsx'; -import tagSuggestionList from "./curatedTagSuggestionList.js"; +import { tagSuggestionList, canonizationList } from './curatedTagSuggestionList.js'; -const TagInput = ({tooltip, label, valuePatterns, values = [], unique = true, placeholder = "", smallText = "", onChange }) => { +const TagInput = ({ tooltip, label, valuePatterns, values = [], unique = true, placeholder = '', smallText = '', onChange })=>{ const [tagList, setTagList] = useState( - values.map((value) => ({ + values.map((value)=>({ value, - editing: false, - draft: "", + editing : false, + draft : '', })), ); - useEffect(() => { + useEffect(()=>{ const incoming = values || []; - const current = tagList.map((t) => t.value); + const current = tagList.map((t)=>t.value); - const changed = incoming.length !== current.length || incoming.some((v, i) => v !== current[i]); + const changed = incoming.length !== current.length || incoming.some((v, i)=>v !== current[i]); - if (changed) { + if(changed) { setTagList( - incoming.map((value) => ({ + incoming.map((value)=>({ value, - editing: false, + editing : false, })), ); } }, [values]); - useEffect(() => { + useEffect(()=>{ onChange?.({ - target: { value: tagList.map((t) => t.value) }, + target : { value: tagList.map((t)=>t.value) }, }); }, [tagList]); - // substrings to be normalized to the first value on the array - const duplicateGroups = [ - ["5e 2024", "5.5e", "5e'24", "5.24", "5e24", "5.5"], - ["5e", "5th Edition"], - ["Dungeons & Dragons", "Dungeons and Dragons", "Dungeons n dragons"], - ["D&D", "DnD", "dnd", "Dnd", "dnD", "d&d", "d&D", "D&d"], - ["P2e", "p2e", "P2E", "Pathfinder 2e"], - ]; - - const normalizeValue = (input) => { + const normalizeValue = (input)=>{ const lowerInput = input.toLowerCase(); let normalizedTag = input; - for (const group of duplicateGroups) { + for (const group of canonizationList) { for (const tag of group) { - if (!tag) continue; + if(!tag) continue; const index = lowerInput.indexOf(tag.toLowerCase()); - if (index !== -1) { + if(index !== -1) { normalizedTag = input.slice(0, index) + group[0] + input.slice(index + tag.length); break; } } } - if (normalizedTag.includes(":")) { - const [rawType, rawValue = ""] = normalizedTag.split(":"); + if(normalizedTag.includes(':')) { + const [rawType, rawValue = ''] = normalizedTag.split(':'); const tagType = rawType.trim().toLowerCase(); const tagValue = rawValue.trim(); - if (tagValue.length > 0) { + if(tagValue.length > 0) { normalizedTag = `${tagType}:${tagValue[0].toUpperCase()}${tagValue.slice(1)}`; } //trims spaces around colon and capitalizes the first word after the colon @@ -75,56 +66,56 @@ const TagInput = ({tooltip, label, valuePatterns, values = [], unique = true, pl return normalizedTag; }; - const submitTag = (newValue, index = null) => { + const submitTag = (newValue, index = null)=>{ const trimmed = newValue?.trim(); - if (!trimmed) return; - if (!valuePatterns.test(trimmed)) return; + if(!trimmed) return; + if(!valuePatterns.test(trimmed)) return; const normalizedTag = normalizeValue(trimmed); - setTagList((prev) => { - const existsIndex = prev.findIndex((t) => t.value.toLowerCase() === normalizedTag.toLowerCase()); - if (unique && existsIndex !== -1) return prev; - if (index !== null) { - return prev.map((t, i) => (i === index ? { ...t, value: normalizedTag, editing: false } : t)); + setTagList((prev)=>{ + const existsIndex = prev.findIndex((t)=>t.value.toLowerCase() === normalizedTag.toLowerCase()); + if(unique && existsIndex !== -1) return prev; + if(index !== null) { + return prev.map((t, i)=>(i === index ? { ...t, value: normalizedTag, editing: false } : t)); } return [...prev, { value: normalizedTag, editing: false }]; }); }; - const removeTag = (index) => { - setTagList((prev) => prev.filter((_, i) => i !== index)); + const removeTag = (index)=>{ + setTagList((prev)=>prev.filter((_, i)=>i !== index)); }; - const editTag = (index) => { - setTagList((prev) => prev.map((t, i) => (i === index ? { ...t, editing: true, draft: t.value } : t))); + const editTag = (index)=>{ + setTagList((prev)=>prev.map((t, i)=>(i === index ? { ...t, editing: true, draft: t.value } : t))); }; - const stopEditing = (index) => { - setTagList((prev) => prev.map((t, i) => (i === index ? { ...t, editing: false, draft: "" } : t))); + const stopEditing = (index)=>{ + setTagList((prev)=>prev.map((t, i)=>(i === index ? { ...t, editing: false, draft: '' } : t))); }; - const suggestionOptions = tagSuggestionList.map((tag) => { - const tagType = tag.split(":"); + const suggestionOptions = tagSuggestionList.map((tag)=>{ + const tagType = tag.split(':'); - let classes = "item"; + let classes = 'item'; switch (tagType[0]) { - case "type": - classes = "item type"; - break; - case "group": - classes = "item group"; - break; - case "meta": - classes = "item meta"; - break; - case "system": - classes = "item system"; - break; - default: - classes = "item"; - break; + case 'type': + classes = 'item type'; + break; + case 'group': + classes = 'item group'; + break; + case 'meta': + classes = 'item meta'; + break; + case 'system': + classes = 'item system'; + break; + default: + classes = 'item'; + break; } return ( @@ -135,73 +126,69 @@ const TagInput = ({tooltip, label, valuePatterns, values = [], unique = true, pl }); return ( -
    +
    submitTag(value)} - onEntry={(e) => { - if (e.key === "Enter") { + onSelect={(value)=>submitTag(value)} + onEntry={(e)=>{ + if(e.key === 'Enter') { e.preventDefault(); submitTag(e.target.value); } }} /> -
      - {tagList.map((t, i) => - t.editing ? ( - - setTagList((prev) => - prev.map((tag, idx) => (idx === i ? { ...tag, draft: e.target.value } : tag)), - ) +
        + {tagList.map((t, i)=>t.editing ? ( + setTagList((prev)=>prev.map((tag, idx)=>(idx === i ? { ...tag, draft: e.target.value } : tag)), + ) + } + onKeyDown={(e)=>{ + if(e.key === 'Enter') { + e.preventDefault(); + submitTag(t.draft, i); // submit draft + setTagList((prev)=>prev.map((tag, idx)=>(idx === i ? { ...tag, draft: '' } : tag)), + ); } - onKeyDown={(e) => { - if (e.key === "Enter") { - e.preventDefault(); - submitTag(t.draft, i); // submit draft - setTagList((prev) => - prev.map((tag, idx) => (idx === i ? { ...tag, draft: "" } : tag)), - ); - } - if (e.key === "Escape") { - stopEditing(i); - e.target.blur(); - } - }} - autoFocus - /> - ) : ( -
      • editTag(i)}> - {t.value} - -
      • - ), + if(e.key === 'Escape') { + stopEditing(i); + e.target.blur(); + } + }} + autoFocus + /> + ) : ( +
      • editTag(i)}> + {t.value} + +
      • + ), )}
    diff --git a/client/homebrew/editor/tagInput/tagSuggestionList.js b/client/homebrew/editor/tagInput/tagSuggestionList.js index 6b8e4060e..eb4891616 100644 --- a/client/homebrew/editor/tagInput/tagSuggestionList.js +++ b/client/homebrew/editor/tagInput/tagSuggestionList.js @@ -1,1980 +1,1980 @@ export default [ - "meta:Theme", - "5e", - "Subclass", - "meta:theme", - "subclass", - "Class", - "Homebrew", - "Race", - "Dungeons and Dragons", - "theme", - "Daggerheart", - "2024", - "One Piece", - "One Piece DND", - "Luffy", - "Dungeons and Devil Fruits", - "Strawhats", - "Template", - "Campaign Frame", - "class", - "Players Handbook", - "dnd", - "osr", - "Dungeon Masters Guide", - "shadowdark", - "dragonbane", - "PHB", - "example", - "Devil Fruits", - "system:pf2e", - "DnD", - "DMG", - "system:dnd5.5", - "Monster", - "homebrew", - "race", - "template", - "Warlock", - "monster", - "Fighter", - "warlock", - "druid", - "sorcerer", - "D&D", - "Magic Item", - "Barbarian", - "Artificer", - "2014", - "system:descent into avernus", - "Sorcerer", - "Adventure", - "Paladin", - "Ranger", - "user help", - "fighter", - "5th Edition", - "Spells", - "Monk", - "Spell", - "NPC", - "Cleric", - "spell", - "Rogue", - "css", - "Item", - "artificer", - "magic item", - "Rules", - "barbarian", - "wizard", - "russian", - "DnD5e", - "Wizard", - "paladin", - "bastionland", - "spells", - "Devil Fruit", - "Bard", - "5.5e", - "rogue", - "Tabletop System", - "Haki", - "Druid", - "mystic bastionland", - "item", - "Lore", - "bard", - "monk", - "system:dnd5e", - "world", - "ranger", - "WIP", - "cleric", - "Dragon", - "Naruto", - "Creature", - "snippet", - "npc", - "DeS", - "Magic", - "guide", - "v3", - "Beast", - "Classe", - "onering", - "Monsters", - "Races", - "Weapon", - "adventure", - "Subclasses", - "stat block", - "weapon", - "Species", - "DONE", - "archetype", - "RPG", - "Hollow Knight", - "5e'24", - "Martial", - "DND", - "Classe Nova", - "Curse of Strahd", - "Boss", - "Hollowed Kingdoms", - "baldurs mouth", - "5.24", - "Homewbrew", - "Encyclopedia", - "Revised", - "OneWorldHD", - "knight", - "DPS", - "srd", - "Undead", - "items", - "DnD 5e", - "Guide", - "Compendium", - "Feat", - "newspaper", - "magic", - "TTRPG", - "descent into avernus", - "reference", - "system:D&D 5e24", - "feat", - "Magic Items", - "Campaign", - "resource", - "Feats", - "Anime", - "dd5", - "races", - "Monstrosity", - "DM Screen", - "2024 Rules", - "Rework", - "Character Build", - "Done", - "5e 2024", - "Construct", - "myth", - "magic items", - "creature", - "Legendary", - "Strahd", - "background", - "Player", - "style", - "Legacy", - "Player Handbook", - "martial", - "Character", - "Dungeons & Dragons", - "Table", - "reddit", - "monsters", - "OneDND", - "dragon", - "Suporte", - "Soulbound", - "Expanded Handbook", - "bestiary", - "Humanoid", - "system:dnd", - "Oredell", - "system:class", - "V3", - "system:5e", - "5e'14", - "Age of Sigmar", - "Items", - "Eberron", - "horror", - "dnd5e", - "star wars", - "Background", - "compendium", - "revision", - "Elemental", - "character", - "Marcial", - "SW5e", - "notes", - "DM", - "Fey", - "one-shot", - "resources", - "NEW", - "campaign", - "wondrous item", - "Setting", - "Archive", - "NIMRE", - "Tanque", - "Jogavel", - "Dnd 5e", - "LotM", - "setting", - "revised", - "Warhammer", - "rework", - "Conjurador", - "GMBinder", - "ItemSet", - "NPCs", - "classes", - "CR 2", - "AetherSail", - "undead", - "Artifact", - "cards", - "Example", - "Guides", - "Theme", - "Swamp", - "CR 1", - "patron", - "Extra", - "concept", - "final fantasy", - "Aberration", - "Elder Scrolls", - "rules", - "meta:gratis", - "Dice Pool", - "Cue", - "dark", - "type:Style", - "rpg", - "meta:free", - "summoner", - "OC", - "rare", - "Fleshing Out", - "francais", - "Dnd", - "Creatures", - "Sims 4", - "sous-classe", - "ffxiv", - "Underdark", - "add-on", - "weapons", - "Subrace", - "dungeons and dragons", - "Naruto 5e", - "Lafari", - "Very Rare", - "d6", - "red", - "Equipment", - "CR 3", - "Patron", - "5E", - "objet magique", - "spellcaster", - "feats", - "5.24e", - "system:d&d5e", - "Rare", - "Thudnfer", - "daggerheart", - "CR 1/2", - "Archetype", - "dnd 5e", - "Pathfinder", - "lineage", - "Celestial", - "Support", - "species", - "ARCHIVED", - "Horror", - "humanoid", - "Subclase", - "book:PHB E&E", - "final fantasy xiv", - "Jungle", - "Feywild", - "Fiend", - "subclasses", - "HB", - "Legacy Challenge", - "Project Horizon", - "vampire", - "WoW", - "DND 5e", - "Weapons", - "system:book clone", - "CoS", - "N5e", - "Summon", - "Spellcaster", - "Koretra", - "Voidborn", - "one shot", - "Templates", - "tables", - "Iphexar", - "Shattered Obelisk", - "Sword Coast", - "elemental", - "lore", - "character sheet", - "discord", - "BetterMonsters", - "players", - "group:simple skans", - "Coastal", - "Forest", - "Unearthed Arcana", - "Old", - "Collection", - "Ancestry", - "Caevash", - "Strixhaven", - "Limbus Company", - "Daydreams & Deviants", - "Statblocks", - "Urban", - "Classes", - "familiar", - "Blood", - "oneshot", - "n5e", - "wip", - "masks", - "Planeshifted", - "Carrioss", - "avernus", - "object", - "1", - "Ruins", - "Anime Character", - "wild shape", - "mask", - "dj9 game", - "Handbook", - "Curse", - "oath", - "Midralis", - "Appendix", - "5.5", - "tales of the valiant", - "player classes", - "Caster", - "Large", - "Fateforge", - "Cursed", - "beast", - "Pathfinder 2e", - "Design", - "Uncommon", - "Endeur", - "Elemental Water", - "SCC", - "sci-fi", - "Dragons", - "human", - "Gods", - "Medium", - "System", - "Help", - "Handout", - "Skyrim", - "BnB", - "draft", - "PC", - "Variant", - "syntax", - "OneShot", - "Clase", - "UESTRPG", - "Savannah", - "Reef", - "CR 5", - "Forgotten Realms", - "collection", - "Combat", - "Historia", - "artifact", - "Expansion", - "Attunement", - "Variant Rules", - "d&d", - "Party Build", - "Evocation", - "homerule", - "Forbidden West", - "how-to", - "tov", - "Mystical Item", - "CR 4", - "Necromancer", - "General Rules", - "Needs Update", - "stat blocks", - "DC Comics", - "Sword", - "Armor", - "blood hunter", - "Blood Hunter", - "Meio Conjurador", - "Mydia", - "3rd Party", - "N5E", - "Delvebound", - "Ocean", - "Subterranean", - "half-caster", - "Demon", - "Fire", - "meta:Template", - "Character Sheet", - "PF2e", - "png", - "fantasy", - "Setting Guide", - "Style", - "Cor", - "legacy", - "Minion", - "meta:khaoz age", - "Book", - "magical item", - "immersion", - "reminder cards", - "Regras", - "Durnovar", - "2025", - "Camp1", - "Abyss", - "armor", - "construct", - "firearms", - "Backgrounds", - "Companion", - "Melee", - "fey", - "Incomplete", - "Vampire", - "Bestiary", - "Worldbuilding", - "History", - "Conjuration", - "necromancy", - "dragons", - "ancestry", - "Mech", - "PbtA", - "COS", - "One Shot", - "Factions", - "Transmutation", - "Spellcasting", - "card", - "Ardh", - "redveil", - "conditions", - "elturel", - "rhye", - "group:James Haeck", - "CaelYuu", - "system:5.24e", - "system:GM Binder", - "Grassland", - "melee", - "Potions", - "anime", - "D&D 5e", - "Healer", - "Gambling", - "Lightning", - "fighting style", - "support", - "Style Template", - "mtg", - "NSFW", - "aventura", - "Manuals", - "plant", - "Incarnate", - "Crafting", - "DnDBeyond", - "Monster Girl", - "Monster Girl Encyclopedia", - "pet", - "npcs", - "Stat Block", - "Styleguide", - "mitologia", - "Objeto maravilloso", - "vaesen rpg", - "dnd-2024", - "Class Handbook", - "Space", - "Taiga", - "CR 6", - "Pact Boon", - "race/ancestry", - "Necromancy", - "cantrip", - "LoL", - "Raza", - "handout", - "Mechanic", - "Conversion", - "Wondrous Item", - "Familiar", - "necromancer", - "uncommon", - "curse", - "Campaign Setting", - "Tetra", - "1e", - "module", - "Evolving", - "boiling sea", - "deck", - "OSR", - "RU", - "VL", - "Underdeep", - "Deep Ocean", - "Giant", - "statblock", - "combat", - "Time", - "5E24", - "session zero", - "elf", - "tank", - "sorcerous origin", - "Drakkenheim", - "Tavern", - "Domain", - "healer", - "Valenor", - "blood", - "Oath", - "spooky", - "fire", - "meta:5e24 Style", - "Notes", - "City", - "Conjurador Completo", - "prop", - "Dotherys", - "Rietuma 3.0", - "5e24", - "Library of Ruina", - "español", - "Project Echo", - "battle of Japan", - "Plant", - "Badlands", - "Neverwinter", - "Fantasy", - "Beastfolk", - "Unarmed", - "Cold", - "Damage", - "attunement", - "Hurthud", - "3rd Level", - "spelljammer", - "mostro", - "Custom", - "PT-BR", - "Alternative Realms", - "The Foot", - "boss", - "demo", - "Supplement", - "FitD", - "classe", - "5.14", - "Copy", - "DnD5e24", - "X-Men", - "TNA", - "CR 8", - "Desert", - "CR 7", - "arme", - "random", - "spellcasting", - "Deprecated", - "Cards", - "finished", - "Ben 10", - "equipment", - "Geography", - "Games", - "For Players", - "Faerun", - "scroll", - "Faction", - "Alchemist", - "drow", - "Lineage", - "mix-blend-mode", - "columns", - "User Help", - "Reami Dimenticati", - "Класс", - "D100", - "nsfw", - "hucaen", - "v1.0", - "Cortex", - "Fallout", - "ww5e", - "MAGIC", - "DnD2024", - "ToV", - "D&D2024", - "The Backrooms", - "Freshwater", - "D20", - "Dragonborn", - "custom", - "sword", - "Dungeons and Dragons 5e", - "Water", - "legendary", - "Dungeon", - "Ravenloft", - "aberration", - "Longsword", - "transmutation", - "Fairy Tail", - "Character background", - "Exandria", - "Updated", - "pitch", - "Half-Caster", - "Complete", - "Money", - "player", - "forgotten-realms", - "Festival", - "Casino", - "SCAG", - "Currency", - "North", - "Toril", - "Scourged Land of Valenor", - "Oota", - "parchment", - "Literature", - "Serrith", - "PNJ", - "Divinity Original Sin 2", - "Wild", - "videogame", - "magic the gathering", - "sweetblossom", - "GMscreen", - "MandM", - "D&D 5.24", - "Camp2", - "Remaster", - "riassunti", - "type:Resource", - "system:D&D", - "tag:Class", - "Excelsior", - "Stat Blocks", - "Sci-Fi", - "Ooze", - "CR 1/8", - "sublclass", - "chart", - "Mountains", - "guns", - "Nature", - "Orc", - "Poison", - "Devil", - "fiend", - "DC", - "pt-br", - "ABnB", - "One-Shot", - "strahd", - "Ring", - "Theme song", - "orc", - "summon", - "Psion", - "Psionics", - "Dungeon Master", - "vehicle", - "DM only", - "Demigod", - "Antica Energia", - "Pirates", - "Sourcebook", - "devil", - "Cantrip", - "mystery", - "MtG", - "conversion", - "Festivals", - "Casinos", - "Taverns", - "Betting", - "Drinking", - "phandelver", - "Warhammer 40k", - "mutant", - "styling", - "FATE", - "Lone Wolf", - "icon", - "New Dawn", - "Magic Set", - "Paladin Subclass", - "Alter Class", - "difficulty classses", - "combat tables", - "phb", - "Project Moon", - "Undertomes", - "EGO", - "Campagne 1", - "Constelação", - "Arvore I", - "Fim da Jornada", - "greek god", - "dwarf", - "Firearms", - "3.5e", - "generator", - "Elf", - "meta: Scenario", - "enchantment", - "buff", - "ITW", - "Tank", - "Archived", - "Martial Archetype", - "caster", - "BR", - "Knight", - "Utility", - "SWADE", - "Star Wars", - "pc", - "Mystic", - "Useful", - "Netherdeep", - "crafting", - "Sapient Undead", - "Maverick", - "Revision", - "Resource", - "Humblewood", - "one piece", - "Bag of Holding", - "medium", - "lightning", - "backgrounds", - "4th Level", - "path", - "BREAK-RPG", - "dark fantasy", - "Players", - "poison", - "psionic", - "gazook89", - "homebrew subclass", - "wild-wasteland", - "CWD", - "Paid", - "Tales of the Valiant", - "Dreadhold", - "arma", - "system:Mutants and Masterminds", - "#Tiefschlaf", - "Brew", - "Myra", - "Swashbuckler", - "dead by daylight", - "Exceptional", - "COD Zombies", - "Hills", - "Tundra", - "type:Campaign", - "wild magic", - "Food", - "Death", - "homebrew rules", - "Remake", - "Witcher", - "water", - "Pet", - "book", - "AAH", - "pact", - "Ice", - "Character Creation", - "animal", - "Pokemon", - "clase", - "5e14", - "DBZ", - "CLONE", - "Evil", - "Tarsere", - "Mythology", - "pf2e", - "Magical", - "type:race", - "Sorcerous Origin", - "Information", - "styles", - "Module", - "gish", - "frames", - "DeltaGreen", - "Magic item", - "food", - "chef", - "basics", - "giant", - "Brew Creation", - "One-shot", - "ttrpg", - "Path", - "Don't Starve", - "MGE", - "firearm", - "DnDBehindTheScreen", - "store", - "The Artisan", - "timeline", - "college", - "dev", - "dungeon of the dead three", - "Cradle", - "Dnd5e", - "dungeon", - "Amaranthine", - "Regno di Oltremare", - "bestia", - "rewrite", - "WiP", - "Subclasse", - "mutants and masterminds", - "The Embrace", - "meta:documentation", - "Mutants And Masterminds", - "khedoria", - "Encounter Pack", - "giorni", - "Statblock", - "Enemies", - "Goblinoids", - "Heavens", - "system:2e", - "Vaalbara", - "Dwarf", - "airos", - "table", - "Artificer Specialization", - "Buff", - "Book 1", - "Ranged", - "cypher", - "utilities", - "40k", - "Psychic", - "Fear", - "steampunk", - "shadow", - "subclase", - "Barbarian Subclass", - "Elements", - "pact boon", - "Clan", - "Fly", - "solo", - "sourcebook", - "Marvel Comics", - "compilation", - "Firearm", - "sidekick", - "infusions", - "Mechanics", - "Summoner", - "Aasimar", - "Human", - "Vehicle", - "Shadow", - "Clone", - "custom css", - "ocean", - "sotdl", - "bandit", - "Wind", - "Printer Friendly", - "Obsolete", - "mechanics", - "illusion", - "5th edition", - "League of Legends", - "Vestige", - "dungeons", - "Dungeons", - "and", - "Elden Ring", - "L5R", - "d20", - "Poisons", - "d15", - "Dungeons And Dragons", - "MTG", - "divine", - "characters", - "witch", - "Anime Homebrew", - "Zombie", - "thunder", - "Jujutsu Kaisen", - "campagne", - "Deadlands", - "spell list", - "1 Person", - "Ritual", - "screen", - "nature", - "Divination", - "Compattare", - "dtrpg", - "quick ref", - "Mago", - "Illivia", - "Shonen", - "Core Deities", - "green ronin", - "Bless", - "D&D5e", - "version:0.1.0", - "curato", - "system:Ord", - "Images", - "Sealed Artifact", - "Giants", - "CR 9", - "CR 11", - "CR 0", - "CR 14", - "Shadowfell", - "Tier 1", - "d100", - "Elemental Air", - "artificiel", - "Cultist", - "Cyberpunk", - "Huge", - "Warrior", - "Gun", - "quest", - "LYRA", - "Music", - "Tiefling", - "Master", - "Witch", - "Linnorm", - "1st-level", - "Mount", - "Animal", - "Comics", - "Superhero", - "creatures", - "Hunter", - "Control", - "Dragon Ball", - "Dragon Ball Z", - "Dagger", - "questingforamonster", - "ICRPG", - "Booklet", - "f and t", - "common", - "Chaos", - "spellblade", - "Constitution", - "artisan", - "arcane", - "Released", - "ring", - "runes", - "gun", - "Supportive Material", - "The Witcher", - "Desarmado", - "Monster Monday", - "Bleach", - "Demon Slayer", - "mice", - "worldbuilding", - "Necrotic", - "ability score", - "demon", - "Armybook Shivatiano", - "warrior", - "Fighter Subclass", - "system", - "whisperveil", - "psychic", - "warhammer", - "Aventura", - "Culture", - "Material", - "meta:npc", - "shops", - "magic weapon", - "nhera", - "Dark Fantasy", - "Regles", - "Wonderous Item", - "Features", - "pokemon", - "Ghosts of Saltmarsh", - "monstrosity", - "DL TWW", - "companion", - "alternate layout", - "Tutorials", - "Kitsune", - "don", - "heroique", - "mini campaign", - "drago", - "Aquatic", - "tool", - "handmade", - "released", - "Spellblade", - "pregen", - "level 2", - "Baldurs gate 3", - "My Hero", - "Technically a subclass", - "5.24e Remastered Subclasses", - "dinosaurs", - "5E.2024", - "Razas", - "Horizon", - "Clothing", - "+2", - "castellano", - "pentacle prophecy", - "tag:Spells", - "gruppo A", - "Rpg", - "razze", - "type:Adventure", - "unfinished", - "3.5", - "gunslinger", - "BBEG", - "Arcane", - "component", - "Bow", - "backstory", - "phandalin", - "Skills", - "Pact", - "Elemental Earth", - "Joke", - "invocation", - "martial class", - "Super Villain", - "Eldritch", - "Elemental Fire", - "Homebrew Class", - "eldritch", - "cyberpunk", - "Player Race", - "Class Mod", - "Heatcoast", - "meta:Guide", - "Yemao", - "evil", - "Named NPC", - "CLASS", - "Angel", - "vecna", - "PT", - "PTBR", - "Ancient", - "Small", - "WotC Style", - "5e Homebrew", - "1st Level", - "dagger", - "Brancalonia", - "encounter", - "cat", - "primal path", - "Ambientazione", - "Magie", - "candlekeep", - "Ongoing", - "Oneshot", - "Wondrous", - "Janbrewery", - "Tattoos", - "5e (2014)", - "concentration", - "very rare", - "Set", - "Kobold", - "martial archetype", - "God", - "blog", - "New Gate", - "Healing", - "OneDnD", - "Incantesimi", - "Player Options", - "contest", - "pirate", - "Manuel", - "Alchimie", - "Herboristerie", - "Ingredients", - "starlost", - "Campaign 1", - "Abandoned", - "Previous Editions", - "Enchantment", - "Tools", - "Oblivion", - "domain", - "5th Level", - "DnD Beyond", - "Reference", - "Sorcerer Subclass", - "Dragon Magazine", - "feature", - "german", - "conjuration", - "strixhaven", - "Sentient", - "JJK", - "10 Generations", - "character creation", - "LevelUp", - "pallid grove", - "primer", - "Requires Attunement", - "College", - "Aesthetic", - "critter", - "home game", - "spanish", - "stats", - "Lairon", - "Hunters Guild", - "original setting", - "Bosses", - "Radiant Citadel", - "actions", - "Reworked", - "Elystera", - "Wyvern", - "vikings", - "thief", - "enemies", - "Obsession", - "Yi Sang", - "aberrazione", - "Limbus", - "animals", - "minecraft", - "mice of legend", - "osric", - "20 Minutes Till Dawn", - "campaign frame", - "latigo", - "DH", - "Eldritch Invocation", - "system:daggerheart", - "100ni", - "meta:Sheet", - "fa-solid fa-sheet-plastic:Ficha", - "tag:Berean", - "AD&D", - "B/X", - "The Codex Of Anomalous Entities", - "monster manual", - "Polar Waters", - "CR 12", - "CR 10", - "blood magic", - "Gunslinger", - "grimoire", - "Drakes", - "Japanese", - "subrace", - "ooze", - "Stats", - "Half Caster", - "Sea", - "time", - "Brawler", - "Session 0", - "Halloween", - "Runeterra", - "Divine", - "Random", - "Lifestar", - "arcane trickster", - "Paddy4530", - "evocation", - "light", - "Steampunk", - "shaman", - "Primal Path", - "monk subclass", - "Full Caster", - "World", - "Planning", - "spirit", - "Nova Era", - "abjuration", - "Christmas", - "Critical Role", - "Gish", - "Bandit", - "Monster Manual", - "party member", - "mgazt", - "Playable Race", - "Donjon.bin.sh", - "Final Fantasy", - "Roleplay", - "monstre", - "fairy", - "frame", - "Minecraft", - "Stealth", - "Manual", - "half caster", - "Storm", - "Sorcery", - "format work", - "Kingdom Hearts", - "hexblade", - "block", - "page layouts", - "Monk Subclass", - "FinyaFluKaiKolja", - "Radiant", - "group:playtest", - "Korrahir", - "noble", - "exorcist", - "xapien", - "Raven Queen", - "markdown", - "damage", - "Alchemy", - "morrigan", - "genasi", - "ZNH", - "folklore", - "Fate", - "hechicero", - "Air", - "Magic Weapon", - "Anime DND 5e", - "Dragon Ball Z TTRPG", - "Dragon Ball Z RPG", - "Dragon Ball Z DND", - "Dragon Ball Z 5e", - "samurai", - "Goblin", - "Base Sheet", - "Shackled City Adventure Path", - "Natureza", - "control", - "Normarch", - "Reddit", - "Genshin Impact", - "Abjuration", - "Myr", - "Flight", - "Vampyre", - "nightmare", - "Lycan", - "Occult", - "circle", - "Christmas Special", - "DoDD", - "Character Options", - "traduction", - "Characters", - "Gear", - "system:sf2e", - "drakkenheim", - "downtime", - "amulet", - "Feiticeiros e Maldicoes", - "Tecnica amaldicoada", - "prorpg", - "enemy", - "No Mercy", - "rain world", - "slugcat", - "fly", - "meta:User Guide", - "Fallout TTRPG", - "regles", - "Ill Tides", - "Light-hearted", - "Vastria", - "school", - "Fillible Online", - "Mezgarr", - "Berserk", - "invocations", - "Classe Refeita", - "Auroboros", - "bosses", - "fabula ultima", - "Shagya", - "wild", - "DnD 2024", - "KaiburrKathHound", - "Barbarian Path", - "fauna", - "5E.2014", - "system:curse of strahd", - "Unofficial", - "how to", - "Glaive", - "A5E", - "pt", - "Consumible", - "Realmers'", - "Versatile Lineage", - "Shichibukai", - "2024e", - "Rencontre", - "tag:Spell List", - "elementalist", - "noncaster", - "blasphemous", - "Mordhiem", - "Wildfrost", - "#Regelwerk", - "Rewrite", - "Maldición de Strahd", - "Scion", - "Entities", - "Hoarwyrm", - "Player utility", - "CR 1/4", - "Temperate Forest", - "Demons", - "Drow", - "type:rules", - "fay", - "2e", - "familier", - "supplement", - "Amberwar", - "slime", - "Lycanthropy", - "meta: Terres de Leyt", - "Strong", - "AAH Vol. 1", - "Force", - "Jump", - "Aboleths", - "lol", - "location", - "small", - "customizable", - "Modern", - "Sky", - "portugues", - "Hero", - "Villain", - "element", - "Tyranny of Dragons", - "Adventure Guide", - "New Class", - "Witchlight", - "Shardblade", - "Plateaux", - "WOTC", - "Snippet", - "Terra", - "Otherworldly Patron", - "ritual", - "hag", - "Cyberpunk 2077", - "tavern", - "Artificer Specialist", - "Werewolf", - "Boesia", - "vampiric", - "monastic tradition", - "Gothic", - "celestial", - "Unfinished", - "Core", - "Arcane Tradition", - "Troll", - "Origin", - "Draconic", - "dj9 member", - "test", - "Hag", - "gem", - "Invocations", - "Dark Sun", - "aarkhen", - "How to", - "ravenloft", - "faerie", - "Playtest", - "Shaman", - "dead", - "Tomba Aniquilacio", - "Pacto", - "fullcaster", - "Electric", - "Ability Score", - "4D", - "pathfinder", - "insect", - "hook", - "page layout", - "healing", - "Lineages", - "Flying", - "Martial Arts", - "journal", - "Aide de jeu", - "hunter", - "headers", - "Dark Souls", - "courtyard", - "crossroads", - "Quest", - "CotF", - "defense", - "Semryss", - "invoked class", - "Session Notes", - "goblin", - "infernal", - "fate", - "oni", - "spellbook", - "Summoning", - "slut", - "whore", - "Greyhawk", - "Mobility", - "Reddit Remake", - "Guild", - "Cosmic Mart", - "7th Level", - "dragonborn", - "curse of strahd", - "Ranger Subclass", - "dossier", - "dossie", - "de", - "pnpde", - "Plane Shift", - "halloween", - "group:aventura", - "9th Level", - "tome", - "cold", - "acid", - "deprecated", - "mind flayer", - "MECHA", - "EssentialsKit", - "2d6", - "ToD", - "Work In Progress", - "Bond", - "Versatile", - "Dead", - "SYWTBAGM", - "summoning", - "english", - "Eilistraee", - "Draft", - "DoD", - "map", - "Frightened", - "Psychic Damage", - "eberron", - "recompensa", - "wizard subclass", - "teiran", - "Saltmarsh", - "jp setting", - "Illithid", - "Longbow", - "hell", - "Monarch", - "type:feat", - "reglas", - "cooking", - "Abenteuer", - "reloaded", - "incompleto", - "mecanica", - "Location", - "Grimlores Grimoire", - "2024 Subclass", - "Chiesa di Toleno", - "finalfantasy", - "The Undertomes", - "Lobotomy Corporation", - "SDHTA", - "D&D 2024", - "other", - "ally", - "images", - "Player's Guide", - "Avalon Sword", - "Cael'Yuu", - "dnd-2014", - "Regelwerk", - "Español", - "br", - "dnd 5.0", - "monstro", - "grand cemetery", - "Phoenix", - "dnd 2024", - "Bloodhunter", - "Sintonizacion", - "dungeons & dragons", - "Fix", - "Rulebook", - "Shadowdark", - "heroic", - "HFW", - "Earthdawn", - "24e", - "cormyr", - "suzail", - "dc20", - "tag:Rules", - "The Griffon's Saddlebag", - "LOTM", - "tag:Adventure", - "drunken master", - "eldritch invocation", - "Персонаж", - "Orcs", - "Lizardfolk", - "Frostfell", - "CR 17", - "Shapechanger", - "Farmland", - "Mages", - "Any", - "CR 13", - "Earth", - "Mountain", - "Drake", - "transformation", - "GM", - "Lich", - "lovecraft", - "unique", - "Optional Rules", - "int", - "creator", - "Primal", - "simple", - "golem", - "Void", - "Armour", - "spellsword", - "General", - "Asian", - "Bringers of chaos", - "Optional Feature", - "subraces", - "Galanoth", - "barbarian subclass", - "felhearth", - "modular", - "Vampires", - "wysteria", - "adaptation", - "beasts", - "naruto", - "ninja", - "Psionic", - "Guns", - "Crystal", - "Guardian", - "NonProfit", - "Mimic", - "languages", - "Epic Boons", - "Primer", - "Icewind Dale", - "joke", - "lycan", - "CR3", - "Armors", - "ff7", - "materia", - "final fantasy 7 remake", - "esper", - "ff7 remake", - "gargantuan", - "Frog", - "CR5", - "blank", - "monster hunter", - "league of legends", - "french", - "Pokémon", - "kobold", - "soul", - "ffxi", - "d10", - "Roman", - "Cute", - "DD5", - "variant", - "tree", - "fr", - "Scenario", - "lycanthrope", - "druide", - "staff", - "eios", - "arkheneios", - "Runic", - "Work", - "Ukrainian", - "cover-page", - "mage", - "deities", - "gods", - "Boss Fight", - "Lair", - "WBTW", - "roguish archetype", - "Character Option", - "Shortsword", - "Illrigger", - "Bloodborne", - "cr6", - "Priest", - "Hamon", - "Toonkind", - "rol", - "Strength", - "forgotten realms", - "Spanish", - "Conclave", - "Electro", - "Magical Tattoos", - "Matt Mercer", - "Wildemount", - "Mighty Nien", - "Campaign 2", - "Resistances", - "Bug", - "impression", - "PF", - "Magnus Archives", - "ice", - "speed", - "Generic NPC", - "Titanic", - "Ink Friendly", - "bleed", - "elder scrolls", - "Immortal", - "LMOP", - "Travel", - "Olphus", - "3d6", - "heist", - "World History", - "ghost", - "genie", - "kids on bikes", - "Russia", - "conclave", - "overhaul", - "manual", - "Adventures In Eden", - "Downtime", - "hamon", - "cloak", - "shadowfell", - "Hellfire", - "Paladin Oath", - "Genshin", - "Nation", - "air", - "Magical Item", - "War", - "Original", - "Monstrous Compendium", - "Calamity", - "Warden", - "Apocalypse", - "shield", - "AC", - "expansion", - "Concentration", - "charm", - "Weave", - "lycanthropy", - "raza", - "far realm", - "fighter subclass", - "ita", - "Pirate", - "Laranja", - "Grapple", - "EastByForce", - "hobgoblin", - "oneshot-notes", - "Holy", - "optional", - "type:cenario", - "group:core", - "The Brewery", - "Alcance", - "Morrowind", - "Indigo", - "Divino", - "2nd Level", - "Sub-Class", - "cantrips", - "Cloak", - "battle master", - "Dark", - "Puzzle", - "Lucky", - "consumable", - "rebalance", - "Shove", - "Area Control", - "Vanguard", - "funny", - "e5", - "Dragonlance", - "psion", - "initiative", - "Tactician", - "Inspiration", - "artificier", - "way", - "inspired", - "historia", - "Medusa", - "2 part", - "holy", - "gift", - "Nimble", - "mostri", - "phoenix", - "travel", - "Class Template", - "Intimidation", - "constructs", - "P666", - "Formatting", - "Divinity", - "Rod", - "Language", - "yokai", - "rune", - "western", - "vampires", - "flying", - "cute", - "Enemy", - "boon", - "Tables", - "ShadowFight", - "meta: Theme", - "SCS", - "vanthampur villa", - "CoA", - "shop", - "destiny", - "magical weapon", - "Arcane Arcade", - "XP to Level 3", - "Dice Average RPG", - "Pip-Boy", - "Dragon Heist", - "session notes", - "tattoo", - "flick", - "P6:66", - "Comic Character", - "experiment", - "Minerva", - "type:Spellbook", - "Realmfall", - "Wand", - "halfling", - "sw5e", - "implementar AP", - "Mask", - "Gazook89", - "Weltenrauch-Chroniken", - "MiA", - "Made in Abyss", - "français", - "fae", - "Lemuria", - "Mork Borg", - "guerrier", - "prunus", - "condition", - "pf2", - "tr", - "costrutto", - "German", - "project moon", - "5r", - "galles", - "Project moon", - "Yisang", - "Spicebush", - "player-accessible", - "Especie", - "Westmarch", - "a", - "Cart", - "Magus", - "group:Mchael Galvis", - "tip", - "werewolf", - "mundane", - "garrett", - "unarmed", - "Arcane Odyssey", - "Tomb of Divinity", - "pets", - "Video Game", - "4 part", - "pbta", - "Druids", - "multiclass", - "manuale", - "mimic", - "plane shift", - "Dotes", - "Hechizos", - "Infernal", - "Enhanced", - "done", - "Mission report", - "Blanks", - "Masks", - "Ultimate Ability", - "shadow-slave", - "Advertising", - "transform", - "Fullmetal Alchemist", - "Fullmetal Alchemist Brotherhood", - "tag:TAoF&F", - "Dwarves", - "Humans", - "Nine Hells", - "Devils", - "Archons", - "CR 15", - "Troglodytes", - "Goliath", - "retired", - "boots", - "ranged", - "shields", - "Zhentarim", - "World of Warcraft", - "Frontline", - "Guildmaster's Guide to Ravnica", - "Dungeons & Dragons 5e", - "beholder", - "NEEDS FIXING", - "mechanic", - "Loot", - "champion", - "Runes", - "Shield", - "Punch", - "Sniper", - "Magical Girl", - "NotDND", - "story", - "Sleep", - "Bard College", - "Illusion", - "Thunder", - "Defender", - "Genasi", - "troll", - "Gehenna", - "Yugoloth", - "social", - "Player Class", - "homebrew class", - "CR 16", - "Ghost", - "Kobolds", - "Trolls", - "Yuan-Ti", - "Elder Scrolls Offline", - "armure", - "Mage", - "CR 18", - "Technology", - "Mystery", - "darkness", - "Airship", - "New Campaign", - "Warframe", - "Wizard Subclass", - "Gold", - "Candor", - "Overhaul", - "Dragon Knight", - "Enoreth", - "Artifacts", - "New", - "AMMO", - "Campagne", - "Valbise", - "Subclasseptember", - "Mecha", - "Yu-Gi-Oh", - "Goblinoid", - "underwater", - "SW5E", - "bardo" -] \ No newline at end of file + 'meta:Theme', + '5e', + 'Subclass', + 'meta:theme', + 'subclass', + 'Class', + 'Homebrew', + 'Race', + 'Dungeons and Dragons', + 'theme', + 'Daggerheart', + '2024', + 'One Piece', + 'One Piece DND', + 'Luffy', + 'Dungeons and Devil Fruits', + 'Strawhats', + 'Template', + 'Campaign Frame', + 'class', + 'Players Handbook', + 'dnd', + 'osr', + 'Dungeon Masters Guide', + 'shadowdark', + 'dragonbane', + 'PHB', + 'example', + 'Devil Fruits', + 'system:pf2e', + 'DnD', + 'DMG', + 'system:dnd5.5', + 'Monster', + 'homebrew', + 'race', + 'template', + 'Warlock', + 'monster', + 'Fighter', + 'warlock', + 'druid', + 'sorcerer', + 'D&D', + 'Magic Item', + 'Barbarian', + 'Artificer', + '2014', + 'system:descent into avernus', + 'Sorcerer', + 'Adventure', + 'Paladin', + 'Ranger', + 'user help', + 'fighter', + '5th Edition', + 'Spells', + 'Monk', + 'Spell', + 'NPC', + 'Cleric', + 'spell', + 'Rogue', + 'css', + 'Item', + 'artificer', + 'magic item', + 'Rules', + 'barbarian', + 'wizard', + 'russian', + 'DnD5e', + 'Wizard', + 'paladin', + 'bastionland', + 'spells', + 'Devil Fruit', + 'Bard', + '5.5e', + 'rogue', + 'Tabletop System', + 'Haki', + 'Druid', + 'mystic bastionland', + 'item', + 'Lore', + 'bard', + 'monk', + 'system:dnd5e', + 'world', + 'ranger', + 'WIP', + 'cleric', + 'Dragon', + 'Naruto', + 'Creature', + 'snippet', + 'npc', + 'DeS', + 'Magic', + 'guide', + 'v3', + 'Beast', + 'Classe', + 'onering', + 'Monsters', + 'Races', + 'Weapon', + 'adventure', + 'Subclasses', + 'stat block', + 'weapon', + 'Species', + 'DONE', + 'archetype', + 'RPG', + 'Hollow Knight', + '5e\'24', + 'Martial', + 'DND', + 'Classe Nova', + 'Curse of Strahd', + 'Boss', + 'Hollowed Kingdoms', + 'baldurs mouth', + '5.24', + 'Homewbrew', + 'Encyclopedia', + 'Revised', + 'OneWorldHD', + 'knight', + 'DPS', + 'srd', + 'Undead', + 'items', + 'DnD 5e', + 'Guide', + 'Compendium', + 'Feat', + 'newspaper', + 'magic', + 'TTRPG', + 'descent into avernus', + 'reference', + 'system:D&D 5e24', + 'feat', + 'Magic Items', + 'Campaign', + 'resource', + 'Feats', + 'Anime', + 'dd5', + 'races', + 'Monstrosity', + 'DM Screen', + '2024 Rules', + 'Rework', + 'Character Build', + 'Done', + '5e 2024', + 'Construct', + 'myth', + 'magic items', + 'creature', + 'Legendary', + 'Strahd', + 'background', + 'Player', + 'style', + 'Legacy', + 'Player Handbook', + 'martial', + 'Character', + 'Dungeons & Dragons', + 'Table', + 'reddit', + 'monsters', + 'OneDND', + 'dragon', + 'Suporte', + 'Soulbound', + 'Expanded Handbook', + 'bestiary', + 'Humanoid', + 'system:dnd', + 'Oredell', + 'system:class', + 'V3', + 'system:5e', + '5e\'14', + 'Age of Sigmar', + 'Items', + 'Eberron', + 'horror', + 'dnd5e', + 'star wars', + 'Background', + 'compendium', + 'revision', + 'Elemental', + 'character', + 'Marcial', + 'SW5e', + 'notes', + 'DM', + 'Fey', + 'one-shot', + 'resources', + 'NEW', + 'campaign', + 'wondrous item', + 'Setting', + 'Archive', + 'NIMRE', + 'Tanque', + 'Jogavel', + 'Dnd 5e', + 'LotM', + 'setting', + 'revised', + 'Warhammer', + 'rework', + 'Conjurador', + 'GMBinder', + 'ItemSet', + 'NPCs', + 'classes', + 'CR 2', + 'AetherSail', + 'undead', + 'Artifact', + 'cards', + 'Example', + 'Guides', + 'Theme', + 'Swamp', + 'CR 1', + 'patron', + 'Extra', + 'concept', + 'final fantasy', + 'Aberration', + 'Elder Scrolls', + 'rules', + 'meta:gratis', + 'Dice Pool', + 'Cue', + 'dark', + 'type:Style', + 'rpg', + 'meta:free', + 'summoner', + 'OC', + 'rare', + 'Fleshing Out', + 'francais', + 'Dnd', + 'Creatures', + 'Sims 4', + 'sous-classe', + 'ffxiv', + 'Underdark', + 'add-on', + 'weapons', + 'Subrace', + 'dungeons and dragons', + 'Naruto 5e', + 'Lafari', + 'Very Rare', + 'd6', + 'red', + 'Equipment', + 'CR 3', + 'Patron', + '5E', + 'objet magique', + 'spellcaster', + 'feats', + '5.24e', + 'system:d&d5e', + 'Rare', + 'Thudnfer', + 'daggerheart', + 'CR 1/2', + 'Archetype', + 'dnd 5e', + 'Pathfinder', + 'lineage', + 'Celestial', + 'Support', + 'species', + 'ARCHIVED', + 'Horror', + 'humanoid', + 'Subclase', + 'book:PHB E&E', + 'final fantasy xiv', + 'Jungle', + 'Feywild', + 'Fiend', + 'subclasses', + 'HB', + 'Legacy Challenge', + 'Project Horizon', + 'vampire', + 'WoW', + 'DND 5e', + 'Weapons', + 'system:book clone', + 'CoS', + 'N5e', + 'Summon', + 'Spellcaster', + 'Koretra', + 'Voidborn', + 'one shot', + 'Templates', + 'tables', + 'Iphexar', + 'Shattered Obelisk', + 'Sword Coast', + 'elemental', + 'lore', + 'character sheet', + 'discord', + 'BetterMonsters', + 'players', + 'group:simple skans', + 'Coastal', + 'Forest', + 'Unearthed Arcana', + 'Old', + 'Collection', + 'Ancestry', + 'Caevash', + 'Strixhaven', + 'Limbus Company', + 'Daydreams & Deviants', + 'Statblocks', + 'Urban', + 'Classes', + 'familiar', + 'Blood', + 'oneshot', + 'n5e', + 'wip', + 'masks', + 'Planeshifted', + 'Carrioss', + 'avernus', + 'object', + '1', + 'Ruins', + 'Anime Character', + 'wild shape', + 'mask', + 'dj9 game', + 'Handbook', + 'Curse', + 'oath', + 'Midralis', + 'Appendix', + '5.5', + 'tales of the valiant', + 'player classes', + 'Caster', + 'Large', + 'Fateforge', + 'Cursed', + 'beast', + 'Pathfinder 2e', + 'Design', + 'Uncommon', + 'Endeur', + 'Elemental Water', + 'SCC', + 'sci-fi', + 'Dragons', + 'human', + 'Gods', + 'Medium', + 'System', + 'Help', + 'Handout', + 'Skyrim', + 'BnB', + 'draft', + 'PC', + 'Variant', + 'syntax', + 'OneShot', + 'Clase', + 'UESTRPG', + 'Savannah', + 'Reef', + 'CR 5', + 'Forgotten Realms', + 'collection', + 'Combat', + 'Historia', + 'artifact', + 'Expansion', + 'Attunement', + 'Variant Rules', + 'd&d', + 'Party Build', + 'Evocation', + 'homerule', + 'Forbidden West', + 'how-to', + 'tov', + 'Mystical Item', + 'CR 4', + 'Necromancer', + 'General Rules', + 'Needs Update', + 'stat blocks', + 'DC Comics', + 'Sword', + 'Armor', + 'blood hunter', + 'Blood Hunter', + 'Meio Conjurador', + 'Mydia', + '3rd Party', + 'N5E', + 'Delvebound', + 'Ocean', + 'Subterranean', + 'half-caster', + 'Demon', + 'Fire', + 'meta:Template', + 'Character Sheet', + 'PF2e', + 'png', + 'fantasy', + 'Setting Guide', + 'Style', + 'Cor', + 'legacy', + 'Minion', + 'meta:khaoz age', + 'Book', + 'magical item', + 'immersion', + 'reminder cards', + 'Regras', + 'Durnovar', + '2025', + 'Camp1', + 'Abyss', + 'armor', + 'construct', + 'firearms', + 'Backgrounds', + 'Companion', + 'Melee', + 'fey', + 'Incomplete', + 'Vampire', + 'Bestiary', + 'Worldbuilding', + 'History', + 'Conjuration', + 'necromancy', + 'dragons', + 'ancestry', + 'Mech', + 'PbtA', + 'COS', + 'One Shot', + 'Factions', + 'Transmutation', + 'Spellcasting', + 'card', + 'Ardh', + 'redveil', + 'conditions', + 'elturel', + 'rhye', + 'group:James Haeck', + 'CaelYuu', + 'system:5.24e', + 'system:GM Binder', + 'Grassland', + 'melee', + 'Potions', + 'anime', + 'D&D 5e', + 'Healer', + 'Gambling', + 'Lightning', + 'fighting style', + 'support', + 'Style Template', + 'mtg', + 'NSFW', + 'aventura', + 'Manuals', + 'plant', + 'Incarnate', + 'Crafting', + 'DnDBeyond', + 'Monster Girl', + 'Monster Girl Encyclopedia', + 'pet', + 'npcs', + 'Stat Block', + 'Styleguide', + 'mitologia', + 'Objeto maravilloso', + 'vaesen rpg', + 'dnd-2024', + 'Class Handbook', + 'Space', + 'Taiga', + 'CR 6', + 'Pact Boon', + 'race/ancestry', + 'Necromancy', + 'cantrip', + 'LoL', + 'Raza', + 'handout', + 'Mechanic', + 'Conversion', + 'Wondrous Item', + 'Familiar', + 'necromancer', + 'uncommon', + 'curse', + 'Campaign Setting', + 'Tetra', + '1e', + 'module', + 'Evolving', + 'boiling sea', + 'deck', + 'OSR', + 'RU', + 'VL', + 'Underdeep', + 'Deep Ocean', + 'Giant', + 'statblock', + 'combat', + 'Time', + '5E24', + 'session zero', + 'elf', + 'tank', + 'sorcerous origin', + 'Drakkenheim', + 'Tavern', + 'Domain', + 'healer', + 'Valenor', + 'blood', + 'Oath', + 'spooky', + 'fire', + 'meta:5e24 Style', + 'Notes', + 'City', + 'Conjurador Completo', + 'prop', + 'Dotherys', + 'Rietuma 3.0', + '5e24', + 'Library of Ruina', + 'español', + 'Project Echo', + 'battle of Japan', + 'Plant', + 'Badlands', + 'Neverwinter', + 'Fantasy', + 'Beastfolk', + 'Unarmed', + 'Cold', + 'Damage', + 'attunement', + 'Hurthud', + '3rd Level', + 'spelljammer', + 'mostro', + 'Custom', + 'PT-BR', + 'Alternative Realms', + 'The Foot', + 'boss', + 'demo', + 'Supplement', + 'FitD', + 'classe', + '5.14', + 'Copy', + 'DnD5e24', + 'X-Men', + 'TNA', + 'CR 8', + 'Desert', + 'CR 7', + 'arme', + 'random', + 'spellcasting', + 'Deprecated', + 'Cards', + 'finished', + 'Ben 10', + 'equipment', + 'Geography', + 'Games', + 'For Players', + 'Faerun', + 'scroll', + 'Faction', + 'Alchemist', + 'drow', + 'Lineage', + 'mix-blend-mode', + 'columns', + 'User Help', + 'Reami Dimenticati', + 'Класс', + 'D100', + 'nsfw', + 'hucaen', + 'v1.0', + 'Cortex', + 'Fallout', + 'ww5e', + 'MAGIC', + 'DnD2024', + 'ToV', + 'D&D2024', + 'The Backrooms', + 'Freshwater', + 'D20', + 'Dragonborn', + 'custom', + 'sword', + 'Dungeons and Dragons 5e', + 'Water', + 'legendary', + 'Dungeon', + 'Ravenloft', + 'aberration', + 'Longsword', + 'transmutation', + 'Fairy Tail', + 'Character background', + 'Exandria', + 'Updated', + 'pitch', + 'Half-Caster', + 'Complete', + 'Money', + 'player', + 'forgotten-realms', + 'Festival', + 'Casino', + 'SCAG', + 'Currency', + 'North', + 'Toril', + 'Scourged Land of Valenor', + 'Oota', + 'parchment', + 'Literature', + 'Serrith', + 'PNJ', + 'Divinity Original Sin 2', + 'Wild', + 'videogame', + 'magic the gathering', + 'sweetblossom', + 'GMscreen', + 'MandM', + 'D&D 5.24', + 'Camp2', + 'Remaster', + 'riassunti', + 'type:Resource', + 'system:D&D', + 'tag:Class', + 'Excelsior', + 'Stat Blocks', + 'Sci-Fi', + 'Ooze', + 'CR 1/8', + 'sublclass', + 'chart', + 'Mountains', + 'guns', + 'Nature', + 'Orc', + 'Poison', + 'Devil', + 'fiend', + 'DC', + 'pt-br', + 'ABnB', + 'One-Shot', + 'strahd', + 'Ring', + 'Theme song', + 'orc', + 'summon', + 'Psion', + 'Psionics', + 'Dungeon Master', + 'vehicle', + 'DM only', + 'Demigod', + 'Antica Energia', + 'Pirates', + 'Sourcebook', + 'devil', + 'Cantrip', + 'mystery', + 'MtG', + 'conversion', + 'Festivals', + 'Casinos', + 'Taverns', + 'Betting', + 'Drinking', + 'phandelver', + 'Warhammer 40k', + 'mutant', + 'styling', + 'FATE', + 'Lone Wolf', + 'icon', + 'New Dawn', + 'Magic Set', + 'Paladin Subclass', + 'Alter Class', + 'difficulty classses', + 'combat tables', + 'phb', + 'Project Moon', + 'Undertomes', + 'EGO', + 'Campagne 1', + 'Constelação', + 'Arvore I', + 'Fim da Jornada', + 'greek god', + 'dwarf', + 'Firearms', + '3.5e', + 'generator', + 'Elf', + 'meta: Scenario', + 'enchantment', + 'buff', + 'ITW', + 'Tank', + 'Archived', + 'Martial Archetype', + 'caster', + 'BR', + 'Knight', + 'Utility', + 'SWADE', + 'Star Wars', + 'pc', + 'Mystic', + 'Useful', + 'Netherdeep', + 'crafting', + 'Sapient Undead', + 'Maverick', + 'Revision', + 'Resource', + 'Humblewood', + 'one piece', + 'Bag of Holding', + 'medium', + 'lightning', + 'backgrounds', + '4th Level', + 'path', + 'BREAK-RPG', + 'dark fantasy', + 'Players', + 'poison', + 'psionic', + 'gazook89', + 'homebrew subclass', + 'wild-wasteland', + 'CWD', + 'Paid', + 'Tales of the Valiant', + 'Dreadhold', + 'arma', + 'system:Mutants and Masterminds', + '#Tiefschlaf', + 'Brew', + 'Myra', + 'Swashbuckler', + 'dead by daylight', + 'Exceptional', + 'COD Zombies', + 'Hills', + 'Tundra', + 'type:Campaign', + 'wild magic', + 'Food', + 'Death', + 'homebrew rules', + 'Remake', + 'Witcher', + 'water', + 'Pet', + 'book', + 'AAH', + 'pact', + 'Ice', + 'Character Creation', + 'animal', + 'Pokemon', + 'clase', + '5e14', + 'DBZ', + 'CLONE', + 'Evil', + 'Tarsere', + 'Mythology', + 'pf2e', + 'Magical', + 'type:race', + 'Sorcerous Origin', + 'Information', + 'styles', + 'Module', + 'gish', + 'frames', + 'DeltaGreen', + 'Magic item', + 'food', + 'chef', + 'basics', + 'giant', + 'Brew Creation', + 'One-shot', + 'ttrpg', + 'Path', + 'Don\'t Starve', + 'MGE', + 'firearm', + 'DnDBehindTheScreen', + 'store', + 'The Artisan', + 'timeline', + 'college', + 'dev', + 'dungeon of the dead three', + 'Cradle', + 'Dnd5e', + 'dungeon', + 'Amaranthine', + 'Regno di Oltremare', + 'bestia', + 'rewrite', + 'WiP', + 'Subclasse', + 'mutants and masterminds', + 'The Embrace', + 'meta:documentation', + 'Mutants And Masterminds', + 'khedoria', + 'Encounter Pack', + 'giorni', + 'Statblock', + 'Enemies', + 'Goblinoids', + 'Heavens', + 'system:2e', + 'Vaalbara', + 'Dwarf', + 'airos', + 'table', + 'Artificer Specialization', + 'Buff', + 'Book 1', + 'Ranged', + 'cypher', + 'utilities', + '40k', + 'Psychic', + 'Fear', + 'steampunk', + 'shadow', + 'subclase', + 'Barbarian Subclass', + 'Elements', + 'pact boon', + 'Clan', + 'Fly', + 'solo', + 'sourcebook', + 'Marvel Comics', + 'compilation', + 'Firearm', + 'sidekick', + 'infusions', + 'Mechanics', + 'Summoner', + 'Aasimar', + 'Human', + 'Vehicle', + 'Shadow', + 'Clone', + 'custom css', + 'ocean', + 'sotdl', + 'bandit', + 'Wind', + 'Printer Friendly', + 'Obsolete', + 'mechanics', + 'illusion', + '5th edition', + 'League of Legends', + 'Vestige', + 'dungeons', + 'Dungeons', + 'and', + 'Elden Ring', + 'L5R', + 'd20', + 'Poisons', + 'd15', + 'Dungeons And Dragons', + 'MTG', + 'divine', + 'characters', + 'witch', + 'Anime Homebrew', + 'Zombie', + 'thunder', + 'Jujutsu Kaisen', + 'campagne', + 'Deadlands', + 'spell list', + '1 Person', + 'Ritual', + 'screen', + 'nature', + 'Divination', + 'Compattare', + 'dtrpg', + 'quick ref', + 'Mago', + 'Illivia', + 'Shonen', + 'Core Deities', + 'green ronin', + 'Bless', + 'D&D5e', + 'version:0.1.0', + 'curato', + 'system:Ord', + 'Images', + 'Sealed Artifact', + 'Giants', + 'CR 9', + 'CR 11', + 'CR 0', + 'CR 14', + 'Shadowfell', + 'Tier 1', + 'd100', + 'Elemental Air', + 'artificiel', + 'Cultist', + 'Cyberpunk', + 'Huge', + 'Warrior', + 'Gun', + 'quest', + 'LYRA', + 'Music', + 'Tiefling', + 'Master', + 'Witch', + 'Linnorm', + '1st-level', + 'Mount', + 'Animal', + 'Comics', + 'Superhero', + 'creatures', + 'Hunter', + 'Control', + 'Dragon Ball', + 'Dragon Ball Z', + 'Dagger', + 'questingforamonster', + 'ICRPG', + 'Booklet', + 'f and t', + 'common', + 'Chaos', + 'spellblade', + 'Constitution', + 'artisan', + 'arcane', + 'Released', + 'ring', + 'runes', + 'gun', + 'Supportive Material', + 'The Witcher', + 'Desarmado', + 'Monster Monday', + 'Bleach', + 'Demon Slayer', + 'mice', + 'worldbuilding', + 'Necrotic', + 'ability score', + 'demon', + 'Armybook Shivatiano', + 'warrior', + 'Fighter Subclass', + 'system', + 'whisperveil', + 'psychic', + 'warhammer', + 'Aventura', + 'Culture', + 'Material', + 'meta:npc', + 'shops', + 'magic weapon', + 'nhera', + 'Dark Fantasy', + 'Regles', + 'Wonderous Item', + 'Features', + 'pokemon', + 'Ghosts of Saltmarsh', + 'monstrosity', + 'DL TWW', + 'companion', + 'alternate layout', + 'Tutorials', + 'Kitsune', + 'don', + 'heroique', + 'mini campaign', + 'drago', + 'Aquatic', + 'tool', + 'handmade', + 'released', + 'Spellblade', + 'pregen', + 'level 2', + 'Baldurs gate 3', + 'My Hero', + 'Technically a subclass', + '5.24e Remastered Subclasses', + 'dinosaurs', + '5E.2024', + 'Razas', + 'Horizon', + 'Clothing', + '+2', + 'castellano', + 'pentacle prophecy', + 'tag:Spells', + 'gruppo A', + 'Rpg', + 'razze', + 'type:Adventure', + 'unfinished', + '3.5', + 'gunslinger', + 'BBEG', + 'Arcane', + 'component', + 'Bow', + 'backstory', + 'phandalin', + 'Skills', + 'Pact', + 'Elemental Earth', + 'Joke', + 'invocation', + 'martial class', + 'Super Villain', + 'Eldritch', + 'Elemental Fire', + 'Homebrew Class', + 'eldritch', + 'cyberpunk', + 'Player Race', + 'Class Mod', + 'Heatcoast', + 'meta:Guide', + 'Yemao', + 'evil', + 'Named NPC', + 'CLASS', + 'Angel', + 'vecna', + 'PT', + 'PTBR', + 'Ancient', + 'Small', + 'WotC Style', + '5e Homebrew', + '1st Level', + 'dagger', + 'Brancalonia', + 'encounter', + 'cat', + 'primal path', + 'Ambientazione', + 'Magie', + 'candlekeep', + 'Ongoing', + 'Oneshot', + 'Wondrous', + 'Janbrewery', + 'Tattoos', + '5e (2014)', + 'concentration', + 'very rare', + 'Set', + 'Kobold', + 'martial archetype', + 'God', + 'blog', + 'New Gate', + 'Healing', + 'OneDnD', + 'Incantesimi', + 'Player Options', + 'contest', + 'pirate', + 'Manuel', + 'Alchimie', + 'Herboristerie', + 'Ingredients', + 'starlost', + 'Campaign 1', + 'Abandoned', + 'Previous Editions', + 'Enchantment', + 'Tools', + 'Oblivion', + 'domain', + '5th Level', + 'DnD Beyond', + 'Reference', + 'Sorcerer Subclass', + 'Dragon Magazine', + 'feature', + 'german', + 'conjuration', + 'strixhaven', + 'Sentient', + 'JJK', + '10 Generations', + 'character creation', + 'LevelUp', + 'pallid grove', + 'primer', + 'Requires Attunement', + 'College', + 'Aesthetic', + 'critter', + 'home game', + 'spanish', + 'stats', + 'Lairon', + 'Hunters Guild', + 'original setting', + 'Bosses', + 'Radiant Citadel', + 'actions', + 'Reworked', + 'Elystera', + 'Wyvern', + 'vikings', + 'thief', + 'enemies', + 'Obsession', + 'Yi Sang', + 'aberrazione', + 'Limbus', + 'animals', + 'minecraft', + 'mice of legend', + 'osric', + '20 Minutes Till Dawn', + 'campaign frame', + 'latigo', + 'DH', + 'Eldritch Invocation', + 'system:daggerheart', + '100ni', + 'meta:Sheet', + 'fa-solid fa-sheet-plastic:Ficha', + 'tag:Berean', + 'AD&D', + 'B/X', + 'The Codex Of Anomalous Entities', + 'monster manual', + 'Polar Waters', + 'CR 12', + 'CR 10', + 'blood magic', + 'Gunslinger', + 'grimoire', + 'Drakes', + 'Japanese', + 'subrace', + 'ooze', + 'Stats', + 'Half Caster', + 'Sea', + 'time', + 'Brawler', + 'Session 0', + 'Halloween', + 'Runeterra', + 'Divine', + 'Random', + 'Lifestar', + 'arcane trickster', + 'Paddy4530', + 'evocation', + 'light', + 'Steampunk', + 'shaman', + 'Primal Path', + 'monk subclass', + 'Full Caster', + 'World', + 'Planning', + 'spirit', + 'Nova Era', + 'abjuration', + 'Christmas', + 'Critical Role', + 'Gish', + 'Bandit', + 'Monster Manual', + 'party member', + 'mgazt', + 'Playable Race', + 'Donjon.bin.sh', + 'Final Fantasy', + 'Roleplay', + 'monstre', + 'fairy', + 'frame', + 'Minecraft', + 'Stealth', + 'Manual', + 'half caster', + 'Storm', + 'Sorcery', + 'format work', + 'Kingdom Hearts', + 'hexblade', + 'block', + 'page layouts', + 'Monk Subclass', + 'FinyaFluKaiKolja', + 'Radiant', + 'group:playtest', + 'Korrahir', + 'noble', + 'exorcist', + 'xapien', + 'Raven Queen', + 'markdown', + 'damage', + 'Alchemy', + 'morrigan', + 'genasi', + 'ZNH', + 'folklore', + 'Fate', + 'hechicero', + 'Air', + 'Magic Weapon', + 'Anime DND 5e', + 'Dragon Ball Z TTRPG', + 'Dragon Ball Z RPG', + 'Dragon Ball Z DND', + 'Dragon Ball Z 5e', + 'samurai', + 'Goblin', + 'Base Sheet', + 'Shackled City Adventure Path', + 'Natureza', + 'control', + 'Normarch', + 'Reddit', + 'Genshin Impact', + 'Abjuration', + 'Myr', + 'Flight', + 'Vampyre', + 'nightmare', + 'Lycan', + 'Occult', + 'circle', + 'Christmas Special', + 'DoDD', + 'Character Options', + 'traduction', + 'Characters', + 'Gear', + 'system:sf2e', + 'drakkenheim', + 'downtime', + 'amulet', + 'Feiticeiros e Maldicoes', + 'Tecnica amaldicoada', + 'prorpg', + 'enemy', + 'No Mercy', + 'rain world', + 'slugcat', + 'fly', + 'meta:User Guide', + 'Fallout TTRPG', + 'regles', + 'Ill Tides', + 'Light-hearted', + 'Vastria', + 'school', + 'Fillible Online', + 'Mezgarr', + 'Berserk', + 'invocations', + 'Classe Refeita', + 'Auroboros', + 'bosses', + 'fabula ultima', + 'Shagya', + 'wild', + 'DnD 2024', + 'KaiburrKathHound', + 'Barbarian Path', + 'fauna', + '5E.2014', + 'system:curse of strahd', + 'Unofficial', + 'how to', + 'Glaive', + 'A5E', + 'pt', + 'Consumible', + 'Realmers\'', + 'Versatile Lineage', + 'Shichibukai', + '2024e', + 'Rencontre', + 'tag:Spell List', + 'elementalist', + 'noncaster', + 'blasphemous', + 'Mordhiem', + 'Wildfrost', + '#Regelwerk', + 'Rewrite', + 'Maldición de Strahd', + 'Scion', + 'Entities', + 'Hoarwyrm', + 'Player utility', + 'CR 1/4', + 'Temperate Forest', + 'Demons', + 'Drow', + 'type:rules', + 'fay', + '2e', + 'familier', + 'supplement', + 'Amberwar', + 'slime', + 'Lycanthropy', + 'meta: Terres de Leyt', + 'Strong', + 'AAH Vol. 1', + 'Force', + 'Jump', + 'Aboleths', + 'lol', + 'location', + 'small', + 'customizable', + 'Modern', + 'Sky', + 'portugues', + 'Hero', + 'Villain', + 'element', + 'Tyranny of Dragons', + 'Adventure Guide', + 'New Class', + 'Witchlight', + 'Shardblade', + 'Plateaux', + 'WOTC', + 'Snippet', + 'Terra', + 'Otherworldly Patron', + 'ritual', + 'hag', + 'Cyberpunk 2077', + 'tavern', + 'Artificer Specialist', + 'Werewolf', + 'Boesia', + 'vampiric', + 'monastic tradition', + 'Gothic', + 'celestial', + 'Unfinished', + 'Core', + 'Arcane Tradition', + 'Troll', + 'Origin', + 'Draconic', + 'dj9 member', + 'test', + 'Hag', + 'gem', + 'Invocations', + 'Dark Sun', + 'aarkhen', + 'How to', + 'ravenloft', + 'faerie', + 'Playtest', + 'Shaman', + 'dead', + 'Tomba Aniquilacio', + 'Pacto', + 'fullcaster', + 'Electric', + 'Ability Score', + '4D', + 'pathfinder', + 'insect', + 'hook', + 'page layout', + 'healing', + 'Lineages', + 'Flying', + 'Martial Arts', + 'journal', + 'Aide de jeu', + 'hunter', + 'headers', + 'Dark Souls', + 'courtyard', + 'crossroads', + 'Quest', + 'CotF', + 'defense', + 'Semryss', + 'invoked class', + 'Session Notes', + 'goblin', + 'infernal', + 'fate', + 'oni', + 'spellbook', + 'Summoning', + 'slut', + 'whore', + 'Greyhawk', + 'Mobility', + 'Reddit Remake', + 'Guild', + 'Cosmic Mart', + '7th Level', + 'dragonborn', + 'curse of strahd', + 'Ranger Subclass', + 'dossier', + 'dossie', + 'de', + 'pnpde', + 'Plane Shift', + 'halloween', + 'group:aventura', + '9th Level', + 'tome', + 'cold', + 'acid', + 'deprecated', + 'mind flayer', + 'MECHA', + 'EssentialsKit', + '2d6', + 'ToD', + 'Work In Progress', + 'Bond', + 'Versatile', + 'Dead', + 'SYWTBAGM', + 'summoning', + 'english', + 'Eilistraee', + 'Draft', + 'DoD', + 'map', + 'Frightened', + 'Psychic Damage', + 'eberron', + 'recompensa', + 'wizard subclass', + 'teiran', + 'Saltmarsh', + 'jp setting', + 'Illithid', + 'Longbow', + 'hell', + 'Monarch', + 'type:feat', + 'reglas', + 'cooking', + 'Abenteuer', + 'reloaded', + 'incompleto', + 'mecanica', + 'Location', + 'Grimlores Grimoire', + '2024 Subclass', + 'Chiesa di Toleno', + 'finalfantasy', + 'The Undertomes', + 'Lobotomy Corporation', + 'SDHTA', + 'D&D 2024', + 'other', + 'ally', + 'images', + 'Player\'s Guide', + 'Avalon Sword', + 'Cael\'Yuu', + 'dnd-2014', + 'Regelwerk', + 'Español', + 'br', + 'dnd 5.0', + 'monstro', + 'grand cemetery', + 'Phoenix', + 'dnd 2024', + 'Bloodhunter', + 'Sintonizacion', + 'dungeons & dragons', + 'Fix', + 'Rulebook', + 'Shadowdark', + 'heroic', + 'HFW', + 'Earthdawn', + '24e', + 'cormyr', + 'suzail', + 'dc20', + 'tag:Rules', + 'The Griffon\'s Saddlebag', + 'LOTM', + 'tag:Adventure', + 'drunken master', + 'eldritch invocation', + 'Персонаж', + 'Orcs', + 'Lizardfolk', + 'Frostfell', + 'CR 17', + 'Shapechanger', + 'Farmland', + 'Mages', + 'Any', + 'CR 13', + 'Earth', + 'Mountain', + 'Drake', + 'transformation', + 'GM', + 'Lich', + 'lovecraft', + 'unique', + 'Optional Rules', + 'int', + 'creator', + 'Primal', + 'simple', + 'golem', + 'Void', + 'Armour', + 'spellsword', + 'General', + 'Asian', + 'Bringers of chaos', + 'Optional Feature', + 'subraces', + 'Galanoth', + 'barbarian subclass', + 'felhearth', + 'modular', + 'Vampires', + 'wysteria', + 'adaptation', + 'beasts', + 'naruto', + 'ninja', + 'Psionic', + 'Guns', + 'Crystal', + 'Guardian', + 'NonProfit', + 'Mimic', + 'languages', + 'Epic Boons', + 'Primer', + 'Icewind Dale', + 'joke', + 'lycan', + 'CR3', + 'Armors', + 'ff7', + 'materia', + 'final fantasy 7 remake', + 'esper', + 'ff7 remake', + 'gargantuan', + 'Frog', + 'CR5', + 'blank', + 'monster hunter', + 'league of legends', + 'french', + 'Pokémon', + 'kobold', + 'soul', + 'ffxi', + 'd10', + 'Roman', + 'Cute', + 'DD5', + 'variant', + 'tree', + 'fr', + 'Scenario', + 'lycanthrope', + 'druide', + 'staff', + 'eios', + 'arkheneios', + 'Runic', + 'Work', + 'Ukrainian', + 'cover-page', + 'mage', + 'deities', + 'gods', + 'Boss Fight', + 'Lair', + 'WBTW', + 'roguish archetype', + 'Character Option', + 'Shortsword', + 'Illrigger', + 'Bloodborne', + 'cr6', + 'Priest', + 'Hamon', + 'Toonkind', + 'rol', + 'Strength', + 'forgotten realms', + 'Spanish', + 'Conclave', + 'Electro', + 'Magical Tattoos', + 'Matt Mercer', + 'Wildemount', + 'Mighty Nien', + 'Campaign 2', + 'Resistances', + 'Bug', + 'impression', + 'PF', + 'Magnus Archives', + 'ice', + 'speed', + 'Generic NPC', + 'Titanic', + 'Ink Friendly', + 'bleed', + 'elder scrolls', + 'Immortal', + 'LMOP', + 'Travel', + 'Olphus', + '3d6', + 'heist', + 'World History', + 'ghost', + 'genie', + 'kids on bikes', + 'Russia', + 'conclave', + 'overhaul', + 'manual', + 'Adventures In Eden', + 'Downtime', + 'hamon', + 'cloak', + 'shadowfell', + 'Hellfire', + 'Paladin Oath', + 'Genshin', + 'Nation', + 'air', + 'Magical Item', + 'War', + 'Original', + 'Monstrous Compendium', + 'Calamity', + 'Warden', + 'Apocalypse', + 'shield', + 'AC', + 'expansion', + 'Concentration', + 'charm', + 'Weave', + 'lycanthropy', + 'raza', + 'far realm', + 'fighter subclass', + 'ita', + 'Pirate', + 'Laranja', + 'Grapple', + 'EastByForce', + 'hobgoblin', + 'oneshot-notes', + 'Holy', + 'optional', + 'type:cenario', + 'group:core', + 'The Brewery', + 'Alcance', + 'Morrowind', + 'Indigo', + 'Divino', + '2nd Level', + 'Sub-Class', + 'cantrips', + 'Cloak', + 'battle master', + 'Dark', + 'Puzzle', + 'Lucky', + 'consumable', + 'rebalance', + 'Shove', + 'Area Control', + 'Vanguard', + 'funny', + 'e5', + 'Dragonlance', + 'psion', + 'initiative', + 'Tactician', + 'Inspiration', + 'artificier', + 'way', + 'inspired', + 'historia', + 'Medusa', + '2 part', + 'holy', + 'gift', + 'Nimble', + 'mostri', + 'phoenix', + 'travel', + 'Class Template', + 'Intimidation', + 'constructs', + 'P666', + 'Formatting', + 'Divinity', + 'Rod', + 'Language', + 'yokai', + 'rune', + 'western', + 'vampires', + 'flying', + 'cute', + 'Enemy', + 'boon', + 'Tables', + 'ShadowFight', + 'meta: Theme', + 'SCS', + 'vanthampur villa', + 'CoA', + 'shop', + 'destiny', + 'magical weapon', + 'Arcane Arcade', + 'XP to Level 3', + 'Dice Average RPG', + 'Pip-Boy', + 'Dragon Heist', + 'session notes', + 'tattoo', + 'flick', + 'P6:66', + 'Comic Character', + 'experiment', + 'Minerva', + 'type:Spellbook', + 'Realmfall', + 'Wand', + 'halfling', + 'sw5e', + 'implementar AP', + 'Mask', + 'Gazook89', + 'Weltenrauch-Chroniken', + 'MiA', + 'Made in Abyss', + 'français', + 'fae', + 'Lemuria', + 'Mork Borg', + 'guerrier', + 'prunus', + 'condition', + 'pf2', + 'tr', + 'costrutto', + 'German', + 'project moon', + '5r', + 'galles', + 'Project moon', + 'Yisang', + 'Spicebush', + 'player-accessible', + 'Especie', + 'Westmarch', + 'a', + 'Cart', + 'Magus', + 'group:Mchael Galvis', + 'tip', + 'werewolf', + 'mundane', + 'garrett', + 'unarmed', + 'Arcane Odyssey', + 'Tomb of Divinity', + 'pets', + 'Video Game', + '4 part', + 'pbta', + 'Druids', + 'multiclass', + 'manuale', + 'mimic', + 'plane shift', + 'Dotes', + 'Hechizos', + 'Infernal', + 'Enhanced', + 'done', + 'Mission report', + 'Blanks', + 'Masks', + 'Ultimate Ability', + 'shadow-slave', + 'Advertising', + 'transform', + 'Fullmetal Alchemist', + 'Fullmetal Alchemist Brotherhood', + 'tag:TAoF&F', + 'Dwarves', + 'Humans', + 'Nine Hells', + 'Devils', + 'Archons', + 'CR 15', + 'Troglodytes', + 'Goliath', + 'retired', + 'boots', + 'ranged', + 'shields', + 'Zhentarim', + 'World of Warcraft', + 'Frontline', + 'Guildmaster\'s Guide to Ravnica', + 'Dungeons & Dragons 5e', + 'beholder', + 'NEEDS FIXING', + 'mechanic', + 'Loot', + 'champion', + 'Runes', + 'Shield', + 'Punch', + 'Sniper', + 'Magical Girl', + 'NotDND', + 'story', + 'Sleep', + 'Bard College', + 'Illusion', + 'Thunder', + 'Defender', + 'Genasi', + 'troll', + 'Gehenna', + 'Yugoloth', + 'social', + 'Player Class', + 'homebrew class', + 'CR 16', + 'Ghost', + 'Kobolds', + 'Trolls', + 'Yuan-Ti', + 'Elder Scrolls Offline', + 'armure', + 'Mage', + 'CR 18', + 'Technology', + 'Mystery', + 'darkness', + 'Airship', + 'New Campaign', + 'Warframe', + 'Wizard Subclass', + 'Gold', + 'Candor', + 'Overhaul', + 'Dragon Knight', + 'Enoreth', + 'Artifacts', + 'New', + 'AMMO', + 'Campagne', + 'Valbise', + 'Subclasseptember', + 'Mecha', + 'Yu-Gi-Oh', + 'Goblinoid', + 'underwater', + 'SW5E', + 'bardo' +]; \ No newline at end of file diff --git a/client/homebrew/homebrew.jsx b/client/homebrew/homebrew.jsx index a3a16bef3..1b07546d1 100644 --- a/client/homebrew/homebrew.jsx +++ b/client/homebrew/homebrew.jsx @@ -1,8 +1,7 @@ - -import 'core-js/es/string/to-well-formed.js'; //Polyfill for older browsers +import 'core-js/es/string/to-well-formed.js'; // Polyfill for older browsers import './homebrew.less'; import React from 'react'; -import { StaticRouter as Router, Route, Routes, useParams, useSearchParams } from 'react-router'; +import { BrowserRouter as Router, Routes, Route, useParams, useSearchParams } from 'react-router'; import { updateLocalStorage } from './utils/updateLocalStorage/updateLocalStorageKeys.js'; @@ -39,28 +38,42 @@ const Homebrew = (props)=>{ }, userThemes, brews, - enable_v4 + enablev4 } = props; global.account = account; global.version = version; global.config = config; - global.enable_v4 = enable_v4; + global.enablev4 = enablev4; const backgroundObject = ()=>{ - if(global.config.deployment || (config.local && config.development)){ - const bgText = global.config.deployment || 'Local'; - return { - backgroundImage : `url("data:image/svg+xml;utf8,${bgText}")` - }; + if(config?.deployment || (config?.local && config?.development)) { + const bgText = config?.deployment || 'Local'; + return { + backgroundImage : `url("data:image/svg+xml;utf8,${bgText}")` + }; } return null; }; + updateLocalStorage(); + if(brew.pureError) { + return ( + +
    + + } /> + +
    +
    + ); + } + + return ( - -
    + +
    } /> } /> @@ -82,4 +95,4 @@ const Homebrew = (props)=>{ ); }; -module.exports = Homebrew; \ No newline at end of file +export default Homebrew; diff --git a/client/homebrew/homebrew.less b/client/homebrew/homebrew.less index 2cbc35857..9bafadffe 100644 --- a/client/homebrew/homebrew.less +++ b/client/homebrew/homebrew.less @@ -1,4 +1,4 @@ -@import 'naturalcrit/styles/core.less'; +@import '@sharedStyles/core.less'; .homebrew { height : 100%; background-color:@steel; diff --git a/client/homebrew/main.jsx b/client/homebrew/main.jsx new file mode 100644 index 000000000..635729d49 --- /dev/null +++ b/client/homebrew/main.jsx @@ -0,0 +1,6 @@ +import { createRoot } from 'react-dom/client'; +import Homebrew from './homebrew.jsx'; + +const props = window.__INITIAL_PROPS__ || {}; + +createRoot(document.getElementById('reactRoot')).render(); diff --git a/client/homebrew/navbar/account.navitem.jsx b/client/homebrew/navbar/account.navitem.jsx index 8c0e92023..0be06c471 100644 --- a/client/homebrew/navbar/account.navitem.jsx +++ b/client/homebrew/navbar/account.navitem.jsx @@ -97,7 +97,7 @@ const Account = createReactClass({ // Logged out // LOCAL ONLY - if(global.config.local) { + if(global.config?.local) { return login ; diff --git a/client/homebrew/navbar/error-navitem.less b/client/homebrew/navbar/error-navitem.less index 637ddac95..4da665915 100644 --- a/client/homebrew/navbar/error-navitem.less +++ b/client/homebrew/navbar/error-navitem.less @@ -1,3 +1,5 @@ +@import '@sharedStyles/core.less'; + .navItem.error { position : relative; background-color : @red; diff --git a/client/homebrew/navbar/metadata.navitem.jsx b/client/homebrew/navbar/metadata.navitem.jsx index bfea2e81a..8ee6b72c0 100644 --- a/client/homebrew/navbar/metadata.navitem.jsx +++ b/client/homebrew/navbar/metadata.navitem.jsx @@ -46,11 +46,6 @@ const MetadataNav = createReactClass({ ; }, - getSystems : function(){ - if(!this.props.brew.systems || this.props.brew.systems.length == 0) return 'No systems'; - return this.props.brew.systems.join(', '); - }, - renderMetaWindow : function(){ return
    @@ -65,10 +60,6 @@ const MetadataNav = createReactClass({

    Tags

    {this.getTags()}

    -
    -

    Systems

    -

    {this.getSystems()}

    -

    Updated

    {Moment(this.props.brew.updatedAt).fromNow()}

    diff --git a/client/homebrew/navbar/navbar.jsx b/client/homebrew/navbar/navbar.jsx index e75be8d59..db9a836c9 100644 --- a/client/homebrew/navbar/navbar.jsx +++ b/client/homebrew/navbar/navbar.jsx @@ -8,16 +8,10 @@ import PatreonNavItem from './patreon.navitem.jsx'; const Navbar = createReactClass({ displayName : 'Navbar', getInitialState : function() { - return { - //showNonChromeWarning : false, - ver : '0.0.0' - }; - }, - - getInitialState : function() { - return { - ver : global.version - }; + return { + // showNonChromeWarning: false, // uncomment if needed + ver : global.version || '0.0.0' + }; }, /* diff --git a/client/homebrew/navbar/navbar.less b/client/homebrew/navbar/navbar.less index 7b0217bf8..eb518e808 100644 --- a/client/homebrew/navbar/navbar.less +++ b/client/homebrew/navbar/navbar.less @@ -1,4 +1,4 @@ -@import 'naturalcrit/styles/colors.less'; +@import '@sharedStyles/core.less'; @navbarHeight : 28px; @viewerToolsHeight : 32px; diff --git a/client/homebrew/navbar/newbrew.navitem.jsx b/client/homebrew/navbar/newbrew.navitem.jsx index 4664d509b..5c91f8465 100644 --- a/client/homebrew/navbar/newbrew.navitem.jsx +++ b/client/homebrew/navbar/newbrew.navitem.jsx @@ -1,7 +1,7 @@ import React from 'react'; import _ from 'lodash'; import Nav from './nav.jsx'; -import { splitTextStyleAndMetadata } from '../../../shared/helpers.js'; +import { splitTextStyleAndMetadata } from '@shared/helpers.js'; const BREWKEY = 'HB_newPage_content'; const STYLEKEY = 'HB_newPage_style'; @@ -24,7 +24,7 @@ const NewBrew = ()=>{ localStorage.setItem(BREWKEY, newBrew.text); localStorage.setItem(STYLEKEY, newBrew.style); localStorage.setItem(METAKEY, JSON.stringify( - _.pick(newBrew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang']) + _.pick(newBrew, ['title', 'description', 'tags', 'renderer', 'theme', 'lang']) )); window.location.href = '/new'; return; diff --git a/client/homebrew/navbar/print.navitem.jsx b/client/homebrew/navbar/print.navitem.jsx index e7a6ff053..e669214b3 100644 --- a/client/homebrew/navbar/print.navitem.jsx +++ b/client/homebrew/navbar/print.navitem.jsx @@ -1,9 +1,25 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import Nav from './nav.jsx'; -import { printCurrentBrew } from '../../../shared/helpers.js'; +import { printCurrentBrew } from '@shared/helpers.js'; export default function(){ + const [printing, setPrinting] = useState(false); + + // listen for print cycle events to display "loading" message since it can take some time. + useEffect(()=>{ + document.addEventListener('print:startprep', handlePrintStartPrep); + document.addEventListener('print:finishedprep', handlePrintPrepFinished); + return ()=>{ + document.removeEventListener('print:startprep', handlePrintStartPrep); + document.removeEventListener('print:finishedprep', handlePrintPrepFinished); + } + }, []); + + const handlePrintStartPrep = ()=>{ setPrinting(true); }; + + const handlePrintPrepFinished = ()=>{ setPrinting(false); }; + return - get PDF + {printing ? 'loading' : 'get PDF'} ; }; diff --git a/client/homebrew/navbar/share.navitem.jsx b/client/homebrew/navbar/share.navitem.jsx index d0c659e2c..e329a4560 100644 --- a/client/homebrew/navbar/share.navitem.jsx +++ b/client/homebrew/navbar/share.navitem.jsx @@ -17,7 +17,7 @@ const getRedditLink = (brew)=>{ return `https://www.reddit.com/r/UnearthedArcana/submit?title=${encodeURIComponent(brew.title.toWellFormed())}&text=${encodeURIComponent(text)}`; }; -export default ({ brew })=>( +export default ({ brew, currentPage })=>( share @@ -28,6 +28,12 @@ export default ({ brew })=>( {navigator.clipboard.writeText(`${global.config.baseUrl}/share/${getShareId(brew)}`);}}> copy url + {currentPage > 1 && + {navigator.clipboard.writeText(`${global.config.baseUrl}/share/${getShareId(brew)}#p${currentPage}`);}}> + copy url (page {currentPage}) + } post to reddit diff --git a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less index d335f3ca9..93685947c 100644 --- a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less +++ b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less @@ -1,3 +1,4 @@ +@import '@sharedStyles/core.less'; .brewItem { position : relative; diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index fa33e2863..a7c6e4595 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -4,34 +4,35 @@ import './editPage.less'; // Common imports import React, { useState, useEffect, useRef } from 'react'; import request from '../../utils/request-middleware.js'; -import Markdown from '../../../../shared/markdown.js'; +import Markdown from '@shared/markdown.js'; import _ from 'lodash'; import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js'; -import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js'; +import { printCurrentBrew, fetchThemeBundle } from '@shared/helpers.js'; import SplitPane from '../../../components/splitPane/splitPane.jsx'; import Editor from '../../editor/editor.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; -import Nav from '../../navbar/nav.jsx'; -import Navbar from '../../navbar/navbar.jsx'; -import NewBrewItem from '../../navbar/newbrew.navitem.jsx'; -import AccountNavItem from '../../navbar/account.navitem.jsx'; -import ErrorNavItem from '../../navbar/error-navitem.jsx'; -import HelpNavItem from '../../navbar/help.navitem.jsx'; -import VaultNavItem from '../../navbar/vault.navitem.jsx'; -import PrintNavItem from '../../navbar/print.navitem.jsx'; -import RecentNavItems from '../../navbar/recent.navitem.jsx'; +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import NewBrewItem from '@navbar/newbrew.navitem.jsx'; +import AccountNavItem from '@navbar/account.navitem.jsx'; +import ErrorNavItem from '@navbar/error-navitem.jsx'; +import HelpNavItem from '@navbar/help.navitem.jsx'; +import VaultNavItem from '@navbar/vault.navitem.jsx'; +import PrintNavItem from '@navbar/print.navitem.jsx'; +import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; // Page specific imports -import { Meta } from 'vitreum/headtags'; +import Headtags from '../../../../vitreum/headtags.js'; +const Meta = Headtags.Meta; import { md5 } from 'hash-wasm'; import { gzipSync, strToU8 } from 'fflate'; import { makePatches, stringifyPatches } from '@sanity/diff-match-patch'; -import ShareNavItem from '../../navbar/share.navitem.jsx'; +import ShareNavItem from '@navbar/share.navitem.jsx'; import LockNotification from './lockNotification/lockNotification.jsx'; import { updateHistory, versionHistoryGarbageCollection } from '../../utils/versionHistory.js'; import googleDriveIcon from '../../googleDrive.svg'; @@ -56,28 +57,28 @@ const EditPage = (props)=>{ ...props }; - const [currentBrew , setCurrentBrew ] = useState(props.brew); - const [isSaving , setIsSaving ] = useState(false); - const [lastSavedTime , setLastSavedTime ] = useState(new Date()); - const [saveGoogle , setSaveGoogle ] = useState(!!props.brew.googleId); - const [error , setError ] = useState(null); - const [HTMLErrors , setHTMLErrors ] = useState(Markdown.validate(props.brew.text)); - const [currentEditorViewPageNum , setCurrentEditorViewPageNum ] = useState(1); + const [currentBrew, setCurrentBrew] = useState(props.brew); + const [isSaving, setIsSaving] = useState(false); + const [lastSavedTime, setLastSavedTime] = useState(new Date()); + const [saveGoogle, setSaveGoogle] = useState(!!props.brew.googleId); + const [error, setError] = useState(null); + const [HTMLErrors, setHTMLErrors] = useState(Markdown.validate(props.brew.text)); + const [currentEditorViewPageNum, setCurrentEditorViewPageNum] = useState(1); const [currentEditorCursorPageNum, setCurrentEditorCursorPageNum] = useState(1); const [currentBrewRendererPageNum, setCurrentBrewRendererPageNum] = useState(1); - const [themeBundle , setThemeBundle ] = useState({}); - const [unsavedChanges , setUnsavedChanges ] = useState(false); - const [alertTrashedGoogleBrew , setAlertTrashedGoogleBrew ] = useState(props.brew.trashed); - const [alertLoginToTransfer , setAlertLoginToTransfer ] = useState(false); - const [confirmGoogleTransfer , setConfirmGoogleTransfer ] = useState(false); - const [autoSaveEnabled , setAutoSaveEnabled ] = useState(true); - const [warnUnsavedChanges , setWarnUnsavedChanges ] = useState(true); + const [themeBundle, setThemeBundle] = useState({}); + const [unsavedChanges, setUnsavedChanges] = useState(false); + const [alertTrashedGoogleBrew, setAlertTrashedGoogleBrew] = useState(props.brew.trashed); + const [alertLoginToTransfer, setAlertLoginToTransfer] = useState(false); + const [confirmGoogleTransfer, setConfirmGoogleTransfer] = useState(false); + const [autoSaveEnabled, setAutoSaveEnabled] = useState(true); + const [warnUnsavedChanges, setWarnUnsavedChanges] = useState(true); const editorRef = useRef(null); const lastSavedBrew = useRef(_.cloneDeep(props.brew)); const saveTimeout = useRef(null); const warnUnsavedTimeout = useRef(null); - const trySaveRef = useRef(trySave); // CTRL+S listener lives outside React and needs ref to use trySave with latest copy of brew + const trySaveRef = useRef(null); // CTRL+S listener lives outside React and needs ref to use trySave with latest copy of brew const unsavedChangesRef = useRef(unsavedChanges); // Similarly, onBeforeUnload lives outside React and needs ref to unsavedChanges useEffect(()=>{ @@ -89,7 +90,7 @@ const EditPage = (props)=>{ const handleControlKeys = (e)=>{ if(!(e.ctrlKey || e.metaKey)) return; - if(e.keyCode === 83) trySaveRef.current(true); + if(e.keyCode === 83) trySaveRef.current(true, true, saveGoogle); if(e.keyCode === 80) printCurrentBrew(); if([83, 80].includes(e.keyCode)) { e.stopPropagation(); @@ -117,13 +118,9 @@ const EditPage = (props)=>{ const hasChange = !_.isEqual(currentBrew, lastSavedBrew.current); setUnsavedChanges(hasChange); - if(autoSaveEnabled) trySave(false, hasChange); + if(autoSaveEnabled) trySave(false, hasChange, saveGoogle); }, [currentBrew]); - useEffect(()=>{ - trySave(true); - }, [saveGoogle]); - const handleSplitMove = ()=>{ editorRef.current?.update(); }; @@ -182,11 +179,13 @@ const EditPage = (props)=>{ }; const toggleGoogleStorage = ()=>{ + const newSaveGoogle = !saveGoogle; setSaveGoogle((prev)=>!prev); setError(null); + trySave(true, true, newSaveGoogle); }; - const trySave = (immediate = false, hasChanges = true)=>{ + const trySave = (immediate = false, hasChanges = true, saveToGoogle = false)=>{ clearTimeout(saveTimeout.current); if(isSaving) return; if(!hasChanges && !immediate) return; @@ -195,7 +194,7 @@ const EditPage = (props)=>{ saveTimeout.current = setTimeout(async ()=>{ setIsSaving(true); setError(null); - await save(currentBrew, saveGoogle) + await save(currentBrew, saveToGoogle) .catch((err)=>{ setError(err); }); @@ -215,7 +214,7 @@ const EditPage = (props)=>{ const brewToSave = { ...brew, text : brew.text.normalize('NFC'), - pageCount : ((brew.renderer === 'legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1, + pageCount : ((brew.renderer === 'legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/gm)) || []).length + 1, patches : stringifyPatches(makePatches(encodeURI(lastSavedBrew.current.text.normalize('NFC')), encodeURI(brew.text.normalize('NFC')))), hash : await md5(lastSavedBrew.current.text.normalize('NFC')), textBin : undefined, @@ -313,7 +312,7 @@ const EditPage = (props)=>{ // #3 - Unsaved changes exist, click to save, show SAVE NOW if(unsavedChanges) - return trySave(true)} color='blue' icon='fas fa-save'>save now; + return trySave(true, true, saveGoogle)} color='blue' icon='fas fa-save'>save now; // #4 - No unsaved changes, autosave is ON, show AUTO-SAVED if(autoSaveEnabled) @@ -364,7 +363,7 @@ const EditPage = (props)=>{ - + diff --git a/client/homebrew/pages/errorPage/errorPage.jsx b/client/homebrew/pages/errorPage/errorPage.jsx index ffbfc43bb..837775b97 100644 --- a/client/homebrew/pages/errorPage/errorPage.jsx +++ b/client/homebrew/pages/errorPage/errorPage.jsx @@ -1,7 +1,7 @@ import './errorPage.less'; import React from 'react'; import UIPage from '../basePages/uiPage/uiPage.jsx'; -import Markdown from '../../../../shared/markdown.js'; +import Markdown from '@shared/markdown.js'; import ErrorIndex from './errors/errorIndex.js'; const ErrorPage = ({ brew })=>{ diff --git a/client/homebrew/pages/errorPage/errorPage.less b/client/homebrew/pages/errorPage/errorPage.less index 2d10301e0..df8dcf98d 100644 --- a/client/homebrew/pages/errorPage/errorPage.less +++ b/client/homebrew/pages/errorPage/errorPage.less @@ -1,7 +1,6 @@ .homebrew { - .uiPage.sitePage { + .uiPage.sitePage:has(.errorTitle) { .errorTitle { - //background-color: @orange; color : #D02727; text-align : center; } diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 36f6f8162..580d69e76 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -1,33 +1,34 @@ -/* eslint-disable max-lines */ + import './homePage.less'; // Common imports import React, { useState, useEffect, useRef } from 'react'; import request from '../../utils/request-middleware.js'; -import Markdown from '../../../../shared/markdown.js'; +import Markdown from '@shared/markdown.js'; import _ from 'lodash'; import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; -import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js'; +import { printCurrentBrew, fetchThemeBundle } from '@shared/helpers.js'; import SplitPane from '../../../components/splitPane/splitPane.jsx'; import Editor from '../../editor/editor.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; -import Nav from '../../navbar/nav.jsx'; -import Navbar from '../../navbar/navbar.jsx'; -import NewBrewItem from '../../navbar/newbrew.navitem.jsx'; -import AccountNavItem from '../../navbar/account.navitem.jsx'; -import ErrorNavItem from '../../navbar/error-navitem.jsx'; -import HelpNavItem from '../../navbar/help.navitem.jsx'; -import VaultNavItem from '../../navbar/vault.navitem.jsx'; -import PrintNavItem from '../../navbar/print.navitem.jsx'; -import RecentNavItems from '../../navbar/recent.navitem.jsx'; +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import NewBrewItem from '@navbar/newbrew.navitem.jsx'; +import AccountNavItem from '@navbar/account.navitem.jsx'; +import ErrorNavItem from '@navbar/error-navitem.jsx'; +import HelpNavItem from '@navbar/help.navitem.jsx'; +import VaultNavItem from '@navbar/vault.navitem.jsx'; +import PrintNavItem from '@navbar/print.navitem.jsx'; +import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; // Page specific imports -import { Meta } from 'vitreum/headtags'; +import Headtags from '@vitreum/headtags.js'; +const Meta = Headtags.Meta; const BREWKEY = 'homebrewery-new'; const STYLEKEY = 'homebrewery-new-style'; @@ -44,16 +45,16 @@ const HomePage =(props)=>{ ...props }; - const [currentBrew , setCurrentBrew] = useState(props.brew); - const [error , setError] = useState(undefined); - const [HTMLErrors , setHTMLErrors] = useState(Markdown.validate(props.brew.text)); - const [currentEditorViewPageNum , setCurrentEditorViewPageNum] = useState(1); + const [currentBrew, setCurrentBrew] = useState(props.brew); + const [error, setError] = useState(undefined); + const [HTMLErrors, setHTMLErrors] = useState(Markdown.validate(props.brew.text)); + const [currentEditorViewPageNum, setCurrentEditorViewPageNum] = useState(1); const [currentEditorCursorPageNum, setCurrentEditorCursorPageNum] = useState(1); const [currentBrewRendererPageNum, setCurrentBrewRendererPageNum] = useState(1); - const [themeBundle , setThemeBundle] = useState({}); - const [unsavedChanges , setUnsavedChanges] = useState(false); - const [isSaving , setIsSaving] = useState(false); - const [autoSaveEnabled , setAutoSaveEnable] = useState(false); + const [themeBundle, setThemeBundle] = useState({}); + const [unsavedChanges, setUnsavedChanges] = useState(false); + const [isSaving, setIsSaving] = useState(false); + const [autoSaveEnabled, setAutoSaveEnable] = useState(false); const editorRef = useRef(null); const lastSavedBrew = useRef(_.cloneDeep(props.brew)); diff --git a/client/homebrew/pages/homePage/homePage.less b/client/homebrew/pages/homePage/homePage.less index b89c2c7dd..fd072c1e1 100644 --- a/client/homebrew/pages/homePage/homePage.less +++ b/client/homebrew/pages/homePage/homePage.less @@ -1,3 +1,5 @@ +@import '@sharedStyles/core.less'; + .homePage { position : relative; a.floatingNewButton { diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 1559d223c..270ca89a0 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -4,29 +4,28 @@ import './newPage.less'; // Common imports import React, { useState, useEffect, useRef } from 'react'; import request from '../../utils/request-middleware.js'; -import Markdown from '../../../../shared/markdown.js'; +import Markdown from '@shared/markdown.js'; import _ from 'lodash'; import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; -import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js'; +import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '@shared/helpers.js'; import SplitPane from '../../../components/splitPane/splitPane.jsx'; import Editor from '../../editor/editor.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; -import Nav from '../../navbar/nav.jsx'; -import Navbar from '../../navbar/navbar.jsx'; -import NewBrewItem from '../../navbar/newbrew.navitem.jsx'; -import AccountNavItem from '../../navbar/account.navitem.jsx'; -import ErrorNavItem from '../../navbar/error-navitem.jsx'; -import HelpNavItem from '../../navbar/help.navitem.jsx'; -import VaultNavItem from '../../navbar/vault.navitem.jsx'; -import PrintNavItem from '../../navbar/print.navitem.jsx'; -import RecentNavItems from '../../navbar/recent.navitem.jsx'; +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import NewBrewItem from '@navbar/newbrew.navitem.jsx'; +import AccountNavItem from '@navbar/account.navitem.jsx'; +import ErrorNavItem from '@navbar/error-navitem.jsx'; +import HelpNavItem from '@navbar/help.navitem.jsx'; +import VaultNavItem from '@navbar/vault.navitem.jsx'; +import PrintNavItem from '@navbar/print.navitem.jsx'; +import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; // Page specific imports -import { Meta } from 'vitreum/headtags'; const BREWKEY = 'HB_newPage_content'; const STYLEKEY = 'HB_newPage_style'; @@ -43,23 +42,23 @@ const NewPage = (props)=>{ ...props }; - const [currentBrew , setCurrentBrew ] = useState(props.brew); - const [isSaving , setIsSaving ] = useState(false); - const [saveGoogle , setSaveGoogle ] = useState(global.account?.googleId ? true : false); - const [error , setError ] = useState(null); - const [HTMLErrors , setHTMLErrors ] = useState(Markdown.validate(props.brew.text)); - const [currentEditorViewPageNum , setCurrentEditorViewPageNum ] = useState(1); + const [currentBrew, setCurrentBrew] = useState(props.brew); + const [isSaving, setIsSaving] = useState(false); + const [saveGoogle, setSaveGoogle] = useState(global.account?.googleId ? true : false); + const [error, setError] = useState(null); + const [HTMLErrors, setHTMLErrors] = useState(Markdown.validate(props.brew.text)); + const [currentEditorViewPageNum, setCurrentEditorViewPageNum] = useState(1); const [currentEditorCursorPageNum, setCurrentEditorCursorPageNum] = useState(1); const [currentBrewRendererPageNum, setCurrentBrewRendererPageNum] = useState(1); - const [themeBundle , setThemeBundle ] = useState({}); - const [unsavedChanges , setUnsavedChanges ] = useState(false); - const [autoSaveEnabled , setAutoSaveEnabled ] = useState(false); + const [themeBundle, setThemeBundle] = useState({}); + const [unsavedChanges, setUnsavedChanges] = useState(false); + const [autoSaveEnabled, setAutoSaveEnabled] = useState(false); const editorRef = useRef(null); const lastSavedBrew = useRef(_.cloneDeep(props.brew)); // const saveTimeout = useRef(null); // const warnUnsavedTimeout = useRef(null); - const trySaveRef = useRef(trySave); // CTRL+S listener lives outside React and needs ref to use trySave with latest copy of brew + const trySaveRef = useRef(null); // CTRL+S listener lives outside React and needs ref to use trySave with latest copy of brew const unsavedChangesRef = useRef(unsavedChanges); // Similarly, onBeforeUnload lives outside React and needs ref to unsavedChanges useEffect(()=>{ @@ -157,7 +156,7 @@ const NewPage = (props)=>{ const updatedBrew = { ...currentBrew }; splitTextStyleAndMetadata(updatedBrew); - const pageRegex = updatedBrew.renderer === 'legacy' ? /\\page/g : /^\\page$/gm; + const pageRegex = updatedBrew.renderer === 'legacy' ? /\\page/g : /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/gm; updatedBrew.pageCount = (updatedBrew.text.match(pageRegex) || []).length + 1; const res = await request diff --git a/client/homebrew/pages/newPage/newPage.less b/client/homebrew/pages/newPage/newPage.less index d2f07ac40..39befb44e 100644 --- a/client/homebrew/pages/newPage/newPage.less +++ b/client/homebrew/pages/newPage/newPage.less @@ -1,3 +1,5 @@ +@import '@sharedStyles/colors.less'; + .newPage { .navItem.save { background-color : @orange; diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 4a0b0f99c..8df241d7b 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -1,18 +1,19 @@ import './sharePage.less'; import React, { useState, useEffect, useCallback } from 'react'; -import { Meta } from 'vitreum/headtags'; +import Headtags from '../../../../vitreum/headtags.js'; +const Meta = Headtags.Meta; -import Nav from '../../navbar/nav.jsx'; -import Navbar from '../../navbar/navbar.jsx'; -import MetadataNav from '../../navbar/metadata.navitem.jsx'; -import PrintNavItem from '../../navbar/print.navitem.jsx'; -import RecentNavItems from '../../navbar/recent.navitem.jsx'; +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import MetadataNav from '@navbar/metadata.navitem.jsx'; +import PrintNavItem from '@navbar/print.navitem.jsx'; +import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; -import Account from '../../navbar/account.navitem.jsx'; +import Account from '@navbar/account.navitem.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js'; -import { printCurrentBrew, fetchThemeBundle } from '../../../../shared/helpers.js'; +import { printCurrentBrew, fetchThemeBundle } from '@shared/helpers.js'; const SharePage = (props)=>{ const { brew = DEFAULT_BREW_LOAD, disableMeta = false } = props; @@ -91,6 +92,19 @@ const SharePage = (props)=>{ clone to new + {navigator.clipboard.writeText(`${global.config.baseUrl}/share/${processShareId()}`);}}> + copy url + + {currentBrewRendererPageNum > 1 && + {navigator.clipboard.writeText(`${global.config.baseUrl}/share/${processShareId()}#p${currentBrewRendererPageNum}`);}}> + copy url (page {currentBrewRendererPageNum}) + } )} diff --git a/client/homebrew/pages/userPage/userPage.jsx b/client/homebrew/pages/userPage/userPage.jsx index a6a43858e..0b2ebb56b 100644 --- a/client/homebrew/pages/userPage/userPage.jsx +++ b/client/homebrew/pages/userPage/userPage.jsx @@ -3,15 +3,15 @@ import _ from 'lodash'; import ListPage from '../basePages/listPage/listPage.jsx'; -import Nav from '../../navbar/nav.jsx'; -import Navbar from '../../navbar/navbar.jsx'; -import RecentNavItems from '../../navbar/recent.navitem.jsx'; +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; -import Account from '../../navbar/account.navitem.jsx'; -import NewBrew from '../../navbar/newbrew.navitem.jsx'; -import HelpNavItem from '../../navbar/help.navitem.jsx'; -import ErrorNavItem from '../../navbar/error-navitem.jsx'; -import VaultNavitem from '../../navbar/vault.navitem.jsx'; +import Account from '@navbar/account.navitem.jsx'; +import NewBrew from '@navbar/newbrew.navitem.jsx'; +import HelpNavItem from '@navbar/help.navitem.jsx'; +import ErrorNavItem from '@navbar/error-navitem.jsx'; +import VaultNavitem from '@navbar/vault.navitem.jsx'; const UserPage = (props)=>{ props = { diff --git a/client/homebrew/pages/vaultPage/vaultPage.jsx b/client/homebrew/pages/vaultPage/vaultPage.jsx index 3a8c6bc25..e6a9768bb 100644 --- a/client/homebrew/pages/vaultPage/vaultPage.jsx +++ b/client/homebrew/pages/vaultPage/vaultPage.jsx @@ -3,13 +3,13 @@ import './vaultPage.less'; import React, { useState, useEffect, useRef } from 'react'; -import Nav from '../../navbar/nav.jsx'; -import Navbar from '../../navbar/navbar.jsx'; -import RecentNavItems from '../../navbar/recent.navitem.jsx'; +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; -import Account from '../../navbar/account.navitem.jsx'; -import NewBrew from '../../navbar/newbrew.navitem.jsx'; -import HelpNavItem from '../../navbar/help.navitem.jsx'; +import Account from '@navbar/account.navitem.jsx'; +import NewBrew from '@navbar/newbrew.navitem.jsx'; +import HelpNavItem from '@navbar/help.navitem.jsx'; import BrewItem from '../basePages/listPage/brewItem/brewItem.jsx'; import SplitPane from '../../../components/splitPane/splitPane.jsx'; import ErrorIndex from '../errorPage/errors/errorIndex.js'; diff --git a/client/homebrew/pages/vaultPage/vaultPage.less b/client/homebrew/pages/vaultPage/vaultPage.less index 304fefc72..b2010b59b 100644 --- a/client/homebrew/pages/vaultPage/vaultPage.less +++ b/client/homebrew/pages/vaultPage/vaultPage.less @@ -1,3 +1,5 @@ +@import '@sharedStyles/core.less'; + .vaultPage { height : 100%; overflow-y : hidden; diff --git a/client/icons/broken-image.jpg b/client/icons/broken-image.jpg new file mode 100644 index 000000000..52fa33195 Binary files /dev/null and b/client/icons/broken-image.jpg differ diff --git a/client/template.js b/client/template.js deleted file mode 100644 index 537be6748..000000000 --- a/client/template.js +++ /dev/null @@ -1,33 +0,0 @@ -const template = async function(name, title='', props = {}){ - const ogTags = []; - const ogMeta = props.ogMeta ?? {}; - Object.entries(ogMeta).forEach(([key, value])=>{ - if(!value) return; - const tag = ``; - ogTags.push(tag); - }); - const ogMetaTags = ogTags.join('\n'); - - const ssrModule = await import(`../build/${name}/ssr.cjs`); - - return ` - - - - - - - ${ogMetaTags} - - ${title.length ? `${title} - The Homebrewery`: 'The Homebrewery - NaturalCrit'} - - -
    ${ssrModule.default(props)}
    - - - - - `; -}; - -export default template; \ No newline at end of file diff --git a/config/default.json b/config/default.json index e1aca3940..e55903405 100644 --- a/config/default.json +++ b/config/default.json @@ -8,5 +8,5 @@ "publicUrl" : "https://homebrewery.naturalcrit.com", "hb_images" : null, "hb_fonts" : null, - "enable_v4" : true + "enablev4" : true } diff --git a/themes/codeMirror/editorThemes.json b/editorThemes.json similarity index 100% rename from themes/codeMirror/editorThemes.json rename to editorThemes.json diff --git a/index.html b/index.html new file mode 100644 index 000000000..d6bd3157d --- /dev/null +++ b/index.html @@ -0,0 +1,46 @@ + + + + + + + + + The Homebrewery - NaturalCrit + + + +
    + + + + diff --git a/package-lock.json b/package-lock.json index aa225f518..eff0d26c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,43 +1,55 @@ { "name": "homebrewery", - "version": "3.20.1", + "version": "3.22.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebrewery", - "version": "3.20.1", + "version": "3.22.0", "hasInstallScript": true, "license": "MIT", "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-runtime": "^7.29.0", - "@babel/preset-env": "^7.29.0", + "@babel/preset-env": "^7.29.5", "@babel/preset-react": "^7.28.5", - "@babel/runtime": "^7.28.4", + "@babel/runtime": "^7.29.2", + "@codemirror/autocomplete": "^6.20.2", + "@codemirror/commands": "^6.10.3", + "@codemirror/highlight": "^0.19.8", + "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-javascript": "^6.2.5", + "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/language": "^6.12.2", + "@codemirror/language-data": "^6.5.2", + "@codemirror/search": "^6.6.0", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.43.0", "@dmsnell/diff-match-patch": "^1.1.0", "@googleapis/drive": "^20.1.0", + "@lezer/highlight": "^1.2.3", "@sanity/diff-match-patch": "^3.2.0", + "@vitejs/plugin-react": "^5.1.2", "body-parser": "^2.2.0", "classnames": "^2.5.1", - "codemirror": "^5.65.6", + "codemirror-5-themes": "^1.5.1", "cookie-parser": "^1.4.7", - "core-js": "^3.47.0", + "core-js": "^3.49.0", "cors": "^2.8.5", "create-react-class": "^15.7.0", "dedent": "^1.7.1", - "expr-eval": "^2.0.2", "express": "^5.1.0", "express-async-handler": "^1.2.0", - "express-static-gzip": "3.0.0", + "express-static-gzip": "3.0.1", "fflate": "^0.8.2", - "fs-extra": "^11.3.3", + "fs-extra": "^11.3.5", "hash-wasm": "^4.12.0", "idb-keyval": "^6.2.2", "js-yaml": "^4.1.1", "jwt-simple": "^0.5.6", - "less": "^3.13.1", - "lodash": "^4.17.21", + "less": "^4.6.4", + "lodash": "^4.18.1", "marked": "15.0.12", "marked-alignment-paragraphs": "^1.0.0", "marked-definition-lists": "^1.0.1", @@ -50,40 +62,39 @@ "marked-variables": "^1.0.5", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^9.2.1", - "nanoid": "5.1.6", + "mongoose": "^9.6.2", + "nanoid": "5.1.11", "nconf": "^0.13.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-frame-component": "^4.1.3", - "react-router": "^7.9.6", - "romans": "^3.1.0", - "sanitize-filename": "1.6.3", - "superagent": "^10.2.1", - "vitreum": "git+https://git@github.com/calculuschild/vitreum.git", - "written-number": "^0.11.1" + "node": "^25.9.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "react-frame-component": "^5.3.2", + "react-router": "^7.15.1", + "sanitize-filename": "1.6.4", + "superagent": "^10.2.1" }, "devDependencies": { - "@stylistic/stylelint-plugin": "^4.0.0", - "babel-jest": "^30.2.0", + "@stylistic/stylelint-plugin": "^5.0.1", + "babel-jest": "^30.4.1", "babel-plugin-transform-import-meta": "^2.3.3", - "eslint": "^9.39.1", - "eslint-plugin-jest": "^29.1.0", + "eslint": "9.7", + "eslint-plugin-jest": "^29.15.1", "eslint-plugin-react": "^7.37.5", "globals": "^16.4.0", - "jest": "^30.2.0", + "jest": "^30.4.2", "jest-expect-message": "^1.1.3", "jsdom": "^28.1.0", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.25.0", - "stylelint-config-recess-order": "^7.3.0", - "stylelint-config-recommended": "^17.0.0", - "supertest": "^7.1.4" + "stylelint": "^17.11.1", + "stylelint-config-recess-order": "^7.7.0", + "stylelint-config-recommended": "^18.0.0", + "supertest": "^7.1.4", + "vite": "^7.3.1" }, "engines": { - "node": "^20.18.x", - "npm": "^10.8.x" + "node": ">=20.18 <25", + "npm": ">=10.8 <12" } }, "node_modules/@acemir/cssom": { @@ -107,30 +118,6 @@ "lru-cache": "^11.2.5" } }, - "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-calc": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", - "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" - } - }, "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-color-parser": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.1.tgz", @@ -159,49 +146,6 @@ "@csstools/css-tokenizer": "^4.0.0" } }, - "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-parser-algorithms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", - "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^4.0.0" - } - }, - "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-tokenizer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", - "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - } - }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { "version": "11.2.6", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", @@ -244,12 +188,12 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -258,9 +202,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -297,13 +241,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -313,25 +257,25 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -341,17 +285,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", - "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.6", + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", "semver": "^6.3.1" }, "engines": { @@ -362,12 +306,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-annotate-as-pure": "^7.29.7", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, @@ -395,49 +339,49 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -447,35 +391,35 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -485,14 +429,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", - "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.28.6" + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -502,54 +446,54 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", - "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -569,12 +513,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -584,13 +528,13 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", - "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -600,12 +544,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -615,12 +559,28 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -630,14 +590,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -647,13 +607,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", - "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/traverse": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -730,12 +690,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", - "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -745,12 +705,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", - "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -911,13 +871,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", - "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -943,12 +903,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -958,14 +918,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", - "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.29.0" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -975,14 +935,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", - "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-remap-async-to-generator": "^7.27.1" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -992,12 +952,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1007,12 +967,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", - "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1022,13 +982,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", - "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1038,13 +998,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", - "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1054,17 +1014,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", - "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-replace-supers": "^7.28.6", - "@babel/traverse": "^7.28.6" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1074,13 +1034,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", - "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/template": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1090,13 +1050,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1106,13 +1066,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", - "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1122,12 +1082,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1137,13 +1097,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", - "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1153,12 +1113,12 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1168,13 +1128,13 @@ } }, "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", - "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1184,12 +1144,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", - "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1199,12 +1159,12 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1214,13 +1174,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1230,14 +1190,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1247,12 +1207,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", - "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1262,12 +1222,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1277,12 +1237,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", - "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1292,12 +1252,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1307,13 +1267,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1323,13 +1283,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", - "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1339,15 +1299,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", - "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", + "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.29.0" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1357,13 +1317,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1373,13 +1333,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", - "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1389,12 +1349,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1404,12 +1364,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", - "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1419,12 +1379,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", - "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1434,16 +1394,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", - "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.6" + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1453,13 +1413,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1469,12 +1429,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", - "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1484,13 +1444,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", - "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1500,12 +1460,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1515,13 +1475,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", - "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1531,14 +1491,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", - "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1548,12 +1508,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1611,6 +1571,36 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-pure-annotations": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", @@ -1628,12 +1618,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", - "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", + "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1643,13 +1633,13 @@ } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", - "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1659,12 +1649,12 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1694,12 +1684,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1709,13 +1699,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", - "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", + "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1725,12 +1715,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1740,12 +1730,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1755,12 +1745,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1770,12 +1760,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1785,13 +1775,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", - "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1801,13 +1791,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1817,13 +1807,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", - "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1833,75 +1823,76 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", - "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.28.6", - "@babel/plugin-syntax-import-attributes": "^7.28.6", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.29.0", - "@babel/plugin-transform-async-to-generator": "^7.28.6", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.6", - "@babel/plugin-transform-class-properties": "^7.28.6", - "@babel/plugin-transform-class-static-block": "^7.28.6", - "@babel/plugin-transform-classes": "^7.28.6", - "@babel/plugin-transform-computed-properties": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.28.6", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.6", - "@babel/plugin-transform-exponentiation-operator": "^7.28.6", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.28.6", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@babel/plugin-transform-modules-systemjs": "^7.29.0", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", - "@babel/plugin-transform-numeric-separator": "^7.28.6", - "@babel/plugin-transform-object-rest-spread": "^7.28.6", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.28.6", - "@babel/plugin-transform-optional-chaining": "^7.28.6", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.28.6", - "@babel/plugin-transform-private-property-in-object": "^7.28.6", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.29.0", - "@babel/plugin-transform-regexp-modifiers": "^7.28.6", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.28.6", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.28.6", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.15", "babel-plugin-polyfill-corejs3": "^0.14.0", @@ -1964,40 +1955,40 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -2005,13 +1996,13 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2038,16 +2029,16 @@ } }, "node_modules/@cacheable/memory": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.0.7.tgz", - "integrity": "sha512-RbxnxAMf89Tp1dLhXMS7ceft/PGsDl1Ip7T20z5nZ+pwIAsQ1p2izPjVG69oCLv/jfQ7HDPHTWK0c9rcAWXN3A==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.0.9.tgz", + "integrity": "sha512-HdMx6DoGywB30vacDbBsITbIX4pgFqj1zsrV58jZBUw3klzkNoXhj7qOqAgledhxG7YZI5rBSJg7Zp8/VG0DuA==", "dev": true, "license": "MIT", "dependencies": { - "@cacheable/utils": "^2.3.3", - "@keyv/bigmap": "^1.3.0", - "hookified": "^1.14.0", - "keyv": "^5.5.5" + "@cacheable/utils": "^2.4.1", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" } }, "node_modules/@cacheable/memory/node_modules/@keyv/bigmap": { @@ -2078,13 +2069,13 @@ } }, "node_modules/@cacheable/utils": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.3.4.tgz", - "integrity": "sha512-knwKUJEYgIfwShABS1BX6JyJJTglAFcEU7EXqzTdiGCXur4voqkiJkdgZIQtWNFhynzDWERcTYv/sETMu3uJWA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.4.1.tgz", + "integrity": "sha512-eiFgzCbIneyMlLOmNG4g9xzF7Hv3Mga4LjxjcSC/ues6VYq2+gUbQI8JqNuw/ZM8tJIeIaBGpswAsqV2V7ApgA==", "dev": true, "license": "MIT", "dependencies": { - "hashery": "^1.3.0", + "hashery": "^1.5.1", "keyv": "^5.6.0" } }, @@ -2098,6 +2089,498 @@ "@keyv/serialize": "^1.1.1" } }, + "node_modules/@codemirror/autocomplete": { + "version": "6.20.2", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.2.tgz", + "integrity": "sha512-G5FPkgIiLjOgZMjqVjvuKQ1rGPtHogLldJr33eFJdVLtmwY+giGrlv/ewljLz6b9BSQLkjxuwBc6g6omDM+YxQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.3.tgz", + "integrity": "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/highlight": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@codemirror/highlight/-/highlight-0.19.8.tgz", + "integrity": "sha512-v/lzuHjrYR8MN2mEJcUD6fHSTXXli9C1XGYpr+ElV6fLBIUhMTNKR3qThp611xuWfXfwDxeL7ppcbkM/MzPV3A==", + "deprecated": "As of 0.20.0, this package has been split between @lezer/highlight and @codemirror/language", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^0.19.0", + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.3", + "@codemirror/view": "^0.19.39", + "@lezer/common": "^0.15.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/highlight/node_modules/@codemirror/language": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.19.10.tgz", + "integrity": "sha512-yA0DZ3RYn2CqAAGW62VrU8c4YxscMQn45y/I9sjBlqB1e2OTQLg4CCkMBuMSLXk4xaqjlsgazeOQWaJQOKfV8Q==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.19.0", + "@codemirror/text": "^0.19.0", + "@codemirror/view": "^0.19.0", + "@lezer/common": "^0.15.5", + "@lezer/lr": "^0.15.0" + } + }, + "node_modules/@codemirror/highlight/node_modules/@codemirror/state": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.19.9.tgz", + "integrity": "sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw==", + "license": "MIT", + "dependencies": { + "@codemirror/text": "^0.19.0" + } + }, + "node_modules/@codemirror/highlight/node_modules/@codemirror/view": { + "version": "0.19.48", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.19.48.tgz", + "integrity": "sha512-0eg7D2Nz4S8/caetCTz61rK0tkHI17V/d15Jy0kLOT8dTLGGNJUponDnW28h2B6bERmPlVHKh8MJIr5OCp1nGw==", + "license": "MIT", + "dependencies": { + "@codemirror/rangeset": "^0.19.5", + "@codemirror/state": "^0.19.3", + "@codemirror/text": "^0.19.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@codemirror/highlight/node_modules/@lezer/common": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz", + "integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==", + "license": "MIT" + }, + "node_modules/@codemirror/highlight/node_modules/@lezer/lr": { + "version": "0.15.8", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz", + "integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^0.15.0" + } + }, + "node_modules/@codemirror/lang-angular": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@codemirror/lang-angular/-/lang-angular-0.1.4.tgz", + "integrity": "sha512-oap+gsltb/fzdlTQWD6BFF4bSLKcDnlxDsLdePiJpCVNKWXSTAbiiQeYI3UmES+BLAdkmIC1WjyztC1pi/bX4g==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-javascript": "^6.1.2", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.3" + } + }, + "node_modules/@codemirror/lang-cpp": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.3.tgz", + "integrity": "sha512-URM26M3vunFFn9/sm6rzqrBzDgfWuDixp85uTY49wKudToc2jTHUrKIGGKs+QWND+YLofNNZpxcNGRynFJfvgA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/cpp": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-css": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz", + "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.1.7" + } + }, + "node_modules/@codemirror/lang-go": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-go/-/lang-go-6.0.1.tgz", + "integrity": "sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/go": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.4.11", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", + "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.12" + } + }, + "node_modules/@codemirror/lang-java": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.2.tgz", + "integrity": "sha512-m5Nt1mQ/cznJY7tMfQTJchmrjdjQ71IDs+55d1GAa8DGaB8JXWsVCkVT284C3RTASaY43YknrK2X3hPO/J3MOQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/java": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.5.tgz", + "integrity": "sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-jinja": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-jinja/-/lang-jinja-6.0.1.tgz", + "integrity": "sha512-P5kyHLObzjtbGj16h+hyvZTxJhSjBEeSx4wMjbnAf3b0uwTy2+F0zGjMZL4PQOm/mh2eGZ5xUDVZXgwP783Nsw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.2.0", + "@lezer/lr": "^1.4.0" + } + }, + "node_modules/@codemirror/lang-json": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz", + "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-less": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-less/-/lang-less-6.0.2.tgz", + "integrity": "sha512-EYdQTG22V+KUUk8Qq582g7FMnCZeEHsyuOJisHRft/mQ+ZSZ2w51NupvDUHiqtsOy7It5cHLPGfHQLpMh9bqpQ==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-css": "^6.2.0", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-liquid": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-liquid/-/lang-liquid-6.3.2.tgz", + "integrity": "sha512-6PDVU3ZnfeYyz1at1E/ttorErZvZFXXt1OPhtfe1EZJ2V2iDFa0CwPqPgG5F7NXN0yONGoBogKmFAafKTqlwIw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.1" + } + }, + "node_modules/@codemirror/lang-markdown": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.5.0.tgz", + "integrity": "sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.7.1", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.3.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/markdown": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-php": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.2.tgz", + "integrity": "sha512-ZKy2v1n8Fc8oEXj0Th0PUMXzQJ0AIR6TaZU+PbDHExFwdu+guzOA4jmCHS1Nz4vbFezwD7LyBdDnddSJeScMCA==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/php": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-python": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.2.1.tgz", + "integrity": "sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.3.2", + "@codemirror/language": "^6.8.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/python": "^1.1.4" + } + }, + "node_modules/@codemirror/lang-rust": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.2.tgz", + "integrity": "sha512-EZaGjCUegtiU7kSMvOfEZpaCReowEf3yNidYu7+vfuGTm9ow4mthAparY5hisJqOHmJowVH3Upu+eJlUji6qqA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/rust": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sass": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-sass/-/lang-sass-6.0.2.tgz", + "integrity": "sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-css": "^6.2.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/sass": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sql": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.10.0.tgz", + "integrity": "sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-vue": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-vue/-/lang-vue-0.1.3.tgz", + "integrity": "sha512-QSKdtYTDRhEHCfo5zOShzxCmqKJvgGrZwDQSdbvCRJ5pRLWBS7pD/8e/tH44aVQT6FKm0t6RVNoSUWHOI5vNug==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-javascript": "^6.1.2", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.1" + } + }, + "node_modules/@codemirror/lang-wast": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-wast/-/lang-wast-6.0.2.tgz", + "integrity": "sha512-Imi2KTpVGm7TKuUkqyJ5NRmeFWF7aMpNiwHnLQe0x9kmrxElndyH0K6H/gXtWwY6UshMRAhpENsgfpSwsgmC6Q==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-xml": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz", + "integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/xml": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-yaml": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.3.tgz", + "integrity": "sha512-AZ8DJBuXGVHybpBQhmZtgew5//4hv3tdkXnr3vDmOUMJRuB6vn/uuwtmTOTlqEaQFg3hQSVeA90NmvIQyUV6FQ==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.2.0", + "@lezer/lr": "^1.0.0", + "@lezer/yaml": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.3.tgz", + "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/language-data": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/language-data/-/language-data-6.5.2.tgz", + "integrity": "sha512-CPkWBKrNS8stYbEU5kwBwTf3JB1kghlbh4FSAwzGW2TEscdeHHH4FGysREW86Mqnj3Qn09s0/6Ea/TutmoTobg==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-angular": "^0.1.0", + "@codemirror/lang-cpp": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-go": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-java": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/lang-jinja": "^6.0.0", + "@codemirror/lang-json": "^6.0.0", + "@codemirror/lang-less": "^6.0.0", + "@codemirror/lang-liquid": "^6.0.0", + "@codemirror/lang-markdown": "^6.0.0", + "@codemirror/lang-php": "^6.0.0", + "@codemirror/lang-python": "^6.0.0", + "@codemirror/lang-rust": "^6.0.0", + "@codemirror/lang-sass": "^6.0.0", + "@codemirror/lang-sql": "^6.0.0", + "@codemirror/lang-vue": "^0.1.1", + "@codemirror/lang-wast": "^6.0.0", + "@codemirror/lang-xml": "^6.0.0", + "@codemirror/lang-yaml": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/legacy-modes": "^6.4.0" + } + }, + "node_modules/@codemirror/legacy-modes": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.5.3.tgz", + "integrity": "sha512-xCsmIzH78MyWkib9jlPaaun57XNkfbMIhagfaZVd0iLTqlpw3jXaIcbZm72MTmmn64eTZpBVNjbyYh+QXnxRsg==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.6.tgz", + "integrity": "sha512-6Kp7r6XfCi/D/5sdXieMfg9pJU1bUEx96WITuLU6ESaKizCz0QHFMjY/TaFSbigDdEAIgi93itLBIUETP4oK+A==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.42.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/rangeset": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.19.9.tgz", + "integrity": "sha512-V8YUuOvK+ew87Xem+71nKcqu1SXd5QROMRLMS/ljT5/3MCxtgrRie1Cvild0G/Z2f1fpWxzX78V0U4jjXBorBQ==", + "deprecated": "As of 0.20.0, this package has been merged into @codemirror/state", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^0.19.0" + } + }, + "node_modules/@codemirror/rangeset/node_modules/@codemirror/state": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.19.9.tgz", + "integrity": "sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw==", + "license": "MIT", + "dependencies": { + "@codemirror/text": "^0.19.0" + } + }, + "node_modules/@codemirror/search": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.0.tgz", + "integrity": "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.37.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.6.0.tgz", + "integrity": "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==", + "license": "MIT", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/text": { + "version": "0.19.6", + "resolved": "https://registry.npmjs.org/@codemirror/text/-/text-0.19.6.tgz", + "integrity": "sha512-T9jnREMIygx+TPC1bOuepz18maGq/92q2a+n4qTqObKwvNMg+8cMTslb8yxeEDEq7S3kpgGWxgO1UWbQRij0dA==", + "deprecated": "As of 0.20.0, this package has been merged into @codemirror/state", + "license": "MIT" + }, + "node_modules/@codemirror/view": { + "version": "6.43.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.0.tgz", + "integrity": "sha512-V7ZCLQO3Jus9hzh2jVCCPW3mO4IBMr43O37PqSUYautJSnnJF41YlgLw21x0fLJTYvJ+Vkm6Gp+qKGH9pltgXA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.6.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@csstools/color-helpers": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.1.tgz", @@ -2118,10 +2601,10 @@ "node": ">=20.19.0" } }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "node_modules/@csstools/css-calc": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", "dev": true, "funding": [ { @@ -2135,16 +2618,40 @@ ], "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.27", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.27.tgz", - "integrity": "sha512-sxP33Jwg1bviSUXAV43cVYdmjt2TLnLXNqCWl9xmxHawWVjGz/kEbdkr7F9pxJNBN2Mh+dq0crgItbW6tQvyow==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz", + "integrity": "sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==", "dev": true, "funding": [ { @@ -2156,12 +2663,20 @@ "url": "https://opencollective.com/csstools" } ], - "license": "MIT-0" + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } }, "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true, "funding": [ { @@ -2175,13 +2690,13 @@ ], "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, "node_modules/@csstools/media-query-list-parser": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", - "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-5.0.0.tgz", + "integrity": "sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg==", "dev": true, "funding": [ { @@ -2195,17 +2710,17 @@ ], "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, - "node_modules/@csstools/selector-specificity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", - "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "node_modules/@csstools/selector-resolve-nested": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-4.0.0.tgz", + "integrity": "sha512-9vAPxmp+Dx3wQBIUwc1v7Mdisw1kbbaGqXUM8QLTgWg7SoPGYtXBsMXvsFs/0Bn5yoFhcktzxNZGNaUt0VjgjA==", "dev": true, "funding": [ { @@ -2219,10 +2734,33 @@ ], "license": "MIT-0", "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "postcss-selector-parser": "^7.0.0" + "postcss-selector-parser": "^7.1.1" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-6.0.0.tgz", + "integrity": "sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.1.1" } }, "node_modules/@dmsnell/diff-match-patch": { @@ -2231,33 +2769,22 @@ "integrity": "sha512-yejLPmM5pjsGvxS9gXablUSbInW7H976c/FJ4iQxWIm7/38xBySRemTPDe34lhg1gVLbJntX0+sH0jYfU+PN9A==", "license": "Apache-2.0" }, - "node_modules/@dual-bundle/import-meta-resolve": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.2.1.tgz", - "integrity": "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/JounQin" - } - }, "node_modules/@emnapi/core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", - "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.1.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, @@ -2266,9 +2793,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, @@ -2276,6 +2803,422 @@ "tslib": "^2.4.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -2319,13 +3262,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.7", + "@eslint/object-schema": "^2.1.4", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -2333,32 +3276,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@eslint/eslintrc": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", @@ -2397,16 +3314,13 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", + "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { @@ -2419,20 +3333,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@exodus/bytes": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.14.1.tgz", @@ -2463,30 +3363,6 @@ "node": ">=12.0.0" } }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -2502,9 +3378,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2584,17 +3460,17 @@ } }, "node_modules/@jest/console": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", - "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.4.1.tgz", + "integrity": "sha512-v3bhyxUh9Hgmo5p6hAOXe14/R3ZxZDOsvHleh4B07z3m/x4/ngPUXEm9XwK4sF4u+f+P2ORb0Ge+MgpaqRMVDA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", + "@jest/types": "30.4.1", "@types/node": "*", "chalk": "^4.1.2", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", + "jest-message-util": "30.4.1", + "jest-util": "30.4.1", "slash": "^3.0.0" }, "engines": { @@ -2602,39 +3478,39 @@ } }, "node_modules/@jest/core": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", - "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.4.2.tgz", + "integrity": "sha512-TZJA6cPJUFxoWhxaLo8t0VX/MZX2wPWr0uIDvLSHIvN4gu9h02vSzqI2kBADG1ExqQlC+cY09xKMSreivvrChQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.2.0", - "@jest/pattern": "30.0.1", - "@jest/reporters": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", + "@jest/console": "30.4.1", + "@jest/pattern": "30.4.0", + "@jest/reporters": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "ci-info": "^4.2.0", "exit-x": "^0.2.2", + "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", - "jest-changed-files": "30.2.0", - "jest-config": "30.2.0", - "jest-haste-map": "30.2.0", - "jest-message-util": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-resolve-dependencies": "30.2.0", - "jest-runner": "30.2.0", - "jest-runtime": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "jest-watcher": "30.2.0", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", + "jest-changed-files": "30.4.1", + "jest-config": "30.4.2", + "jest-haste-map": "30.4.1", + "jest-message-util": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.1", + "jest-resolve-dependencies": "30.4.2", + "jest-runner": "30.4.2", + "jest-runtime": "30.4.2", + "jest-snapshot": "30.4.1", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", + "jest-watcher": "30.4.1", + "pretty-format": "30.4.1", "slash": "^3.0.0" }, "engines": { @@ -2650,9 +3526,9 @@ } }, "node_modules/@jest/diff-sequences": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", + "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", "dev": true, "license": "MIT", "engines": { @@ -2660,39 +3536,39 @@ } }, "node_modules/@jest/environment": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", - "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.4.1.tgz", + "integrity": "sha512-AK9yNRqgKxiabqMoe4oW+3/TSSeV8vkdC7BGaxZdU0AFXfOpofTLqdru2GXKZghP3sdgwE9XXpnVwfZ8JnFV4w==", "dev": true, "license": "MIT", "dependencies": { - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", + "@jest/fake-timers": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", - "jest-mock": "30.2.0" + "jest-mock": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.4.1.tgz", + "integrity": "sha512-ginrj6TMgh2GshLUGCjO94Ptx9HhdZA/I6A9iUfyeLKFtdAjnKzHDgzgP9HYQgbxM1lbXScQ2eUBz2lGeVDPWA==", "dev": true, "license": "MIT", "dependencies": { - "expect": "30.2.0", - "jest-snapshot": "30.2.0" + "expect": "30.4.1", + "jest-snapshot": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", - "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.1.tgz", + "integrity": "sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2703,18 +3579,18 @@ } }, "node_modules/@jest/fake-timers": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", - "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.4.1.tgz", + "integrity": "sha512-iW5umdmfPeWzehrVhugFQZqCchSCud5S1l2YT0O9ZhjRR0ExclANDZkiSBwzqtnlOn0J1JXvO+HZ6rkuyOVOgQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "@sinonjs/fake-timers": "^13.0.0", + "@jest/types": "30.4.1", + "@sinonjs/fake-timers": "^15.4.0", "@types/node": "*", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-util": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -2731,62 +3607,62 @@ } }, "node_modules/@jest/globals": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", - "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.4.1.tgz", + "integrity": "sha512-ZbuY4cmXC8DkxYjfvT2DbcHWL2T6vmsMhXCDcmTB2T0y0gaezBI77ufq5ZAIdcRkYZ7NEQEDg1xFeKbxUJ5v5Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/expect": "30.2.0", - "@jest/types": "30.2.0", - "jest-mock": "30.2.0" + "@jest/environment": "30.4.1", + "@jest/expect": "30.4.1", + "@jest/types": "30.4.1", + "jest-mock": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/pattern": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", - "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", + "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", - "jest-regex-util": "30.0.1" + "jest-regex-util": "30.4.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/reporters": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", - "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.4.1.tgz", + "integrity": "sha512-/SnkPCzEQpUaBH81kjdEdDdo2WZl5hxw+BmLDGWjRkm8o7XlhjwsU36cqwe5PGBE5WYpBvDzRSdXx9rbGuJtNA==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", + "@jest/console": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", "@jridgewell/trace-mapping": "^0.3.25", "@types/node": "*", "chalk": "^4.1.2", "collect-v8-coverage": "^1.0.2", "exit-x": "^0.2.2", - "glob": "^10.3.10", + "glob": "^10.5.0", "graceful-fs": "^4.2.11", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^6.0.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "jest-worker": "30.2.0", + "jest-message-util": "30.4.1", + "jest-util": "30.4.1", + "jest-worker": "30.4.1", "slash": "^3.0.0", "string-length": "^4.0.2", "v8-to-istanbul": "^9.0.1" @@ -2804,9 +3680,9 @@ } }, "node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", + "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2817,13 +3693,13 @@ } }, "node_modules/@jest/snapshot-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", - "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.4.1.tgz", + "integrity": "sha512-ObY4ljvQ95mt6iwKtVLetR/4yXiAgl3H4nJxhztr0MTjrN97TwDYrnCp/kF60Ec9HdhkWTHSu+Hg05aXfngpOA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", + "@jest/types": "30.4.1", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "natural-compare": "^1.4.0" @@ -2848,14 +3724,14 @@ } }, "node_modules/@jest/test-result": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", - "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.4.1.tgz", + "integrity": "sha512-/ZG7pgEiOmmWkN9TplKbOu4id2N5lh7FHwRwlkgBVAzGdRH+OkkQ8wX/kIxg4zmd3ZQvAL1RwL2yWsvNYYECTw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.2.0", - "@jest/types": "30.2.0", + "@jest/console": "30.4.1", + "@jest/types": "30.4.1", "@types/istanbul-lib-coverage": "^2.0.6", "collect-v8-coverage": "^1.0.2" }, @@ -2864,15 +3740,15 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", - "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.4.1.tgz", + "integrity": "sha512-PeYE+4td5rKjoRPxztObrXU+H8hsjZfxKMXOcmrr34JerSyB/ROOxbbicz8B7A5j9R9VayDnVPvBmedqCsFCdw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.2.0", + "@jest/test-result": "30.4.1", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", + "jest-haste-map": "30.4.1", "slash": "^3.0.0" }, "engines": { @@ -2880,24 +3756,23 @@ } }, "node_modules/@jest/transform": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", - "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.4.1.tgz", + "integrity": "sha512-Wz0LyktlTvRefoymh+n64hQ84KNXsRGcwdoZ8CSa0Ea+fgYcHZlnk+hDP7v2MS7il2bQ5uTEIxf4/NNfhMN4KQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/types": "30.2.0", + "@jest/types": "30.4.1", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "micromatch": "^4.0.8", + "jest-haste-map": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-util": "30.4.1", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" @@ -2907,14 +3782,14 @@ } }, "node_modules/@jest/types": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", - "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.1.tgz", + "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.5", + "@jest/pattern": "30.4.0", + "@jest/schemas": "30.4.1", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", @@ -2977,26 +3852,215 @@ "dev": true, "license": "MIT" }, + "node_modules/@lezer/common": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", + "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", + "license": "MIT" + }, + "node_modules/@lezer/cpp": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.6.tgz", + "integrity": "sha512-vh9gWWJOXFVY8HBHK3Twzq8MgwG2iN4GSyzBP9sCGTe37P15x2R14VaBQk0VA0ezTRN1KHYBBsHhvpGZ2Xy/pA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/css": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.3.tgz", + "integrity": "sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/go": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.1.tgz", + "integrity": "sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.3.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz", + "integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/java": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.1.3.tgz", + "integrity": "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", + "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", + "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz", + "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/markdown": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.6.4.tgz", + "integrity": "sha512-N0SxazMj4k65DBfaf1azqtMZd6u7MqluP84/NZnB/io8Td9aleFmAhz9hcbvSfsxT5tdYlJ5qgv5aMJGY4zEtA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@lezer/php": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.5.tgz", + "integrity": "sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.1.0" + } + }, + "node_modules/@lezer/python": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.19.tgz", + "integrity": "sha512-MhQIURHRytsNzP/YXnqpYKW6la6voAH3kyplTOOiCdjyFY6cWWGFVmYVdHIPrElqSDf4iCDktQCockB9FxuhzQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/rust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.2.tgz", + "integrity": "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/sass": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lezer/sass/-/sass-1.1.0.tgz", + "integrity": "sha512-3mMGdCTUZ/84ArHOuXWQr37pnf7f+Nw9ycPUeKX+wu19b7pSMcZGLbaXwvD2APMBDOGxPmpK/O6S1v1EvLoqgQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/xml": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz", + "integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/yaml": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.4.tgz", + "integrity": "sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.4.0" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "license": "MIT" + }, "node_modules/@mongodb-js/saslprep": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.6.tgz", - "integrity": "sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g==", + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.11.tgz", + "integrity": "sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA==", "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@noble/hashes": { @@ -3069,18 +4133,349 @@ } }, "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", "dev": true, "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/pkgr" } }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sanity/diff-match-patch": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@sanity/diff-match-patch/-/diff-match-patch-3.2.0.tgz", @@ -3091,12 +4486,25 @@ } }, "node_modules/@sinclair/typebox": { - "version": "0.34.48", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", - "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", "dev": true, "license": "MIT" }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", @@ -3108,9 +4516,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", + "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -3118,31 +4526,28 @@ } }, "node_modules/@stylistic/stylelint-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-4.0.1.tgz", - "integrity": "sha512-jKZSZr/S/NehfgayNJI3O/JEq+W5lSeHUJNvdOebRPNFP2ZylTbAx/p5qR8scQFpiVzy1VQM9R+G0kIB62r1Pw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-5.2.0.tgz", + "integrity": "sha512-pfa2PMvlH87qwoOMUH4rqz7x/vuO5Kh+r/R1Pe+/5T8sukDPe/VfF6mbdUGE5gwZPlj5O1X56qw55IZrFFRF0g==", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/media-query-list-parser": "^4.0.3", - "postcss": "^8.5.6", - "postcss-selector-parser": "^7.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "@csstools/media-query-list-parser": "^5.0.0", + "postcss": "^8.5.8", + "postcss-selector-parser": "^7.1.1", "postcss-value-parser": "^4.2.0", "style-search": "^0.1.0" }, - "engines": { - "node": "^18.12 || >=20.9" - }, "peerDependencies": { - "stylelint": "^16.22.0" + "stylelint": "^17.6.0" } }, "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, "license": "MIT", "optional": true, @@ -3154,7 +4559,6 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", @@ -3168,7 +4572,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -3178,7 +4581,6 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", @@ -3189,7 +4591,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.2" @@ -3199,7 +4600,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-coverage": { @@ -3229,18 +4629,11 @@ "@types/istanbul-lib-report": "*" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/node": { "version": "25.3.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~7.18.0" @@ -3479,16 +4872,16 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", "dev": true, "license": "ISC" }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", - "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", "cpu": [ "arm" ], @@ -3500,9 +4893,9 @@ ] }, "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", - "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", "cpu": [ "arm64" ], @@ -3514,9 +4907,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", - "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", "cpu": [ "arm64" ], @@ -3528,9 +4921,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", - "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", "cpu": [ "x64" ], @@ -3542,9 +4935,9 @@ ] }, "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", - "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", "cpu": [ "x64" ], @@ -3556,9 +4949,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", - "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", "cpu": [ "arm" ], @@ -3570,9 +4963,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", - "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", "cpu": [ "arm" ], @@ -3584,9 +4977,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", - "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", "cpu": [ "arm64" ], @@ -3598,9 +4991,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", - "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", "cpu": [ "arm64" ], @@ -3611,10 +5004,38 @@ "linux" ] }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", - "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", "cpu": [ "ppc64" ], @@ -3626,9 +5047,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", - "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", "cpu": [ "riscv64" ], @@ -3640,9 +5061,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", - "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", "cpu": [ "riscv64" ], @@ -3654,9 +5075,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", - "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", "cpu": [ "s390x" ], @@ -3668,9 +5089,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", "cpu": [ "x64" ], @@ -3682,9 +5103,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", "cpu": [ "x64" ], @@ -3695,10 +5116,24 @@ "linux" ] }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", - "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", "cpu": [ "wasm32" ], @@ -3706,16 +5141,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", - "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", "cpu": [ "arm64" ], @@ -3727,9 +5164,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", - "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", "cpu": [ "ia32" ], @@ -3741,9 +5178,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", - "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", "cpu": [ "x64" ], @@ -3754,6 +5191,26 @@ "win32" ] }, + "node_modules/@vitejs/plugin-react": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", + "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -3790,38 +5247,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "node_modules/acorn-node/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -3895,6 +5320,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -3910,33 +5336,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", @@ -3977,25 +5376,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", @@ -4100,42 +5480,6 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "license": "MIT" }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "license": "MIT" - }, - "node_modules/assert": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", - "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", - "license": "MIT", - "dependencies": { - "object.assign": "^4.1.4", - "util": "^0.10.4" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -4152,18 +5496,6 @@ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, - "node_modules/async-each": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", - "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", @@ -4180,31 +5512,11 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "license": "(MIT OR Apache-2.0)", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -4217,16 +5529,16 @@ } }, "node_modules/babel-jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", - "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.4.1.tgz", + "integrity": "sha512-fATAbM8piYxkiXQp3RBXmZHxZVNJZAVXXfyeyCN2Tida3+qJ8ea9UxhiJ2y4fLO90ZImKt6k9FlcH2+rLkJGhw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/transform": "30.2.0", + "@jest/transform": "30.4.1", "@types/babel__core": "^7.20.5", "babel-plugin-istanbul": "^7.0.1", - "babel-preset-jest": "30.2.0", + "babel-preset-jest": "30.4.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" @@ -4259,9 +5571,9 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", - "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.4.0.tgz", + "integrity": "sha512-9EdtWM/sSfXLOGLwSn+GS6pIXyBnL07/8gyJlwFXjWy4DxMOyItqyUT29d4lQiS380EZwYlX7/At4PgBS+m2aA==", "dev": true, "license": "MIT", "dependencies": { @@ -4352,13 +5664,13 @@ } }, "node_modules/babel-preset-jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", - "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.4.0.tgz", + "integrity": "sha512-lBY4jxsNmCnSiu7kquw8ZC9F4+XLMOKypT3RnNHPvU2Kpd4W0xaPuLr5ZkRyOsvLYAY4yaW1ZwTW4xB7NIiZzg==", "dev": true, "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "30.2.0", + "babel-plugin-jest-hoist": "30.4.0", "babel-preset-current-node-syntax": "^1.2.0" }, "engines": { @@ -4374,49 +5686,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "license": "MIT", - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -4465,34 +5734,6 @@ "node": "*" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "license": "MIT" - }, "node_modules/body-parser": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", @@ -4521,6 +5762,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -4531,6 +5773,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -4539,227 +5782,6 @@ "node": ">=8" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "license": "MIT" - }, - "node_modules/browser-pack": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", - "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", - "license": "MIT", - "dependencies": { - "combine-source-map": "~0.8.0", - "defined": "^1.0.0", - "JSONStream": "^1.0.3", - "safe-buffer": "^5.1.1", - "through2": "^2.0.0", - "umd": "^3.0.0" - }, - "bin": { - "browser-pack": "bin/cmd.js" - } - }, - "node_modules/browser-pack/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/browser-resolve": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", - "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", - "license": "MIT", - "dependencies": { - "resolve": "^1.17.0" - } - }, - "node_modules/browserify": { - "version": "16.5.2", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.5.2.tgz", - "integrity": "sha512-TkOR1cQGdmXU9zW4YukWzWVSJwrxmNdADFbqbE3HFgQWe5wqZmOawqZ7J/8MPCwk/W8yY7Y0h+7mOtcZxLP23g==", - "license": "MIT", - "dependencies": { - "assert": "^1.4.0", - "browser-pack": "^6.0.1", - "browser-resolve": "^2.0.0", - "browserify-zlib": "~0.2.0", - "buffer": "~5.2.1", - "cached-path-relative": "^1.0.0", - "concat-stream": "^1.6.0", - "console-browserify": "^1.1.0", - "constants-browserify": "~1.0.0", - "crypto-browserify": "^3.0.0", - "defined": "^1.0.0", - "deps-sort": "^2.0.0", - "domain-browser": "^1.2.0", - "duplexer2": "~0.1.2", - "events": "^2.0.0", - "glob": "^7.1.0", - "has": "^1.0.0", - "htmlescape": "^1.1.0", - "https-browserify": "^1.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^7.0.0", - "JSONStream": "^1.0.3", - "labeled-stream-splicer": "^2.0.0", - "mkdirp-classic": "^0.5.2", - "module-deps": "^6.2.3", - "os-browserify": "~0.3.0", - "parents": "^1.0.1", - "path-browserify": "~0.0.0", - "process": "~0.11.0", - "punycode": "^1.3.2", - "querystring-es3": "~0.2.0", - "read-only-stream": "^2.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.4", - "shasum": "^1.0.0", - "shell-quote": "^1.6.1", - "stream-browserify": "^2.0.0", - "stream-http": "^3.0.0", - "string_decoder": "^1.1.1", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^2.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "0.0.1", - "url": "~0.11.0", - "util": "~0.10.1", - "vm-browserify": "^1.0.0", - "xtend": "^4.0.0" - }, - "bin": { - "browserify": "bin/cmd.js" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "license": "MIT", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "license": "MIT", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", - "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", - "license": "MIT", - "dependencies": { - "bn.js": "^5.2.1", - "randombytes": "^2.1.0", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", - "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", - "license": "ISC", - "dependencies": { - "bn.js": "^5.2.2", - "browserify-rsa": "^4.1.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.6.1", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.9", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "license": "MIT", - "dependencies": { - "pako": "~1.0.5" - } - }, - "node_modules/browserify/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/browserify/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "license": "MIT" - }, - "node_modules/browserify/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", @@ -4812,16 +5834,6 @@ "node": ">=20.19.0" } }, - "node_modules/buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", - "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -4832,18 +5844,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "license": "MIT" - }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "dev": true, "license": "MIT" }, "node_modules/bytes": { @@ -4855,38 +5856,18 @@ "node": ">= 0.8" } }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "license": "MIT", - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cacheable": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.3.2.tgz", - "integrity": "sha512-w+ZuRNmex9c1TR9RcsxbfTKCjSL0rh1WA5SABbrWprIHeNBdmyQLSYonlDy9gpD+63XT8DgZ/wNh1Smvc9WnJA==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.3.5.tgz", + "integrity": "sha512-EQfaKe09tl615iNvq/TBRWTFf1AKJNXYQSsMx0Z3EI0nA+pVsVPS8wJhnRlkbdacKPh1d0qVIhwTc2zsQNFEEg==", "dev": true, "license": "MIT", "dependencies": { - "@cacheable/memory": "^2.0.7", - "@cacheable/utils": "^2.3.3", + "@cacheable/memory": "^2.0.8", + "@cacheable/utils": "^2.4.1", "hookified": "^1.15.0", - "keyv": "^5.5.5", - "qified": "^0.6.0" + "keyv": "^5.6.0", + "qified": "^0.10.1" } }, "node_modules/cacheable/node_modules/keyv": { @@ -4899,16 +5880,11 @@ "@keyv/serialize": "^1.1.1" } }, - "node_modules/cached-path-relative": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz", - "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==", - "license": "MIT" - }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -5019,42 +5995,6 @@ "node": ">=10" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/ci-info": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", @@ -5071,20 +6011,6 @@ "node": ">=8" } }, - "node_modules/cipher-base": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", - "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.2" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/cjs-module-lexer": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", @@ -5092,21 +6018,6 @@ "dev": true, "license": "MIT" }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "license": "MIT", - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", @@ -5202,11 +6113,13 @@ "node": ">= 0.12.0" } }, - "node_modules/codemirror": { - "version": "5.65.21", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.21.tgz", - "integrity": "sha512-6teYk0bA0nR3QP0ihGMoxuKzpl5W80FpnHpBJpgy66NK3cZv5b/d/HY8PnRvfSsCG1MTfr92u2WUl+wT0E40mQ==", - "license": "MIT" + "node_modules/codemirror-5-themes": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/codemirror-5-themes/-/codemirror-5-themes-1.5.2.tgz", + "integrity": "sha512-4kxGXgmGRqlwNlM+Lpq+/qWgrfkx11PmDO4tUZKoEy6RB8+xVjSeHi+YbTl2Prl7Yru6Znezs9w9GhbouXoFvQ==", + "dependencies": { + "@codemirror/view": "^6.41.1" + } }, "node_modules/collect-v8-coverage": { "version": "1.0.3", @@ -5215,19 +6128,6 @@ "dev": true, "license": "MIT" }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", - "license": "MIT", - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -5253,33 +6153,6 @@ "dev": true, "license": "MIT" }, - "node_modules/combine-source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", - "integrity": "sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==", - "license": "MIT", - "dependencies": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.6.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.5.3" - } - }, - "node_modules/combine-source-map/node_modules/convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", - "license": "MIT" - }, - "node_modules/combine-source-map/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -5305,32 +6178,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "dev": true, "license": "MIT" }, "node_modules/content-disposition": { @@ -5396,30 +6244,24 @@ "license": "MIT" }, "node_modules/copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", "license": "MIT", "dependencies": { - "is-what": "^3.14.1" + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" }, "funding": { "url": "https://github.com/sponsors/mesqueeb" } }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/core-js": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", - "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -5440,12 +6282,6 @@ "url": "https://opencollective.com/core-js" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, "node_modules/cors": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", @@ -5464,9 +6300,9 @@ } }, "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5490,49 +6326,6 @@ } } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "license": "MIT" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, "node_modules/create-react-class": { "version": "15.7.0", "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", @@ -5543,6 +6336,12 @@ "object-assign": "^4.1.1" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -5557,32 +6356,6 @@ "node": ">= 8" } }, - "node_modules/crypto-browserify": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", - "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", - "license": "MIT", - "dependencies": { - "browserify-cipher": "^1.0.1", - "browserify-sign": "^4.2.3", - "create-ecdh": "^4.0.4", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "diffie-hellman": "^5.0.3", - "hash-base": "~3.0.4", - "inherits": "^2.0.4", - "pbkdf2": "^3.1.2", - "public-encrypt": "^4.0.3", - "randombytes": "^2.1.0", - "randomfill": "^1.0.4" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/css-functions-list": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.3.3.tgz", @@ -5594,14 +6367,14 @@ } }, "node_modules/css-tree": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", - "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dev": true, "license": "MIT", "dependencies": { - "mdn-data": "2.12.2", - "source-map-js": "^1.0.1" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" @@ -5646,12 +6419,6 @@ "node": "20 || >=22" } }, - "node_modules/dash-ast": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", - "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", - "license": "Apache-2.0" - }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -5753,15 +6520,6 @@ "dev": true, "license": "MIT" }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, "node_modules/dedent": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", @@ -5797,6 +6555,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -5814,6 +6573,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -5827,27 +6587,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "license": "MIT", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -5866,41 +6605,6 @@ "node": ">= 0.8" } }, - "node_modules/deps-sort": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", - "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", - "license": "MIT", - "dependencies": { - "JSONStream": "^1.0.3", - "shasum-object": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^2.0.0" - }, - "bin": { - "deps-sort": "bin/cmd.js" - } - }, - "node_modules/deps-sort/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -5911,23 +6615,6 @@ "node": ">=8" } }, - "node_modules/detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "license": "MIT", - "dependencies": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "detective": "bin/detective.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/dezalgo": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", @@ -5938,36 +6625,6 @@ "wrappy": "1" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "license": "MIT" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -5981,16 +6638,6 @@ "node": ">=0.10.0" } }, - "node_modules/domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "license": "MIT", - "engines": { - "node": ">=0.4", - "npm": ">=1.2" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -6005,15 +6652,6 @@ "node": ">= 0.4" } }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "license": "BSD-3-Clause", - "dependencies": { - "readable-stream": "^2.0.2" - } - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -6041,27 +6679,6 @@ "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "license": "ISC" }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "license": "MIT" - }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -6309,6 +6926,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -6338,32 +6996,28 @@ } }, "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.7.0.tgz", + "integrity": "sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.7.0", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", + "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -6373,11 +7027,15 @@ "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "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", - "optionator": "^0.9.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" @@ -6387,20 +7045,12 @@ }, "funding": { "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } } }, "node_modules/eslint-plugin-jest": { - "version": "29.15.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.0.tgz", - "integrity": "sha512-ZCGr7vTH2WSo2hrK5oM2RULFmMruQ7W3cX7YfwoTiPfzTGTFBMmrVIz45jZHd++cGKj/kWf02li/RhTGcANJSA==", + "version": "29.15.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.2.tgz", + "integrity": "sha512-kEN4r9RZl1xcsb4arGq89LrcVdOUFII/JSCwtTPJyv16mDwmPrcuEQwpxqZHeINvcsd7oK5O/rhdGlxFRaZwvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6413,7 +7063,7 @@ "@typescript-eslint/eslint-plugin": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "jest": "*", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <7.0.0" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -6514,6 +7164,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/eslint/node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -6563,6 +7223,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", @@ -6649,25 +7322,6 @@ "node": ">= 0.6" } }, - "node_modules/events": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", - "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", - "license": "MIT", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -6709,52 +7363,19 @@ "node": ">= 0.8.0" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", - "license": "MIT", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, "node_modules/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.1.tgz", + "integrity": "sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.2.0", + "@jest/expect-utils": "30.4.1", "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-util": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -6816,9 +7437,9 @@ "license": "MIT" }, "node_modules/express-static-gzip": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/express-static-gzip/-/express-static-gzip-3.0.0.tgz", - "integrity": "sha512-36O10S0asHl3QojOBQQ0ZjXNtElmhgPS6erSUCCZymXkB/CK1mnGqOj4BTJN+FYRDIzVFnzo3wLFCZJvAk6rQQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/express-static-gzip/-/express-static-gzip-3.0.1.tgz", + "integrity": "sha512-LMeU/3YjFlFUa4vrPX+RoMMRW5mIpF4Iysgs6gX7A59WCY4BzyF3O28mBr4eMlWuW4DU9wVAVuVcfx29ln1N6g==", "license": "MIT", "dependencies": { "mime-types": "^3.0.1", @@ -6841,62 +7462,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "license": "MIT", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "license": "MIT", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7043,17 +7608,11 @@ "node": ">=16.0.0" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT", - "optional": true - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -7112,9 +7671,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -7122,6 +7681,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -7133,15 +7693,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -7233,18 +7784,6 @@ "node": ">= 0.6" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", - "license": "MIT", - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", @@ -7255,9 +7794,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", - "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -7272,6 +7811,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -7376,12 +7916,6 @@ "node": ">=6.9.0" } }, - "node_modules/get-assigned-identifiers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", - "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", - "license": "Apache-2.0" - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -7391,6 +7925,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -7469,15 +8016,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", @@ -7621,21 +8159,57 @@ } }, "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.0.tgz", + "integrity": "sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" }, "engines": { - "node": ">=10" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/globby/node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7722,15 +8296,6 @@ "node": ">=18" } }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -7758,6 +8323,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -7809,106 +8375,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", - "license": "MIT", - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", - "license": "MIT", - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "license": "MIT", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hash-base": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", - "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/hash-wasm": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz", "integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==", "license": "MIT" }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hashery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.0.tgz", - "integrity": "sha512-nhQ6ExaOIqti2FDWoEMWARUqIKyjr2VcZzXShrI+A3zpeiuPWzx6iPftt44LhP74E5sW36B75N6VHbvRtpvO6Q==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", "dev": true, "license": "MIT", "dependencies": { - "hookified": "^1.14.0" + "hookified": "^1.15.0" }, "engines": { "node": ">=20" @@ -7926,17 +8406,6 @@ "node": ">= 0.4" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/hookified": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", @@ -7965,27 +8434,18 @@ "license": "MIT" }, "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-5.1.0.tgz", + "integrity": "sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=20.10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/htmlescape": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", - "integrity": "sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", @@ -8020,12 +8480,6 @@ "node": ">= 14" } }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "license": "MIT" - }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -8071,26 +8525,6 @@ "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", "license": "Apache-2.0" }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -8101,12 +8535,6 @@ "node": ">= 4" } }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "license": "ISC" - }, "node_modules/image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", @@ -8167,6 +8595,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -8182,6 +8621,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -8203,55 +8643,6 @@ "node": ">=10" } }, - "node_modules/inline-source-map": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.3.tgz", - "integrity": "sha512-1aVsPEsJWMJq/pdMU61CDlm1URcW702MTB4w9/zUjMus6H/Py8o7g68Pr9D4I6QluWGt/KdmswuRhaA05xVR1w==", - "license": "MIT", - "dependencies": { - "source-map": "~0.5.3" - } - }, - "node_modules/inline-source-map/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/insert-module-globals": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", - "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", - "license": "MIT", - "dependencies": { - "acorn-node": "^1.5.2", - "combine-source-map": "^0.8.0", - "concat-stream": "^1.6.1", - "is-buffer": "^1.1.0", - "JSONStream": "^1.0.3", - "path-is-absolute": "^1.0.1", - "process": "~0.11.0", - "through2": "^2.0.0", - "undeclared-identifiers": "^1.1.2", - "xtend": "^4.0.0" - }, - "bin": { - "insert-module-globals": "bin/cmd.js" - } - }, - "node_modules/insert-module-globals/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -8276,18 +8667,6 @@ "node": ">= 0.10" } }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", - "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -8349,18 +8728,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-boolean-object": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", @@ -8378,16 +8745,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "license": "MIT" - }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8411,18 +8773,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", - "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/is-data-view": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", @@ -8458,32 +8808,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8548,6 +8877,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -8586,6 +8916,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -8608,14 +8939,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/is-potential-custom-element-name": { @@ -8731,6 +9062,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -8789,24 +9121,22 @@ } }, "node_modules/is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "license": "MIT" - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" } }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -8815,15 +9145,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -8942,16 +9263,16 @@ } }, "node_modules/jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", - "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.4.2.tgz", + "integrity": "sha512-Yi1jqNC/Oq0N4hBgNH/YvBpP1P57QqundgytzYqy3yqAa7NZPNjSoi4SGbRAXDMdBzNE6xBCi5U7RgfrvMEUVQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.2.0", - "@jest/types": "30.2.0", + "@jest/core": "30.4.2", + "@jest/types": "30.4.1", "import-local": "^3.2.0", - "jest-cli": "30.2.0" + "jest-cli": "30.4.2" }, "bin": { "jest": "bin/jest.js" @@ -8969,14 +9290,14 @@ } }, "node_modules/jest-changed-files": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", - "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.4.1.tgz", + "integrity": "sha512-IuctmYrxi21iOSOaIXpJWalHyPAsVv0GeBHKDn8C1CA4W5htHn7INL+wdnL4Bo0+olEndvAFkmb++tIQJG+vvg==", "dev": true, "license": "MIT", "dependencies": { "execa": "^5.1.1", - "jest-util": "30.2.0", + "jest-util": "30.4.1", "p-limit": "^3.1.0" }, "engines": { @@ -8984,29 +9305,29 @@ } }, "node_modules/jest-circus": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", - "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.4.2.tgz", + "integrity": "sha512-rvHH7VlY6LgbJXJTQ87GW62g1FntOtbhh0zT+v04kC+pgL6aBKyYINXxWukCpj3dcIBMw5/XUbtDS9dU9JTXeQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/expect": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", + "@jest/environment": "30.4.1", + "@jest/expect": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", "chalk": "^4.1.2", "co": "^4.6.0", "dedent": "^1.6.0", "is-generator-fn": "^2.1.0", - "jest-each": "30.2.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-runtime": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", + "jest-each": "30.4.1", + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-runtime": "30.4.2", + "jest-snapshot": "30.4.1", + "jest-util": "30.4.1", "p-limit": "^3.1.0", - "pretty-format": "30.2.0", + "pretty-format": "30.4.1", "pure-rand": "^7.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" @@ -9016,21 +9337,21 @@ } }, "node_modules/jest-cli": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", - "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.4.2.tgz", + "integrity": "sha512-jfA2ocvVHMXS2QijrJ0d31ektP+d/W0T5RpcTX2Pq+3sVqHlsXVCM2+FmwpL+bdY8OfHpIg9xMxLF17Zg0U49Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", + "@jest/core": "30.4.2", + "@jest/test-result": "30.4.1", + "@jest/types": "30.4.1", "chalk": "^4.1.2", "exit-x": "^0.2.2", "import-local": "^3.2.0", - "jest-config": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", + "jest-config": "30.4.2", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", "yargs": "^17.7.2" }, "bin": { @@ -9049,34 +9370,33 @@ } }, "node_modules/jest-config": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", - "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.4.2.tgz", + "integrity": "sha512-rNHAShJQqQwFNoL0hbf3BphSBOWnpOUAKvidLS/AjNVLPfoj5mSf4jQMfW3cYOs6hXeZC7nF7mDHaBnbxELOzg==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", "@jest/get-type": "30.1.0", - "@jest/pattern": "30.0.1", - "@jest/test-sequencer": "30.2.0", - "@jest/types": "30.2.0", - "babel-jest": "30.2.0", + "@jest/pattern": "30.4.0", + "@jest/test-sequencer": "30.4.1", + "@jest/types": "30.4.1", + "babel-jest": "30.4.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "deepmerge": "^4.3.1", - "glob": "^10.3.10", + "glob": "^10.5.0", "graceful-fs": "^4.2.11", - "jest-circus": "30.2.0", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-runner": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "micromatch": "^4.0.8", + "jest-circus": "30.4.2", + "jest-docblock": "30.4.0", + "jest-environment-node": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.1", + "jest-runner": "30.4.2", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", "parse-json": "^5.2.0", - "pretty-format": "30.2.0", + "pretty-format": "30.4.1", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -9101,25 +9421,25 @@ } }, "node_modules/jest-diff": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", - "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", + "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/diff-sequences": "30.0.1", + "@jest/diff-sequences": "30.4.0", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "pretty-format": "30.2.0" + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-docblock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", - "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.4.0.tgz", + "integrity": "sha512-ZPMabUZCx5MpbZ2eBYSvZ0J8fvo3dR9oM+eeUpb3aKNQFuS2tu3Duw1TNlMoP8k3WQgKGJuhcMFvwcVuq6T7oA==", "dev": true, "license": "MIT", "dependencies": { @@ -9130,36 +9450,36 @@ } }, "node_modules/jest-each": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", - "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.4.1.tgz", + "integrity": "sha512-/8MJbH6fuj48TstjrMf+u/pd06Qezz5xOXvZA6442heNOWr8bdeoGZX2d9fCn028CoMgYmroH9//zky5GfyYmA==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", - "@jest/types": "30.2.0", + "@jest/types": "30.4.1", "chalk": "^4.1.2", - "jest-util": "30.2.0", - "pretty-format": "30.2.0" + "jest-util": "30.4.1", + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-environment-node": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", - "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.4.1.tgz", + "integrity": "sha512-4FZYVOk85hz2AyT6BbarKy9u37g6DbrDyCdFhsnDdXqyrueYQvB+0zO4f/kqLCRD0BsPRXPMNJeQwihKZV8naw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", + "@jest/environment": "30.4.1", + "@jest/fake-timers": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", - "jest-mock": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0" + "jest-mock": "30.4.1", + "jest-util": "30.4.1", + "jest-validate": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -9173,21 +9493,21 @@ "license": "MIT" }, "node_modules/jest-haste-map": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", - "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.4.1.tgz", + "integrity": "sha512-rFrcONd8jeFsyw+Z9CrScJgglRf2+NFmNam8dKu7n+SoHqNYT47mn0DdEcVUZJpvh7Iz6/si7f7yUH7GJHVgnw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", + "@jest/types": "30.4.1", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", - "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "jest-worker": "30.2.0", - "micromatch": "^4.0.8", + "jest-regex-util": "30.4.0", + "jest-util": "30.4.1", + "jest-worker": "30.4.1", + "picomatch": "^4.0.3", "walker": "^1.0.8" }, "engines": { @@ -9197,50 +9517,64 @@ "fsevents": "^2.3.3" } }, + "node_modules/jest-haste-map/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-leak-detector": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", - "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.4.1.tgz", + "integrity": "sha512-IpmyiioeHxiWDhesHnUFmOxcTzwCwKpgACgWajtAP+nYQXiY7DakTxB6Bx9JFiRMljr0AX1PvnQdaU1KFoz6NQ==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", - "pretty-format": "30.2.0" + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", - "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.1.tgz", + "integrity": "sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "jest-diff": "30.2.0", - "pretty-format": "30.2.0" + "jest-diff": "30.4.1", + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-message-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", - "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.1.tgz", + "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.2.0", + "@jest/types": "30.4.1", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", + "jest-util": "30.4.1", + "picomatch": "^4.0.3", + "pretty-format": "30.4.1", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -9248,16 +9582,29 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-message-util/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-mock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", - "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.1.tgz", + "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", + "@jest/types": "30.4.1", "@types/node": "*", - "jest-util": "30.2.0" + "jest-util": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -9282,9 +9629,9 @@ } }, "node_modules/jest-regex-util": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", - "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", + "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", "dev": true, "license": "MIT", "engines": { @@ -9292,18 +9639,18 @@ } }, "node_modules/jest-resolve": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", - "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.4.1.tgz", + "integrity": "sha512-Zry8Yq/yJcNAZ7dJ5F2heic8AheXvbFZ7XI5V+h28nrYZ7Qoyy4dItq8OodjnYD270mvX+ZudmrNV9cysqhW5Q==", "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", + "jest-haste-map": "30.4.1", "jest-pnp-resolver": "^1.2.3", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", "slash": "^3.0.0", "unrs-resolver": "^1.7.11" }, @@ -9312,46 +9659,46 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", - "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.4.2.tgz", + "integrity": "sha512-gDiVh1I+GxYzz9oXlyw+1wv6VOYX1WYxMOfjsA3iGKePV2oxmbHhwxfkALxNxYy1ciw6APWwkW2zZONwP97aEQ==", "dev": true, "license": "MIT", "dependencies": { - "jest-regex-util": "30.0.1", - "jest-snapshot": "30.2.0" + "jest-regex-util": "30.4.0", + "jest-snapshot": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-runner": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", - "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.4.2.tgz", + "integrity": "sha512-2dw0PslVYXxffXGpLo+Ejad+KcI1Qkjn7f4X4619gf21oCUmL+SPfjqIa/losUem3yEOvfNZe/F1HWUcNpODcg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.2.0", - "@jest/environment": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", + "@jest/console": "30.4.1", + "@jest/environment": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", "chalk": "^4.1.2", "emittery": "^0.13.1", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.2.0", - "jest-haste-map": "30.2.0", - "jest-leak-detector": "30.2.0", - "jest-message-util": "30.2.0", - "jest-resolve": "30.2.0", - "jest-runtime": "30.2.0", - "jest-util": "30.2.0", - "jest-watcher": "30.2.0", - "jest-worker": "30.2.0", + "jest-docblock": "30.4.0", + "jest-environment-node": "30.4.1", + "jest-haste-map": "30.4.1", + "jest-leak-detector": "30.4.1", + "jest-message-util": "30.4.1", + "jest-resolve": "30.4.1", + "jest-runtime": "30.4.2", + "jest-util": "30.4.1", + "jest-watcher": "30.4.1", + "jest-worker": "30.4.1", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -9360,32 +9707,32 @@ } }, "node_modules/jest-runtime": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", - "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.4.2.tgz", + "integrity": "sha512-3/5e8iPz2k/VLqlr8DgTftYyLUv8Su3FkCAO2/Od81UsUTpSxOrS6O5x5KkoQwyUjmpYyDJKeyAvg2T2nvpNkQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/fake-timers": "30.2.0", - "@jest/globals": "30.2.0", + "@jest/environment": "30.4.1", + "@jest/fake-timers": "30.4.1", + "@jest/globals": "30.4.1", "@jest/source-map": "30.0.1", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", "chalk": "^4.1.2", "cjs-module-lexer": "^2.1.0", "collect-v8-coverage": "^1.0.2", - "glob": "^10.3.10", + "glob": "^10.5.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", + "jest-haste-map": "30.4.1", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.1", + "jest-snapshot": "30.4.1", + "jest-util": "30.4.1", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -9394,9 +9741,9 @@ } }, "node_modules/jest-snapshot": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", - "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.4.1.tgz", + "integrity": "sha512-tEOkkfOMppUyeiHwjZswOQ3lcnoTnws/q5FnGIaeIh/jmoU0ZlgMYRR8sTlTj+nNGCoJ0RDq6SfxGxCsyMTPmw==", "dev": true, "license": "MIT", "dependencies": { @@ -9405,20 +9752,20 @@ "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", - "@jest/expect-utils": "30.2.0", + "@jest/expect-utils": "30.4.1", "@jest/get-type": "30.1.0", - "@jest/snapshot-utils": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", + "@jest/snapshot-utils": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", - "expect": "30.2.0", + "expect": "30.4.1", "graceful-fs": "^4.2.11", - "jest-diff": "30.2.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "pretty-format": "30.2.0", + "jest-diff": "30.4.1", + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-util": "30.4.1", + "pretty-format": "30.4.1", "semver": "^7.7.2", "synckit": "^0.11.8" }, @@ -9427,9 +9774,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -9440,27 +9787,27 @@ } }, "node_modules/jest-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", - "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.1.tgz", + "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", + "@jest/types": "30.4.1", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", - "picomatch": "^4.0.2" + "picomatch": "^4.0.3" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-util/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -9471,18 +9818,18 @@ } }, "node_modules/jest-validate": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", - "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.4.1.tgz", + "integrity": "sha512-PDWi4SOwLnwqNDfHZjOcsEFyZ4fc/2W2gVL3DEoyqnB6jCQMLRtfBong8s6omIw3lI0HWOus12xfnFmQtjW3fw==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", - "@jest/types": "30.2.0", + "@jest/types": "30.4.1", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", - "pretty-format": "30.2.0" + "pretty-format": "30.4.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -9502,19 +9849,19 @@ } }, "node_modules/jest-watcher": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", - "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.4.1.tgz", + "integrity": "sha512-/l9UonmvCwjHH7d2h3iAwIloLc1H0S8mJZ/LNK3i86hqwPAz8otUJjP9MfYtz9Tt77Su5FD2xGjZn8d31IZHlw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", + "@jest/test-result": "30.4.1", + "@jest/types": "30.4.1", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "emittery": "^0.13.1", - "jest-util": "30.2.0", + "jest-util": "30.4.1", "string-length": "^4.0.2" }, "engines": { @@ -9522,15 +9869,15 @@ } }, "node_modules/jest-worker": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", - "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.4.1.tgz", + "integrity": "sha512-SHynN/q/QD++iNyvMdy+WMmbCGk8jIsNcRxycXbWubSOhvo6T+j2afcfUSl+3hYsiBebOTo0cT7c2H7CXugu1g==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.2.0", + "jest-util": "30.4.1", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" }, @@ -9665,15 +10012,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-stable-stringify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", - "integrity": "sha512-nKtD/Qxm7tWdZqJoldEC7fF0S41v0mWbeaXG3637stOWfyGxTgWTYE2wtfKmjzpvxv2MA2xzxsXOIiwUpkX6Qw==", - "license": "MIT", - "dependencies": { - "jsonify": "~0.0.0" - } - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -9705,40 +10043,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", - "license": "Public Domain", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "engines": [ - "node >= 0.2.0" - ], - "license": "MIT" - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "license": "(MIT OR Apache-2.0)", - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -9786,9 +10090,9 @@ } }, "node_modules/kareem": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-3.2.0.tgz", - "integrity": "sha512-VS8MWZz/cT+SqBCpVfNN4zoVz5VskR3N4+sTmUXme55e9avQHntpwpNq0yjnosISXqwJ3AQVjlbI4Dyzv//JtA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-3.3.0.tgz", + "integrity": "sha512-kpSuLD3/7RenBnjnJdOHXCKC8dTd1JzeOiJhN0necWWci6cC+qX+VuwPnMVgb+a4+KNJSfgqahpnfWaeDXCimw==", "license": "Apache-2.0", "engines": { "node": ">=18.0.0" @@ -9808,42 +10112,26 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/known-css-properties": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.37.0.tgz", - "integrity": "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/labeled-stream-splicer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", - "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "stream-splicer": "^2.0.0" - } - }, "node_modules/less": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/less/-/less-3.13.1.tgz", - "integrity": "sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/less/-/less-4.6.4.tgz", + "integrity": "sha512-OJmO5+HxZLLw0RLzkqaNHzcgEAQG7C0y3aMbwtCzIUFZsLMNNq/1IdAdHEycQ58CwUO3jPTHmoN+tE5I7FQxNg==", "license": "Apache-2.0", "dependencies": { - "copy-anything": "^2.0.1", - "tslib": "^1.10.0" + "copy-anything": "^3.0.5", + "parse-node-version": "^1.0.1" }, "bin": { "lessc": "bin/lessc" }, "engines": { - "node": ">=6" + "node": ">=18" }, "optionalDependencies": { "errno": "^0.1.1", @@ -9851,7 +10139,7 @@ "image-size": "~0.5.0", "make-dir": "^2.1.0", "mime": "^1.4.1", - "native-request": "^1.0.5", + "needle": "^3.1.0", "source-map": "~0.6.0" } }, @@ -9879,12 +10167,6 @@ "semver": "bin/semver" } }, - "node_modules/less/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -9916,30 +10198,6 @@ "dev": true, "license": "MIT" }, - "node_modules/livereload": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz", - "integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==", - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.0", - "livereload-js": "^3.3.1", - "opts": ">= 1.2.0", - "ws": "^7.4.3" - }, - "bin": { - "livereload": "bin/livereload.js" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/livereload-js": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.4.1.tgz", - "integrity": "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==", - "license": "MIT" - }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -9954,9 +10212,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -9965,12 +10223,6 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, - "node_modules/lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -10023,9 +10275,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -10045,27 +10297,6 @@ "tmpl": "1.0.5" } }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", - "license": "MIT", - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/marked": { "version": "15.0.12", "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", @@ -10190,9 +10421,9 @@ } }, "node_modules/mathml-tag-names": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", - "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-4.0.0.tgz", + "integrity": "sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ==", "dev": true, "license": "MIT", "funding": { @@ -10200,21 +10431,10 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "node_modules/mdn-data": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", - "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "dev": true, "license": "CC0-1.0" }, @@ -10234,13 +10454,13 @@ "license": "MIT" }, "node_modules/meow": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", - "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-14.1.0.tgz", + "integrity": "sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -10298,25 +10518,6 @@ "node": ">=8.6" } }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "license": "MIT" - }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -10365,22 +10566,11 @@ "node": ">=6" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "license": "MIT" - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -10389,15 +10579,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minipass": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", @@ -10407,88 +10588,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "license": "MIT", - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT" - }, - "node_modules/module-deps": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", - "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", - "license": "MIT", - "dependencies": { - "browser-resolve": "^2.0.0", - "cached-path-relative": "^1.0.2", - "concat-stream": "~1.6.0", - "defined": "^1.0.0", - "detective": "^5.2.0", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "JSONStream": "^1.0.3", - "parents": "^1.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.4.0", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "bin": { - "module-deps": "bin/cmd.js" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/module-deps/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -10546,13 +10645,13 @@ } }, "node_modules/mongoose": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.2.1.tgz", - "integrity": "sha512-fmNLwgct5km7iL1MqvTMncarR1E1TIw2lmc9A4UoDVdS7AQe95K+DnRK0qATkSUdwUC9V/5wlDcqnkQQjbSRkA==", + "version": "9.6.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.6.3.tgz", + "integrity": "sha512-vI6dTTlQnfMCyyQ5TrvhG0bCRs4dq5e1uFNPtOOWsOhn0fSg8AoIHjfyyCYr8aybyvPs845dRHGxsC3w/fHcBA==", "license": "MIT", "dependencies": { - "kareem": "3.2.0", - "mongodb": "~7.0", + "kareem": "3.3.0", + "mongodb": "~7.2", "mpath": "0.9.0", "mquery": "6.0.0", "ms": "2.1.3", @@ -10583,13 +10682,13 @@ } }, "node_modules/mongoose/node_modules/mongodb": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.0.0.tgz", - "integrity": "sha512-vG/A5cQrvGGvZm2mTnCSz1LUcbOPl83hfB6bxULKQ8oFZauyox/2xbZOoGNl+64m8VBrETkdGCDBdOsCr3F3jg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.2.0.tgz", + "integrity": "sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw==", "license": "Apache-2.0", "dependencies": { "@mongodb-js/saslprep": "^1.3.0", - "bson": "^7.0.0", + "bson": "^7.2.0", "mongodb-connection-string-url": "^7.0.0" }, "engines": { @@ -10652,17 +10751,10 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/nan": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.25.0.tgz", - "integrity": "sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==", - "license": "MIT", - "optional": true - }, "node_modules/nanoid": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", - "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.11.tgz", + "integrity": "sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==", "funding": [ { "type": "github", @@ -10677,91 +10769,6 @@ "node": "^18 || >=20" } }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "license": "MIT", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/nanomatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/napi-postinstall": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", @@ -10778,13 +10785,6 @@ "url": "https://opencollective.com/napi-postinstall" } }, - "node_modules/native-request": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.1.2.tgz", - "integrity": "sha512-/etjwrK0J4Ebbcnt35VMWnfiUX/B04uwGJxyJInagxDqf2z5drSt/lsOvEMWGYunz1kaLZAFrV4NDAbOoDKvAQ==", - "license": "MIT", - "optional": true - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -10903,6 +10903,36 @@ "node": ">=10" } }, + "node_modules/needle": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.5.0.tgz", + "integrity": "sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -10912,6 +10942,28 @@ "node": ">= 0.6" } }, + "node_modules/node": { + "version": "25.9.0", + "resolved": "https://registry.npmjs.org/node/-/node-25.9.0.tgz", + "integrity": "sha512-tfIfIRJVc32gUI+cQrxwAGWLwTy/EENnB3vF95RuAFosqBGjMTY+o0/3T4oPOipUFrsebQ5WDMsRyAqn65RMFQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-bin-setup": "^1.0.0" + }, + "bin": { + "node": "bin/node" + }, + "engines": { + "npm": ">=5.0.0" + } + }, + "node_modules/node-bin-setup": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.4.tgz", + "integrity": "sha512-vWNHOne0ZUavArqPP5LJta50+S8R261Fr5SvGul37HbEDcowvLjwdvd0ZeSr0r2lTSrPxl6okq9QUw8BFGiAxA==", + "license": "ISC" + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -10982,77 +11034,11 @@ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "license": "MIT" }, - "node_modules/nodemon": { - "version": "2.0.22", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", - "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11080,32 +11066,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", - "license": "MIT", - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -11122,27 +11082,17 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object.assign": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -11194,18 +11144,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object.values": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", @@ -11280,27 +11218,6 @@ "node": ">= 0.8.0" } }, - "node_modules/opts": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz", - "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==", - "license": "BSD-2-Clause" - }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", - "license": "MIT" - }, - "node_modules/outpipe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz", - "integrity": "sha512-BnNY/RwnDrkmQdUa9U+OfN/Y7AWmKuUPCCd+hbRclZnnANvYpO72zp/a6Q4n829hPbdqEac31XCcsvlEvb+rtA==", - "license": "MIT", - "dependencies": { - "shell-quote": "^1.4.2" - } - }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -11380,12 +11297,6 @@ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -11399,31 +11310,6 @@ "node": ">=6" } }, - "node_modules/parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==", - "license": "MIT", - "dependencies": { - "path-platform": "~0.11.15" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", - "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", - "license": "ISC", - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "pbkdf2": "^3.1.5", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -11443,6 +11329,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", @@ -11465,27 +11360,6 @@ "node": ">= 0.8" } }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "license": "MIT" - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", - "license": "MIT" - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -11500,6 +11374,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11520,15 +11395,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, - "node_modules/path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -11561,33 +11427,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", - "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", - "license": "MIT", - "dependencies": { - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "ripemd160": "^2.0.3", - "safe-buffer": "^5.2.1", - "sha.js": "^2.4.12", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -11598,6 +11437,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -11639,29 +11479,20 @@ "node": ">=8" } }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -11678,7 +11509,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -11699,13 +11530,6 @@ "postcss": "^8.3.5" } }, - "node_modules/postcss-resolve-nested-selector": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz", - "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==", - "dev": true, - "license": "MIT" - }, "node_modules/postcss-safe-parser": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", @@ -11766,10 +11590,9 @@ "license": "MIT" }, "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", @@ -11795,15 +11618,16 @@ } }, "node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", + "@jest/schemas": "30.4.1", "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -11822,21 +11646,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -11874,32 +11683,6 @@ "license": "MIT", "optional": true }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "license": "MIT" - }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "license": "MIT" - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -11927,18 +11710,25 @@ "license": "MIT" }, "node_modules/qified": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/qified/-/qified-0.6.0.tgz", - "integrity": "sha512-tsSGN1x3h569ZSU1u6diwhltLyfUWDp3YbFHedapTmpBl0B3P6U3+Qptg7xu+v+1io1EwhdPyyRHYbEw0KN2FA==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", "dev": true, "license": "MIT", "dependencies": { - "hookified": "^1.14.0" + "hookified": "^2.1.1" }, "engines": { "node": ">=20" } }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "dev": true, + "license": "MIT" + }, "node_modules/qs": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", @@ -11954,14 +11744,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -11983,25 +11765,6 @@ ], "license": "MIT" }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "license": "MIT", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -12027,52 +11790,66 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.2.6" } }, "node_modules/react-frame-component": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-4.1.3.tgz", - "integrity": "sha512-4PurhctiqnmC1F5prPZ+LdsalH7pZ3SFA5xoc0HBe8mSHctdLLt4Cr2WXfXOoajHBYq/yiipp9zOgx+vy8GiEA==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-5.3.2.tgz", + "integrity": "sha512-ce0/9xAnnkLDY6zxnTegP3Yjchw5z9aEaz0qKEGecrdnh3nAnQ5kehO84sNeLj3wQPB5ZM0OoVVQDQilhaE/5Q==", "license": "MIT", "peerDependencies": { - "prop-types": "^15.5.9", - "react": ">= 16.3", - "react-dom": ">= 16.3" + "prop-types": "^15.8.1 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react": ">= 16.8 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": ">= 16.8 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/react-is": { + "node_modules/react-is-18": { + "name": "react-is", "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, + "node_modules/react-is-19": { + "name": "react-is", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", + "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-router": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", - "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.16.0.tgz", + "integrity": "sha512-wArC8lVyJb3+jM9OpDyW6hLCizACWkvQR/sSGqSs+o5uEXEtGlqdZ4v8hENR3Jad6i+LRkK93q/+bQAcvl6V1A==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -12104,63 +11881,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/read-only-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", - "integrity": "sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w==", - "license": "MIT", - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -12202,56 +11922,6 @@ "node": ">=4" } }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "license": "MIT", - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -12308,30 +11978,6 @@ "regjsparser": "bin/parser" } }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "license": "ISC" - }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -12394,22 +12040,6 @@ "node": ">=8" } }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "license": "MIT" - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "license": "MIT", - "engines": { - "node": ">=0.12" - } - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -12436,32 +12066,48 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ripemd160": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", - "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "node_modules/rollup": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", "license": "MIT", "dependencies": { - "hash-base": "^3.1.2", - "inherits": "^2.0.4" + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">= 0.8" - } - }, - "node_modules/ripemd160/node_modules/hash-base": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", - "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.1" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "engines": { - "node": ">= 0.8" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", + "fsevents": "~2.3.2" } }, "node_modules/romans": { @@ -12567,15 +12213,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", - "license": "MIT", - "dependencies": { - "ret": "~0.1.10" - } - }, "node_modules/safe-regex-test": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", @@ -12601,14 +12238,24 @@ "license": "MIT" }, "node_modules/sanitize-filename": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", - "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.4.tgz", + "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", "license": "WTFPL OR ISC", "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "optional": true, + "engines": { + "node": ">=11.0.0" + } + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", @@ -12623,13 +12270,10 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/secure-keys": { "version": "1.0.0", @@ -12701,6 +12345,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -12745,81 +12390,12 @@ "node": ">= 0.4" } }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "license": "MIT", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, - "node_modules/sha.js": { - "version": "2.4.12", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", - "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.0" - }, - "bin": { - "sha.js": "bin.js" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/shasum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", - "integrity": "sha512-UTzHm/+AzKfO9RgPgRpDIuMSNie1ubXRaljjlhFMNGYoG7z+rm9AHLPMf70R7887xboDH9Q+5YQbWKObFHEAtw==", - "license": "MIT", - "dependencies": { - "json-stable-stringify": "~0.0.0", - "sha.js": "~2.4.4" - } - }, - "node_modules/shasum-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.1.tgz", - "integrity": "sha512-SsC+1tW7XKQ/94D4k1JhLmjDFpVGET/Nf54jVDtbavbALf8Zhp0Td9zTlxScjMW6nbEIrpADtPWfLk9iCXzHDQ==", - "license": "Apache-2.0", - "dependencies": { - "fast-safe-stringify": "^2.0.7" - }, - "bin": { - "shasum-object": "bin.js" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -12841,18 +12417,6 @@ "node": ">=8" } }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -12943,47 +12507,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", - "license": "MIT", - "dependencies": { - "semver": "~7.0.0" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -13012,116 +12535,11 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "license": "MIT", - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "license": "MIT", - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "license": "MIT", - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -13131,26 +12549,11 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "license": "MIT", - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, "node_modules/source-map-support": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", @@ -13162,13 +12565,6 @@ "source-map": "^0.6.0" } }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", - "license": "MIT" - }, "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", @@ -13178,55 +12574,6 @@ "memory-pager": "^1.0.2" } }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "license": "MIT", - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -13257,19 +12604,6 @@ "node": ">=8" } }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", - "license": "MIT", - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -13293,71 +12627,6 @@ "node": ">= 0.4" } }, - "node_modules/stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "license": "MIT", - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "node_modules/stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", - "license": "MIT", - "dependencies": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - } - }, - "node_modules/stream-http": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", - "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", - "license": "MIT", - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "xtend": "^4.0.2" - } - }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", - "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -13622,6 +12891,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-mod": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", + "license": "MIT" + }, "node_modules/style-search": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", @@ -13630,9 +12905,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.26.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.26.1.tgz", - "integrity": "sha512-v20V59/crfc8sVTAtge0mdafI3AdnzQ2KsWe6v523L4OA1bJO02S7MO2oyXDCS6iWb9ckIPnqAFVItqSBQr7jw==", + "version": "17.12.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.12.0.tgz", + "integrity": "sha512-KIlzWXMHUvgfPUR0R7TK3H80yCIi0uoivUwf+6Az4yrHJD1Q3c1qIkh/H5Z0i/K3QXgtq/UMEkWyBUSUwnpnOg==", "dev": true, "funding": [ { @@ -13646,68 +12921,64 @@ ], "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-syntax-patches-for-csstree": "^1.0.19", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/media-query-list-parser": "^4.0.3", - "@csstools/selector-specificity": "^5.0.0", - "@dual-bundle/import-meta-resolve": "^4.2.1", - "balanced-match": "^2.0.0", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@csstools/css-tokenizer": "^4.0.0", + "@csstools/media-query-list-parser": "^5.0.0", + "@csstools/selector-resolve-nested": "^4.0.0", + "@csstools/selector-specificity": "^6.0.0", "colord": "^2.9.3", - "cosmiconfig": "^9.0.0", - "css-functions-list": "^3.2.3", - "css-tree": "^3.1.0", + "cosmiconfig": "^9.0.1", + "css-functions-list": "^3.3.3", + "css-tree": "^3.2.1", "debug": "^4.4.3", "fast-glob": "^3.3.3", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^11.1.1", + "file-entry-cache": "^11.1.3", "global-modules": "^2.0.0", - "globby": "^11.1.0", + "globby": "^16.2.0", "globjoin": "^0.1.4", - "html-tags": "^3.3.1", + "html-tags": "^5.1.0", "ignore": "^7.0.5", - "imurmurhash": "^0.1.4", - "is-plain-object": "^5.0.0", - "known-css-properties": "^0.37.0", - "mathml-tag-names": "^2.1.3", - "meow": "^13.2.0", + "import-meta-resolve": "^4.2.0", + "mathml-tag-names": "^4.0.0", + "meow": "^14.1.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "picocolors": "^1.1.1", - "postcss": "^8.5.6", - "postcss-resolve-nested-selector": "^0.1.6", + "postcss": "^8.5.14", "postcss-safe-parser": "^7.0.1", - "postcss-selector-parser": "^7.1.0", + "postcss-selector-parser": "^7.1.1", "postcss-value-parser": "^4.2.0", - "resolve-from": "^5.0.0", - "string-width": "^4.2.3", - "supports-hyperlinks": "^3.2.0", + "string-width": "^8.2.1", + "supports-hyperlinks": "^4.4.0", "svg-tags": "^1.0.0", "table": "^6.9.0", - "write-file-atomic": "^5.0.1" + "write-file-atomic": "^7.0.1" }, "bin": { "stylelint": "bin/stylelint.mjs" }, "engines": { - "node": ">=18.12.0" + "node": ">=20.19.0" } }, "node_modules/stylelint-config-recess-order": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-7.6.1.tgz", - "integrity": "sha512-ac0H/Iy2chh1YBADrua87G+nJCmG/SdG7gjnoLvtfpN0D+RuNfuADawfbCKvm0LMp5hvuRFNkJsu6xNoLM5ToA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-7.7.0.tgz", + "integrity": "sha512-TWRkg+BrwHOki4pi9y1emWgx6pFwZXOYZhNsbEObke/mzYUJVJvDEzJJQXhH7ajslQJGcrExy8ZvJqDiUbhFpA==", "dev": true, "license": "ISC", "peerDependencies": { "stylelint": "^16.18.0 || ^17.0.0", - "stylelint-order": "^7.0.0" + "stylelint-order": "^7.0.0 || ^8.0.0" } }, "node_modules/stylelint-config-recommended": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-17.0.0.tgz", - "integrity": "sha512-WaMSdEiPfZTSFVoYmJbxorJfA610O0tlYuU2aEwY33UQhSPgFbClrVJYWvy3jGJx+XW37O+LyNLiZOEXhKhJmA==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-18.0.0.tgz", + "integrity": "sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg==", "dev": true, "funding": [ { @@ -13721,10 +12992,10 @@ ], "license": "MIT", "engines": { - "node": ">=18.12.0" + "node": ">=20.19.0" }, "peerDependencies": { - "stylelint": "^16.23.0" + "stylelint": "^17.0.0" } }, "node_modules/stylelint-order": { @@ -13745,49 +13016,25 @@ "stylelint": "^16.18.0 || ^17.0.0" } }, - "node_modules/stylelint/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/stylelint/node_modules/balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "dev": true, - "license": "MIT" - }, - "node_modules/stylelint/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, "node_modules/stylelint/node_modules/file-entry-cache": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.2.tgz", - "integrity": "sha512-N2WFfK12gmrK1c1GXOqiAJ1tc5YE+R53zvQ+t5P8S5XhnmKYVB5eZEiLNZKDSmoG8wqqbF9EXYBBW/nef19log==", + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.3.tgz", + "integrity": "sha512-oMbq0PD6VIiIwMF6LIa7MEwd/l9huKwmqRKXqmrkqIZv8CvRbfowL+L0ryAl8h//HfAS0zS+4SbYoRyAoA6BJA==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^6.1.20" + "flat-cache": "^6.1.22" } }, "node_modules/stylelint/node_modules/flat-cache": { - "version": "6.1.20", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.20.tgz", - "integrity": "sha512-AhHYqwvN62NVLp4lObVXGVluiABTHapoB57EyegZVmazN+hhGhLTn3uZbOofoTw4DSDvVCadzzyChXhOAvy8uQ==", + "version": "6.1.22", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.22.tgz", + "integrity": "sha512-N2dnzVJIphnNsjHcrxGW7DePckJ6haPrSFqpsBUhHYgwtKGVq4JrBGielEGD2fCVnsGm1zlBVZ8wGhkyuetgug==", "dev": true, "license": "MIT", "dependencies": { - "cacheable": "^2.3.2", - "flatted": "^3.3.3", + "cacheable": "^2.3.4", + "flatted": "^3.4.2", "hookified": "^1.15.0" } }, @@ -13802,40 +13049,33 @@ } }, "node_modules/stylelint/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stylelint/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/stylelint/node_modules/write-file-atomic": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", + "integrity": "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-regex": "^5.0.1" + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", - "license": "MIT", - "dependencies": { - "minimist": "^1.1.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/superagent": { @@ -13909,22 +13149,48 @@ } }, "node_modules/supports-hyperlinks": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", - "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-4.4.0.tgz", + "integrity": "sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "has-flag": "^5.0.1", + "supports-color": "^10.2.2" }, "engines": { - "node": ">=14.18" + "node": ">=20" }, "funding": { "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-5.0.1.tgz", + "integrity": "sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -13951,13 +13217,13 @@ "license": "MIT" }, "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", "dev": true, "license": "MIT", "dependencies": { - "@pkgr/core": "^0.2.9" + "@pkgr/core": "^0.3.6" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -13966,15 +13232,6 @@ "url": "https://opencollective.com/synckit" } }, - "node_modules/syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "license": "MIT", - "dependencies": { - "acorn-node": "^1.2.0" - } - }, "node_modules/table": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", @@ -14098,38 +13355,17 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, "license": "MIT" }, - "node_modules/through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "node_modules/timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==", - "dependencies": { - "process": "~0.11.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -14146,7 +13382,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -14164,7 +13399,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -14200,63 +13434,11 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/to-buffer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", - "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", - "license": "MIT", - "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", - "license": "MIT", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "license": "MIT", - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -14265,69 +13447,6 @@ "node": ">=8.0" } }, - "node_modules/to-regex/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/to-regex/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -14337,15 +13456,6 @@ "node": ">=0.6" } }, - "node_modules/touch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", - "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", - "license": "ISC", - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, "node_modules/tough-cookie": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", @@ -14401,12 +13511,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "license": "MIT" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -14461,6 +13565,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -14534,12 +13639,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "license": "MIT" - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -14555,15 +13654,6 @@ "node": ">=14.17" } }, - "node_modules/umd": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", - "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", - "license": "MIT", - "bin": { - "umd": "bin/cli.js" - } - }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -14583,28 +13673,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/undeclared-identifiers": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", - "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", - "license": "Apache-2.0", - "dependencies": { - "acorn-node": "^1.3.0", - "dash-ast": "^1.0.0", - "get-assigned-identifiers": "^1.2.0", - "simple-concat": "^1.0.0", - "xtend": "^4.0.1" - }, - "bin": { - "undeclared-identifiers": "bin.js" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "license": "MIT" - }, "node_modules/undici": { "version": "7.22.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", @@ -14619,7 +13687,7 @@ "version": "7.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -14662,19 +13730,17 @@ "node": ">=4" } }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, "license": "MIT", - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/universalify": { @@ -14696,102 +13762,41 @@ } }, "node_modules/unrs-resolver": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", - "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "napi-postinstall": "^0.3.0" + "napi-postinstall": "^0.3.4" }, "funding": { "url": "https://opencollective.com/unrs-resolver" }, "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.11.1", - "@unrs/resolver-binding-android-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-x64": "1.11.1", - "@unrs/resolver-binding-freebsd-x64": "1.11.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-musl": "1.11.1", - "@unrs/resolver-binding-wasm32-wasi": "1.11.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" - } - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", - "license": "MIT", - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", - "license": "MIT", - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", - "license": "MIT", - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "license": "MIT", - "engines": { - "node": ">=4", - "yarn": "*" + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" } }, "node_modules/update-browserslist-db": { @@ -14834,74 +13839,25 @@ "punycode": "^2.1.0" } }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "license": "MIT" - }, - "node_modules/url": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", - "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", - "license": "MIT", - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.12.3" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==", "license": "BSD" }, - "node_modules/url/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "license": "MIT" - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/utf8-byte-length": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", "license": "(WTFPL OR MIT)" }, - "node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "license": "MIT", - "dependencies": { - "inherits": "2.0.3" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, "license": "MIT" }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "license": "ISC" - }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -14926,57 +13882,113 @@ "node": ">= 0.8" } }, - "node_modules/vitreum": { - "version": "6.0.4", - "resolved": "git+https://git@github.com/calculuschild/vitreum.git#929c351881c4229550374421c7e2890a94f4dca7", - "hasInstallScript": true, + "node_modules/vite": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.3.tgz", + "integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==", "license": "MIT", "dependencies": { - "browserify": "^16.5.0", - "fs-extra": "^9.0.1", - "livereload": "^0.9.1", - "nodemon": "^2.0.2", - "source-map-support": "^0.5.16", - "through2": "^3.0.1", - "watchify": "^3.11.1" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, - "peerDependencies": { - "@babel/core": "^7.9.0", - "@babel/preset-react": "^7.9.4", - "less": "^3.11.1", - "react": "^18.3.1", - "react-dom": "^18.3.1" - } - }, - "node_modules/vitreum/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/vitreum/node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", "license": "MIT" }, "node_modules/w3c-xmlserializer": { @@ -15002,314 +14014,6 @@ "makeerror": "1.0.12" } }, - "node_modules/watchify": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.11.1.tgz", - "integrity": "sha512-WwnUClyFNRMB2NIiHgJU9RQPQNqVeFk7OmZaWf5dC5EnNa0Mgr7imBydbaJ7tGTuPM2hz1Cb4uiBvK9NVxMfog==", - "license": "MIT", - "dependencies": { - "anymatch": "^2.0.0", - "browserify": "^16.1.0", - "chokidar": "^2.1.1", - "defined": "^1.0.0", - "outpipe": "^1.1.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "bin": { - "watchify": "bin/cmd.js" - } - }, - "node_modules/watchify/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "license": "ISC", - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/watchify/node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "license": "MIT", - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "license": "MIT", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "license": "MIT", - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "optionalDependencies": { - "fsevents": "^1.2.7" - } - }, - "node_modules/watchify/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "license": "MIT", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/watchify/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "license": "ISC", - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/watchify/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", - "license": "MIT", - "dependencies": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/watchify/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "license": "MIT", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "license": "MIT", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/micromatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchify/node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/watchify/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/watchify/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "license": "MIT", - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -15440,6 +14144,7 @@ "version": "1.1.20", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -15581,27 +14286,6 @@ "integrity": "sha512-LhQ68uUnzHH0bwm/QiGA9JwqgadSDOwqB2AIs/LBsrOY6ScqVXKRN2slTCeKAhstDBJ/Of/Yxcjn0pnQmVlmtg==", "license": "MIT" }, - "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -15619,15 +14303,6 @@ "dev": true, "license": "MIT" }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 7004ec51d..ffd9ac423 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,19 @@ { "name": "homebrewery", "description": "Create authentic looking D&D homebrews using only markdown", - "version": "3.20.1", + "version": "3.22.0", "type": "module", "engines": { - "npm": "^10.8.x", - "node": "^20.18.x" + "npm": ">=10.8 <12", + "node": ">=20.18 <25" }, "repository": { "type": "git", "url": "git://github.com/naturalcrit/homebrewery.git" }, "scripts": { - "dev": "node --experimental-require-module scripts/dev.js", - "quick": "node --experimental-require-module scripts/quick.js", - "build": "node --experimental-require-module scripts/buildHomebrew.js && node --experimental-require-module scripts/buildAdmin.js", - "builddev": "node --experimental-require-module scripts/buildHomebrew.js --dev", + "start": "node server.js", + "build": "vite build", "lint": "eslint --fix", "lint:dry": "eslint", "stylelint": "stylelint --fix **/*.{less}", @@ -44,7 +42,6 @@ "phb": "node --experimental-require-module scripts/phb.js", "prod": "set NODE_ENV=production && npm run build", "postinstall": "npm run build", - "start": "node --experimental-require-module server.js", "docker:build": "docker build -t ${DOCKERID}/homebrewery:$npm_package_version .", "docker:publish": "docker login && docker push ${DOCKERID}/homebrewery:$npm_package_version" }, @@ -61,7 +58,7 @@ "server" ], "transformIgnorePatterns": [ - "node_modules/(?!(nanoid|@exodus/bytes|parse5|@asamuzakjp|@csstools)/)" + "node_modules/(?!(nanoid|@exodus/bytes|parse5|@asamuzakjp|@csstools|entities)/)" ], "transform": { "^.+\\.[jt]s$": "babel-jest", @@ -91,32 +88,44 @@ "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-runtime": "^7.29.0", - "@babel/preset-env": "^7.29.0", + "@babel/preset-env": "^7.29.5", "@babel/preset-react": "^7.28.5", - "@babel/runtime": "^7.28.4", + "@babel/runtime": "^7.29.2", + "@codemirror/autocomplete": "^6.20.2", + "@codemirror/commands": "^6.10.3", + "@codemirror/highlight": "^0.19.8", + "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-javascript": "^6.2.5", + "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/language": "^6.12.2", + "@codemirror/language-data": "^6.5.2", + "@codemirror/search": "^6.6.0", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.43.0", "@dmsnell/diff-match-patch": "^1.1.0", "@googleapis/drive": "^20.1.0", + "@lezer/highlight": "^1.2.3", "@sanity/diff-match-patch": "^3.2.0", + "@vitejs/plugin-react": "^5.1.2", "body-parser": "^2.2.0", "classnames": "^2.5.1", - "codemirror": "^5.65.6", + "codemirror-5-themes": "^1.5.1", "cookie-parser": "^1.4.7", - "core-js": "^3.47.0", + "core-js": "^3.49.0", "cors": "^2.8.5", "create-react-class": "^15.7.0", "dedent": "^1.7.1", - "expr-eval": "^2.0.2", "express": "^5.1.0", "express-async-handler": "^1.2.0", - "express-static-gzip": "3.0.0", + "express-static-gzip": "3.0.1", "fflate": "^0.8.2", - "fs-extra": "^11.3.3", + "fs-extra": "^11.3.5", "hash-wasm": "^4.12.0", "idb-keyval": "^6.2.2", "js-yaml": "^4.1.1", "jwt-simple": "^0.5.6", - "less": "^3.13.1", - "lodash": "^4.17.21", + "less": "^4.6.4", + "lodash": "^4.18.1", "marked": "15.0.12", "marked-alignment-paragraphs": "^1.0.0", "marked-definition-lists": "^1.0.1", @@ -129,35 +138,34 @@ "marked-variables": "^1.0.5", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^9.2.1", - "nanoid": "5.1.6", + "mongoose": "^9.6.2", + "nanoid": "5.1.11", "nconf": "^0.13.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-frame-component": "^4.1.3", - "react-router": "^7.9.6", - "romans": "^3.1.0", - "sanitize-filename": "1.6.3", - "superagent": "^10.2.1", - "vitreum": "git+https://git@github.com/calculuschild/vitreum.git", - "written-number": "^0.11.1" + "node": "^25.9.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "react-frame-component": "^5.3.2", + "react-router": "^7.15.1", + "sanitize-filename": "1.6.4", + "superagent": "^10.2.1" }, "devDependencies": { - "@stylistic/stylelint-plugin": "^4.0.0", - "babel-jest": "^30.2.0", + "@stylistic/stylelint-plugin": "^5.0.1", + "babel-jest": "^30.4.1", "babel-plugin-transform-import-meta": "^2.3.3", - "eslint": "^9.39.1", - "eslint-plugin-jest": "^29.1.0", + "eslint": "9.7", + "eslint-plugin-jest": "^29.15.1", "eslint-plugin-react": "^7.37.5", "globals": "^16.4.0", - "jest": "^30.2.0", + "jest": "^30.4.2", "jest-expect-message": "^1.1.3", "jsdom": "^28.1.0", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.25.0", - "stylelint-config-recess-order": "^7.3.0", - "stylelint-config-recommended": "^17.0.0", - "supertest": "^7.1.4" + "stylelint": "^17.11.1", + "stylelint-config-recess-order": "^7.7.0", + "stylelint-config-recommended": "^18.0.0", + "supertest": "^7.1.4", + "vite": "^7.3.1" } } diff --git a/scripts/buildAdmin.js b/scripts/buildAdmin.js deleted file mode 100644 index 9c77315ef..000000000 --- a/scripts/buildAdmin.js +++ /dev/null @@ -1,32 +0,0 @@ - -import fs from 'fs-extra'; -import Proj from './project.json' with { type: 'json' }; -import vitreum from 'vitreum'; -const { pack } = vitreum; - -import lessTransform from 'vitreum/transforms/less.js'; -import assetTransform from 'vitreum/transforms/asset.js'; - -const isDev = !!process.argv.find((arg)=>arg=='--dev'); - -const transforms = { - '.less' : lessTransform, - '*' : assetTransform('./build') -}; - -const build = async ({ bundle, render, ssr })=>{ - const css = await lessTransform.generate({ paths: './shared' }); - await fs.outputFile('./build/admin/bundle.css', css); - await fs.outputFile('./build/admin/bundle.js', bundle); - await fs.outputFile('./build/admin/ssr.cjs', ssr); -}; - -fs.emptyDirSync('./build/admin'); -pack('./client/admin/admin.jsx', { - paths : ['./shared'], - libs : Proj.libs, - dev : isDev && build, - transforms -}) - .then(build) - .catch(console.error); diff --git a/scripts/buildHomebrew.js b/scripts/buildHomebrew.js deleted file mode 100644 index 4d55a4176..000000000 --- a/scripts/buildHomebrew.js +++ /dev/null @@ -1,169 +0,0 @@ -import fs from 'fs-extra'; -import zlib from 'zlib'; -import Proj from './project.json' with { type: 'json' }; -import vitreum from 'vitreum'; -const { pack, watchFile, livereload } = vitreum; - -import lessTransform from 'vitreum/transforms/less.js'; -import assetTransform from 'vitreum/transforms/asset.js'; -import babel from '@babel/core'; -import babelConfig from '../babel.config.json' with { type : 'json' }; -import less from 'less'; - -const isDev = !!process.argv.find((arg)=>arg === '--dev'); - -const babelify = async (code)=>(await babel.transformAsync(code, babelConfig)).code; - -const transforms = { - '.js' : (code, filename, opts)=>babelify(code), - '.jsx' : (code, filename, opts)=>babelify(code), - '.less' : lessTransform, - '*' : assetTransform('./build') -}; - -const build = async ({ bundle, render, ssr })=>{ - const css = await lessTransform.generate({ paths: './shared' }); - //css = `@layer bundle {\n${css}\n}`; - await fs.outputFile('./build/homebrew/bundle.css', css); - await fs.outputFile('./build/homebrew/bundle.js', bundle); - await fs.outputFile('./build/homebrew/ssr.cjs', ssr); - - await fs.copy('./client/homebrew/favicon.ico', './build/assets/favicon.ico'); - - //compress files in production - if(!isDev){ - await fs.outputFile('./build/homebrew/bundle.css.br', zlib.brotliCompressSync(css)); - await fs.outputFile('./build/homebrew/bundle.js.br', zlib.brotliCompressSync(bundle)); - await fs.outputFile('./build/homebrew/ssr.js.br', zlib.brotliCompressSync(ssr)); - } else { - await fs.remove('./build/homebrew/bundle.css.br'); - await fs.remove('./build/homebrew/bundle.js.br'); - await fs.remove('./build/homebrew/ssr.js.br'); - } -}; - -fs.emptyDirSync('./build'); - - -(async ()=>{ - - //v==----------------------------- COMPILE THEMES --------------------------------==v// - - // Update list of all Theme files - const themes = { Legacy: {}, V3: {} }; - - let themeFiles = fs.readdirSync('./themes/Legacy'); - for (const dir of themeFiles) { - const themeData = JSON.parse(fs.readFileSync(`./themes/Legacy/${dir}/settings.json`).toString()); - themeData.path = dir; - themes.Legacy[dir] = (themeData); - //fs.copy(`./themes/Legacy/${dir}/dropdownTexture.png`, `./build/themes/Legacy/${dir}/dropdownTexture.png`); - const src = `./themes/Legacy/${dir}/style.less`; - ((outputDirectory)=>{ - less.render(fs.readFileSync(src).toString(), { - compress : !isDev - }, function(e, output) { - fs.outputFile(outputDirectory, output.css); - }); - })(`./build/themes/Legacy/${dir}/style.css`); - - } - - themeFiles = fs.readdirSync('./themes/V3'); - for (const dir of themeFiles) { - const themeData = JSON.parse(fs.readFileSync(`./themes/V3/${dir}/settings.json`).toString()); - themeData.path = dir; - themes.V3[dir] = (themeData); - fs.copy(`./themes/V3/${dir}/dropdownTexture.png`, `./build/themes/V3/${dir}/dropdownTexture.png`); - fs.copy(`./themes/V3/${dir}/dropdownPreview.png`, `./build/themes/V3/${dir}/dropdownPreview.png`); - const src = `./themes/V3/${dir}/style.less`; - ((outputDirectory)=>{ - less.render(fs.readFileSync(src).toString(), { - compress : !isDev - }, function(e, output) { - fs.outputFile(outputDirectory, output.css); - }); - })(`./build/themes/V3/${dir}/style.css`); - } - - await fs.outputFile('./themes/themes.json', JSON.stringify(themes, null, 2)); - - // await less.render(lessCode, { - // compress : !dev, - // sourceMap : (dev ? { - // sourceMapFileInline: true, - // outputSourceFiles: true - // } : false), - // }) - - // Move assets - await fs.copy('./themes/fonts', './build/fonts'); - await fs.copy('./themes/assets', './build/assets'); - await fs.copy('./client/icons', './build/icons'); - - //v==---------------------------MOVE CM EDITOR THEMES -----------------------------==v// - - const editorThemesBuildDir = './build/homebrew/cm-themes'; - await fs.copy('./node_modules/codemirror/theme', editorThemesBuildDir); - await fs.copy('./themes/codeMirror/customThemes', editorThemesBuildDir); - const editorThemeFiles = fs.readdirSync(editorThemesBuildDir); - - const editorThemeFile = './themes/codeMirror/editorThemes.json'; - if(fs.existsSync(editorThemeFile)) fs.rmSync(editorThemeFile); - const stream = fs.createWriteStream(editorThemeFile, { flags: 'a' }); - stream.write('[\n"default"'); - - for (const themeFile of editorThemeFiles) { - stream.write(`,\n"${themeFile.slice(0, -4)}"`); - } - stream.write('\n]\n'); - stream.end(); - - - await fs.copy('./themes/codeMirror', './build/homebrew/codeMirror'); - - //v==----------------------------- BUNDLE PACKAGES --------------------------------==v// - - const bundles = await pack('./client/homebrew/homebrew.jsx', { - paths : ['./shared', './'], - libs : Proj.libs, - dev : isDev && build, - transforms - }); - build(bundles); - - // Possible method for generating separate bundles for theme snippets: factor-bundle first sending all common files to bundle.js, then again using default settings, keeping only snippet bundles - // await fs.outputFile('./build/junk.js', ''); - // await fs.outputFile('./build/themes/Legacy/5ePHB/snippets.js', ''); - // - // const files = ['./client/homebrew/homebrew.jsx','./themes/Legacy/5ePHB/snippets.js']; - // - // bundles = await pack(files, { - // dedupe: false, - // plugin : [['factor-bundle', { outputs: [ './build/junk.js','./build/themes/Legacy/5ePHB/snippets.js'], threshold : function(row, groups) { - // console.log(groups); - // if (groups.some(group => /.*homebrew.jsx$/.test(group))) { - // console.log("found homebrewery") - // return true; - // } - // return this._defaultThreshold(row, groups); - // }}]], - // paths : ['./shared','./','./build'], - // libs : Proj.libs, - // dev : isDev && build, - // transforms - // }); - // build(bundles); - // - - //In development, set up LiveReload (refreshes browser), and Nodemon (restarts server) - if(isDev){ - livereload('./build'); // Install the Chrome extension LiveReload to automatically refresh the browser - watchFile('./server.js', { // Restart server when change detected to this file or any nested directory from here - ignore : ['./build', './client', './themes'], // Ignore folders that are not running server code / avoids unneeded restarts - ext : 'js json' // Extensions to watch (only .js/.json by default) - //watch : ['./server', './themes'], // Watch additional folders if needed - }); - } - -})().catch(console.error); \ No newline at end of file diff --git a/scripts/dev.js b/scripts/dev.js deleted file mode 100644 index 45f6c3d99..000000000 --- a/scripts/dev.js +++ /dev/null @@ -1,22 +0,0 @@ -const label = 'dev'; -console.time(label); - -const jsx = require('vitreum/steps/jsx.watch.js'); -const less = require('vitreum/steps/less.watch.js'); -const assets = require('vitreum/steps/assets.watch.js'); -const server = require('vitreum/steps/server.watch.js'); -const livereload = require('vitreum/steps/livereload.js'); - -const Proj = require('./project.json'); - -Promise.resolve() - .then(()=>jsx('homebrew', './client/homebrew/homebrew.jsx', { libs: Proj.libs, shared: ['./shared'] })) - .then((deps)=>less('homebrew', { shared: ['./shared'] }, deps)) - .then(()=>jsx('admin', './client/admin/admin.jsx', { libs: Proj.libs, shared: ['./shared'] })) - .then((deps)=>less('admin', { shared: ['./shared'] }, deps)) - - .then(()=>assets(Proj.assets, ['./shared', './client'])) - .then(()=>livereload()) - .then(()=>server('./server.js', ['server'])) - .then(console.timeEnd.bind(console, label)) - .catch(console.error); \ No newline at end of file diff --git a/scripts/quick.js b/scripts/quick.js deleted file mode 100644 index e763d85f7..000000000 --- a/scripts/quick.js +++ /dev/null @@ -1,17 +0,0 @@ -const label = 'quick'; -console.time(label); - -const jsx = require('vitreum/steps/jsx.js').partial; -const less = require('vitreum/steps/less.js').partial; -const server = require('vitreum/steps/server.watch.js').partial; - -const Proj = require('./project.json'); - -Promise.resolve() - .then(jsx('homebrew', './client/homebrew/homebrew.jsx', Proj.libs, ['./shared'])) - .then(less('homebrew', ['./shared'])) - .then(jsx('admin', './client/admin/admin.jsx', Proj.libs, ['./shared'])) - .then(less('admin', ['./shared'])) - .then(server('./server.js', ['server'])) - .then(console.timeEnd.bind(console, label)) - .catch(console.error); \ No newline at end of file diff --git a/server.js b/server.js index fe5a9a363..db97336e2 100644 --- a/server.js +++ b/server.js @@ -1,12 +1,29 @@ -import DB from './server/db.js'; -import server from './server/app.js'; +import DB from './server/db.js'; +import createApp from './server/app.js'; import config from './server/config.js'; +import { createServer as createViteServer } from 'vite'; -DB.connect(config).then(()=>{ - // Ensure that we have successfully connected to the database - // before launching server - const PORT = process.env.PORT || config.get('web_port') || 8000; - server.listen(PORT, ()=>{ +const isDev = process.env.NODE_ENV === 'local'; + +async function start() { + let vite; + + if(isDev) { + vite = await createViteServer({ + server : { middlewareMode: true }, + appType : 'custom', + }); + } + + await DB.connect(config).catch((err)=>{ + console.error('Database connection failed:', err); + process.exit(1); + }); + + const app = await createApp(vite); + + const PORT = process.env.PORT || config.get('web_port') || 3000; + app.listen(PORT, ()=>{ const reset = '\x1b[0m'; // Reset to default style const bright = '\x1b[1m'; // Bright (bold) style const cyan = '\x1b[36m'; // Cyan color @@ -14,7 +31,10 @@ DB.connect(config).then(()=>{ console.log(`\n\tserver started at: ${new Date().toLocaleString()}`); console.log(`\tserver on port: ${PORT}`); - console.log(`\t${bright + cyan}Open in browser: ${reset}${underline + bright + cyan}http://localhost:${PORT}${reset}\n\n`); - + console.log( + `\t${bright + cyan}Open in browser: ${reset}${underline + bright + cyan}http://localhost:${PORT}${reset}\n\n`, + ); }); -}); +} + +start(); diff --git a/server/admin.api.js b/server/admin.api.js index a3d7622f1..f55eefdf2 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -4,64 +4,69 @@ import { model as NotificationModel } from './notifications.model.js'; import express from 'express'; import Moment from 'moment'; import zlib from 'zlib'; -import templateFn from '../client/template.js'; +import config from './config.js'; +import path from 'path'; +import fs from 'fs-extra'; + +const nodeEnv = config.get('node_env'); +const isProd = nodeEnv === 'production'; import HomebrewAPI from './homebrew.api.js'; import asyncHandler from 'express-async-handler'; import { splitTextStyleAndMetadata } from '../shared/helpers.js'; -const router = express.Router(); - - process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin'; process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3'; -const mw = { - adminOnly : (req, res, next)=>{ - if(!req.get('authorization')){ - return res +export default function createAdminApi(vite) { + const router = express.Router(); + + const mw = { + adminOnly : (req, res, next)=>{ + if(!req.get('authorization')){ + return res .set('WWW-Authenticate', 'Basic realm="Authorization Required"') .status(401) .send('Authorization Required'); - } - const [username, password] = Buffer.from(req.get('authorization').split(' ').pop(), 'base64') + } + const [username, password] = Buffer.from(req.get('authorization').split(' ').pop(), 'base64') .toString('ascii') .split(':'); - if(process.env.ADMIN_USER === username && process.env.ADMIN_PASS === password){ - return next(); + if(process.env.ADMIN_USER === username && process.env.ADMIN_PASS === password){ + return next(); + } + throw { HBErrorCode: '52', code: 401, message: 'Access denied' }; } - throw { HBErrorCode: '52', code: 401, message: 'Access denied' }; - } -}; + }; -const junkBrewPipeline = [ - { $match : { - updatedAt : { $lt: Moment().subtract(30, 'days').toDate() }, - lastViewed : { $lt: Moment().subtract(30, 'days').toDate() } - } }, - { $project: { textBinSize: { $binarySize: '$textBin' } } }, - { $match: { textBinSize: { $lt: 140 } } }, - { $limit: 100 } -]; + const junkBrewPipeline = [ + { $match : { + updatedAt : { $lt: Moment().subtract(30, 'days').toDate() }, + lastViewed : { $lt: Moment().subtract(30, 'days').toDate() } + } }, + { $project: { textBinSize: { $binarySize: '$textBin' } } }, + { $match: { textBinSize: { $lt: 140 } } }, + { $limit: 100 } + ]; -/* Search for brews that aren't compressed (missing the compressed text field) */ -const uncompressedBrewQuery = HomebrewModel.find({ - 'text' : { '$exists': true } -}).lean().limit(10000).select('_id'); + /* Search for brews that aren't compressed (missing the compressed text field) */ + const uncompressedBrewQuery = HomebrewModel.find({ + 'text' : { '$exists': true } + }).lean().limit(10000).select('_id'); -// Search for up to 100 brews that have not been viewed or updated in 30 days and are shorter than 140 bytes -router.get('/admin/cleanup', mw.adminOnly, (req, res)=>{ - HomebrewModel.aggregate(junkBrewPipeline).option({ maxTimeMS: 60000 }) + // Search for up to 100 brews that have not been viewed or updated in 30 days and are shorter than 140 bytes + router.get('/admin/cleanup', mw.adminOnly, (req, res)=>{ + HomebrewModel.aggregate(junkBrewPipeline).option({ maxTimeMS: 60000 }) .then((objs)=>res.json({ count: objs.length })) .catch((error)=>{ console.error(error); res.status(500).json({ error: 'Internal Server Error' }); }); -}); + }); -// Delete up to 100 brews that have not been viewed or updated in 30 days and are shorter than 140 bytes -router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{ - HomebrewModel.aggregate(junkBrewPipeline).option({ maxTimeMS: 60000 }) + // Delete up to 100 brews that have not been viewed or updated in 30 days and are shorter than 140 bytes + router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{ + HomebrewModel.aggregate(junkBrewPipeline).option({ maxTimeMS: 60000 }) .then((docs)=>{ const ids = docs.map((doc)=>doc._id); return HomebrewModel.deleteMany({ _id: { $in: ids } }); @@ -71,18 +76,18 @@ router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{ console.error(error); res.status(500).json({ error: 'Internal Server Error' }); }); -}); + }); -/* Searches for matching edit or share id, also attempts to partial match */ -router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res, next)=>{ - return res.json(req.brew); -}); + /* Searches for matching edit or share id, also attempts to partial match */ + router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res, next)=>{ + return res.json(req.brew); + }); -/* Find 50 brews that aren't compressed yet */ -router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{ - const query = uncompressedBrewQuery.clone(); + /* Find 50 brews that aren't compressed yet */ + router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{ + const query = uncompressedBrewQuery.clone(); - query.exec() + query.exec() .then((objs)=>{ const ids = objs.map((obj)=>obj._id); res.json({ count: ids.length, ids }); @@ -91,46 +96,46 @@ router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{ console.error(err); res.status(500).send(err.message || 'Internal Server Error'); }); -}); - -/* Cleans `` from the "text" field of a brew */ -router.put('/admin/clean/script/:id', asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res)=>{ - console.log(`[ADMIN: ${req.account?.username || 'Not Logged In'}] Cleaning script tags from ShareID ${req.params.id}`); - - function cleanText(text){return text.replaceAll(/(<\/?s)cript/gi, '');}; - - const brew = req.brew; - - const properties = ['text', 'description', 'title']; - properties.forEach((property)=>{ - brew[property] = cleanText(brew[property]); }); - splitTextStyleAndMetadata(brew); + /* Cleans `` from the "text" field of a brew */ + router.put('/admin/clean/script/:id', asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res)=>{ + console.log(`[ADMIN: ${req.account?.username || 'Not Logged In'}] Cleaning script tags from ShareID ${req.params.id}`); - req.body = brew; + function cleanText(text){return text.replaceAll(/(<\/?s)cript/gi, '');}; - // Remove Account from request to prevent Admin user from being added to brew as an Author - req.account = undefined; + const brew = req.brew; - return await HomebrewAPI.updateBrew(req, res); -}); + const properties = ['text', 'description', 'title']; + properties.forEach((property)=>{ + brew[property] = cleanText(brew[property]); + }); -/* Get list of a user's documents */ -router.get('/admin/user/list/:user', mw.adminOnly, async (req, res)=>{ - const username = req.params.user; - const fields = { _id: 0, text: 0, textBin: 0 }; // Remove unnecessary fields from document lists + splitTextStyleAndMetadata(brew); - console.log(`[ADMIN: ${req.account?.username || 'Not Logged In'}] Get brew list for ${username}`); + req.body = brew; - const brews = await HomebrewModel.getByUser(username, true, fields); + // Remove Account from request to prevent Admin user from being added to brew as an Author + req.account = undefined; - return res.json(brews); -}); + return await HomebrewAPI.updateBrew(req, res); + }); -/* Compresses the "text" field of a brew to binary */ -router.put('/admin/compress/:id', (req, res)=>{ - HomebrewModel.findOne({ _id: req.params.id }) + /* Get list of a user's documents */ + router.get('/admin/user/list/:user', mw.adminOnly, async (req, res)=>{ + const username = req.params.user; + const fields = { _id: 0, text: 0, textBin: 0 }; // Remove unnecessary fields from document lists + + console.log(`[ADMIN: ${req.account?.username || 'Not Logged In'}] Get brew list for ${username}`); + + const brews = await HomebrewModel.getByUser(username, true, fields); + + return res.json(brews); + }); + + /* Compresses the "text" field of a brew to binary */ + router.put('/admin/compress/:id', (req, res)=>{ + HomebrewModel.findOne({ _id: req.params.id }) .then((brew)=>{ if(!brew) return res.status(404).send('Brew not found'); @@ -147,239 +152,252 @@ router.put('/admin/compress/:id', (req, res)=>{ console.error(err); res.status(500).send('Error while saving'); }); -}); + }); -router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ - try { - const totalBrewsCount = await HomebrewModel.countDocuments({}); - const publishedBrewsCount = await HomebrewModel.countDocuments({ published: true }); + router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ + try { + const totalBrewsCount = await HomebrewModel.countDocuments({}); + const publishedBrewsCount = await HomebrewModel.countDocuments({ published: true }); - return res.json({ - totalBrews : totalBrewsCount, - totalPublishedBrews : publishedBrewsCount - }); - } catch (error) { - console.error(error); - return res.status(500).json({ error: 'Internal Server Error' }); - } -}); + return res.json({ + totalBrews : totalBrewsCount, + totalPublishedBrews : publishedBrewsCount + }); + } catch (error) { + console.error(error); + return res.status(500).json({ error: 'Internal Server Error' }); + } + }); -// ####################### LOCKS + // ####################### LOCKS -router.get('/api/lock/count', mw.adminOnly, asyncHandler(async (req, res)=>{ + router.get('/api/lock/count', mw.adminOnly, asyncHandler(async (req, res)=>{ - const countLocksQuery = { - lock : { $exists: true } - }; - const count = await HomebrewModel.countDocuments(countLocksQuery) + const countLocksQuery = { + lock : { $exists: true } + }; + const count = await HomebrewModel.countDocuments(countLocksQuery) .catch((error)=>{ throw { name: 'Lock Count Error', message: 'Unable to get lock count', status: 500, HBErrorCode: '61', error }; }); - return res.json({ count }); + return res.json({ count }); -})); + })); -router.get('/api/locks', mw.adminOnly, asyncHandler(async (req, res)=>{ - const countLocksPipeline = [ - { + router.get('/api/locks', mw.adminOnly, asyncHandler(async (req, res)=>{ + const countLocksPipeline = [ + { $match : { 'lock' : { '$exists': 1 } }, - }, - { - $project : { - shareId : 1, - editId : 1, - title : 1, - lock : 1 + }, + { + $project : { + shareId : 1, + editId : 1, + title : 1, + lock : 1 + } } - } - ]; - const lockedDocuments = await HomebrewModel.aggregate(countLocksPipeline) + ]; + const lockedDocuments = await HomebrewModel.aggregate(countLocksPipeline) .catch((error)=>{ throw { name: 'Can Not Get Locked Brews', message: 'Unable to get locked brew collection', status: 500, HBErrorCode: '68', error }; }); - return res.json({ - lockedDocuments - }); + return res.json({ + lockedDocuments + }); -})); + })); -router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ + router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ - const lock = req.body; + const lock = req.body; - lock.applied = new Date; + lock.applied = new Date; - const filter = { - shareId : req.params.id - }; + const filter = { + shareId : req.params.id + }; - const brew = await HomebrewModel.findOne(filter); + const brew = await HomebrewModel.findOne(filter); - if(!brew) throw { name: 'Brew Not Found', message: 'Cannot find brew to lock', shareId: req.params.id, status: 500, HBErrorCode: '63' }; + if(!brew) throw { name: 'Brew Not Found', message: 'Cannot find brew to lock', shareId: req.params.id, status: 500, HBErrorCode: '63' }; - if(brew.lock && !lock.overwrite) { - throw { name: 'Already Locked', message: 'Lock already exists on brew', shareId: req.params.id, title: brew.title, status: 500, HBErrorCode: '64' }; - } + if(brew.lock && !lock.overwrite) { + throw { name: 'Already Locked', message: 'Lock already exists on brew', shareId: req.params.id, title: brew.title, status: 500, HBErrorCode: '64' }; + } - lock.overwrite = undefined; + lock.overwrite = undefined; - brew.lock = lock; - brew.markModified('lock'); + brew.lock = lock; + brew.markModified('lock'); - await brew.save() + await brew.save() .catch((error)=>{ throw { name: 'Lock Error', message: 'Unable to set lock', shareId: req.params.id, status: 500, HBErrorCode: '62', error }; }); - return res.json({ name: 'LOCKED', message: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, ...lock }); + return res.json({ name: 'LOCKED', message: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, ...lock }); -})); + })); -router.put('/api/unlock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ + router.put('/api/unlock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ - const filter = { - shareId : req.params.id - }; + const filter = { + shareId : req.params.id + }; - const brew = await HomebrewModel.findOne(filter); + const brew = await HomebrewModel.findOne(filter); - if(!brew) throw { name: 'Brew Not Found', message: 'Cannot find brew to unlock', shareId: req.params.id, status: 500, HBErrorCode: '66' }; + if(!brew) throw { name: 'Brew Not Found', message: 'Cannot find brew to unlock', shareId: req.params.id, status: 500, HBErrorCode: '66' }; - if(!brew.lock) throw { name: 'Not Locked', message: 'Cannot unlock as brew is not locked', shareId: req.params.id, status: 500, HBErrorCode: '67' }; + if(!brew.lock) throw { name: 'Not Locked', message: 'Cannot unlock as brew is not locked', shareId: req.params.id, status: 500, HBErrorCode: '67' }; - brew.lock = undefined; - brew.markModified('lock'); + brew.lock = undefined; + brew.markModified('lock'); - await brew.save() + await brew.save() .catch((error)=>{ throw { name: 'Cannot Unlock', message: 'Unable to clear lock', shareId: req.params.id, status: 500, HBErrorCode: '65', error }; }); - return res.json({ name: 'Unlocked', message: `Lock removed from brew ID ${req.params.id}` }); -})); + return res.json({ name: 'Unlocked', message: `Lock removed from brew ID ${req.params.id}` }); + })); -router.get('/api/lock/reviews', mw.adminOnly, asyncHandler(async (req, res)=>{ - const countReviewsPipeline = [ - { + router.get('/api/lock/reviews', mw.adminOnly, asyncHandler(async (req, res)=>{ + const countReviewsPipeline = [ + { $match : { 'lock.reviewRequested' : { '$exists': 1 } }, - }, - { - $project : { - shareId : 1, - editId : 1, - title : 1, - lock : 1 + }, + { + $project : { + shareId : 1, + editId : 1, + title : 1, + lock : 1 + } } - } - ]; - const reviewDocuments = await HomebrewModel.aggregate(countReviewsPipeline) + ]; + const reviewDocuments = await HomebrewModel.aggregate(countReviewsPipeline) .catch((error)=>{ throw { name: 'Can Not Get Reviews', message: 'Unable to get review collection', status: 500, HBErrorCode: '68', error }; }); - return res.json({ - reviewDocuments - }); + return res.json({ + reviewDocuments + }); -})); + })); -router.put('/api/lock/review/request/:id', asyncHandler(async (req, res)=>{ + router.put('/api/lock/review/request/:id', asyncHandler(async (req, res)=>{ // === This route is NOT Admin only === // Any user can request a review of their document - const filter = { - shareId : req.params.id, - lock : { $exists: 1 } - }; + const filter = { + shareId : req.params.id, + lock : { $exists: 1 } + }; - const brew = await HomebrewModel.findOne(filter); - if(!brew) { throw { name: 'Brew Not Found', message: `Cannot find a locked brew with ID ${req.params.id}`, code: 500, HBErrorCode: '70' }; }; + const brew = await HomebrewModel.findOne(filter); + if(!brew) { throw { name: 'Brew Not Found', message: `Cannot find a locked brew with ID ${req.params.id}`, code: 500, HBErrorCode: '70' }; }; - if(brew.lock.reviewRequested){ - throw { name: 'Review Already Requested', message: `Review already requested for brew ${brew.shareId} - ${brew.title}`, code: 500, HBErrorCode: '71' }; - }; + if(brew.lock.reviewRequested){ + throw { name: 'Review Already Requested', message: `Review already requested for brew ${brew.shareId} - ${brew.title}`, code: 500, HBErrorCode: '71' }; + }; - brew.lock.reviewRequested = new Date(); - brew.markModified('lock'); + brew.lock.reviewRequested = new Date(); + brew.markModified('lock'); - await brew.save() + await brew.save() .catch((error)=>{ throw { name: 'Can Not Set Review Request', message: `Unable to set request for review on brew ID ${req.params.id}`, code: 500, HBErrorCode: '69', error }; }); - return res.json({ name: 'Review Requested', message: `Review requested on brew ID ${brew.shareId} - ${brew.title}` }); + return res.json({ name: 'Review Requested', message: `Review requested on brew ID ${brew.shareId} - ${brew.title}` }); -})); + })); -router.put('/api/lock/review/remove/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ + router.put('/api/lock/review/remove/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ - const filter = { - shareId : req.params.id, - 'lock.reviewRequested' : { $exists: 1 } - }; + const filter = { + shareId : req.params.id, + 'lock.reviewRequested' : { $exists: 1 } + }; - const brew = await HomebrewModel.findOne(filter); - if(!brew) { throw { name: 'Can Not Clear Review Request', message: `Brew ID ${req.params.id} does not have a review pending!`, HBErrorCode: '73' }; }; + const brew = await HomebrewModel.findOne(filter); + if(!brew) { throw { name: 'Can Not Clear Review Request', message: `Brew ID ${req.params.id} does not have a review pending!`, HBErrorCode: '73' }; }; - brew.lock.reviewRequested = undefined; - brew.markModified('lock'); + brew.lock.reviewRequested = undefined; + brew.markModified('lock'); - await brew.save() + await brew.save() .catch((error)=>{ throw { name: 'Can Not Clear Review Request', message: `Unable to remove request for review on brew ID ${req.params.id}`, HBErrorCode: '72', error }; }); - return res.json({ name: 'Review Request Cleared', message: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); + return res.json({ name: 'Review Request Cleared', message: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); -})); + })); -// ####################### NOTIFICATIONS + // ####################### NOTIFICATIONS -router.get('/admin/notification/all', async (req, res, next)=>{ - try { - const notifications = await NotificationModel.getAll(); - return res.json(notifications); + router.get('/admin/notification/all', async (req, res, next)=>{ + try { + const notifications = await NotificationModel.getAll(); + return res.json(notifications); - } catch (error) { - console.log('Error getting all notifications: ', error.message); - return res.status(500).json({ message: error.message }); - } -}); - -router.post('/admin/notification/add', mw.adminOnly, async (req, res, next)=>{ - try { - const notification = await NotificationModel.addNotification(req.body); - return res.status(201).json(notification); - } catch (error) { - console.log('Error adding notification: ', error.message); - return res.status(500).json({ message: error.message }); - } -}); - -router.delete('/admin/notification/delete/:id', mw.adminOnly, async (req, res, next)=>{ - try { - const notification = await NotificationModel.deleteNotification(req.params.id); - return res.json(notification); - } catch (error) { - console.error('Error deleting notification: { key: ', req.params.id, ' error: ', error.message, ' }'); - return res.status(500).json({ message: error.message }); - } -}); - -router.get('/admin', mw.adminOnly, (req, res)=>{ - templateFn('admin', { - url : req.originalUrl - }) - .then((page)=>res.send(page)) - .catch((err)=>{ - console.log(err); - res.sendStatus(500); + } catch (error) { + console.log('Error getting all notifications: ', error.message); + return res.status(500).json({ message: error.message }); + } }); -}); -export default router; + router.post('/admin/notification/add', mw.adminOnly, async (req, res, next)=>{ + try { + const notification = await NotificationModel.addNotification(req.body); + return res.status(201).json(notification); + } catch (error) { + console.log('Error adding notification: ', error.message); + return res.status(500).json({ message: error.message }); + } + }); + + router.delete('/admin/notification/delete/:id', mw.adminOnly, async (req, res, next)=>{ + try { + const notification = await NotificationModel.deleteNotification(req.params.id); + return res.json(notification); + } catch (error) { + console.error('Error deleting notification: { key: ', req.params.id, ' error: ', error.message, ' }'); + return res.status(500).json({ message: error.message }); + } + }); + + router.get('/admin', mw.adminOnly, asyncHandler(async (req, res)=>{ + const props = { + url : req.originalUrl + }; + + const htmlPath = isProd + ? path.resolve('build', 'index.html') + : path.resolve('index.html'); + + let html = fs.readFileSync(htmlPath, 'utf-8'); + + if(!isProd && vite?.transformIndexHtml) { + html = await vite.transformIndexHtml(req.originalUrl, html); + } + + res.send(html.replace( + '', + `\n` + )); + })); + + + return router; +} + diff --git a/server/admin.api.spec.js b/server/admin.api.spec.js index cb25dd67d..ce2a06d0d 100644 --- a/server/admin.api.spec.js +++ b/server/admin.api.spec.js @@ -1,42 +1,45 @@ /*eslint max-lines: ["warn", {"max": 1000, "skipBlankLines": true, "skipComments": true}]*/ import mongoose from 'mongoose'; import supertest from 'supertest'; -import HBApp from './app.js'; +import createApp from './app.js'; import { model as NotificationModel } from './notifications.model.js'; import { model as HomebrewModel } from './homebrew.model.js'; - -// Mimic https responses to avoid being redirected all the time -const app = supertest.agent(HBApp).set('X-Forwarded-Proto', 'https'); - +let app; +let request; let dbState; +beforeAll(async ()=>{ + app = await createApp(); + request = supertest.agent(app).set('X-Forwarded-Proto', 'https'); +}); + describe('Tests for admin api', ()=>{ beforeEach(()=>{ - // Mock DB ready (for dbCheck middleware) dbState = mongoose.connection.readyState; mongoose.connection.readyState = 1; }); afterEach(()=>{ - // Restore DB ready state mongoose.connection.readyState = dbState; - jest.resetAllMocks(); }); + afterAll(async ()=>{ + await mongoose.connection.close(); + }); + describe('Notifications', ()=>{ it('should return list of all notifications', async ()=>{ const testNotifications = ['a', 'b']; - jest.spyOn(NotificationModel, 'find') - .mockImplementationOnce(()=>{ + jest.spyOn(NotificationModel, 'find').mockImplementationOnce(()=>{ return { exec: jest.fn().mockResolvedValue(testNotifications) }; }); - const response = await app - .get('/admin/notification/all') - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); + const response = await request + .get('/admin/notification/all') + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(200); expect(response.body).toEqual(testNotifications); @@ -56,18 +59,17 @@ describe('Tests for admin api', ()=>{ _id : expect.any(String), createdAt : expect.any(String), startAt : inputNotification.startAt, - stopAt : inputNotification.stopAt, + stopAt : inputNotification.stopAt }; - jest.spyOn(NotificationModel.prototype, 'save') - .mockImplementationOnce(function() { - return Promise.resolve(this); - }); + jest.spyOn(NotificationModel.prototype, 'save').mockImplementationOnce(function () { + return Promise.resolve(this); + }); - const response = await app - .post('/admin/notification/add') - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .send(inputNotification); + const response = await request + .post('/admin/notification/add') + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) + .send(inputNotification); expect(response.status).toBe(201); expect(response.body).toEqual(savedNotification); @@ -81,16 +83,14 @@ describe('Tests for admin api', ()=>{ stopAt : new Date().toISOString() }; - //Change 'save' function to just return itself instead of actually interacting with the database - jest.spyOn(NotificationModel.prototype, 'save') - .mockImplementationOnce(function() { - return Promise.resolve(this); - }); + jest.spyOn(NotificationModel.prototype, 'save').mockImplementationOnce(function () { + return Promise.resolve(this); + }); - const response = await app - .post('/admin/notification/add') - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .send(inputNotification); + const response = await request + .post('/admin/notification/add') + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) + .send(inputNotification); expect(response.status).toBe(500); expect(response.body).toEqual({ message: 'Dismiss key is required!' }); @@ -99,15 +99,15 @@ describe('Tests for admin api', ()=>{ it('should delete a notification based on its dismiss key', async ()=>{ const dismissKey = 'testKey'; - jest.spyOn(NotificationModel, 'findOneAndDelete') - .mockImplementationOnce((key)=>{ - return { exec: jest.fn().mockResolvedValue(key) }; - }); - const response = await app - .delete(`/admin/notification/delete/${dismissKey}`) - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); + jest.spyOn(NotificationModel, 'findOneAndDelete').mockImplementationOnce((key)=>{ + return { exec: jest.fn().mockResolvedValue(key) }; + }); - expect(NotificationModel.findOneAndDelete).toHaveBeenCalledWith({ 'dismissKey': 'testKey' }); + const response = await request + .delete(`/admin/notification/delete/${dismissKey}`) + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); + + expect(NotificationModel.findOneAndDelete).toHaveBeenCalledWith({ dismissKey: 'testKey' }); expect(response.status).toBe(200); expect(response.body).toEqual({ dismissKey: 'testKey' }); }); @@ -115,15 +115,15 @@ describe('Tests for admin api', ()=>{ it('should handle error deleting a notification that doesnt exist', async ()=>{ const dismissKey = 'testKey'; - jest.spyOn(NotificationModel, 'findOneAndDelete') - .mockImplementationOnce(()=>{ - return { exec: jest.fn().mockResolvedValue() }; - }); - const response = await app - .delete(`/admin/notification/delete/${dismissKey}`) - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); + jest.spyOn(NotificationModel, 'findOneAndDelete').mockImplementationOnce(()=>{ + return { exec: jest.fn().mockResolvedValue() }; + }); - expect(NotificationModel.findOneAndDelete).toHaveBeenCalledWith({ 'dismissKey': 'testKey' }); + const response = await request + .delete(`/admin/notification/delete/${dismissKey}`) + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); + + expect(NotificationModel.findOneAndDelete).toHaveBeenCalledWith({ dismissKey: 'testKey' }); expect(response.status).toBe(500); expect(response.body).toEqual({ message: 'Notification not found' }); }); @@ -132,30 +132,24 @@ describe('Tests for admin api', ()=>{ describe('Locks', ()=>{ describe('Count', ()=>{ it('Count of all locked documents', async ()=>{ - const testNumber = 16777216; // 8^8, because why not + const testNumber = 16777216; - jest.spyOn(HomebrewModel, 'countDocuments') - .mockImplementationOnce(()=>{ - return Promise.resolve(testNumber); - }); + jest.spyOn(HomebrewModel, 'countDocuments').mockImplementationOnce(()=>Promise.resolve(testNumber)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .get('/api/lock/count'); + const response = await request + .get('/api/lock/count') + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(200); expect(response.body).toEqual({ count: testNumber }); }); it('Handle error while fetching count of locked documents', async ()=>{ - jest.spyOn(HomebrewModel, 'countDocuments') - .mockImplementationOnce(()=>{ - return Promise.reject(); - }); + jest.spyOn(HomebrewModel, 'countDocuments').mockImplementationOnce(()=>Promise.reject()); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .get('/api/lock/count'); + const response = await request + .get('/api/lock/count') + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -163,7 +157,7 @@ describe('Tests for admin api', ()=>{ message : 'Unable to get lock count', name : 'Lock Count Error', originalUrl : '/api/lock/count', - status : 500, + status : 500 }); }); }); @@ -172,28 +166,22 @@ describe('Tests for admin api', ()=>{ it('Get list of all locked documents', async ()=>{ const testLocks = ['a', 'b']; - jest.spyOn(HomebrewModel, 'aggregate') - .mockImplementationOnce(()=>{ - return Promise.resolve(testLocks); - }); + jest.spyOn(HomebrewModel, 'aggregate').mockImplementationOnce(()=>Promise.resolve(testLocks)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .get('/api/locks'); + const response = await request + .get('/api/locks') + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(200); expect(response.body).toEqual({ lockedDocuments: testLocks }); }); it('Handle error while fetching list of all locked documents', async ()=>{ - jest.spyOn(HomebrewModel, 'aggregate') - .mockImplementationOnce(()=>{ - return Promise.reject(); - }); + jest.spyOn(HomebrewModel, 'aggregate').mockImplementationOnce(()=>Promise.reject()); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .get('/api/locks'); + const response = await request + .get('/api/locks') + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -208,28 +196,22 @@ describe('Tests for admin api', ()=>{ it('Get list of all locked documents with pending review requests', async ()=>{ const testLocks = ['a', 'b']; - jest.spyOn(HomebrewModel, 'aggregate') - .mockImplementationOnce(()=>{ - return Promise.resolve(testLocks); - }); + jest.spyOn(HomebrewModel, 'aggregate').mockImplementationOnce(()=>Promise.resolve(testLocks)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .get('/api/lock/reviews'); + const response = await request + .get('/api/lock/reviews') + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(200); expect(response.body).toEqual({ reviewDocuments: testLocks }); }); it('Handle error while fetching list of all locked documents with pending review requests', async ()=>{ - jest.spyOn(HomebrewModel, 'aggregate') - .mockImplementationOnce(()=>{ - return Promise.reject(); - }); + jest.spyOn(HomebrewModel, 'aggregate').mockImplementationOnce(()=>Promise.reject()); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .get('/api/lock/reviews'); + const response = await request + .get('/api/lock/reviews') + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -247,8 +229,8 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.resolve(); } + markModified : ()=>true, + save : ()=>Promise.resolve() }; const testLock = { @@ -257,15 +239,12 @@ describe('Tests for admin api', ()=>{ shareMessage : 'share' }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .post(`/api/lock/${testBrew.shareId}`) - .send(testLock); + const response = await request + .post(`/api/lock/${testBrew.shareId}`) + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) + .send(testLock); expect(response.status).toBe(200); expect(response.body).toMatchObject({ @@ -289,24 +268,21 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.resolve(); }, + markModified : ()=>true, + save : ()=>Promise.resolve(), lock : { code : 1, editMessage : 'oldEdit', - shareMessage : 'oldShare', + shareMessage : 'oldShare' } }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .post(`/api/lock/${testBrew.shareId}`) - .send(testLock); + const response = await request + .post(`/api/lock/${testBrew.shareId}`) + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) + .send(testLock); expect(response.status).toBe(200); expect(response.body).toMatchObject({ @@ -329,24 +305,21 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.resolve(); }, + markModified : ()=>true, + save : ()=>Promise.resolve(), lock : { code : 1, editMessage : 'oldEdit', - shareMessage : 'oldShare', + shareMessage : 'oldShare' } }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .post(`/api/lock/${testBrew.shareId}`) - .send(testLock); + const response = await request + .post(`/api/lock/${testBrew.shareId}`) + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) + .send(testLock); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -364,8 +337,8 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.reject(); } + markModified : ()=>true, + save : ()=>Promise.reject() }; const testLock = { @@ -374,15 +347,12 @@ describe('Tests for admin api', ()=>{ shareMessage : 'share' }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .post(`/api/lock/${testBrew.shareId}`) - .send(testLock); + const response = await request + .post(`/api/lock/${testBrew.shareId}`) + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) + .send(testLock); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -408,19 +378,17 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.resolve(); }, + markModified : ()=>true, + save : ()=>Promise.resolve(), lock : testLock }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .put(`/api/unlock/${testBrew.shareId}`); + const response = await request.put(`/api/unlock/${testBrew.shareId}`).set( + 'Authorization', + `Basic ${Buffer.from('admin:password3').toString('base64')}` + ); expect(response.status).toBe(200); expect(response.body).toEqual({ @@ -433,18 +401,16 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.resolve(); }, + markModified : ()=>true, + save : ()=>Promise.resolve() }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .put(`/api/unlock/${testBrew.shareId}`); + const response = await request.put(`/api/unlock/${testBrew.shareId}`).set( + 'Authorization', + `Basic ${Buffer.from('admin:password3').toString('base64')}` + ); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -453,7 +419,7 @@ describe('Tests for admin api', ()=>{ name : 'Not Locked', originalUrl : `/api/unlock/${testBrew.shareId}`, shareId : testBrew.shareId, - status : 500, + status : 500 }); }); @@ -468,19 +434,17 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.reject(); }, + markModified : ()=>true, + save : ()=>Promise.reject(), lock : testLock }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .put(`/api/unlock/${testBrew.shareId}`); + const response = await request.put(`/api/unlock/${testBrew.shareId}`).set( + 'Authorization', + `Basic ${Buffer.from('admin:password3').toString('base64')}` + ); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -506,40 +470,28 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.resolve(); }, + markModified : ()=>true, + save : ()=>Promise.resolve(), lock : testLock }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .put(`/api/lock/review/request/${testBrew.shareId}`); + const response = await request.put(`/api/lock/review/request/${testBrew.shareId}`); expect(response.status).toBe(200); expect(response.body).toEqual({ message : `Review requested on brew ID ${testBrew.shareId} - ${testBrew.title}`, - name : 'Review Requested', + name : 'Review Requested' }); }); it('Error when cannot find a locked brew', async ()=>{ - const testBrew = { - shareId : 'shareId' - }; + const testBrew = { shareId: 'shareId' }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(false); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(false)); - - const response = await app - .put(`/api/lock/review/request/${testBrew.shareId}`) - .catch((err)=>{return err;}); + const response = await request.put(`/api/lock/review/request/${testBrew.shareId}`); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -569,25 +521,20 @@ describe('Tests for admin api', ()=>{ }; jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(false); - }); + .mockImplementationOnce(()=>Promise.resolve(testBrew)); - - const response = await app - .put(`/api/lock/review/request/${testBrew.shareId}`) - .catch((err)=>{return err;}); + const response = await request + .put(`/api/lock/review/request/${testBrew.shareId}`); expect(response.status).toBe(500); expect(response.body).toEqual({ - HBErrorCode : '70', + HBErrorCode : '71', code : 500, - message : `Cannot find a locked brew with ID ${testBrew.shareId}`, - name : 'Brew Not Found', + message : `Review already requested for brew ${testBrew.shareId} - ${testBrew.title}`, + name : 'Review Already Requested', originalUrl : `/api/lock/review/request/${testBrew.shareId}` }); }); - it('Handle error while adding review request to a locked brew', async ()=>{ const testLock = { applied : 'YES', @@ -599,18 +546,14 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.reject(); }, + markModified : ()=>true, + save : ()=>Promise.reject(), lock : testLock }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .put(`/api/lock/review/request/${testBrew.shareId}`); + const response = await request.put(`/api/lock/review/request/${testBrew.shareId}`); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -634,19 +577,16 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.resolve(); }, + markModified : ()=>true, + save : ()=>Promise.resolve(), lock : testLock }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .put(`/api/lock/review/remove/${testBrew.shareId}`); + const response = await request + .put(`/api/lock/review/remove/${testBrew.shareId}`) + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(200); expect(response.body).toEqual({ @@ -656,18 +596,13 @@ describe('Tests for admin api', ()=>{ }); it('Error when clearing review request from a brew with no review request', async ()=>{ - const testBrew = { - shareId : 'shareId', - }; + const testBrew = { shareId: 'shareId' }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(false); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(false)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .put(`/api/lock/review/remove/${testBrew.shareId}`); + const response = await request + .put(`/api/lock/review/remove/${testBrew.shareId}`) + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(500); expect(response.body).toEqual({ @@ -690,19 +625,16 @@ describe('Tests for admin api', ()=>{ const testBrew = { shareId : 'shareId', title : 'title', - markModified : ()=>{ return true; }, - save : ()=>{ return Promise.reject(); }, + markModified : ()=>true, + save : ()=>Promise.reject(), lock : testLock }; - jest.spyOn(HomebrewModel, 'findOne') - .mockImplementationOnce(()=>{ - return Promise.resolve(testBrew); - }); + jest.spyOn(HomebrewModel, 'findOne').mockImplementationOnce(()=>Promise.resolve(testBrew)); - const response = await app - .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`) - .put(`/api/lock/review/remove/${testBrew.shareId}`); + const response = await request + .put(`/api/lock/review/remove/${testBrew.shareId}`) + .set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`); expect(response.status).toBe(500); expect(response.body).toEqual({ diff --git a/server/app.js b/server/app.js index 25ac8e909..b1e0e1c25 100644 --- a/server/app.js +++ b/server/app.js @@ -12,10 +12,9 @@ import _ from 'lodash'; import jwt from 'jwt-simple'; import express from 'express'; import config from './config.js'; +import path from 'path'; import fs from 'fs-extra'; -const app = express(); - import api from './homebrew.api.js'; const { homebrewApi, getBrew, getUsersBrewThemes, getCSS } = api; import adminApi from './admin.api.js'; @@ -24,7 +23,6 @@ import GoogleActions from './googleActions.js'; import serveCompressedStaticAssets from './static-assets.mv.js'; import sanitizeFilename from 'sanitize-filename'; import asyncHandler from 'express-async-handler'; -import templateFn from '../client/template.js'; import { model as HomebrewModel } from './homebrew.model.js'; import { DEFAULT_BREW } from './brewDefaults.js'; @@ -37,600 +35,626 @@ import cookieParser from 'cookie-parser'; import forceSSL from './forcessl.mw.js'; import dbCheck from './middleware/dbCheck.js'; - -const sanitizeBrew = (brew, accessType)=>{ - brew._id = undefined; - brew.__v = undefined; - if(accessType !== 'edit' && accessType !== 'shareAuthor') { - brew.editId = undefined; - } - return brew; -}; - -app.set('trust proxy', 1 /* number of proxies between user and server */); - -app.use('/', serveCompressedStaticAssets(`build`)); -app.use(contentNegotiation); -app.use(bodyParser.json({ limit: '25mb' })); -app.use(cookieParser()); -app.use(forceSSL); - import cors from 'cors'; -const nodeEnv = config.get('node_env'); -const isLocalEnvironment = config.get('local_environments').includes(nodeEnv); +export default async function createApp(vite) { + const app = express(); -const corsOptions = { - origin : (origin, callback)=>{ + const nodeEnv = config.get('node_env'); + const isProd = nodeEnv === 'production'; + const isLocalEnvironment = config.get('local_environments').includes(nodeEnv); - const allowedOrigins = [ - 'https://homebrewery.naturalcrit.com', - 'https://www.naturalcrit.com', - 'https://naturalcrit-stage.herokuapp.com', - 'https://homebrewery-stage.herokuapp.com', - ]; - - const localNetworkRegex = /^http:\/\/(localhost|127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2\d|3[0-1])\.\d+\.\d+):\d+$/; - - const herokuRegex = /^https:\/\/(?:homebrewery-pr-\d+\.herokuapp\.com|naturalcrit-pr-\d+\.herokuapp\.com)$/; // Matches any Heroku app - - if(!origin || allowedOrigins.includes(origin) || herokuRegex.test(origin) || (isLocalEnvironment && localNetworkRegex.test(origin))) { - callback(null, true); - } else { - console.log(origin, 'not allowed'); - callback(new Error('Not allowed by CORS, if you think this is an error, please contact us')); + const sanitizeBrew = (brew, accessType)=>{ + brew._id = undefined; + brew.__v = undefined; + if(accessType !== 'edit' && accessType !== 'shareAuthor') { + brew.editId = undefined; } - }, - methods : ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], - credentials : true, -}; + return brew; + }; -app.use(cors(corsOptions)); + app.set('trust proxy', 1 /* number of proxies between user and server */); -//Account Middleware -app.use((req, res, next)=>{ - if(req.cookies && req.cookies.nc_session){ - try { - req.account = jwt.decode(req.cookies.nc_session, config.get('secret')); + if(vite) { + app.use(vite.middlewares); + } + + app.use('/', serveCompressedStaticAssets('build')); + app.use(contentNegotiation); + app.use(bodyParser.json({ limit: '25mb' })); + app.use(cookieParser()); + app.use(forceSSL); + + + const corsOptions = { + origin : (origin, callback)=>{ + + const allowedOrigins = [ + 'https://homebrewery.naturalcrit.com', + 'https://www.naturalcrit.com', + 'https://naturalcrit-stage.herokuapp.com', + 'https://homebrewery-stage.herokuapp.com', + ]; + + const localNetworkRegex = /^http:\/\/(localhost|127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2\d|3[0-1])\.\d+\.\d+):\d+$/; + + const herokuRegex = /^https:\/\/(?:homebrewery-pr-\d+\.herokuapp\.com|naturalcrit-pr-\d+\.herokuapp\.com)$/; // Matches any Heroku app + + if(!origin || allowedOrigins.includes(origin) || herokuRegex.test(origin) || (isLocalEnvironment && localNetworkRegex.test(origin))) { + callback(null, true); + } else { + console.log(origin, 'not allowed'); + callback(new Error('Not allowed by CORS, if you think this is an error, please contact us')); + } + }, + methods : ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + credentials : true, + }; + + app.use(cors(corsOptions)); + + //Account Middleware + app.use((req, res, next)=>{ + if(req.cookies && req.cookies.nc_session){ + try { + req.account = jwt.decode(req.cookies.nc_session, config.get('secret')); //console.log("Just loaded up JWT from cookie:"); //console.log(req.account); - } catch (e){ - console.log(e); + } catch (e){ + console.log(e); + } } - } - req.config = { - google_client_id : config.get('google_client_id'), - google_client_secret : config.get('google_client_secret') - }; - return next(); -}); - -app.use(homebrewApi); -app.use(adminApi); -app.use(vaultApi); - -const welcomeText = fs.readFileSync('client/homebrew/pages/homePage/welcome_msg.md', 'utf8'); -const welcomeTextLegacy = fs.readFileSync('client/homebrew/pages/homePage/welcome_msg_legacy.md', 'utf8'); -const migrateText = fs.readFileSync('client/homebrew/pages/homePage/migrate.md', 'utf8'); -const changelogText = fs.readFileSync('changelog.md', 'utf8'); -const faqText = fs.readFileSync('faq.md', 'utf8'); - -String.prototype.replaceAll = function(s, r){return this.split(s).join(r);}; - -const defaultMetaTags = { - site_name : 'The Homebrewery - Make your Homebrew content look legit!', - title : 'The Homebrewery', - description : 'A NaturalCrit Tool for creating authentic Homebrews using Markdown.', - image : `${config.get('publicUrl')}/thumbnail.png`, - type : 'website' -}; - -//Robots.txt -app.get('/robots.txt', (req, res)=>{ - return res.sendFile(`robots.txt`, { root: process.cwd() }); -}); - -//Home page -app.get('/', (req, res, next)=>{ - req.brew = { - text : welcomeText, - renderer : 'V3', - theme : '5ePHB' - }, - - req.ogMeta = { ...defaultMetaTags, - title : 'Homepage', - description : 'Homepage' - }; - - splitTextStyleAndMetadata(req.brew); - return next(); -}); - -//Home page Legacy -app.get('/legacy', (req, res, next)=>{ - req.brew = { - text : welcomeTextLegacy, - renderer : 'legacy', - theme : '5ePHB' - }, - - req.ogMeta = { ...defaultMetaTags, - title : 'Homepage (Legacy)', - description : 'Homepage' - }; - - splitTextStyleAndMetadata(req.brew); - return next(); -}); - -//Legacy/Other Document -> v3 Migration Guide -app.get('/migrate', (req, res, next)=>{ - req.brew = { - text : migrateText, - renderer : 'V3', - theme : '5ePHB' - }, - - req.ogMeta = { ...defaultMetaTags, - title : 'v3 Migration Guide', - description : 'A brief guide to converting Legacy documents to the v3 renderer.' - }; - - splitTextStyleAndMetadata(req.brew); - return next(); -}); - -//Changelog page -app.get('/changelog', async (req, res, next)=>{ - req.brew = { - title : 'Changelog', - text : changelogText, - renderer : 'V3', - theme : '5ePHB' - }, - - req.ogMeta = { ...defaultMetaTags, - title : 'Changelog', - description : 'Development changelog.' - }; - - splitTextStyleAndMetadata(req.brew); - return next(); -}); - -//FAQ page -app.get('/faq', async (req, res, next)=>{ - req.brew = { - title : 'FAQ', - text : faqText, - renderer : 'V3', - theme : '5ePHB' - }, - - req.ogMeta = { ...defaultMetaTags, - title : 'FAQ', - description : 'Frequently Asked Questions' - }; - - splitTextStyleAndMetadata(req.brew); - return next(); -}); - -//Source page -app.get('/source/:id', asyncHandler(getBrew('share')), (req, res)=>{ - const { brew } = req; - - const replaceStrings = { '&': '&', '<': '<', '>': '>' }; - let text = brew.text; - for (const replaceStr in replaceStrings) { - text = text.replaceAll(replaceStr, replaceStrings[replaceStr]); - } - text = `
    ${text}
    `; - res.status(200).send(text); -}); - -//Download brew source page -app.get('/download/:id', asyncHandler(getBrew('share')), (req, res)=>{ - const { brew } = req; - sanitizeBrew(brew, 'share'); - const prefix = 'HB - '; - - const encodeRFC3986ValueChars = (str)=>{ - return ( - encodeURIComponent(str) - .replace(/[!'()*]/g, (char)=>{`%${char.charCodeAt(0).toString(16).toUpperCase()}`;}) - ); - }; - - let fileName = sanitizeFilename(`${prefix}${brew.title}`).replaceAll(' ', ''); - if(!fileName || !fileName.length) { fileName = `${prefix}-Untitled-Brew`; }; - res.set({ - 'Cache-Control' : 'no-cache', - 'Content-Type' : 'text/plain', - 'Content-Disposition' : `attachment; filename*=UTF-8''${encodeRFC3986ValueChars(fileName)}.txt` + req.config = { + google_client_id : config.get('google_client_id'), + google_client_secret : config.get('google_client_secret') + }; + return next(); }); - res.status(200).send(brew.text); -}); -//Serve brew metadata -app.get('/metadata/:id', asyncHandler(getBrew('share')), (req, res)=>{ - const { brew } = req; - sanitizeBrew(brew, 'share'); + app.use(homebrewApi); + app.use(adminApi(vite)); + app.use(vaultApi); - const fields = ['title', 'pageCount', 'description', 'authors', 'lang', + const welcomeText = fs.readFileSync('./client/homebrew/pages/homePage/welcome_msg.md', 'utf8'); + const welcomeTextLegacy = fs.readFileSync('./client/homebrew/pages/homePage/welcome_msg_legacy.md', 'utf8'); + const migrateText = fs.readFileSync('./client/homebrew/pages/homePage/migrate.md', 'utf8'); + const changelogText = fs.readFileSync('changelog.md', 'utf8'); + const faqText = fs.readFileSync('faq.md', 'utf8'); + + String.prototype.replaceAll = function(s, r){return this.split(s).join(r);}; + + const defaultMetaTags = { + site_name : 'The Homebrewery - Make your Homebrew content look legit!', + title : 'The Homebrewery', + description : 'A NaturalCrit Tool for creating authentic Homebrews using Markdown.', + image : `${config.get('publicUrl')}/thumbnail.png`, + type : 'website' + }; + + //Robots.txt + app.get('/robots.txt', (req, res)=>{ + return res.sendFile(`robots.txt`, { root: process.cwd() }); + }); + + //Home page + app.get('/', (req, res, next)=>{ + req.brew = { + text : welcomeText, + renderer : 'V3', + theme : '5ePHB' + }, + + req.ogMeta = { ...defaultMetaTags, + title : 'Homepage', + description : 'Homepage' + }; + + splitTextStyleAndMetadata(req.brew); + return next(); + }); + + //Home page Legacy + app.get('/legacy', (req, res, next)=>{ + req.brew = { + text : welcomeTextLegacy, + renderer : 'legacy', + theme : '5ePHB' + }, + + req.ogMeta = { ...defaultMetaTags, + title : 'Homepage (Legacy)', + description : 'Homepage' + }; + + splitTextStyleAndMetadata(req.brew); + return next(); + }); + + //Legacy/Other Document -> v3 Migration Guide + app.get('/migrate', (req, res, next)=>{ + req.brew = { + text : migrateText, + renderer : 'V3', + theme : '5ePHB' + }, + + req.ogMeta = { ...defaultMetaTags, + title : 'v3 Migration Guide', + description : 'A brief guide to converting Legacy documents to the v3 renderer.' + }; + + splitTextStyleAndMetadata(req.brew); + return next(); + }); + + //Changelog page + app.get('/changelog', async (req, res, next)=>{ + req.brew = { + title : 'Changelog', + text : changelogText, + renderer : 'V3', + theme : '5ePHB' + }, + + req.ogMeta = { ...defaultMetaTags, + title : 'Changelog', + description : 'Development changelog.' + }; + + splitTextStyleAndMetadata(req.brew); + return next(); + }); + + //FAQ page + app.get('/faq', async (req, res, next)=>{ + req.brew = { + title : 'FAQ', + text : faqText, + renderer : 'V3', + theme : '5ePHB' + }, + + req.ogMeta = { ...defaultMetaTags, + title : 'FAQ', + description : 'Frequently Asked Questions' + }; + + splitTextStyleAndMetadata(req.brew); + return next(); + }); + + //Source page + app.get('/source/:id', asyncHandler(getBrew('share')), (req, res)=>{ + const { brew } = req; + + const replaceStrings = { '&': '&', '<': '<', '>': '>' }; + let text = brew.text; + for (const replaceStr in replaceStrings) { + text = text.replaceAll(replaceStr, replaceStrings[replaceStr]); + } + text = `
    ${text}
    `; + res.status(200).send(text); + }); + + //Download brew source page + app.get('/download/:id', asyncHandler(getBrew('share')), (req, res)=>{ + const { brew } = req; + sanitizeBrew(brew, 'share'); + const prefix = 'HB - '; + + const encodeRFC3986ValueChars = (str)=>{ + return ( + encodeURIComponent(str) + .replace(/[!'()*]/g, (char)=>{`%${char.charCodeAt(0).toString(16).toUpperCase()}`;}) + ); + }; + + let fileName = sanitizeFilename(`${prefix}${brew.title}`).replaceAll(' ', ''); + if(!fileName || !fileName.length) { fileName = `${prefix}-Untitled-Brew`; }; + res.set({ + 'Cache-Control' : 'no-cache', + 'Content-Type' : 'text/plain', + 'Content-Disposition' : `attachment; filename*=UTF-8''${encodeRFC3986ValueChars(fileName)}.txt` + }); + res.status(200).send(brew.text); + }); + + //Serve brew metadata + app.get('/metadata/:id', asyncHandler(getBrew('share')), (req, res)=>{ + const { brew } = req; + sanitizeBrew(brew, 'share'); + + const fields = ['title', 'pageCount', 'description', 'authors', 'lang', 'published', 'views', 'shareId', 'createdAt', 'updatedAt', 'lastViewed', 'thumbnail', 'tags' - ]; + ]; - const metadata = fields.reduce((acc, field)=>{ + const metadata = fields.reduce((acc, field)=>{ if(brew[field] !== undefined) acc[field] = brew[field]; return acc; - }, {}); - res.status(200).json(metadata); -}); + }, {}); + res.status(200).json(metadata); + }); -//Serve brew styling -app.get('/css/:id', asyncHandler(getBrew('share')), (req, res)=>{getCSS(req, res);}); + //Serve brew styling + app.get('/css/:id', asyncHandler(getBrew('share')), (req, res)=>{getCSS(req, res);}); -//User Page -app.get('/user/:username', dbCheck, async (req, res, next)=>{ - const ownAccount = req.account && (req.account.username == req.params.username); + //User Page + app.get('/user/:username', dbCheck, async (req, res, next)=>{ + const ownAccount = req.account && (req.account.username == req.params.username); - req.ogMeta = { ...defaultMetaTags, - title : `${req.params.username}'s Collection`, - description : 'View my collection of homebrew on the Homebrewery.' + req.ogMeta = { ...defaultMetaTags, + title : `${req.params.username}'s Collection`, + description : 'View my collection of homebrew on the Homebrewery.' // type : could be 'profile'? - }; + }; - const fields = [ - 'googleId', - 'title', - 'pageCount', - 'description', - 'authors', - 'lang', - 'published', - 'views', - 'shareId', - 'editId', - 'createdAt', - 'updatedAt', - 'lastViewed', - 'thumbnail', - 'tags' - ]; + const fields = [ + 'googleId', + 'title', + 'pageCount', + 'description', + 'authors', + 'lang', + 'published', + 'views', + 'shareId', + 'editId', + 'createdAt', + 'updatedAt', + 'lastViewed', + 'thumbnail', + 'tags' + ]; - let brews = await HomebrewModel.getByUser(req.params.username, ownAccount, fields) + let brews = await HomebrewModel.getByUser(req.params.username, ownAccount, fields) .catch((err)=>{ console.log(err); }); - brews.forEach((brew)=>brew.stubbed = true); //All brews from MongoDB are "stubbed" + brews.forEach((brew)=>brew.stubbed = true); //All brews from MongoDB are "stubbed" - if(ownAccount && req?.account?.googleId){ - const auth = await GoogleActions.authCheck(req.account, res); - let googleBrews = await GoogleActions.listGoogleBrews(auth) + if(ownAccount && req?.account?.googleId){ + const auth = await GoogleActions.authCheck(req.account, res); + let googleBrews = await GoogleActions.listGoogleBrews(auth) .catch((err)=>{ console.error(err); }); - // If stub matches file from Google, use Google metadata over stub metadata - if(googleBrews && googleBrews.length > 0) { - for (const brew of brews.filter((brew)=>brew.googleId)) { - const match = googleBrews.findIndex((b)=>b.editId === brew.editId); - if(match !== -1) { - brew.googleId = googleBrews[match].googleId; - brew.pageCount = googleBrews[match].pageCount; - brew.renderer = googleBrews[match].renderer; - brew.version = googleBrews[match].version; - brew.webViewLink = googleBrews[match].webViewLink; - googleBrews.splice(match, 1); + // If stub matches file from Google, use Google metadata over stub metadata + if(googleBrews && googleBrews.length > 0) { + for (const brew of brews.filter((brew)=>brew.googleId)) { + const match = googleBrews.findIndex((b)=>b.editId === brew.editId); + if(match !== -1) { + brew.googleId = googleBrews[match].googleId; + brew.pageCount = googleBrews[match].pageCount; + brew.renderer = googleBrews[match].renderer; + brew.version = googleBrews[match].version; + brew.webViewLink = googleBrews[match].webViewLink; + googleBrews.splice(match, 1); + } } + + //Remaining unstubbed google brews display current user as author + googleBrews = googleBrews.map((brew)=>({ ...brew, authors: [req.account.username] })); + brews = _.concat(brews, googleBrews); } - - //Remaining unstubbed google brews display current user as author - googleBrews = googleBrews.map((brew)=>({ ...brew, authors: [req.account.username] })); - brews = _.concat(brews, googleBrews); } - } - req.brews = _.map(brews, (brew)=>{ + req.brews = _.map(brews, (brew)=>{ // Clean up brew data - brew.title = brew.title?.trim(); - brew.description = brew.description?.trim(); - return sanitizeBrew(brew, ownAccount ? 'edit' : 'share'); + brew.title = brew.title?.trim(); + brew.description = brew.description?.trim(); + return sanitizeBrew(brew, ownAccount ? 'edit' : 'share'); + }); + + return next(); }); - return next(); -}); + //Change author name on brews + app.put('/api/user/rename', dbCheck, async (req, res)=>{ + const { username, newUsername } = req.body; + const ownAccount = req.account && (req.account.username == newUsername); -//Change author name on brews -app.put('/api/user/rename', dbCheck, async (req, res)=>{ - const { username, newUsername } = req.body; - const ownAccount = req.account && (req.account.username == newUsername); + if(!username || !newUsername) + return res.status(400).json({ error: 'Username and newUsername are required.' }); + if(!ownAccount) + return res.status(403).json({ error: 'Must be logged in to change your username' }); + try { + const brews = await HomebrewModel.getByUser(username, true, ['authors']); + const renamePromises = brews.map(async (brew)=>{ + const updatedAuthors = brew.authors.map((author)=>author === username ? newUsername : author + ); + return HomebrewModel.updateOne( + { _id: brew._id }, + { $set: { authors: updatedAuthors } } + ); + }); + await Promise.all(renamePromises); - if(!username || !newUsername) - return res.status(400).json({ error: 'Username and newUsername are required.' }); - if(!ownAccount) - return res.status(403).json({ error: 'Must be logged in to change your username' }); - try { - const brews = await HomebrewModel.getByUser(username, true, ['authors']); - const renamePromises = brews.map(async (brew)=>{ - const updatedAuthors = brew.authors.map((author)=>author === username ? newUsername : author - ); - return HomebrewModel.updateOne( - { _id: brew._id }, - { $set: { authors: updatedAuthors } } - ); - }); - await Promise.all(renamePromises); - - return res.json({ success: true, message: `Brews for ${username} renamed to ${newUsername}.` }); - } catch (error) { - console.error('Error renaming brews:', error); - return res.status(500).json({ error: 'Failed to rename brews.' }); - } -}); - -//Edit Page -app.get('/edit/:id', asyncHandler(getBrew('edit')), asyncHandler(async(req, res, next)=>{ - req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; - - req.userThemes = await(getUsersBrewThemes(req.account?.username)); - - req.ogMeta = { ...defaultMetaTags, - title : req.brew.title || 'Untitled Brew', - description : req.brew.description || 'No description.', - image : req.brew.thumbnail || defaultMetaTags.image, - locale : req.brew.lang, - type : 'article' - }; - - sanitizeBrew(req.brew, 'edit'); - splitTextStyleAndMetadata(req.brew); - res.header('Cache-Control', 'no-cache, no-store'); //reload the latest saved brew when pressing back button, not the cached version before save. - return next(); -})); - -//New Page from ID -app.get('/new/:id', asyncHandler(getBrew('share')), asyncHandler(async(req, res, next)=>{ - sanitizeBrew(req.brew, 'share'); - splitTextStyleAndMetadata(req.brew); - const brew = { - shareId : req.brew.shareId, - title : `CLONE - ${req.brew.title}`, - text : req.brew.text, - style : req.brew.style, - renderer : req.brew.renderer, - theme : req.brew.theme, - tags : req.brew.tags, - snippets : req.brew.snippets - }; - req.brew = _.defaults(brew, DEFAULT_BREW); - - req.userThemes = await(getUsersBrewThemes(req.account?.username)); - - req.ogMeta = { ...defaultMetaTags, - title : 'New', - description : 'Start crafting your homebrew on the Homebrewery!' - }; - - return next(); -})); - -//New Page -app.get('/new', asyncHandler(async(req, res, next)=>{ - req.userThemes = await(getUsersBrewThemes(req.account?.username)); - - req.ogMeta = { ...defaultMetaTags, - title : 'New', - description : 'Start crafting your homebrew on the Homebrewery!' - }; - - return next(); -})); - -//Share Page -app.get('/share/:id', dbCheck, asyncHandler(getBrew('share')), asyncHandler(async (req, res, next)=>{ - const { brew } = req; - req.ogMeta = { ...defaultMetaTags, - title : `${req.brew.title || 'Untitled Brew'} - ${req.brew.authors[0] || 'No author.'}`, - description : req.brew.description || 'No description.', - image : req.brew.thumbnail || defaultMetaTags.image, - type : 'article' - }; - - // increase visitor view count, do not include visits by author(s) - if(!brew.authors.includes(req.account?.username)){ - if(req.params.id.length > 12 && !brew._id) { - const googleId = brew.googleId; - const shareId = brew.shareId; - await GoogleActions.increaseView(googleId, shareId, 'share', brew) - .catch((err)=>{next(err);}); - } else { - await HomebrewModel.increaseView({ shareId: brew.shareId }); + return res.json({ success: true, message: `Brews for ${username} renamed to ${newUsername}.` }); + } catch (error) { + console.error('Error renaming brews:', error); + return res.status(500).json({ error: 'Failed to rename brews.' }); } - }; + }); - brew.authors.includes(req.account?.username) ? sanitizeBrew(req.brew, 'shareAuthor') : sanitizeBrew(req.brew, 'share'); - splitTextStyleAndMetadata(req.brew); - return next(); -})); + //Edit Page + app.get('/edit/:id', asyncHandler(getBrew('edit')), asyncHandler(async(req, res, next)=>{ + req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; -//Account Page -app.get('/account', dbCheck, asyncHandler(async (req, res, next)=>{ - const data = {}; - data.title = 'Account Information Page'; + req.userThemes = await(getUsersBrewThemes(req.account?.username)); - if(!req.account) { - res.set('WWW-Authenticate', 'Bearer realm="Authorization Required"'); - const error = new Error('No valid account'); - error.status = 401; - error.HBErrorCode = '50'; - error.page = data.title; - return next(error); - }; + req.ogMeta = { ...defaultMetaTags, + title : req.brew.title || 'Untitled Brew', + description : req.brew.description || 'No description.', + image : req.brew.thumbnail || defaultMetaTags.image, + locale : req.brew.lang, + type : 'article' + }; - let auth; - let googleCount = []; - if(req.account) { - if(req.account.googleId) { - auth = await GoogleActions.authCheck(req.account, res, false); + sanitizeBrew(req.brew, 'edit'); + splitTextStyleAndMetadata(req.brew); + res.header('Cache-Control', 'no-cache, no-store'); //reload the latest saved brew when pressing back button, not the cached version before save. + return next(); + })); - googleCount = await GoogleActions.listGoogleBrews(auth) + //New Page from ID + app.get('/new/:id', asyncHandler(getBrew('share')), asyncHandler(async(req, res, next)=>{ + sanitizeBrew(req.brew, 'share'); + splitTextStyleAndMetadata(req.brew); + const brew = { + shareId : req.brew.shareId, + title : `CLONE - ${req.brew.title}`, + text : req.brew.text, + style : req.brew.style, + renderer : req.brew.renderer, + theme : req.brew.theme, + tags : req.brew.tags, + snippets : req.brew.snippets + }; + req.brew = _.defaults(brew, DEFAULT_BREW); + + req.userThemes = await(getUsersBrewThemes(req.account?.username)); + + req.ogMeta = { ...defaultMetaTags, + title : 'New', + description : 'Start crafting your homebrew on the Homebrewery!' + }; + + return next(); + })); + + //New Page + app.get('/new', asyncHandler(async(req, res, next)=>{ + req.userThemes = await(getUsersBrewThemes(req.account?.username)); + + req.ogMeta = { ...defaultMetaTags, + title : 'New', + description : 'Start crafting your homebrew on the Homebrewery!' + }; + + return next(); + })); + + //Share Page + app.get('/share/:id', dbCheck, asyncHandler(getBrew('share')), asyncHandler(async (req, res, next)=>{ + const { brew } = req; + req.ogMeta = { ...defaultMetaTags, + title : `${req.brew.title || 'Untitled Brew'} - ${req.brew.authors[0] || 'No author.'}`, + description : req.brew.description || 'No description.', + image : req.brew.thumbnail || defaultMetaTags.image, + type : 'article' + }; + + // increase visitor view count, do not include visits by author(s) + if(!brew.authors.includes(req.account?.username)){ + if(req.params.id.length > 12 && !brew._id) { + const googleId = brew.googleId; + const shareId = brew.shareId; + await GoogleActions.increaseView(googleId, shareId, 'share', brew) + .catch((err)=>{next(err);}); + } else { + await HomebrewModel.increaseView({ shareId: brew.shareId }); + } + }; + + brew.authors.includes(req.account?.username) ? sanitizeBrew(req.brew, 'shareAuthor') : sanitizeBrew(req.brew, 'share'); + splitTextStyleAndMetadata(req.brew); + return next(); + })); + + //Account Page + app.get('/account', dbCheck, asyncHandler(async (req, res, next)=>{ + const data = {}; + data.title = 'Account Information Page'; + + if(!req.account) { + res.set('WWW-Authenticate', 'Bearer realm="Authorization Required"'); + const error = new Error('No valid account'); + error.status = 401; + error.HBErrorCode = '50'; + error.page = data.title; + return next(error); + }; + + let auth; + let googleCount = []; + if(req.account) { + if(req.account.googleId) { + auth = await GoogleActions.authCheck(req.account, res, false); + + googleCount = await GoogleActions.listGoogleBrews(auth) .catch((err)=>{ console.error(err); }); - } + } - const query = { authors: req.account.username, googleId: { $exists: false } }; - const mongoCount = await HomebrewModel.countDocuments(query) + const query = { authors: req.account.username, googleId: { $exists: false } }; + const mongoCount = await HomebrewModel.countDocuments(query) .catch((err)=>{ console.log(err); return 0; }); - data.accountDetails = { - username : req.account.username, - issued : req.account.issued, - googleId : Boolean(req.account.googleId), - authCheck : Boolean(req.account.googleId && auth?.credentials.access_token), - mongoCount : mongoCount, - googleCount : googleCount?.length + data.accountDetails = { + username : req.account.username, + issued : req.account.issued, + googleId : Boolean(req.account.googleId), + authCheck : Boolean(req.account.googleId && auth?.credentials.access_token), + mongoCount : mongoCount, + googleCount : googleCount?.length + }; + } + + req.brew = data; + + req.ogMeta = { ...defaultMetaTags, + title : `Account Page`, + description : null }; - } - req.brew = data; + return next(); + })); - req.ogMeta = { ...defaultMetaTags, - title : `Account Page`, - description : null - }; - - return next(); -})); - -// Local only -if(isLocalEnvironment){ + // Local only + if(isLocalEnvironment){ // Login - app.post('/local/login', (req, res)=>{ - const username = req.body.username; - if(!username) return; + app.post('/local/login', (req, res)=>{ + const username = req.body.username; + if(!username) return; - const payload = jwt.encode({ username: username, issued: new Date }, config.get('secret')); - return res.json(payload); - }); -} - -// Add Static Local Paths -app.use('/staticImages', express.static(config.get('hb_images') && fs.existsSync(config.get('hb_images')) ? config.get('hb_images') :'staticImages')); -app.use('/staticFonts', express.static(config.get('hb_fonts') && fs.existsSync(config.get('hb_fonts')) ? config.get('hb_fonts'):'staticFonts')); - -//Vault Page -app.get('/vault', asyncHandler(async(req, res, next)=>{ - req.ogMeta = { ...defaultMetaTags, - title : 'The Vault', - description : 'Search for Brews' - }; - return next(); -})); - -//Send rendered page -app.use(asyncHandler(async (req, res, next)=>{ - if(!req.route) return res.redirect('/'); // Catch-all for invalid routes - - const page = await renderPage(req, res); - if(!page) return; - res.send(page); -})); - -//Render the page -const renderPage = async (req, res)=>{ - // Create configuration object - const configuration = { - local : isLocalEnvironment, - publicUrl : config.get('publicUrl') ?? '', - baseUrl : `${req.protocol}://${req.get('host')}`, - environment : nodeEnv, - deployment : config.get('heroku_app_name') ?? '' - }; - const props = { - version : version, - url : req.customUrl || req.originalUrl, - brew : req.brew, - brews : req.brews, - googleBrews : req.googleBrews, - account : req.account, - config : configuration, - ogMeta : req.ogMeta, - userThemes : req.userThemes, - enable_v4 : config.get('enable_v4') - }; - const title = req.brew ? req.brew.title : ''; - const page = await templateFn('homebrew', title, props) - .catch((err)=>{ - console.log(err); + const payload = jwt.encode({ username: username, issued: new Date }, config.get('secret')); + return res.json(payload); }); - return page; -}; - -//v=====----- Error-Handling Middleware -----=====v// -//Format Errors as plain objects so all fields will appear in the string sent -const formatErrors = (key, value)=>{ - if(value instanceof Error) { - const error = {}; - Object.getOwnPropertyNames(value).forEach(function (key) { - error[key] = value[key]; - }); - return error; } - return value; -}; -const getPureError = (error)=>{ - return JSON.parse(JSON.stringify(error, formatErrors)); -}; + // Add Static Local Paths + app.use('/staticImages', express.static(config.get('hb_images') && fs.existsSync(config.get('hb_images')) ? config.get('hb_images') :'staticImages')); + app.use('/staticFonts', express.static(config.get('hb_fonts') && fs.existsSync(config.get('hb_fonts')) ? config.get('hb_fonts'):'staticFonts')); -app.use(async (err, req, res, next)=>{ - err.originalUrl = req.originalUrl; - console.error(err); + //Vault Page + app.get('/vault', asyncHandler(async(req, res, next)=>{ + req.ogMeta = { ...defaultMetaTags, + title : 'The Vault', + description : 'Search for Brews' + }; + return next(); + })); - if(err.originalUrl?.startsWith('/api')) { + //Send rendered page + app.use(asyncHandler(async (req, res, next)=>{ + if(!req.route) return res.redirect('/'); // Catch-all for invalid routes + + const page = await renderPage(req, res); + if(!page) return; + res.send(page); + })); + + //Render the page + const renderPage = async (req, res)=>{ + + // Create configuration object + const configuration = { + local : isLocalEnvironment, + publicUrl : config.get('publicUrl') ?? '', + baseUrl : `${req.protocol}://${req.get('host')}`, + environment : nodeEnv, + deployment : config.get('heroku_app_name') ?? '' + }; + const props = { + version : version, + url : req.customUrl || req.originalUrl, + brew : req.brew, + brews : req.brews, + googleBrews : req.googleBrews, + account : req.account, + config : configuration, + ogMeta : req.ogMeta, + userThemes : req.userThemes + }; + + const ogTags = []; + const ogMeta = req.ogMeta ?? {}; + Object.entries(ogMeta).forEach(([key, value])=>{ + if(!value) return; + const tag = ``; + ogTags.push(tag); + }); + const ogMetaTags = ogTags.join('\n'); + + const htmlPath = isProd ? path.resolve('build', 'index.html') : path.resolve('index.html'); + let html = fs.readFileSync(htmlPath, 'utf-8'); + + if(!isProd && vite?.transformIndexHtml) { + html = await vite.transformIndexHtml(req.originalUrl, html); + } + + html = html.replace( + '', + ()=>{ return `\n\n${ogMetaTags}`; } + ); + + return html; + }; + + //v=====----- Error-Handling Middleware -----=====v// + //Format Errors as plain objects so all fields will appear in the string sent + const formatErrors = (key, value)=>{ + if(value instanceof Error) { + const error = {}; + Object.getOwnPropertyNames(value).forEach(function (key) { + error[key] = value[key]; + }); + return error; + } + return value; + }; + + const getPureError = (error)=>{ + return JSON.parse(JSON.stringify(error, formatErrors)); + }; + + app.use(async (err, req, res, next)=>{ + err.originalUrl = req.originalUrl; + console.error(err); + + if(err.originalUrl?.startsWith('/api')) { // console.log('API error'); - res.status(err.status || err.response?.status || 500).send(err); - return; - } + res.status(err.status || err.response?.status || 500).send(err); + return; + } - // console.log('non-API error'); - const status = err.status || err.code || 500; + // console.log('non-API error'); + const status = err.status || err.code || 500; - req.ogMeta = { ...defaultMetaTags, - title : 'Error Page', - description : 'Something went wrong!' - }; - req.brew = { - ...err, - title : 'Error - Something went wrong!', - text : err.errors?.map((error)=>{return error.message;}).join('\n\n') || err.message || 'Unknown error!', - status : status, - HBErrorCode : err.HBErrorCode ?? '00', - pureError : getPureError(err) - }; - req.customUrl= '/error'; + req.ogMeta = { ...defaultMetaTags, + title : 'Error Page', + description : 'Something went wrong!' + }; + req.brew = { + ...err, + title : 'Error - Something went wrong!', + text : err.errors?.map((error)=>{return error.message;}).join('\n\n') || err.message || 'Unknown error!', + status : status, + HBErrorCode : err.HBErrorCode ?? '00', + pureError : getPureError(err) + }; + req.customUrl= '/error'; - const page = await renderPage(req, res); - if(!page) return; - res.send(page); -}); + const page = await renderPage(req, res); + if(!page) return; + res.send(page); + }); -app.use((req, res)=>{ - if(!res.headersSent) { - console.error('Headers have not been sent, responding with a server error.', req.url); - res.status(500).send('An error occurred and the server did not send a response. The error has been logged, please note the time this occurred and report this issue.'); - } -}); -//^=====--------------------------------------=====^// + app.use((req, res)=>{ + if(!res.headersSent) { + console.error('Headers have not been sent, responding with a server error.', req.url); + res.status(500).send('An error occurred and the server did not send a response. The error has been logged, please note the time this occurred and report this issue.'); + } + }); + //^=====--------------------------------------=====^// -export default app; + return app; +} diff --git a/server/brewDefaults.js b/server/brewDefaults.js index 11a84b9e9..501914735 100644 --- a/server/brewDefaults.js +++ b/server/brewDefaults.js @@ -14,7 +14,6 @@ const DEFAULT_BREW = { theme : '5ePHB', authors : [], tags : [], - systems : [], lang : 'en', thumbnail : '', views : 0, diff --git a/server/googleActions.js b/server/googleActions.js index b13ca11b9..d50549051 100644 --- a/server/googleActions.js +++ b/server/googleActions.js @@ -151,7 +151,6 @@ const GoogleActions = { description : file.description, views : parseInt(file.properties.views), published : file.properties.published ? file.properties.published == 'true' : false, - systems : [], lang : file.properties.lang, thumbnail : file.properties.thumbnail, webViewLink : file.webViewLink @@ -298,7 +297,6 @@ const GoogleActions = { text : file.data, description : obj.data.description, - systems : obj.data.properties.systems ? obj.data.properties.systems.split(',') : [], authors : [], lang : obj.data.properties.lang, published : obj.data.properties.published ? obj.data.properties.published == 'true' : false, diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 4d4f5a911..17aaa2518 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -31,6 +31,27 @@ const isStaticTheme = (renderer, themeName)=>{ // }); // }; + +const migrateSystemsToTags = (brew)=>{ + if(!('systems' in brew)) return brew; + + if(!Array.isArray(brew.systems) || brew.systems.length === 0) { + brew.systems = undefined; + return brew; + } + const systemMap = { + '5e' : 'system:D&D 5e', + '4e' : 'system:D&D 4e', + '3.5e' : 'system:D&D 3.5e', + 'Pathfinder' : 'system:Pathfinder 2e' + }; + const systemTags = brew.systems.map((s)=>systemMap[s]); + brew.tags = _.uniq([...(brew.tags || []), ...systemTags]); + + brew.systems = undefined; + return brew; +}; + const MAX_TITLE_LENGTH = 100; const api = { @@ -167,7 +188,10 @@ const api = { stub.renderer = stub.renderer || undefined; // Clear empty strings stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields - req.brew = stub; + + + const fixedStub = migrateSystemsToTags(stub); + req.brew = fixedStub; next(); }; }, @@ -193,7 +217,7 @@ const api = { `\`\`\`\n\n` + `${text}`; } - const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']); + const metadata = _.pick(brew, ['title', 'description', 'tags', 'renderer', 'theme']); const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets; metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined; text = `\`\`\`metadata\n` + @@ -368,22 +392,29 @@ const api = { if(brewFromServer?.hash !== brewFromClient?.hash) { console.log(`Hash mismatch on brew ${brewFromClient.editId}`); - //debugTextMismatch(brewFromClient.text, brewFromServer.text, `edit/${brewFromClient.editId}`); + debugTextMismatch(brewFromClient.text, brewFromServer.text, `edit/${brewFromClient.editId}`); res.setHeader('Content-Type', 'application/json'); return res.status(409).send(JSON.stringify({ message: `The server copy is out of sync with the saved brew. Please save your changes elsewhere, refresh, and try again.` })); } + let result = []; try { const patches = parsePatch(brewFromClient.patches); // Patch to a throwaway variable while parallelizing - we're more concerned with error/no error. - const patchedResult = decodeURI(applyPatches(patches, encodeURI(brewFromServer.text))[0]); - if(patchedResult != brewFromClient.text) + result = applyPatches(patches, encodeURI(brewFromServer.text)); + const failedPatches = patches.map((patch, index)=>{if(!result[1][index]){ return patch; }}); + if(failedPatches > 0){ + throw (`Patch failure: ${failedPatches}/${result[1].length} did not apply`); + } + if(decodeURI(result[0]) != brewFromClient.text){ throw ('Patches did not apply cleanly, text mismatch detected'); + } // brew.text = applyPatches(patches, brewFromServer.text)[0]; } catch (err) { - //debugTextMismatch(brewFromClient.text, brewFromServer.text, `edit/${brewFromClient.editId}`); + debugTextMismatch(brewFromClient.text, brewFromServer.text, `edit/${brewFromClient.editId}`); console.error('Failed to apply patches:', { - //patches : brewFromClient.patches, + // patches : brewFromClient.patches, + // result : result, brewId : brewFromClient.editId || 'unknown', error : err }); @@ -392,6 +423,9 @@ const api = { } let brew = _.assign(brewFromServer, brewFromClient); + + migrateSystemsToTags(brew); + brew.title = brew.title.trim(); brew.description = brew.description.trim() || ''; brew.text = api.mergeBrewText(brew); @@ -481,7 +515,7 @@ const api = { await HomebrewModel.deleteOne({ editId: id }); return next(); } - throw(err); + throw (err); } let brew = req.brew; diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 0a6d1d452..05ae8c51a 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -63,7 +63,6 @@ describe('Tests for api', ()=>{ title : 'some title', description : 'this is a description', tags : ['something', 'fun'], - systems : ['D&D 5e'], lang : 'en', renderer : 'v3', theme : 'phb', @@ -351,7 +350,6 @@ describe('Tests for api', ()=>{ renderer : 'legacy', lang : 'en', shareId : undefined, - systems : [], tags : [], theme : '5ePHB', thumbnail : '', @@ -390,7 +388,6 @@ describe('Tests for api', ()=>{ title : 'some title', description : 'this is a description', tags : ['something', 'fun'], - systems : ['D&D 5e'], renderer : 'v3', theme : 'phb', googleId : '12345' @@ -402,8 +399,6 @@ description: this is a description tags: - something - fun -systems: - - D&D 5e renderer: v3 theme: phb @@ -419,7 +414,6 @@ brew`); title : 'some title', description : 'this is a description', tags : ['something', 'fun'], - systems : ['D&D 5e'], renderer : 'v3', theme : 'phb', googleId : '12345' @@ -431,8 +425,6 @@ description: this is a description tags: - something - fun -systems: - - D&D 5e renderer: v3 theme: phb @@ -463,7 +455,6 @@ brew`); expect(sent).toEqual(googleBrew); expect(result.tags).toBeUndefined(); - expect(result.systems).toBeUndefined(); expect(result.published).toBeUndefined(); expect(result.authors).toBeUndefined(); expect(result.owner).toBeUndefined(); @@ -558,7 +549,6 @@ brew`); lang : 'en', shareId : expect.any(String), style : undefined, - systems : [], tags : [], text : undefined, textBin : expect.objectContaining({}), @@ -618,7 +608,6 @@ brew`); shareId : expect.any(String), googleId : expect.any(String), style : undefined, - systems : [], tags : [], text : undefined, textBin : undefined, @@ -1076,7 +1065,6 @@ brew`); 'title: title\n' + 'description: description\n' + 'tags: [ \'tag a\' , \'tag b\' ]\n' + - 'systems: [ test system ]\n' + 'renderer: legacy\n' + 'theme: 5ePHB\n' + 'lang: en\n' + @@ -1097,8 +1085,6 @@ brew`); // Metadata expect(testBrew.title).toEqual('title'); expect(testBrew.description).toEqual('description'); - expect(testBrew.tags).toEqual(['tag a', 'tag b']); - expect(testBrew.systems).toEqual(['test system']); expect(testBrew.renderer).toEqual('legacy'); expect(testBrew.theme).toEqual('5ePHB'); expect(testBrew.lang).toEqual('en'); @@ -1107,19 +1093,6 @@ brew`); // Text expect(testBrew.text).toEqual('text\n'); }); - - it('convert tags string to array', async ()=>{ - const testBrew = { - text : '```metadata\n' + - 'tags: tag a\n' + - '```\n\n' - }; - - splitTextStyleAndMetadata(testBrew); - - // Metadata - expect(testBrew.tags).toEqual(['tag a']); - }); }); describe('updateBrew', ()=>{ diff --git a/server/homebrew.model.js b/server/homebrew.model.js index ff371ee42..e923ac928 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -15,7 +15,7 @@ const HomebrewSchema = mongoose.Schema({ description : { type: String, default: '' }, tags : { type: [String], index: true }, - systems : [String], + systems : { type: [String], default: undefined }, lang : { type: String, default: 'en', index: true }, renderer : { type: String, default: '', index: true }, authors : { type: [String], index: true }, diff --git a/shared/helpers.js b/shared/helpers.js index 8177aa7a9..3610ccea4 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -91,7 +91,7 @@ const splitTextStyleAndMetadata = (brew)=>{ const index = brew.text.indexOf('\n```\n\n'); const metadataSection = brew.text.slice(11, index + 1); const metadata = yaml.load(metadataSection); - Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); + Object.assign(brew, _.pick(metadata, ['title', 'description', 'renderer', 'theme', 'lang'])); brew.snippets = yamlSnippetsToText(_.pick(metadata, ['snippets']).snippets || ''); brew.text = brew.text.slice(index + 6); } @@ -105,14 +105,35 @@ const splitTextStyleAndMetadata = (brew)=>{ if(typeof brew.tags === 'string') brew.tags = brew.tags ? [brew.tags] : []; }; -const printCurrentBrew = ()=>{ +const printCurrentBrew = async ()=>{ if(window.typeof !== 'undefined') { - window.frames['BrewRenderer'].contentWindow.print(); - //Force DOM reflow; Print dialog causes a repaint, and @media print CSS somehow makes out-of-view pages disappear - const node = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer').item(0); - node.style.display='none'; - node.offsetHeight; // accessing this is enough to trigger a reflow - node.style.display=''; + // fire a custom event for the print cycle + document.dispatchEvent(new CustomEvent('print:startprep')); + try { + const iframeDoc = window.frames['BrewRenderer'].contentDocument; + + // get all img elements with lazy loading (currently only elements generated through MarkedJS) + const lazyImages = [...iframeDoc.querySelectorAll('img[loading="lazy"]')]; + lazyImages.forEach((img)=>{ img.loading = 'eager'; }); + + // waits for images to load before resolving promise and opening print dialog + await Promise.all( + lazyImages + .filter((img)=>!img.complete) + .map((img)=>new Promise((resolve)=>{ img.onload = resolve; img.onerror = resolve; })) + ); + + window.frames['BrewRenderer'].contentWindow.print(); + + //Force DOM reflow; Print dialog causes a repaint, and @media print CSS somehow makes out-of-view pages disappear + const node = iframeDoc.getElementsByClassName('brewRenderer').item(0); + node.style.display='none'; + node.offsetHeight; // accessing this is enough to trigger a reflow + node.style.display=''; + } finally { + // when lazy load images have all been loaded, and the doc re-rendered for print preview, emit 'finished' event. + document.dispatchEvent(new CustomEvent('print:finishedprep')); + } } }; @@ -160,9 +181,35 @@ const debugTextMismatch = (clientTextRaw, serverTextRaw, label)=>{ // Char-level diff for (let i = 0; i < Math.min(clientText.length, serverText.length); i++) { if(clientText[i] !== serverText[i]) { + const getMismatchContext = (text, index, name, size = 10)=>{ + const lower = Math.max(index - size, 0); + const upper = Math.min(index + size, text.length); + const slice = `${JSON.stringify(text.slice(lower, index)).slice(1, -1)}\u001B[31m${JSON.stringify(text[i]).slice(1, -1)}\u001B[0m${JSON.stringify(text.slice(index+1, upper)).slice(1, -1)}`; + const lineNo = text.slice(0, index).split('\n').length; + const code = `U+${text.charCodeAt(i).toString(16).toUpperCase()}`; + + return { + name, + lineNo, + code, + lower, + upper, + slice + }; + }; + + const boundSize = 10; + + const clientContext = getMismatchContext(clientText, i, 'Client', boundSize); + const serverContext = getMismatchContext(serverText, i, 'Server', boundSize); + + const logContext = (context)=>{ + console.log(` ${context.name} - line ${context.lineNo} : (${context.code})\t${context.slice}`); + }; + console.log(`Char mismatch at index ${i}:`); - console.log(` Client: '${clientText[i]}' (U+${clientText.charCodeAt(i).toString(16).toUpperCase()})`); - console.log(` Server: '${serverText[i]}' (U+${serverText.charCodeAt(i).toString(16).toUpperCase()})`); + logContext(clientContext); + logContext(serverContext); break; } } diff --git a/shared/markdown.js b/shared/markdown.js index adb058042..05a564254 100644 --- a/shared/markdown.js +++ b/shared/markdown.js @@ -1,4 +1,4 @@ -/* eslint-disable max-depth */ + /* eslint-disable max-lines */ import _ from 'lodash'; import { marked as Marked } from 'marked'; @@ -70,9 +70,9 @@ renderer.link = function (token) { if(title) { out += ` title="${escape(title)}"`; } - if(self) { - out += ' target="_self"'; - } + // if(self) { + // out += ' target="_self"'; + // } out += `>${text}`; return out; }; @@ -83,7 +83,7 @@ renderer.image = function (token) { if(href === null) return text; - let out = `${text}${text}`; return out; }; diff --git a/shared/naturalcrit/styles/core.less b/shared/naturalcrit/styles/core.less index 02db5db18..3ff3e37fe 100644 --- a/shared/naturalcrit/styles/core.less +++ b/shared/naturalcrit/styles/core.less @@ -1,17 +1,10 @@ -@import 'naturalcrit/styles/reset.less'; -//@import 'naturalcrit/styles/elements.less'; -@import 'naturalcrit/styles/animations.less'; -@import 'naturalcrit/styles/colors.less'; -@import 'naturalcrit/styles/tooltip.less'; -@font-face { - font-family : 'CodeLight'; - src : data-uri('naturalcrit/styles/CODE Light.otf') format('opentype'); -} -@font-face { - font-family : 'CodeBold'; - src : data-uri('naturalcrit/styles/CODE Bold.otf') format('opentype'); -} +@import './reset.less'; +//@import './elements.less'; +@import './animations.less'; +@import './colors.less'; +@import './tooltip.less'; +@import './fonts/fonts.css'; html,body, #reactRoot { height : 100vh; min-height : 100vh; diff --git a/shared/naturalcrit/styles/CODE Bold.otf b/shared/naturalcrit/styles/fonts/CODE Bold.otf similarity index 100% rename from shared/naturalcrit/styles/CODE Bold.otf rename to shared/naturalcrit/styles/fonts/CODE Bold.otf diff --git a/shared/naturalcrit/styles/CODE Light.otf b/shared/naturalcrit/styles/fonts/CODE Light.otf similarity index 100% rename from shared/naturalcrit/styles/CODE Light.otf rename to shared/naturalcrit/styles/fonts/CODE Light.otf diff --git a/shared/naturalcrit/styles/fonts/fonts.css b/shared/naturalcrit/styles/fonts/fonts.css new file mode 100644 index 000000000..f7c0c4371 --- /dev/null +++ b/shared/naturalcrit/styles/fonts/fonts.css @@ -0,0 +1,38 @@ +/* open-sans-latin-wght-normal */ + +@font-face { + font-family : 'Open Sans'; + font-style : normal; + font-weight : normal; + src : url('open-sans-latin-400-normal.woff2') format('woff2'); + font-display : swap; + unicode-range : U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; +} + +/* +* Nowhere is font-weight: 700 actually used with Open Sans, everything is set to 800. +* But, 800 *is* too bold. And since we don't have an 800 font file, it's just using the +* 700 font file and it looks fine. Not sure it's worth changing everything to 700? +*/ +@font-face { + font-family : 'Open Sans'; + font-style : normal; + font-weight : bold; + src : url('open-sans-latin-700-normal.woff2') format('woff2'); + font-display : swap; + unicode-range : U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; +} + +@font-face { + font-family : 'CodeLight'; + font-style : normal; + src : url('./CODE Light.otf') format('opentype'); + font-display : block; +} + +@font-face { + font-family : 'CodeBold'; + font-style : normal; + src : url('./CODE Bold.otf') format('opentype'); + font-display : block; +} \ No newline at end of file diff --git a/shared/naturalcrit/styles/fonts/open-sans-latin-400-normal.woff2 b/shared/naturalcrit/styles/fonts/open-sans-latin-400-normal.woff2 new file mode 100644 index 000000000..e2d3fa4ea Binary files /dev/null and b/shared/naturalcrit/styles/fonts/open-sans-latin-400-normal.woff2 differ diff --git a/shared/naturalcrit/styles/fonts/open-sans-latin-700-normal.woff2 b/shared/naturalcrit/styles/fonts/open-sans-latin-700-normal.woff2 new file mode 100644 index 000000000..f5977a43a Binary files /dev/null and b/shared/naturalcrit/styles/fonts/open-sans-latin-700-normal.woff2 differ diff --git a/tests/html/safeHTML.test.js b/tests/html/safeHTML.test.js index 208101f9a..0b5b4c169 100644 --- a/tests/html/safeHTML.test.js +++ b/tests/html/safeHTML.test.js @@ -1,6 +1,6 @@ import globalJsdom from 'jsdom-global'; globalJsdom(); -import { safeHTML } from '../../client/homebrew/brewRenderer/safeHTML'; +import safeHTML from '../../client/homebrew/brewRenderer/safeHTML'; test('Exit if no document', function() { const doc = document; diff --git a/tests/markdown/basic.test.js b/tests/markdown/basic.test.js index ddceb9197..6a131eb91 100644 --- a/tests/markdown/basic.test.js +++ b/tests/markdown/basic.test.js @@ -1,6 +1,6 @@ -import Markdown from 'markdown.js'; +import Markdown from '../../shared/markdown.js'; test('Processes the markdown within an HTML block if its just a class wrapper', function() { const source = '
    *Bold text*
    '; @@ -8,8 +8,10 @@ test('Processes the markdown within an HTML block if its just a class wrapper', expect(rendered).toBe('

    Bold text

    \n
    '); }); -test('Check markdown is using the custom renderer; specifically that it adds target=_self attribute to internal links in HTML blocks', function() { - const source = '
    [Has _self Attribute?](#p1)
    '; - const rendered = Markdown.render(source); - expect(rendered).toBe(''); -}); +// TEST REMOVED AS IT IS NO LONGER REQUIRED +// +// test('Check markdown is using the custom renderer; specifically that it adds target=_self attribute to internal links in HTML blocks', function() { +// const source = '
    [Has _self Attribute?](#p1)
    '; +// const rendered = Markdown.render(source); +// expect(rendered).toBe(''); +// }); diff --git a/tests/markdown/definition-lists.test.js b/tests/markdown/definition-lists.test.js index 12499d559..35ad12ef7 100644 --- a/tests/markdown/definition-lists.test.js +++ b/tests/markdown/definition-lists.test.js @@ -1,6 +1,6 @@ -import Markdown from 'markdown.js'; +import Markdown from '../../shared/markdown.js'; describe('Inline Definition Lists', ()=>{ test('No Term 1 Definition', function() { diff --git a/tests/markdown/emojis.test.js b/tests/markdown/emojis.test.js index 5f0e102c9..072de10f9 100644 --- a/tests/markdown/emojis.test.js +++ b/tests/markdown/emojis.test.js @@ -1,4 +1,4 @@ -import Markdown from 'markdown.js'; +import Markdown from '../../shared/markdown.js'; import dedent from 'dedent'; // Marked.js adds line returns after closing tags on some default tokens. diff --git a/tests/markdown/hard-breaks.test.js b/tests/markdown/hard-breaks.test.js index 068b2053a..1f48f8f1e 100644 --- a/tests/markdown/hard-breaks.test.js +++ b/tests/markdown/hard-breaks.test.js @@ -1,6 +1,6 @@ -import Markdown from 'markdown.js'; +import Markdown from '../../shared/markdown.js'; describe('Hard Breaks', ()=>{ test('Single Break', function() { diff --git a/tests/markdown/mustache-syntax.test.js b/tests/markdown/mustache-syntax.test.js index 8562ae412..378263e58 100644 --- a/tests/markdown/mustache-syntax.test.js +++ b/tests/markdown/mustache-syntax.test.js @@ -1,7 +1,7 @@ /* eslint-disable max-lines */ import dedent from 'dedent'; -import Markdown from 'markdown.js'; +import Markdown from '../../shared/markdown.js'; // Marked.js adds line returns after closing tags on some default tokens. // This removes those line returns for comparison sake. @@ -324,7 +324,7 @@ describe('Injection: When an injection tag follows an element', ()=>{ it('Renders an image element with injected style', function() { const source = '![alt text](https://i.imgur.com/hMna6G0.png){position:absolute}'; const rendered = Markdown.render(source).trimReturns(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    alt text

    '); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

    alt text

    '); }); it('Renders an element modified by only the first of two consecutive injections', function() { @@ -343,19 +343,19 @@ describe('Injection: When an injection tag follows an element', ()=>{ it('Renders an image with added attributes', function() { const source = `![homebrew mug](https://i.imgur.com/hMna6G0.png) {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e}`; const rendered = Markdown.render(source).trimReturns(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    homebrew mug

    `); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    homebrew mug

    `); }); it('Renders an image with "=" in the url, and added attributes', function() { const source = `![homebrew mug](https://i.imgur.com/hMna6G0.png?auth=12345&height=1024) {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e}`; const rendered = Markdown.render(source).trimReturns(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    homebrew mug

    `); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    homebrew mug

    `); }); it('Renders an image and added attributes with "=" in the value, ', function() { const source = `![homebrew mug](https://i.imgur.com/hMna6G0.png) {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e,otherUrl="url?auth=12345"}`; const rendered = Markdown.render(source).trimReturns(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    homebrew mug

    `); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

    homebrew mug

    `); }); }); diff --git a/tests/markdown/non-breaking-spaces.test.js b/tests/markdown/non-breaking-spaces.test.js index 9da59b047..731d0546e 100644 --- a/tests/markdown/non-breaking-spaces.test.js +++ b/tests/markdown/non-breaking-spaces.test.js @@ -1,6 +1,6 @@ -import Markdown from 'markdown.js'; +import Markdown from '../../shared/markdown.js'; describe('Non-Breaking Spaces Interactions', ()=>{ test('I am actually a single-line definition list!', function() { diff --git a/tests/markdown/paragraph-justification.test.js b/tests/markdown/paragraph-justification.test.js index f5a5b12ab..6ce454623 100644 --- a/tests/markdown/paragraph-justification.test.js +++ b/tests/markdown/paragraph-justification.test.js @@ -1,6 +1,6 @@ -import Markdown from 'markdown.js'; +import Markdown from '../../shared/markdown.js'; describe('Justification', ()=>{ test('Left Justify', function() { diff --git a/tests/markdown/variables.test.js b/tests/markdown/variables.test.js index 49cd333c8..ad23c87c1 100644 --- a/tests/markdown/variables.test.js +++ b/tests/markdown/variables.test.js @@ -1,7 +1,7 @@ /* eslint-disable max-lines */ import dedent from 'dedent'; -import Markdown from 'markdown.js'; +import Markdown from '../../shared/markdown.js'; // Marked.js adds line returns after closing tags on some default tokens. // This removes those line returns for comparison sake. @@ -315,21 +315,21 @@ describe('Normal Links and Images', ()=>{ const source = `![alt text](url)`; const rendered = Markdown.render(source).trimReturns(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(dedent` -

    alt text

    `.trimReturns()); +

    alt text

    `.trimReturns()); }); it('Renders normal images with a title', function() { const source = 'An image ![alt text](url "and title")!'; const rendered = Markdown.render(source).trimReturns(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(dedent` -

    An image alt text!

    `.trimReturns()); +

    An image alt text!

    `.trimReturns()); }); it('Applies curly injectors to images', function() { const source = `![alt text](url){width:100px}`; const rendered = Markdown.render(source).trimReturns(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(dedent` -

    alt text

    `.trimReturns()); +

    alt text

    `.trimReturns()); }); it('Renders normal links', function() { @@ -438,25 +438,25 @@ describe('Regression Tests', ()=>{ it('Handle Extra spaces in image alt-text 1', function(){ const source='![ where is my image??](http://i.imgur.com/hMna6G0.png)'; const rendered = Markdown.render(source).trimReturns(); - expect(rendered).toBe('

    \"where

    '); + expect(rendered).toBe('

    \"where

    '); }); it('Handle Extra spaces in image alt-text 2', function(){ const source='![where is my image??](http://i.imgur.com/hMna6G0.png)'; const rendered = Markdown.render(source).trimReturns(); - expect(rendered).toBe('

    \"where

    '); + expect(rendered).toBe('

    \"where

    '); }); it('Handle Extra spaces in image alt-text 3', function(){ const source='![where is my image?? ](http://i.imgur.com/hMna6G0.png)'; const rendered = Markdown.render(source).trimReturns(); - expect(rendered).toBe('

    \"where

    '); + expect(rendered).toBe('

    \"where

    '); }); it('Handle Extra spaces in image alt-text 4', function(){ const source='![where is my image??](http://i.imgur.com/hMna6G0.png){height=20%,width=20%}'; const rendered = Markdown.render(source).trimReturns(); - expect(rendered).toBe('

    \"where

    '); + expect(rendered).toBe('

    \"where

    '); }); }); diff --git a/tests/routes/static-pages.test.js b/tests/routes/static-pages.test.js index ebfa48dd4..2741b8d70 100644 --- a/tests/routes/static-pages.test.js +++ b/tests/routes/static-pages.test.js @@ -1,27 +1,32 @@ import supertest from 'supertest'; -import HBApp from 'app.js'; +import createApp from '../../server/app.js'; -// Mimic https responses to avoid being redirected all the time -const app = supertest.agent(HBApp).set('X-Forwarded-Proto', 'https'); +let app; +let request; + +beforeAll(async ()=>{ + app = await createApp(); + request = supertest.agent(app).set('X-Forwarded-Proto', 'https'); +}); describe('Tests for static pages', ()=>{ - it('Home page works', ()=>{ - return app.get('/').expect(200); + it('Home page works', async ()=>{ + await request.get('/').expect(200); }); - it('Home page legacy works', ()=>{ - return app.get('/legacy').expect(200); + it('Home page legacy works', async ()=>{ + await request.get('/legacy').expect(200); }); - it('Changelog page works', ()=>{ - return app.get('/changelog').expect(200); + it('Changelog page works', async ()=>{ + await request.get('/changelog').expect(200); }); - it('FAQ page works', ()=>{ - return app.get('/faq').expect(200); + it('FAQ page works', async ()=>{ + await request.get('/faq').expect(200); }); - it('robots.txt works', ()=>{ - return app.get('/robots.txt').expect(200); + it('robots.txt works', async ()=>{ + await request.get('/robots.txt').expect(200); }); -}); +}); \ No newline at end of file diff --git a/themes/Legacy/5ePHB/snippets.js b/themes/Legacy/5ePHB/snippets.js index a6a9dbe88..5bf74b4ca 100644 --- a/themes/Legacy/5ePHB/snippets.js +++ b/themes/Legacy/5ePHB/snippets.js @@ -1,12 +1,12 @@ /* eslint-disable max-lines */ -import MagicGen from './snippets/magic.gen.js'; +import MagicGen from './snippets/magic.gen.js'; import ClassTableGen from './snippets/classtable.gen.js'; import MonsterBlockGen from './snippets/monsterblock.gen.js'; import ClassFeatureGen from './snippets/classfeature.gen.js'; import CoverPageGen from './snippets/coverpage.gen.js'; import TableOfContentsGen from './snippets/tableOfContents.gen.js'; -import dedent from 'dedent'; +import dedent from 'dedent'; export default [ diff --git a/themes/Legacy/5ePHB/snippets/classfeature.gen.js b/themes/Legacy/5ePHB/snippets/classfeature.gen.js index b92d527f9..70085d647 100644 --- a/themes/Legacy/5ePHB/snippets/classfeature.gen.js +++ b/themes/Legacy/5ePHB/snippets/classfeature.gen.js @@ -1,6 +1,6 @@ import _ from 'lodash'; -export default function(classname){ +function classFeatureGen(classname) { classname = _.sample(['archivist', 'fancyman', 'linguist', 'fletcher', 'notary', 'berserker-typist', 'fishmongerer', 'manicurist', 'haberdasher', 'concierge']); @@ -49,4 +49,6 @@ export default function(classname){ `- ${_.sample(['10 lint fluffs', '1 button', 'a cherished lost sock'])}`, '\n\n\n' ].join('\n'); -}; +} + +export default classFeatureGen; diff --git a/themes/Legacy/5ePHB/snippets/coverpage.gen.js b/themes/Legacy/5ePHB/snippets/coverpage.gen.js index 0cd0e50d5..9c2de2943 100644 --- a/themes/Legacy/5ePHB/snippets/coverpage.gen.js +++ b/themes/Legacy/5ePHB/snippets/coverpage.gen.js @@ -98,7 +98,7 @@ const subtitles = [ ]; -export default ()=>{ +function coverPageGen() { return ``); + return null; + }, +}; + +export const Inject = ({ tag, children, ...props })=>{ + useEffect(()=>{ + injectTag(tag, props, children); + }, []); + return null; +}; + +export const generate = ()=>Object.values(NamedTags).concat(UnnamedTags).join('\n'); + +export const flush = ()=>{ + NamedTags = {}; + UnnamedTags = []; +}; + +export const Meta = HeadComponents.Meta; + +export default { + Inject, + ...HeadComponents, + generate, + flush, +};