diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 71dfdbdf2..ab614b39d 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -1,30 +1,15 @@ import './editPage.less'; // Common imports -import React, { useState, useEffect, useRef, useEffectEvent } from 'react'; -import request from '../../utils/request-middleware.js'; - -import _ from 'lodash'; - -import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js'; - +import React from 'react'; +import request from '../../utils/request-middleware.js'; +import _ from 'lodash'; import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx'; - -import Nav from '@navbar/nav.jsx'; +import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js'; // Page specific imports -import { md5 } from 'hash-wasm'; import { gzipSync, strToU8 } from 'fflate'; -import { makePatches, stringifyPatches } from '@sanity/diff-match-patch'; - import { updateHistory, versionHistoryGarbageCollection } from '../../utils/versionHistory.js'; -import googleDriveIcon from '../../googleDrive.svg'; - -const useLocalStorage = false; -const sandbox = false; -const showFloatingButtons = false; -const showEditorButtons = true; -const pageName = 'editPage'; const EditPage = (props)=>{ props = { @@ -32,75 +17,19 @@ const EditPage = (props)=>{ ...props }; - const [currentBrew, setCurrentBrew] = useState(props.brew); - const [saveGoogle, setSaveGoogle] = useState(!!props.brew.googleId); - const [error, setError] = useState(null); - const [alertTrashedGoogleBrew, setAlertTrashedGoogleBrew] = useState(props.brew.trashed); - const [alertNoGoogleToTransfer, setAlertNoGoogleToTransfer] = useState(false); - const [alertOwnershipToTransfer, setAlertOwnershipToTransfer] = useState(false); - const [confirmGoogleTransfer, setConfirmGoogleTransfer] = useState(false); - - const lastSavedBrew = useRef(_.cloneDeep(props.brew)); - - const handleGoogleClick = ()=>{ - if(currentBrew.authors.length > 0 && global.account?.username !== currentBrew.authors[0]) { - setAlertOwnershipToTransfer(true); - return; - } - if(!global.account?.googleId) { - setAlertNoGoogleToTransfer(true); - return; - } - - setConfirmGoogleTransfer((prev)=>!prev); - setError(null); - }; - - const closeAlerts = (e)=>{ - e.stopPropagation(); //Only handle click once so alert doesn't reopen - setAlertTrashedGoogleBrew(false); - setAlertNoGoogleToTransfer(false); - setConfirmGoogleTransfer(false); - setAlertOwnershipToTransfer(false); - }; - - const toggleGoogleStorage = (e)=>{ - closeAlerts(e); - const newSaveGoogle = !saveGoogle; - setSaveGoogle((prev)=>!prev); - setError(null); - trySave(true, true, newSaveGoogle); - }; - const save = async (brew, saveToGoogle)=>{ await updateHistory(brew).catch(console.error); await versionHistoryGarbageCollection().catch(console.error); - //Prepare content to send to server - const brewToSave = { - ...brew, - text : brew.text.normalize('NFC'), - 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, - version : lastSavedBrew.current.version - }; - - const compressedBrew = gzipSync(strToU8(JSON.stringify(brewToSave))); + const compressedBrew = gzipSync(strToU8(JSON.stringify(brew))); const transfer = saveToGoogle === _.isNil(brew.googleId); const params = transfer ? `?${saveToGoogle ? 'saveToGoogle' : 'removeFromGoogle'}=true` : ''; const res = await request - .put(`/api/update/${brewToSave.editId}${params}`) + .put(`/api/update/${brew.editId}${params}`) .set('Content-Encoding', 'gzip') .set('Content-Type', 'application/json') - .send(compressedBrew) - .catch((err)=>{ - console.error('Error Updating Local Brew'); - setError(err); - }); - if(!res) return; + .send(compressedBrew); const updatedFields = { googleId : res.body.googleId ?? null, //TODO: investigate if we can set googleId:null in server/update instead of undefined @@ -116,70 +45,18 @@ const EditPage = (props)=>{ history.replaceState(null, null, `/edit/${savedBrew.editId}`);; }; - const renderGoogleDriveIcon = ()=>( - - Google Drive icon - - {alertOwnershipToTransfer && ( -
- You must be the Owner to transfer between the Homebrewery and Google Drive! - The owner of this file is {currentBrew.authors[0]}. -

