Просмотр исходного кода

Merge branch 'master' into fix/170293-swagger-jsdoc

Shun Miyazawa 7 месяцев назад
Родитель
Сommit
32cd153703

+ 14 - 1
CHANGELOG.md

@@ -1,9 +1,22 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v7.2.8...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v7.2.9...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v7.2.9](https://github.com/weseek/growi/compare/v7.2.8...v7.2.9) - 2025-07-01
+
+### 🚀 Improvement
+
+* imprv(ai): Assistant instructions (#10129) @yuki-takei
+* imprv: OpenTelemetry phase 2 (#10095) @yuki-takei
+* imprv: Adjust margin-top for .main at md and lg breakpoints (#10131) @yuki-takei
+
+### 🐛 Bug Fixes
+
+* fix: Sharelink expiration date parsing when the date is cleared by the calendar UI (#10132) @yuki-takei
+* fix: Cannot change file upload destination to "MongoDB (GridFS)" or "local" for dev/7.2.x (#10119) @miya
+
 ## [v7.2.8](https://github.com/weseek/growi/compare/v7.2.7...v7.2.8) - 2025-06-26
 
 ### 💎 Features

+ 3 - 1
apps/app/.env.development

@@ -30,7 +30,9 @@ OGP_URI="http://ogp:8088"
 # AUDIT_LOG_ADDITIONAL_ACTIONS=
 # AUDIT_LOG_EXCLUDE_ACTIONS=
 
-# OpenTelemetry Official Configuration
+SERVICE_TYPE=dev
+
+# OpenTelemetry Official Configuration for dev
 # Environment variables starting with 'OTEL_' are automatically loaded by the OpenTelemetry SDK
 OPENTELEMETRY_ENABLED=false
 OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317

+ 1 - 1
apps/app/.env.production

@@ -7,6 +7,6 @@ MIGRATIONS_DIR=dist/migrations/
 
 # OpenTelemetry Official Configuration
 # Environment variables starting with 'OTEL_' are automatically loaded by the OpenTelemetry SDK
-OTEL_TRACES_SAMPLER_ARG=0.1
+OTEL_TRACES_SAMPLER_ARG=0.01
 OTEL_METRIC_EXPORT_INTERVAL=300000
 OTEL_EXPORTER_OTLP_ENDPOINT="https://telemetry.growi.org"

+ 1 - 1
apps/app/package.json

@@ -158,7 +158,7 @@
     "mdast-util-from-markdown": "^2.0.1",
     "mdast-util-gfm-table": "^2.0.0",
     "mdast-util-wiki-link": "^0.1.2",
-    "mermaid": "^11.9.0",
+    "mermaid": "^11.10.0",
     "method-override": "^3.0.0",
     "micromark-extension-gfm-table": "^2.1.0",
     "micromark-extension-wiki-link": "^0.0.4",

+ 27 - 18
apps/app/src/client/components/Common/CopyDropdown/CopyDropdown.jsx → apps/app/src/client/components/Common/CopyDropdown/CopyDropdown.tsx

@@ -1,10 +1,9 @@
 import React, {
-  useState, useMemo, useCallback,
+  useState, useMemo, useCallback, type ReactNode, type CSSProperties,
 } from 'react';
 
 import { pagePathUtils } from '@growi/core/dist/utils';
 import { useTranslation } from 'next-i18next';
-import PropTypes from 'prop-types';
 import { CopyToClipboard } from 'react-copy-to-clipboard';
 import {
   Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
@@ -15,9 +14,26 @@ import styles from './CopyDropdown.module.scss';
 
 const { encodeSpaces } = pagePathUtils;
 
+interface DropdownItemContentsProps {
+  title: string;
+  contents: ReactNode;
+  className?: string;
+  style?: CSSProperties;
+}
+
+interface CopyDropdownProps {
+  children: ReactNode;
+  dropdownToggleId: string;
+  pagePath: string;
+  pageId?: string;
+  dropdownToggleClassName?: string;
+  dropdownMenuContainer?: string | HTMLElement | React.RefObject<HTMLElement>;
+  isShareLinkMode?: boolean;
+}
+
 /* eslint-disable react/prop-types */
-const DropdownItemContents = ({
-  title, contents, className, style,
+const DropdownItemContents: React.FC<DropdownItemContentsProps> = ({
+  title, contents, className = '', style,
 }) => (
   <>
     <div className="h6 mt-1 mb-2"><strong>{title}</strong></div>
@@ -27,7 +43,7 @@ const DropdownItemContents = ({
 /* eslint-enable react/prop-types */
 
 
-export const CopyDropdown = (props) => {
+export const CopyDropdown: React.FC<CopyDropdownProps> = (props) => {
   const [dropdownOpen, setDropdownOpen] = useState(false);
   const [tooltipOpen, setTooltipOpen] = useState(false);
   const [isParamsAppended, setParamsAppended] = useState(!props.isShareLinkMode);
@@ -105,7 +121,10 @@ export const CopyDropdown = (props) => {
    */
   const { t } = useTranslation('commons');
   const {
-    dropdownToggleId, pageId, dropdownToggleClassName, children, isShareLinkMode,
+    dropdownToggleId, pageId,
+    dropdownToggleClassName,
+    dropdownMenuContainer,
+    children, isShareLinkMode,
   } = props;
 
   const customSwitchForParamsId = `customSwitchForParams_${dropdownToggleId}`;
@@ -128,7 +147,7 @@ export const CopyDropdown = (props) => {
         <DropdownMenu
           className={`${styles['copy-clipboard-dropdown-menu']}`}
           strategy="fixed"
-          container="body"
+          container={dropdownMenuContainer}
         >
           <div className="d-flex align-items-center justify-content-between">
             <DropdownItem header className="px-3">
@@ -209,7 +228,7 @@ export const CopyDropdown = (props) => {
           { pageId && (
             <CopyToClipboard text={markdownLink} onCopy={showToolTip}>
               <DropdownItem className="px-3 text-wrap">
-                <DropdownItemContents title={t('copy_to_clipboard.Markdown link')} contents={markdownLink} isContentsWrap />
+                <DropdownItemContents title={t('copy_to_clipboard.Markdown link')} contents={markdownLink} />
               </DropdownItem>
             </CopyToClipboard>
           )}
@@ -223,13 +242,3 @@ export const CopyDropdown = (props) => {
     </>
   );
 };
-
-CopyDropdown.propTypes = {
-  children: PropTypes.node.isRequired,
-  dropdownToggleId: PropTypes.string.isRequired,
-  pagePath: PropTypes.string.isRequired,
-
-  pageId: PropTypes.string,
-  dropdownToggleClassName: PropTypes.string,
-  isShareLinkMode: PropTypes.bool,
-};

+ 1 - 0
apps/app/src/client/components/PageHeader/PageTitleHeader.tsx

@@ -166,6 +166,7 @@ export const PageTitleHeader = (props: Props): JSX.Element => {
           pagePath={currentPage.path}
           dropdownToggleId={`copydropdown-in-pagetitleheader-${currentPage._id}`}
           dropdownToggleClassName="p-1"
+          dropdownMenuContainer="body"
         >
           <span className="material-symbols-outlined fs-6">content_paste</span>
         </CopyDropdown>

+ 7 - 1
apps/app/src/components/Common/PagePathNav/PagePathNavLayout.tsx

@@ -64,7 +64,13 @@ export const PagePathNavLayout = (props: Props): JSX.Element => {
               <span className="badge text-bg-secondary">WIP</span>
             )}
             <span className="grw-page-path-nav-copydropdown">
-              <CopyDropdown pageId={pageId} pagePath={pagePath} dropdownToggleId={copyDropdownId} dropdownToggleClassName="p-2">
+              <CopyDropdown
+                pageId={pageId}
+                pagePath={pagePath}
+                dropdownToggleId={copyDropdownId}
+                dropdownToggleClassName="p-2"
+                dropdownMenuContainer="body"
+              >
                 <span className="material-symbols-outlined">content_paste</span>
               </CopyDropdown>
             </span>

+ 60 - 6
apps/app/src/features/opentelemetry/server/node-sdk.spec.ts

@@ -3,7 +3,7 @@ import { NodeSDK } from '@opentelemetry/sdk-node';
 
 import { configManager } from '~/server/service/config-manager';
 
-import { setupAdditionalResourceAttributes, initInstrumentation } from './node-sdk';
+import { setupAdditionalResourceAttributes, initInstrumentation, startOpenTelemetry } from './node-sdk';
 import { getResource } from './node-sdk-resource';
 
 // Only mock configManager as it's external to what we're testing
@@ -67,15 +67,10 @@ describe('node-sdk', () => {
 
   describe('initInstrumentation', () => {
     it('should call setupCustomMetrics when instrumentation is enabled', async() => {
-      const { setupCustomMetrics } = await import('./custom-metrics');
-
       // Mock instrumentation as enabled
       mockInstrumentationEnabled();
 
       await initInstrumentation();
-
-      // Verify setupCustomMetrics was called
-      expect(setupCustomMetrics).toHaveBeenCalledOnce();
     });
 
     it('should not call setupCustomMetrics when instrumentation is disabled', async() => {
@@ -203,4 +198,63 @@ describe('node-sdk', () => {
       await expect(setupAdditionalResourceAttributes()).resolves.toBeUndefined();
     });
   });
+
+  describe('startOpenTelemetry', () => {
+    it('should start SDK and call setupCustomMetrics when instrumentation is enabled and SDK instance exists', async() => {
+      const { setupCustomMetrics } = await import('./custom-metrics');
+
+      // Mock instrumentation as enabled
+      mockInstrumentationEnabled();
+
+      // Initialize SDK first
+      await initInstrumentation();
+
+      // Get SDK instance and mock its start method
+      const { __testing__ } = await import('./node-sdk');
+      const sdkInstance = __testing__.getSdkInstance();
+      expect(sdkInstance).toBeDefined();
+
+      if (sdkInstance != null) {
+        const startSpy = vi.spyOn(sdkInstance, 'start');
+
+        // Call startOpenTelemetry
+        startOpenTelemetry();
+
+        // Verify that start method was called
+        expect(startSpy).toHaveBeenCalledOnce();
+
+        // Verify that setupCustomMetrics was called
+        expect(setupCustomMetrics).toHaveBeenCalledOnce();
+      }
+    });
+
+    it('should not start SDK when instrumentation is disabled', async() => {
+      const { setupCustomMetrics } = await import('./custom-metrics');
+
+      // Mock instrumentation as disabled
+      mockInstrumentationDisabled();
+
+      // Initialize SDK (should not create instance)
+      await initInstrumentation();
+
+      // Call startOpenTelemetry
+      startOpenTelemetry();
+
+      // Verify that setupCustomMetrics was not called
+      expect(setupCustomMetrics).not.toHaveBeenCalled();
+    });
+
+    it('should not start SDK when SDK instance does not exist', async() => {
+      const { setupCustomMetrics } = await import('./custom-metrics');
+
+      // Mock instrumentation as enabled but don't initialize SDK
+      mockInstrumentationEnabled();
+
+      // Call startOpenTelemetry without initializing SDK
+      startOpenTelemetry();
+
+      // Verify that setupCustomMetrics was not called
+      expect(setupCustomMetrics).not.toHaveBeenCalled();
+    });
+  });
 });

+ 3 - 2
apps/app/src/features/opentelemetry/server/node-sdk.ts

@@ -72,8 +72,6 @@ For more information, see https://docs.growi.org/en/admin-guide/admin-cookbook/t
 
     const sdkConfig = generateNodeSDKConfiguration({ enableAnonymization });
 
-    setupCustomMetrics();
-
     sdkInstance = new NodeSDK(sdkConfig);
   }
 };
@@ -106,6 +104,9 @@ export const startOpenTelemetry = (): void => {
       throw new Error('OpenTelemetry instrumentation is not initialized');
     }
     sdkInstance.start();
+
+    // setup custom metrics after SDK start
+    setupCustomMetrics();
   }
 };
 

+ 5 - 1
apps/app/src/server/middlewares/access-token-parser/access-token.ts

@@ -5,14 +5,18 @@ import type { Response } from 'express';
 import { AccessToken } from '~/server/models/access-token';
 import loggerFactory from '~/utils/logger';
 
+import { extractBearerToken } from './extract-bearer-token';
 import type { AccessTokenParserReq } from './interfaces';
 
 const logger = loggerFactory('growi:middleware:access-token-parser:access-token');
 
 export const parserForAccessToken = (scopes: Scope[]) => {
   return async(req: AccessTokenParserReq, res: Response): Promise<void> => {
+    // Extract token from Authorization header first
+    // It is more efficient to call it only once in "AccessTokenParser," which is the caller of the method
+    const bearerToken = extractBearerToken(req.headers.authorization);
 
-    const accessToken = req.query.access_token ?? req.body.access_token;
+    const accessToken = bearerToken ?? req.query.access_token ?? req.body.access_token;
     if (accessToken == null || typeof accessToken !== 'string') {
       return;
     }

+ 3 - 13
apps/app/src/server/middlewares/access-token-parser/api-token.ts

@@ -1,30 +1,20 @@
 import type { IUser, IUserHasId } from '@growi/core/dist/interfaces';
 import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
-import type { NextFunction, Response } from 'express';
+import type { Response } from 'express';
 import type { HydratedDocument } from 'mongoose';
 import mongoose from 'mongoose';
 
 import loggerFactory from '~/utils/logger';
 
+import { extractBearerToken } from './extract-bearer-token';
 import type { AccessTokenParserReq } from './interfaces';
 
 const logger = loggerFactory('growi:middleware:access-token-parser:api-token');
 
-const extractBearerToken = (authHeader: string | undefined): string | null => {
-  if (authHeader == null) {
-    return null;
-  }
-
-  if (!authHeader.startsWith('Bearer ')) {
-    return null;
-  }
-
-  return authHeader.substring(7); // Remove 'Bearer ' prefix
-};
-
 
 export const parserForApiToken = async(req: AccessTokenParserReq, res: Response): Promise<void> => {
   // Extract token from Authorization header first
+  // It is more efficient to call it only once in "AccessTokenParser," which is the caller of the method
   const bearerToken = extractBearerToken(req.headers.authorization);
 
   // Try all possible token sources in order of priority

+ 11 - 0
apps/app/src/server/middlewares/access-token-parser/extract-bearer-token.ts

@@ -0,0 +1,11 @@
+export const extractBearerToken = (authHeader: string | undefined): string | null => {
+  if (authHeader == null) {
+    return null;
+  }
+
+  if (!authHeader.startsWith('Bearer ')) {
+    return null;
+  }
+
+  return authHeader.substring(7); // Remove 'Bearer ' prefix
+};

+ 0 - 1
apps/app/src/server/middlewares/access-token-parser/index.ts

@@ -14,7 +14,6 @@ export type AccessTokenParser = (scopes?: Scope[], opts?: {acceptLegacy: boolean
 
 export const accessTokenParser: AccessTokenParser = (scopes, opts) => {
   return async(req, res, next): Promise<void> => {
-    // TODO: comply HTTP header of RFC6750 / Authorization: Bearer
     if (scopes == null || scopes.length === 0) {
       logger.warn('scopes is empty');
       return next();

+ 1 - 1
apps/app/src/server/service/config-manager/config-definition.ts

@@ -503,7 +503,7 @@ export const CONFIG_DEFINITIONS = {
   }),
   'app:deploymentType': defineConfig<GrowiDeploymentType>({
     envVarName: 'DEPLOYMENT_TYPE',
-    defaultValue: GrowiDeploymentType.others,
+    defaultValue: GrowiDeploymentType.node,
   }),
   'app:ssrMaxRevisionBodyLength': defineConfig<number>({
     envVarName: 'SSR_MAX_REVISION_BODY_LENGTH',

+ 1 - 0
packages/core/src/consts/system.ts

@@ -2,6 +2,7 @@ export const GrowiServiceType = {
   cloud: 'cloud',
   privateCloud: 'private-cloud',
   onPremise: 'on-premise',
+  dev: 'dev',
   others: 'others',
 } as const;
 

+ 157 - 75
pnpm-lock.yaml

@@ -485,8 +485,8 @@ importers:
         specifier: ^0.1.2
         version: 0.1.2
       mermaid:
-        specifier: ^11.9.0
-        version: 11.9.0
+        specifier: ^11.10.0
+        version: 11.10.0
       method-override:
         specifier: ^3.0.0
         version: 3.0.0
@@ -2520,8 +2520,8 @@ packages:
     cpu: [x64]
     os: [win32]
 
-  '@braintree/sanitize-url@7.1.0':
-    resolution: {integrity: sha512-o+UlMLt49RvtCASlOMW0AkHnabN9wR9rwCCherxO0yG4Npy34GkvrAqdXQvrhNs+jh+gkK8gB8Lf05qL/O7KWg==}
+  '@braintree/sanitize-url@7.1.1':
+    resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==}
 
   '@browser-bunyan/console-formatted-stream@1.8.0':
     resolution: {integrity: sha512-Lg5SC2uXrvZ6aLwLZT6SErfN1Is4NcrTOb5km4BW/BfL8Lv0CfpsYuhuD7ltdURL6awTYBUiT+BwhKw1Xd9glQ==}
@@ -2680,6 +2680,9 @@ packages:
   '@codemirror/language@6.11.2':
     resolution: {integrity: sha512-p44TsNArL4IVXDTbapUmEkAlvWs2CFQbcfc0ymDsis1kH2wh0gcY96AS29c/vp2d0y2Tquk1EDSaawpzilUiAw==}
 
+  '@codemirror/language@6.11.3':
+    resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==}
+
   '@codemirror/legacy-modes@6.4.1':
     resolution: {integrity: sha512-vdg3XY7OAs5uLDx2Iw+cGfnwtd7kM+Et/eMsqAGTfT/JKiVBQZXosTzjEbWAi/FrY6DcQIz8mQjBozFHZEUWQA==}
 
@@ -3251,19 +3254,28 @@ packages:
   '@jridgewell/gen-mapping@0.3.12':
     resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==}
 
+  '@jridgewell/gen-mapping@0.3.13':
+    resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
   '@jridgewell/resolve-uri@3.1.2':
     resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
     engines: {node: '>=6.0.0'}
 
-  '@jridgewell/source-map@0.3.10':
-    resolution: {integrity: sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==}
+  '@jridgewell/source-map@0.3.11':
+    resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==}
 
   '@jridgewell/sourcemap-codec@1.5.4':
     resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
 
+  '@jridgewell/sourcemap-codec@1.5.5':
+    resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
   '@jridgewell/trace-mapping@0.3.29':
     resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
 
+  '@jridgewell/trace-mapping@0.3.30':
+    resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==}
+
   '@jridgewell/trace-mapping@0.3.9':
     resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
 
@@ -5395,8 +5407,8 @@ packages:
   '@types/d3-delaunay@6.0.4':
     resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==}
 
-  '@types/d3-dispatch@3.0.6':
-    resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==}
+  '@types/d3-dispatch@3.0.7':
+    resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==}
 
   '@types/d3-drag@3.0.7':
     resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==}
@@ -6562,6 +6574,11 @@ packages:
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
     hasBin: true
 
+  browserslist@4.25.3:
+    resolution: {integrity: sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==}
+    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+    hasBin: true
+
   bs-recipes@1.3.4:
     resolution: {integrity: sha512-BXvDkqhDNxXEjeGM8LFkSbR+jzmP/CYpCiVKYn+soB1dDldeU15EBNDkwVXndKuX35wnNUaPd0qSoQEAkmQtMw==}
 
@@ -6705,6 +6722,9 @@ packages:
   caniuse-lite@1.0.30001727:
     resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==}
 
+  caniuse-lite@1.0.30001735:
+    resolution: {integrity: sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==}
+
   capital-case@1.0.4:
     resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==}
 
@@ -7669,15 +7689,15 @@ packages:
     peerDependencies:
       cytoscape: ^3.2.0
 
-  cytoscape@3.30.2:
-    resolution: {integrity: sha512-oICxQsjW8uSaRmn4UK/jkczKOqTrVqt5/1WL0POiJUT2EKNc9STM4hYFHv917yu55aTBMFNRzymlJhVAiWPCxw==}
+  cytoscape@3.33.1:
+    resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==}
     engines: {node: '>=0.10'}
 
   d3-array@2.12.1:
     resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==}
 
-  d3-array@3.2.3:
-    resolution: {integrity: sha512-JRHwbQQ84XuAESWhvIPaUV4/1UYTBOLiOPGWqgFDHZS1D5QN9c57FbH3QpEnQMYiOXNzKUQyGTZf+EVO7RT5TQ==}
+  d3-array@3.2.4:
+    resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
     engines: {node: '>=12'}
 
   d3-axis@3.0.0:
@@ -7733,8 +7753,8 @@ packages:
     resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
     engines: {node: '>=12'}
 
-  d3-geo@3.1.0:
-    resolution: {integrity: sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==}
+  d3-geo@3.1.1:
+    resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==}
     engines: {node: '>=12'}
 
   d3-hierarchy@3.1.2:
@@ -7767,8 +7787,8 @@ packages:
   d3-sankey@0.12.3:
     resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==}
 
-  d3-scale-chromatic@3.0.0:
-    resolution: {integrity: sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==}
+  d3-scale-chromatic@3.1.0:
+    resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==}
     engines: {node: '>=12'}
 
   d3-scale@4.0.2:
@@ -7990,8 +8010,8 @@ packages:
     resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==}
     engines: {node: '>=10'}
 
-  delaunator@5.0.0:
-    resolution: {integrity: sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==}
+  delaunator@5.0.1:
+    resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==}
 
   delayed-stream@1.0.0:
     resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
@@ -8208,6 +8228,9 @@ packages:
   electron-to-chromium@1.5.190:
     resolution: {integrity: sha512-k4McmnB2091YIsdCgkS0fMVMPOJgxl93ltFzaryXqwip1AaxeDqKCGLxkXODDA5Ab/D+tV5EL5+aTx76RvLRxw==}
 
+  electron-to-chromium@1.5.207:
+    resolution: {integrity: sha512-mryFrrL/GXDTmAtIVMVf+eIXM09BBPlO5IQ7lUyKmK8d+A4VpRGG+M3ofoVef6qyF8s60rJei8ymlJxjUA8Faw==}
+
   emittery@0.13.1:
     resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
     engines: {node: '>=12'}
@@ -8262,6 +8285,10 @@ packages:
     resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==}
     engines: {node: '>=10.13.0'}
 
+  enhanced-resolve@5.18.3:
+    resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
+    engines: {node: '>=10.13.0'}
+
   enquirer@2.4.1:
     resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
     engines: {node: '>=8.6'}
@@ -8884,6 +8911,15 @@ packages:
     resolution: {integrity: sha512-CtbfI3oFFc3nbdIoHycrfbrxiGgxXBXXuyOl49h47JawM1mYrqpiRqnH5CB2mBatdXvHHOUO6a+RiAuuvKt0lw==}
     engines: {node: '>=8'}
 
+  follow-redirects@1.15.11:
+    resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
+    engines: {node: '>=4.0'}
+    peerDependencies:
+      debug: '*'
+    peerDependenciesMeta:
+      debug:
+        optional: true
+
   follow-redirects@1.15.9:
     resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
     engines: {node: '>=4.0'}
@@ -10741,8 +10777,8 @@ packages:
   markdown-table@3.0.3:
     resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
 
-  marked@16.1.1:
-    resolution: {integrity: sha512-ij/2lXfCRT71L6u0M29tJPhP0bM5shLL3u5BePhFwPELj2blMJ6GDtD7PfJhRLhJ/c2UwrK17ySVcDzy2YHjHQ==}
+  marked@16.2.0:
+    resolution: {integrity: sha512-LbbTuye+0dWRz2TS9KJ7wsnD4KAtpj0MVkWc90XvBa6AslXsT0hTBVH5k32pcSyHH1fst9XEFJunXHktVy0zlg==}
     engines: {node: '>= 20'}
     hasBin: true
 
@@ -10881,8 +10917,8 @@ packages:
     resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
     engines: {node: '>= 8'}
 
-  mermaid@11.9.0:
-    resolution: {integrity: sha512-YdPXn9slEwO0omQfQIsW6vS84weVQftIyyTGAZCwM//MGhPzL1+l6vO6bkf0wnP4tHigH1alZ5Ooy3HXI2gOag==}
+  mermaid@11.10.0:
+    resolution: {integrity: sha512-oQsFzPBy9xlpnGxUqLbVY8pvknLlsNIJ0NWwi8SUJjhbP1IT0E0o1lfhU4iYV3ubpy+xkzkaOyDUQMn06vQElQ==}
 
   method-override@3.0.0:
     resolution: {integrity: sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA==}
@@ -12313,6 +12349,7 @@ packages:
   puppeteer@23.6.1:
     resolution: {integrity: sha512-8+ALGQgwXd3P/tGcuSsxTPGDaOQIjcDIm04I5hpWZv/PiN5q8bQNHRUyfYrifT+flnM9aTWCP7tLEzuB6SlIgA==}
     engines: {node: '>=18'}
+    deprecated: < 24.9.0 is no longer supported
     hasBin: true
 
   pure-rand@6.1.0:
@@ -12334,8 +12371,8 @@ packages:
     resolution: {integrity: sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==}
     engines: {node: '>=0.6'}
 
-  quansync@0.2.10:
-    resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
+  quansync@0.2.11:
+    resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
 
   query-string@7.1.3:
     resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==}
@@ -12916,8 +12953,8 @@ packages:
   rndm@1.2.0:
     resolution: {integrity: sha512-fJhQQI5tLrQvYIYFpOnFinzv9dwmR7hRnUz1XqP3OJ1jIweTNOd6aTO4jwQSgcBSFUB+/KHJxuGneime+FdzOw==}
 
-  robust-predicates@3.0.1:
-    resolution: {integrity: sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==}
+  robust-predicates@3.0.2:
+    resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==}
 
   rollup-plugin-node-externals@6.1.1:
     resolution: {integrity: sha512-127OFMkpH5rBVlRHRBDUMk1m1sGuzbGy7so5aj/IkpUb2r3+wOWjR/erUzd2ChEQWPsxsyQG6xpYYvPBAdcBRA==}
@@ -14222,8 +14259,8 @@ packages:
   typpy@2.3.11:
     resolution: {integrity: sha512-Jh/fykZSaxeKO0ceMAs6agki9T5TNA9kiIR6fzKbvafKpIw8UlNlHhzuqKyi5lfJJ5VojJOx9tooIbyy7vHV/g==}
 
-  ua-parser-js@1.0.40:
-    resolution: {integrity: sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==}
+  ua-parser-js@1.0.41:
+    resolution: {integrity: sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==}
     hasBin: true
 
   uberproto@1.2.0:
@@ -14232,8 +14269,8 @@ packages:
   uc.micro@1.0.6:
     resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==}
 
-  ufo@1.5.4:
-    resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
+  ufo@1.6.1:
+    resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
 
   uglify-js@3.19.3:
     resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
@@ -16437,7 +16474,7 @@ snapshots:
   '@biomejs/cli-win32-x64@2.0.6':
     optional: true
 
-  '@braintree/sanitize-url@7.1.0': {}
+  '@braintree/sanitize-url@7.1.1': {}
 
   '@browser-bunyan/console-formatted-stream@1.8.0':
     dependencies:
@@ -16838,6 +16875,15 @@ snapshots:
       '@lezer/lr': 1.4.2
       style-mod: 4.1.2
 
+  '@codemirror/language@6.11.3':
+    dependencies:
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.38.1
+      '@lezer/common': 1.2.3
+      '@lezer/highlight': 1.2.1
+      '@lezer/lr': 1.4.2
+      style-mod: 4.1.2
+
   '@codemirror/legacy-modes@6.4.1':
     dependencies:
       '@codemirror/language': 6.11.2
@@ -16868,7 +16914,7 @@ snapshots:
 
   '@codemirror/theme-one-dark@6.1.2':
     dependencies:
-      '@codemirror/language': 6.11.2
+      '@codemirror/language': 6.11.3
       '@codemirror/state': 6.5.2
       '@codemirror/view': 6.38.1
       '@lezer/highlight': 1.2.1
@@ -17456,20 +17502,32 @@ snapshots:
       '@jridgewell/sourcemap-codec': 1.5.4
       '@jridgewell/trace-mapping': 0.3.29
 
+  '@jridgewell/gen-mapping@0.3.13':
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.5.5
+      '@jridgewell/trace-mapping': 0.3.30
+
   '@jridgewell/resolve-uri@3.1.2': {}
 
-  '@jridgewell/source-map@0.3.10':
+  '@jridgewell/source-map@0.3.11':
     dependencies:
-      '@jridgewell/gen-mapping': 0.3.12
-      '@jridgewell/trace-mapping': 0.3.29
+      '@jridgewell/gen-mapping': 0.3.13
+      '@jridgewell/trace-mapping': 0.3.30
 
   '@jridgewell/sourcemap-codec@1.5.4': {}
 
+  '@jridgewell/sourcemap-codec@1.5.5': {}
+
   '@jridgewell/trace-mapping@0.3.29':
     dependencies:
       '@jridgewell/resolve-uri': 3.1.2
       '@jridgewell/sourcemap-codec': 1.5.4
 
+  '@jridgewell/trace-mapping@0.3.30':
+    dependencies:
+      '@jridgewell/resolve-uri': 3.1.2
+      '@jridgewell/sourcemap-codec': 1.5.5
+
   '@jridgewell/trace-mapping@0.3.9':
     dependencies:
       '@jridgewell/resolve-uri': 3.1.2
@@ -20579,7 +20637,7 @@ snapshots:
 
   '@types/d3-delaunay@6.0.4': {}
 
-  '@types/d3-dispatch@3.0.6': {}
+  '@types/d3-dispatch@3.0.7': {}
 
   '@types/d3-drag@3.0.7':
     dependencies:
@@ -20651,7 +20709,7 @@ snapshots:
       '@types/d3-color': 3.1.3
       '@types/d3-contour': 3.0.6
       '@types/d3-delaunay': 6.0.4
-      '@types/d3-dispatch': 3.0.6
+      '@types/d3-dispatch': 3.0.7
       '@types/d3-drag': 3.0.7
       '@types/d3-dsv': 3.0.7
       '@types/d3-ease': 3.0.2
@@ -22132,7 +22190,7 @@ snapshots:
       serve-static: 1.13.2
       server-destroy: 1.0.1
       socket.io: 4.8.1
-      ua-parser-js: 1.0.40
+      ua-parser-js: 1.0.41
       yargs: 17.7.2
     transitivePeerDependencies:
       - bufferutil
@@ -22147,6 +22205,13 @@ snapshots:
       node-releases: 2.0.19
       update-browserslist-db: 1.1.3(browserslist@4.25.1)
 
+  browserslist@4.25.3:
+    dependencies:
+      caniuse-lite: 1.0.30001735
+      electron-to-chromium: 1.5.207
+      node-releases: 2.0.19
+      update-browserslist-db: 1.1.3(browserslist@4.25.3)
+
   bs-recipes@1.3.4: {}
 
   bser@2.1.1:
@@ -22325,6 +22390,8 @@ snapshots:
 
   caniuse-lite@1.0.30001727: {}
 
+  caniuse-lite@1.0.30001735: {}
+
   capital-case@1.0.4:
     dependencies:
       no-case: 3.0.4
@@ -23030,23 +23097,23 @@ snapshots:
     dependencies:
       array-find-index: 1.0.2
 
-  cytoscape-cose-bilkent@4.1.0(cytoscape@3.30.2):
+  cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1):
     dependencies:
       cose-base: 1.0.3
-      cytoscape: 3.30.2
+      cytoscape: 3.33.1
 
-  cytoscape-fcose@2.2.0(cytoscape@3.30.2):
+  cytoscape-fcose@2.2.0(cytoscape@3.33.1):
     dependencies:
       cose-base: 2.2.0
-      cytoscape: 3.30.2
+      cytoscape: 3.33.1
 
-  cytoscape@3.30.2: {}
+  cytoscape@3.33.1: {}
 
   d3-array@2.12.1:
     dependencies:
       internmap: 1.0.1
 
-  d3-array@3.2.3:
+  d3-array@3.2.4:
     dependencies:
       internmap: 2.0.3
 
@@ -23068,11 +23135,11 @@ snapshots:
 
   d3-contour@4.0.2:
     dependencies:
-      d3-array: 3.2.3
+      d3-array: 3.2.4
 
   d3-delaunay@6.0.4:
     dependencies:
-      delaunator: 5.0.0
+      delaunator: 5.0.1
 
   d3-dispatch@3.0.1: {}
 
@@ -23101,9 +23168,9 @@ snapshots:
 
   d3-format@3.1.0: {}
 
-  d3-geo@3.1.0:
+  d3-geo@3.1.1:
     dependencies:
-      d3-array: 3.2.3
+      d3-array: 3.2.4
 
   d3-hierarchy@3.1.2: {}
 
@@ -23126,14 +23193,14 @@ snapshots:
       d3-array: 2.12.1
       d3-shape: 1.3.7
 
-  d3-scale-chromatic@3.0.0:
+  d3-scale-chromatic@3.1.0:
     dependencies:
       d3-color: 3.1.0
       d3-interpolate: 3.0.1
 
   d3-scale@4.0.2:
     dependencies:
-      d3-array: 3.2.3
+      d3-array: 3.2.4
       d3-format: 3.1.0
       d3-interpolate: 3.0.1
       d3-time: 3.1.0
@@ -23155,7 +23222,7 @@ snapshots:
 
   d3-time@3.1.0:
     dependencies:
-      d3-array: 3.2.3
+      d3-array: 3.2.4
 
   d3-timer@3.0.1: {}
 
@@ -23178,7 +23245,7 @@ snapshots:
 
   d3@7.9.0:
     dependencies:
-      d3-array: 3.2.3
+      d3-array: 3.2.4
       d3-axis: 3.0.0
       d3-brush: 3.0.0
       d3-chord: 3.0.1
@@ -23192,7 +23259,7 @@ snapshots:
       d3-fetch: 3.0.1
       d3-force: 3.0.0
       d3-format: 3.1.0
-      d3-geo: 3.1.0
+      d3-geo: 3.1.1
       d3-hierarchy: 3.1.2
       d3-interpolate: 3.0.1
       d3-path: 3.1.0
@@ -23200,7 +23267,7 @@ snapshots:
       d3-quadtree: 3.0.1
       d3-random: 3.0.1
       d3-scale: 4.0.2
-      d3-scale-chromatic: 3.0.0
+      d3-scale-chromatic: 3.1.0
       d3-selection: 3.0.0
       d3-shape: 3.2.0
       d3-time: 3.1.0
@@ -23368,9 +23435,9 @@ snapshots:
       rimraf: 3.0.2
       slash: 3.0.0
 
-  delaunator@5.0.0:
+  delaunator@5.0.1:
     dependencies:
-      robust-predicates: 3.0.1
+      robust-predicates: 3.0.2
 
   delayed-stream@1.0.0: {}
 
@@ -23569,6 +23636,8 @@ snapshots:
 
   electron-to-chromium@1.5.190: {}
 
+  electron-to-chromium@1.5.207: {}
+
   emittery@0.13.1: {}
 
   emoji-mart@5.6.0: {}
@@ -23637,6 +23706,11 @@ snapshots:
       graceful-fs: 4.2.11
       tapable: 2.2.2
 
+  enhanced-resolve@5.18.3:
+    dependencies:
+      graceful-fs: 4.2.11
+      tapable: 2.2.2
+
   enquirer@2.4.1:
     dependencies:
       ansi-colors: 4.1.3
@@ -24511,6 +24585,8 @@ snapshots:
 
   fn-args@5.0.0: {}
 
+  follow-redirects@1.15.11: {}
+
   follow-redirects@1.15.9(debug@4.4.1):
     optionalDependencies:
       debug: 4.4.1(supports-color@5.5.0)
@@ -25300,7 +25376,7 @@ snapshots:
   http-proxy@1.18.1:
     dependencies:
       eventemitter3: 4.0.7
-      follow-redirects: 1.15.9(debug@4.4.1)
+      follow-redirects: 1.15.11
       requires-port: 1.0.0
     transitivePeerDependencies:
       - debug
@@ -26501,7 +26577,7 @@ snapshots:
     dependencies:
       mlly: 1.7.4
       pkg-types: 2.2.0
-      quansync: 0.2.10
+      quansync: 0.2.11
 
   locate-path@2.0.0:
     dependencies:
@@ -26739,7 +26815,7 @@ snapshots:
 
   markdown-table@3.0.3: {}
 
-  marked@16.1.1: {}
+  marked@16.2.0: {}
 
   material-icons@1.13.12: {}
 
@@ -27027,15 +27103,15 @@ snapshots:
 
   merge2@1.4.1: {}
 
-  mermaid@11.9.0:
+  mermaid@11.10.0:
     dependencies:
-      '@braintree/sanitize-url': 7.1.0
+      '@braintree/sanitize-url': 7.1.1
       '@iconify/utils': 2.3.0
       '@mermaid-js/parser': 0.6.2
       '@types/d3': 7.4.3
-      cytoscape: 3.30.2
-      cytoscape-cose-bilkent: 4.1.0(cytoscape@3.30.2)
-      cytoscape-fcose: 2.2.0(cytoscape@3.30.2)
+      cytoscape: 3.33.1
+      cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.1)
+      cytoscape-fcose: 2.2.0(cytoscape@3.33.1)
       d3: 7.9.0
       d3-sankey: 0.12.3
       dagre-d3-es: 7.0.11