-
Okay
-
- )} - - {alertNoGoogleToTransfer && ( -
- You must be signed in to a Google account to transfer between the Homebrewery and Google Drive! - -
Sign In
-
-
Not Now
-
- )} - - {alertTrashedGoogleBrew && ( -
- This brew is currently in your Trash folder on Google Drive!
- If you want to keep it, make sure to move it before it is deleted permanently!
-
Save my brew
-
- )} - - {confirmGoogleTransfer && ( -
- {saveGoogle - ? 'Would you like to transfer this brew from your Google Drive storage back to the Homebrewery?' - : 'Would you like to transfer this brew from the Homebrewery to your personal Google Drive storage?'} -
-
Yes
-
No
-
- )} -
- ); - const { renderPanels, - trySave, } = useCommonEditPageFunctions({ - saveGoogle, - setSaveGoogle, - error, - setError, - currentBrew, - setCurrentBrew, - useLocalStorage, - sandbox, - showFloatingButtons, - lastSavedBrew, + useLocalStorage : false, + sandbox : false, + showFloatingButtons : false, + showEditorButtons : true, + pageName : 'newPage', + brew : props.brew, + userThemes : props.userThemes, save, onSaveSuccess, - pageName, - showEditorButtons, - renderGoogleDriveIcon, - userThemes : props.userThemes }); return renderPanels(); diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 20b75b486..014cc8e42 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -1,20 +1,11 @@ import './homePage.less'; // Common imports -import React, { useState, useEffect, useRef, useEffectEvent } from 'react'; -import request from '../../utils/request-middleware.js'; -import _ from 'lodash'; - -import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; - +import React from 'react'; +import request from '../../utils/request-middleware.js'; +import _ from 'lodash'; import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx'; - -// Page specific imports -const useLocalStorage = false; -const sandbox = true; -const showFloatingButtons = true; -const showEditorButtons = false; -const pageName = 'homePage'; +import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; const HomePage =(props)=>{ props = { @@ -22,21 +13,10 @@ const HomePage =(props)=>{ ...props }; - const [currentBrew, setCurrentBrew] = useState(props.brew); - const [saveGoogle, setSaveGoogle] = useState(global.account?.googleId ? true : false); - const [error, setError] = useState(undefined); - - const lastSavedBrew = useRef(_.cloneDeep(props.brew)); - const save = async (brew, saveToGoogle)=>{ const res = await request - .post(`/api${saveGoogle ? '?saveToGoogle=true' : ''}`) - .send(brew) - .catch((err)=>{ - console.error('Error Updating Local Brew'); - setError(err); - }); - if(!res) return; + .post(`/api${saveToGoogle ? '?saveToGoogle=true' : ''}`) + .send(brew); return res.body; }; @@ -49,21 +29,15 @@ const HomePage =(props)=>{ const { renderPanels } = useCommonEditPageFunctions({ - saveGoogle, - setSaveGoogle, - error, - setError, - currentBrew, - setCurrentBrew, - useLocalStorage, - sandbox, - showFloatingButtons, - lastSavedBrew, + useLocalStorage : false, + sandbox : true, + showFloatingButtons : true, + showEditorButtons : false, + pageName : 'homePage', + brew : props.brew, + userThemes : {}, save, onSaveSuccess, - pageName, - showEditorButtons, - userThemes : {} }); return renderPanels(); diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 8606cc752..9ce022d0d 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -1,20 +1,11 @@ import './newPage.less'; // Common imports -import React, { useState, useEffect, useRef, useEffectEvent } from 'react'; -import request from '../../utils/request-middleware.js'; -import _ from 'lodash'; - -import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; - +import React from 'react'; +import request from '../../utils/request-middleware.js'; +import _ from 'lodash'; import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx'; - -// Page specific imports -const useLocalStorage = true; -const sandbox = true; -const showFloatingButtons = false; -const showEditorButtons = true; -const pageName = 'newPage'; +import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; const NewPage = (props)=>{ props = { @@ -22,29 +13,10 @@ const NewPage = (props)=>{ ...props }; - const [currentBrew, setCurrentBrew] = useState(props.brew); - const [saveGoogle, setSaveGoogle] = useState(global.account?.googleId ? true : false); - const [error, setError] = useState(null); - - const lastSavedBrew = useRef(_.cloneDeep(props.brew)); - const save = async (brew, saveToGoogle)=>{ - //Prepare content to send to server - const brewToSave = { - ...brew, - text : brew.text.normalize('NFC'), - pageCount : ((brew.renderer === 'legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/gm)) || []).length + 1, - textBin : undefined - }; - const res = await request - .post(`/api${saveGoogle ? '?saveToGoogle=true' : ''}`) - .send(brewToSave) - .catch((err)=>{ - console.error('Error Updating Local Brew'); - setError(err); - }); - if(!res) return; + .post(`/api${saveToGoogle ? '?saveToGoogle=true' : ''}`) + .send(brew); return res.body; }; @@ -57,21 +29,15 @@ const NewPage = (props)=>{ const { renderPanels } = useCommonEditPageFunctions({ - saveGoogle, - setSaveGoogle, - error, - setError, - currentBrew, - setCurrentBrew, - useLocalStorage, - sandbox, - showFloatingButtons, - lastSavedBrew, + useLocalStorage : true, + sandbox : true, + showFloatingButtons : false, + showEditorButtons : true, + pageName : 'newPage', + brew : props.brew, + userThemes : props.userThemes, save, onSaveSuccess, - pageName, - showEditorButtons, - userThemes : props.userThemes }); return renderPanels(); diff --git a/client/homebrew/utils/commonEditPageFunctions.jsx b/client/homebrew/utils/commonEditPageFunctions.jsx index 701680ecf..b65ce34c1 100644 --- a/client/homebrew/utils/commonEditPageFunctions.jsx +++ b/client/homebrew/utils/commonEditPageFunctions.jsx @@ -2,6 +2,8 @@ import React, { useState, useEffect, useEffectEvent, useRef } from 'react'; import { printCurrentBrew, fetchThemeBundle } from '@shared/helpers.js'; import _ from 'lodash'; import { hbfm } from 'marked-hbfm'; +import { md5 } from 'hash-wasm'; +import { makePatches, stringifyPatches } from '@sanity/diff-match-patch'; import Headtags from '@vitreum/headtags.js'; import SplitPane from '@components/splitPane/splitPane.jsx'; @@ -22,6 +24,7 @@ import PrintNavItem from '@navbar/print.navitem.jsx'; import ShareNavItem from '@navbar/share.navitem.jsx'; import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; +import googleDriveIcon from '../googleDrive.svg'; const AUTOSAVE_KEY = 'HB_editor_autoSaveOn'; const BREWKEY = 'HB_newPage_content'; @@ -36,24 +39,18 @@ const UNSAVED_WARNING_POPUP_TIMEOUT = 4000; //Show the warning for 4 seconds export default function useCommonEditPageFunctions(dependencies) { const { - saveGoogle, - setSaveGoogle, - error, - setError, - currentBrew, - setCurrentBrew, + brew, useLocalStorage, sandbox, showFloatingButtons, - lastSavedBrew, save, onSaveSuccess, pageName, - renderGoogleDriveIcon = ()=>{}, showEditorButtons, userThemes = {} } = dependencies; + const [currentBrew, setCurrentBrew] = useState(brew); const [isSaving, setIsSaving] = useState(false); const [lastSavedTime, setLastSavedTime] = useState(new Date()); const [autoSaveEnabled, setAutoSaveEnabled] = useState(!sandbox); @@ -61,6 +58,13 @@ export default function useCommonEditPageFunctions(dependencies) { const [unsavedChanges, setUnsavedChanges] = useState(false); const [themeBundle, setThemeBundle] = useState({}); const [HTMLErrors, setHTMLErrors] = useState(hbfm.validate(currentBrew.text)); + const [saveGoogle, setSaveGoogle] = useState(currentBrew.googleId); + const [error, setError] = useState(null); + + const [alertTrashedGoogleBrew, setAlertTrashedGoogleBrew] = useState(currentBrew.trashed); + const [alertNoGoogleToTransfer, setAlertNoGoogleToTransfer] = useState(false); + const [alertOwnershipToTransfer, setAlertOwnershipToTransfer] = useState(false); + const [confirmGoogleTransfer, setConfirmGoogleTransfer] = useState(false); const [currentEditorViewPageNum, setCurrentEditorViewPageNum] = useState(1); const [currentEditorCursorPageNum, setCurrentEditorCursorPageNum] = useState(1); @@ -68,6 +72,7 @@ export default function useCommonEditPageFunctions(dependencies) { const unsavedChangesRef = useRef(unsavedChanges); // onBeforeUnload lives outside React and needs ref to unsavedChanges const warnUnsavedTimeout = useRef(null); // timers live outside React and need ref to consistently track time + const lastSavedBrew = useRef(_.cloneDeep(currentBrew)); const saveTimeout = useRef(null); const editorRef = useRef(null); @@ -202,12 +207,27 @@ export default function useCommonEditPageFunctions(dependencies) { setIsSaving(true); setError(null); setHTMLErrors(hbfm.validate(currentBrew.text)); - const brewToSave = currentBrew; - let savedBrew = await save(brewToSave, saveToGoogle) - .catch((err)=>{setError(err);}); + + //Prepare content to send to server + const snapshotBrewBeforeSave = currentBrew; + const brewToSave = { + ...currentBrew, + text : currentBrew.text.normalize('NFC'), + pageCount : ((currentBrew.renderer === 'legacy' ? currentBrew.text.match(/\\page/g) : currentBrew.text.match(/^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/gm)) || []).length + 1, + patches : stringifyPatches(makePatches(encodeURI(lastSavedBrew.current.text.normalize('NFC')), encodeURI(currentBrew.text.normalize('NFC')))), + hash : await md5(lastSavedBrew.current.text.normalize('NFC')), + textBin : undefined, + version : lastSavedBrew.current.version + }; + + const savedBrew = await save(brewToSave, saveToGoogle) + .catch((err)=>{ + console.error('Error Updating Local Brew'); + setError(err); + }); if(savedBrew) { lastSavedBrew.current = { - ...brewToSave, + ...snapshotBrewBeforeSave, ...savedBrew }; @@ -217,11 +237,11 @@ export default function useCommonEditPageFunctions(dependencies) { })); if(useLocalStorage) clearLocalStorage(); + setLastSavedTime(new Date()); + if(!autoSaveEnabled) resetWarnUnsavedTimer(); onSaveSuccess(savedBrew); } setIsSaving(false); - setLastSavedTime(new Date()); - if(!autoSaveEnabled) resetWarnUnsavedTimer(); }, newTimeout); }); @@ -262,18 +282,94 @@ export default function useCommonEditPageFunctions(dependencies) { snippets : newData.snippets })); + //======----- Google Toggle Button -----====== + const closeAlerts = (e)=>{ + e.stopPropagation(); //Only handle click once so alert doesn't reopen + setAlertTrashedGoogleBrew(false); + setAlertNoGoogleToTransfer(false); + setConfirmGoogleTransfer(false); + setAlertOwnershipToTransfer(false); + }; + + const handleGoogleClick = ()=>{ + if(currentBrew.authors.length > 0 && global.account?.username !== currentBrew.authors[0]) { + setAlertOwnershipToTransfer(true); + return; + } + if(!global.account?.googleId) { + setAlertNoGoogleToTransfer(true); + return; + } + + setConfirmGoogleTransfer((prev)=>!prev); + setError(null); + }; + + const toggleGoogleStorage = (e)=>{ + closeAlerts(e); + const newSaveGoogle = !saveGoogle; + setSaveGoogle((prev)=>!prev); + setError(null); + trySave(true, true, newSaveGoogle); + }; + + const renderGoogleDriveIcon = ()=>( + + Google Drive icon + + {alertOwnershipToTransfer && ( +
+ You must be the Owner to transfer between the Homebrewery and Google Drive! + The owner of this file is {currentBrew.authors[0]}. +