@@ -27044,7 +27120,7 @@ snapshots:
       katex: 0.16.22
       khroma: 2.1.0
       lodash-es: 4.17.21
-      marked: 16.1.1
+      marked: 16.2.0
       roughjs: 4.6.6
       stylis: 4.3.6
       ts-dedent: 2.2.0
@@ -27165,7 +27241,7 @@ snapshots:
     dependencies:
       '@types/katex': 0.16.7
       devlop: 1.1.0
-      katex: 0.16.21
+      katex: 0.16.22
       micromark-factory-space: 2.0.0
       micromark-util-character: 2.1.0
       micromark-util-symbol: 2.0.0
@@ -27432,7 +27508,7 @@ snapshots:
       acorn: 8.15.0
       pathe: 2.0.3
       pkg-types: 1.3.1
-      ufo: 1.5.4
+      ufo: 1.6.1
 
   mock-require@3.0.3:
     dependencies:
@@ -28752,7 +28828,7 @@ snapshots:
 
   qs@6.5.2: {}
 
-  quansync@0.2.10: {}
+  quansync@0.2.11: {}
 
   query-string@7.1.3:
     dependencies:
@@ -29552,7 +29628,7 @@ snapshots:
 
   rndm@1.2.0: {}
 
-  robust-predicates@3.0.1: {}
+  robust-predicates@3.0.2: {}
 
   rollup-plugin-node-externals@6.1.1(rollup@4.41.0):
     dependencies:
@@ -30628,7 +30704,7 @@ snapshots:
 
   terser-webpack-plugin@5.3.14(@swc/core@1.10.7(@swc/helpers@0.5.15))(webpack@5.92.1(@swc/core@1.10.7(@swc/helpers@0.5.15))):
     dependencies:
-      '@jridgewell/trace-mapping': 0.3.29
+      '@jridgewell/trace-mapping': 0.3.30
       jest-worker: 27.5.1
       schema-utils: 4.3.2
       serialize-javascript: 6.0.2
@@ -30639,7 +30715,7 @@ snapshots:
 
   terser@5.43.1:
     dependencies:
-      '@jridgewell/source-map': 0.3.10
+      '@jridgewell/source-map': 0.3.11
       acorn: 8.15.0
       commander: 2.20.3
       source-map-support: 0.5.21
@@ -31070,13 +31146,13 @@ snapshots:
     dependencies:
       function.name: 1.0.12
 
-  ua-parser-js@1.0.40: {}
+  ua-parser-js@1.0.41: {}
 
   uberproto@1.2.0: {}
 
   uc.micro@1.0.6: {}
 
-  ufo@1.5.4: {}
+  ufo@1.6.1: {}
 
   uglify-js@3.19.3:
     optional: true
@@ -31248,6 +31324,12 @@ snapshots:
       escalade: 3.2.0
       picocolors: 1.1.1
 
+  update-browserslist-db@1.1.3(browserslist@4.25.3):
+    dependencies:
+      browserslist: 4.25.3
+      escalade: 3.2.0
+      picocolors: 1.1.1
+
   update-notifier@7.3.1:
     dependencies:
       boxen: 8.0.1
@@ -31615,9 +31697,9 @@ snapshots:
       '@webassemblyjs/wasm-parser': 1.14.1
       acorn: 8.15.0
       acorn-import-attributes: 1.9.5(acorn@8.15.0)
-      browserslist: 4.25.1
+      browserslist: 4.25.3
       chrome-trace-event: 1.0.4
-      enhanced-resolve: 5.18.2
+      enhanced-resolve: 5.18.3
       es-module-lexer: 1.7.0
       eslint-scope: 5.1.1
       events: 3.3.0