+
Okay
+
+ )} + + {alertNoGoogleToTransfer && ( +
+ You must be signed in to a Google account to transfer between the Homebrewery and Google Drive! + +
Sign In
+
+
Not Now
+
+ )} + + {alertTrashedGoogleBrew && ( +
+ This brew is currently in your Trash folder on Google Drive!
+ If you want to keep it, make sure to move it before it is deleted permanently!
+
Save my brew
+
+ )} + + {confirmGoogleTransfer && ( +
+ {saveGoogle + ? 'Would you like to transfer this brew from your Google Drive storage back to the Homebrewery?' + : 'Would you like to transfer this brew from the Homebrewery to your personal Google Drive storage?'} +
+
Yes
+
No
+
+ )} +
+ ); + + //======----- Navbar -----====== const renderNavbar = ()=>( {currentBrew.title} - {renderGoogleDriveIcon()} + {(pageName == 'editPage') && renderGoogleDriveIcon()} {error ? : {renderSaveButton()} - {pageName == 'editPage' && renderAutoSaveButton()} + {(pageName == 'editPage') && renderAutoSaveButton()} } diff --git a/package-lock.json b/package-lock.json index be79fc6b9..57553c211 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "@codemirror/search": "^6.6.0", "@codemirror/state": "^6.7.6", "@codemirror/view": "^6.43.13", - "@googleapis/drive": "^26.0.1", + "@googleapis/drive": "^26.0.2", "@lezer/highlight": "^1.2.4", "@oddbird/css-anchor-positioning": "^0.10.2", "@sanity/diff-match-patch": "^3.2.1", @@ -52,7 +52,7 @@ "marked-hbfm": "^1.0.1", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.31.0", - "mongoose": "^9.10.2", + "mongoose": "^9.10.4", "nanoid": "6.0.1", "nconf": "^0.13.0", "node": "^26.10.0", @@ -65,7 +65,7 @@ "superagent": "^10.4.1" }, "devDependencies": { - "@stylistic/stylelint-plugin": "^5.3.0", + "@stylistic/stylelint-plugin": "^5.3.1", "babel-jest": "^30.5.2", "babel-plugin-transform-import-meta": "^3.0.0", "eslint": "9.7", @@ -77,11 +77,11 @@ "jsdom": "^30.1.1", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^17.15.0", + "stylelint": "^17.16.0", "stylelint-config-recess-order": "^7.7.0", "stylelint-config-recommended": "^18.0.0", - "supertest": "^7.3.0", - "vite": "^8.3.1" + "supertest": "^7.3.1", + "vite": "^8.3.2" }, "engines": { "node": ">=26.4.0", @@ -2516,9 +2516,9 @@ "license": "MIT" }, "node_modules/@googleapis/drive": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-26.0.1.tgz", - "integrity": "sha512-q1U+WNS2OPAS3Prn3FD0otYNudnv+feXX9DP8qrDqGGwIVU90OBnP6NV66aTc0qJrqeJvnrCYcnjddjm4h23iQ==", + "version": "26.0.2", + "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-26.0.2.tgz", + "integrity": "sha512-VeKVZvzgH4ioczJZrZ5sy73RJbHrYLI1XZIZ3ZqGKQhC4U03XsOOOiBHKqvH4F9vbXrxR2LawmktoIJuTJhzYg==", "license": "Apache-2.0", "dependencies": { "googleapis-common": "^9.0.0" @@ -4339,9 +4339,9 @@ "license": "MIT" }, "node_modules/@stylistic/stylelint-plugin": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-5.3.0.tgz", - "integrity": "sha512-xbyxPeaO9Vns6A8/0MQV6PzZ5nNZCoGV4q1ERaNd5EBAKlWt+YcpaPapNYNUkZaiQg98+xPbikdA58ehquJG3g==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-5.3.1.tgz", + "integrity": "sha512-w6WFLYzQS6nhbcoq8pwYP+OJYYhsdGEiCxY+eINi2+ouDwRLXTucXZj6IrDzkY4di+vsGOPVvJ4/gXChSeOtlw==", "dev": true, "license": "MIT", "dependencies": { @@ -11858,9 +11858,9 @@ } }, "node_modules/mongoose": { - "version": "9.10.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.10.2.tgz", - "integrity": "sha512-oFcFL3dsX5tDzMwBD+GGoDqKIj6RNG3bu3oqlvcUIgPulHP14/6N7c07j3s0XgbrlT7U/lbiXOD89hmPtEXnfQ==", + "version": "9.10.4", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.10.4.tgz", + "integrity": "sha512-p1hx2MSD4B+4shFTpRcd/uTwD6DtZeDJ+YxM9ja8/VBDH7vqqLynwGLA6rWa/tD7voOBoGqQR1wM3+/LcUoEfA==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", @@ -11879,31 +11879,6 @@ "url": "https://opencollective.com/mongoose" } }, - "node_modules/mongoose/node_modules/gcp-metadata": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", - "integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/mongoose/node_modules/google-logging-utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.2.0.tgz", - "integrity": "sha512-WE9av4wKDZgRjBwgVUabocx8T6/7o3Ca1Fat46FXDhXVAFibzNadedcOXrdgd1Kzmk8tsk/9ZH89Wyf/SqeZ3A==", - "extraneous": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, "node_modules/mongoose/node_modules/mongodb": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.6.0.tgz", @@ -13765,9 +13740,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -14103,9 +14078,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "17.15.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.15.0.tgz", - "integrity": "sha512-mWIkesYQvQjf4Kvdeu9ns0IL8/K/wtjaGxPqsPd6DlLZvaQxGysJsocxUDrBcyHQ5VleAk4uSMat4yMrVED7PA==", + "version": "17.16.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.16.0.tgz", + "integrity": "sha512-ejlWnbJ13x1GU32+zZXa6sYQJsKKkwSdv2B4rAdO3OWdEmvhSJKcXi5pOphQYSzyaj1kXpuGJr7pcMBNfDIuPw==", "dev": true, "funding": [ { @@ -14305,9 +14280,9 @@ } }, "node_modules/supertest": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.3.0.tgz", - "integrity": "sha512-UwwmWq3xLhyU96c521wYNaBg7IqX78Wpj4FKs6Katp6vdklX42zU5ESvX3KeZRLFyO44RwFp4yvxYMNZzCcX9g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.3.1.tgz", + "integrity": "sha512-vNaNCFoCR/edDbErQZp5KLNT8R4dSPHX7rlDLoE8hWLAm/878j6ShMbe8HK/E6RwwuhlSXVelXAIg9AxR5WWPw==", "dev": true, "license": "MIT", "dependencies": { @@ -15104,15 +15079,15 @@ } }, "node_modules/vite": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.1.tgz", - "integrity": "sha512-/bvH9E9tmCXRGp2uXY3WbOldqpTwFkbha/8ANaEQ6VkxhH60KyqLwgZq6lG2y+4uT55x9+9eUHMpQ7uGnOCKjA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.2.tgz", + "integrity": "sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==", "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", "postcss": "^8.5.28", - "rolldown": "~1.2.9", + "rolldown": "~1.2.11", "tinyglobby": "^0.2.17" }, "bin": { diff --git a/package.json b/package.json index 726664122..55a0dc29c 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "@codemirror/search": "^6.6.0", "@codemirror/state": "^6.7.6", "@codemirror/view": "^6.43.13", - "@googleapis/drive": "^26.0.1", + "@googleapis/drive": "^26.0.2", "@lezer/highlight": "^1.2.4", "@oddbird/css-anchor-positioning": "^0.10.2", "@sanity/diff-match-patch": "^3.2.1", @@ -129,7 +129,7 @@ "marked-hbfm": "^1.0.1", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.31.0", - "mongoose": "^9.10.2", + "mongoose": "^9.10.4", "nanoid": "6.0.1", "nconf": "^0.13.0", "node": "^26.10.0", @@ -142,7 +142,7 @@ "superagent": "^10.4.1" }, "devDependencies": { - "@stylistic/stylelint-plugin": "^5.3.0", + "@stylistic/stylelint-plugin": "^5.3.1", "babel-jest": "^30.5.2", "babel-plugin-transform-import-meta": "^3.0.0", "eslint": "9.7", @@ -154,10 +154,10 @@ "jsdom": "^30.1.1", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^17.15.0", + "stylelint": "^17.16.0", "stylelint-config-recess-order": "^7.7.0", "stylelint-config-recommended": "^18.0.0", - "supertest": "^7.3.0", - "vite": "^8.3.1" + "supertest": "^7.3.1", + "vite": "^8.3.2" } }