diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..a9a98328 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Mongo Modeler Extension", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/packages/vscode-extension" + ], + "outFiles": ["${workspaceFolder}/packages/vscode-extension/dist/**/*.mjs"] + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..fa2d2ef2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "mongo-modeler.appUrl": "http://localhost:5173/editor.html" +} diff --git a/apps/web/src/core/vscode/env.helpers.ts b/apps/web/src/core/vscode/env.helpers.ts new file mode 100644 index 00000000..c1cd5712 --- /dev/null +++ b/apps/web/src/core/vscode/env.helpers.ts @@ -0,0 +1,2 @@ +export const isVSCodeEnv = (): boolean => + new URLSearchParams(window.location.search).get('env') === 'vscode'; diff --git a/apps/web/src/core/vscode/index.ts b/apps/web/src/core/vscode/index.ts new file mode 100644 index 00000000..e270eacb --- /dev/null +++ b/apps/web/src/core/vscode/index.ts @@ -0,0 +1 @@ +export * from './use-vscode-sync.hook'; diff --git a/apps/web/src/core/vscode/use-vscode-auto-save.hook.ts b/apps/web/src/core/vscode/use-vscode-auto-save.hook.ts new file mode 100644 index 00000000..229a20e9 --- /dev/null +++ b/apps/web/src/core/vscode/use-vscode-auto-save.hook.ts @@ -0,0 +1,46 @@ +import { APP_MESSAGE_TYPE } from '@lemoncode/mongo-modeler-bridge-protocol'; +import { useEffect, useRef, type MutableRefObject } from 'react'; +import { useCanvasSchemaContext } from '@/core/providers'; +import { isVSCodeEnv } from './env.helpers'; +import { sendToExtension } from './vscode-bridge.helpers'; +import { serializeSchema } from './vscode-sync.helpers'; + +const AUTO_SAVE_DEBOUNCE_MS = 500; + +export const useVSCodeAutoSave = ( + hasReceivedFileRef: MutableRefObject +): void => { + const { canvasSchema } = useCanvasSchemaContext(); + + const lastSavedContentRef = useRef(null); + const debounceTimerRef = useRef | null>(null); + + useEffect(() => { + if (!isVSCodeEnv() || !hasReceivedFileRef.current) return; + + const content = serializeSchema(canvasSchema); + + if (lastSavedContentRef.current === null) { + lastSavedContentRef.current = content; + return; + } + + if (content === lastSavedContentRef.current) return; + + debounceTimerRef.current = setTimeout(() => { + sendToExtension({ + type: APP_MESSAGE_TYPE.SAVE, + payload: { content }, + }); + lastSavedContentRef.current = content; + debounceTimerRef.current = null; + }, AUTO_SAVE_DEBOUNCE_MS); + + return () => { + if (debounceTimerRef.current !== null) { + clearTimeout(debounceTimerRef.current); + debounceTimerRef.current = null; + } + }; + }, [canvasSchema]); +}; diff --git a/apps/web/src/core/vscode/use-vscode-file-load.hook.ts b/apps/web/src/core/vscode/use-vscode-file-load.hook.ts new file mode 100644 index 00000000..82cdf1f8 --- /dev/null +++ b/apps/web/src/core/vscode/use-vscode-file-load.hook.ts @@ -0,0 +1,50 @@ +import { + useCanvasSchemaContext, + useCanvasViewSettingsContext, +} from '@/core/providers'; +import { + APP_MESSAGE_TYPE, + HOST_MESSAGE_TYPE, + type LoadFilePayload, +} from '@lemoncode/mongo-modeler-bridge-protocol'; +import { useEffect, useRef, type MutableRefObject } from 'react'; +import { isVSCodeEnv } from './env.helpers'; +import { onMessage, sendToExtension } from './vscode-bridge.helpers'; +import { deserializeSchema } from './vscode-sync.helpers'; + +export const useVSCodeFileLoad = (): MutableRefObject => { + const { loadSchema } = useCanvasSchemaContext(); + const { setFilename, setLoadSample } = useCanvasViewSettingsContext(); + + const loadSchemaRef = useRef(loadSchema); + const setFilenameRef = useRef(setFilename); + const setLoadSampleRef = useRef(setLoadSample); + + useEffect(() => { + loadSchemaRef.current = loadSchema; + setFilenameRef.current = setFilename; + setLoadSampleRef.current = setLoadSample; + }); + + const hasReceivedFileRef = useRef(false); + + useEffect(() => { + if (!isVSCodeEnv()) return; + + const unsubscribe = onMessage( + HOST_MESSAGE_TYPE.LOAD_FILE, + (payload: LoadFilePayload) => { + hasReceivedFileRef.current = true; + setFilenameRef.current(payload.fileName); + setLoadSampleRef.current(false); + loadSchemaRef.current(deserializeSchema(payload.data)); + } + ); + + sendToExtension({ type: APP_MESSAGE_TYPE.WEBVIEW_READY }); + + return unsubscribe; + }, []); + + return hasReceivedFileRef; +}; diff --git a/apps/web/src/core/vscode/use-vscode-sync.hook.ts b/apps/web/src/core/vscode/use-vscode-sync.hook.ts new file mode 100644 index 00000000..ab933994 --- /dev/null +++ b/apps/web/src/core/vscode/use-vscode-sync.hook.ts @@ -0,0 +1,13 @@ +import { useVSCodeAutoSave } from './use-vscode-auto-save.hook'; +import { useVSCodeFileLoad } from './use-vscode-file-load.hook'; +import { useVSCodeTheme } from './use-vscode-theme.hook'; + +/** + * Wires the VS Code webview bridge. The inner hooks no-op when not running + * inside a VS Code webview, so this can be called unconditionally. + */ +export const useVSCodeSync = (): void => { + const hasReceivedFileRef = useVSCodeFileLoad(); + useVSCodeAutoSave(hasReceivedFileRef); + useVSCodeTheme(); +}; diff --git a/apps/web/src/core/vscode/use-vscode-theme.hook.ts b/apps/web/src/core/vscode/use-vscode-theme.hook.ts new file mode 100644 index 00000000..cd20ca13 --- /dev/null +++ b/apps/web/src/core/vscode/use-vscode-theme.hook.ts @@ -0,0 +1,40 @@ +import { + HOST_MESSAGE_TYPE, + type ThemePayload, +} from '@lemoncode/mongo-modeler-bridge-protocol'; +import { useEffect } from 'react'; +import { isVSCodeEnv } from './env.helpers'; +import { onMessage } from './vscode-bridge.helpers'; + +const CSS_VAR_MAP: Record = { + // VS Code sends a reduced palette; we fan out colors to existing app tokens in a simplified way. + background: ['--bg-canvas', '--background-800', '--background-900'], + backgroundSecondary: [ + '--bg-toolbar', + '--bg-table', + '--bg-input', + '--background-700', + '--background-400', + ], + foreground: ['--text-color'], +}; + +const applyTheme = (theme: ThemePayload): void => { + const root = document.documentElement; + for (const [key, cssVars] of Object.entries(CSS_VAR_MAP)) { + const value = theme[key as keyof ThemePayload]; + if (!value) continue; + for (const cssVar of cssVars) { + root.style.setProperty(cssVar, value); + } + } + if (theme.background) document.body.style.backgroundColor = theme.background; + if (theme.foreground) document.body.style.color = theme.foreground; +}; + +export const useVSCodeTheme = (): void => { + useEffect(() => { + if (!isVSCodeEnv()) return; + return onMessage(HOST_MESSAGE_TYPE.THEME, applyTheme); + }, []); +}; diff --git a/apps/web/src/core/vscode/vscode-bridge.helpers.ts b/apps/web/src/core/vscode/vscode-bridge.helpers.ts new file mode 100644 index 00000000..62cc2f63 --- /dev/null +++ b/apps/web/src/core/vscode/vscode-bridge.helpers.ts @@ -0,0 +1,54 @@ +import type { + AppMessage, + HostMessage, + PayloadOf, +} from '@lemoncode/mongo-modeler-bridge-protocol'; +import { isVSCodeEnv } from './env.helpers'; + +type HandlerFor = ( + payload: PayloadOf +) => void; + +type AnyHandler = (payload: unknown) => void; + +const handlers = new Map>(); + +export const sendToExtension = (msg: AppMessage): void => { + if (!isVSCodeEnv()) return; + // In VS Code webviews the parent origin is not a stable app URL. + // We post to parent and rely on origin/source checks in the bridge listeners. + window.parent.postMessage(msg, '*'); +}; + +export const onMessage = ( + type: T, + handler: HandlerFor +): (() => void) => { + if (!isVSCodeEnv()) return () => { }; + + const existing = handlers.get(type) ?? new Set(); + existing.add(handler as AnyHandler); + handlers.set(type, existing); + + return () => { + const set = handlers.get(type); + if (!set) return; + set.delete(handler as AnyHandler); + if (set.size === 0) handlers.delete(type); + }; +}; + +if (typeof window !== 'undefined' && isVSCodeEnv()) { + window.addEventListener('message', (event: MessageEvent) => { + if (event.source !== window.parent) return; + + const msg = event.data as Partial | undefined; + if (!msg?.type) return; + + const set = handlers.get(msg.type); + if (!set) return; + + const payload = (msg as { payload?: unknown }).payload; + for (const handler of set) handler(payload); + }); +} diff --git a/apps/web/src/core/vscode/vscode-sync.helpers.ts b/apps/web/src/core/vscode/vscode-sync.helpers.ts new file mode 100644 index 00000000..33949dbd --- /dev/null +++ b/apps/web/src/core/vscode/vscode-sync.helpers.ts @@ -0,0 +1,8 @@ +import { type DatabaseSchemaVm } from '@/core/providers'; +import { mapSchemaToLatestVersion } from '@/core/providers/canvas-schema/canvas-schema.mapper'; + +export const deserializeSchema = (data: unknown): DatabaseSchemaVm => + mapSchemaToLatestVersion(data); + +export const serializeSchema = (schema: DatabaseSchemaVm): string => + JSON.stringify(schema, null, 2); diff --git a/apps/web/src/pods/toolbar/toolbar.pod.tsx b/apps/web/src/pods/toolbar/toolbar.pod.tsx index 98d21997..1120b062 100644 --- a/apps/web/src/pods/toolbar/toolbar.pod.tsx +++ b/apps/web/src/pods/toolbar/toolbar.pod.tsx @@ -1,21 +1,22 @@ +import { isVSCodeEnv } from '@/core/vscode/env.helpers'; import React from 'react'; import { - // CanvasSettingButton, - ZoomInButton, - ZoomOutButton, - ThemeToggleButton, + AboutButton, + CanvasSettingButton, + CopyButton, + DeleteButton, ExportButton, + ImportButton, NewButton, OpenButton, + PasteButton, + RedoButton, SaveButton, + ThemeToggleButton, UndoButton, - RedoButton, - DeleteButton, - AboutButton, - CanvasSettingButton, - CopyButton, - PasteButton, - ImportButton, + // CanvasSettingButton, + ZoomInButton, + ZoomOutButton, } from './components'; import classes from './toolbar.pod.module.css'; @@ -36,7 +37,9 @@ export const ToolbarPod: React.FC = () => { - + {!isVSCodeEnv() && ( + + )} ); }; diff --git a/apps/web/src/scenes/main.scene.tsx b/apps/web/src/scenes/main.scene.tsx index 34c4c066..b935ea7a 100644 --- a/apps/web/src/scenes/main.scene.tsx +++ b/apps/web/src/scenes/main.scene.tsx @@ -1,14 +1,18 @@ +import { ModalDialog } from '@/common/components'; +import { useDeviceContext, useModalDialogContext } from '@/core/providers'; +import { useVSCodeSync } from '@/core/vscode'; import { CanvasPod } from '@/pods/canvas/canvas.pod'; +import { FloatingBarPod } from '@/pods/floating-bar'; +import { FooterPod } from '@/pods/footer'; import { ToolbarPod } from '@/pods/toolbar/toolbar.pod'; -import { useDeviceContext, useModalDialogContext } from '@/core/providers'; -import { ModalDialog } from '@/common/components'; import classes from './main.scene.module.css'; -import { FooterPod } from '@/pods/footer'; -import { FloatingBarPod } from '@/pods/floating-bar'; export const MainScene: React.FC = () => { const { modalDialog } = useModalDialogContext(); const { isTabletOrMobileDevice } = useDeviceContext(); + + useVSCodeSync(); + return ( <>
diff --git a/package-lock.json b/package-lock.json index a61e65ee..85f018e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "oxlint": "1.60.0", "prettier": "3.8.3", "tsx": "4.21.0", - "turbo": "2.9.6", + "turbo": "^2.9.14", "typescript": "6.0.2" }, "engines": { @@ -853,17 +853,6 @@ "node": ">=18" } }, - "node_modules/@emnapi/wasi-threads": { - "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, - "dependencies": { - "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", @@ -1415,7 +1404,7 @@ } }, "node_modules/@lemoncode/mongo-modeler-bridge-protocol": { - "resolved": "packages/bridge-protocol", + "resolved": "packages/vscode-bridge-protocol", "link": true }, "node_modules/@lemoncode/mongo-modeler-web": { @@ -1506,25 +1495,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/@napi-rs/wasm-runtime": { - "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": { - "@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/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1949,159 +1919,6 @@ ], "license": "MIT" }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz", - "integrity": "sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.16.tgz", - "integrity": "sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.16.tgz", - "integrity": "sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.16.tgz", - "integrity": "sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.16.tgz", - "integrity": "sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.16.tgz", - "integrity": "sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.16.tgz", - "integrity": "sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.16.tgz", - "integrity": "sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.16.tgz", - "integrity": "sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/@rolldown/binding-linux-x64-gnu": { "version": "1.0.0-rc.16", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.16.tgz", @@ -2136,76 +1953,6 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.16.tgz", - "integrity": "sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.16.tgz", - "integrity": "sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.9.2", - "@emnapi/runtime": "1.9.2", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.16.tgz", - "integrity": "sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.16.tgz", - "integrity": "sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-rc.7", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", @@ -2609,9 +2356,9 @@ } }, "node_modules/@turbo/darwin-64": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/@turbo/darwin-64/-/darwin-64-2.9.6.tgz", - "integrity": "sha512-X/56SnVXIQZBLKwniGTwEQTGmtE5brSACnKMBWpY3YafuxVYefrC2acamfjgxP7BG5w3I+6jf0UrLoSzgPcSJg==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/@turbo/darwin-64/-/darwin-64-2.9.14.tgz", + "integrity": "sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A==", "cpu": [ "x64" ], @@ -2623,9 +2370,9 @@ ] }, "node_modules/@turbo/darwin-arm64": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/@turbo/darwin-arm64/-/darwin-arm64-2.9.6.tgz", - "integrity": "sha512-aalBeSl4agT/QtYGDyf/XLajedWzUC9Vg/pm/YO6QQ93vkQ91Vz5uK1ta5RbVRDozQSz4njxUNqRNmOXDzW+qw==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/@turbo/darwin-arm64/-/darwin-arm64-2.9.14.tgz", + "integrity": "sha512-d23147mC9BsCPA9mJ0h/ubcpbRgcJBXbcG3+Vq7YLhjz3IXuvQsJ1UXH8f4MD76ZjJ4m/E4aRdJV+MW88CDfbw==", "cpu": [ "arm64" ], @@ -2637,9 +2384,9 @@ ] }, "node_modules/@turbo/linux-64": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/@turbo/linux-64/-/linux-64-2.9.6.tgz", - "integrity": "sha512-YKi05jnNHaD7vevgYwahpzGwbsNNTwzU2c7VZdmdFm7+cGDP4oREUWSsainiMfRqjRuolQxBwRn8wf1jmu+YZA==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/@turbo/linux-64/-/linux-64-2.9.14.tgz", + "integrity": "sha512-P3ZKB5tuUDdDQWuAsACGUR1qv9W7BNWxdxqVJ0kZNuNNPRaVYTPPikLcp79+GiEcW3npsR+KyP38lnQiBc5aSA==", "cpu": [ "x64" ], @@ -2651,9 +2398,9 @@ ] }, "node_modules/@turbo/linux-arm64": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/@turbo/linux-arm64/-/linux-arm64-2.9.6.tgz", - "integrity": "sha512-02o/ZS69cOYEDczXvOB2xmyrtzjQ2hVFtWZK1iqxXUfzMmTjZK4UumrfNnjckSg+gqeBfnPRHa0NstA173Ik3g==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/@turbo/linux-arm64/-/linux-arm64-2.9.14.tgz", + "integrity": "sha512-ZRTlzcUMrrPv9ZuDzRF9n60Ym13bKeG9jDB8WjxyLhWNzV+AJQN+zdpIk3NJYf2zQsGUm1mNar2P0elRzLw25g==", "cpu": [ "arm64" ], @@ -2665,9 +2412,9 @@ ] }, "node_modules/@turbo/windows-64": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/@turbo/windows-64/-/windows-64-2.9.6.tgz", - "integrity": "sha512-wVdQjvnBI15wB6JrA+43CtUtagjIMmX6XYO758oZHAsCNSxqRlJtdyujih0D8OCnwCRWiGWGI63zAxR0hO6s9g==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/@turbo/windows-64/-/windows-64-2.9.14.tgz", + "integrity": "sha512-exanwN6sIduZwykYeiTQj8kCmOhazP5WOz3bvXMcYtjhL6Z3iRWLewKrXCBq0bqwSP3iBMb/AerRCnHI4lx46A==", "cpu": [ "x64" ], @@ -2679,9 +2426,9 @@ ] }, "node_modules/@turbo/windows-arm64": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/@turbo/windows-arm64/-/windows-arm64-2.9.6.tgz", - "integrity": "sha512-1XUUyWW0W6FTSqGEhU8RHVqb2wP1SPkr7hIvBlMEwH9jr+sJQK5kqeosLJ/QaUv4ecSAd1ZhIrLoW7qslAzT4A==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/@turbo/windows-arm64/-/windows-arm64-2.9.14.tgz", + "integrity": "sha512-fVdCsnmYoKICsycbWuuGp6Jvi51/3G/UluFWuAUCvR8PIW5IJkAk5BM9UF8PSm0Q2IphWHFZjYEgjHsh3B9y/g==", "cpu": [ "arm64" ], @@ -2692,17 +2439,6 @@ "win32" ] }, - "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==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -3143,24 +2879,10 @@ "@vscode/vsce-sign-win32-x64": "2.0.6" } }, - "node_modules/@vscode/vsce-sign-alpine-arm64": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz", - "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "alpine" - ] - }, - "node_modules/@vscode/vsce-sign-alpine-x64": { + "node_modules/@vscode/vsce-sign-linux-x64": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz", - "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", + "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==", "cpu": [ "x64" ], @@ -3168,126 +2890,28 @@ "license": "SEE LICENSE IN LICENSE.txt", "optional": true, "os": [ - "alpine" + "linux" ] }, - "node_modules/@vscode/vsce-sign-darwin-arm64": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz", - "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==", - "cpu": [ - "arm64" - ], + "node_modules/@vscode/vsce/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "darwin" - ] + "license": "MIT", + "engines": { + "node": ">=18" + } }, - "node_modules/@vscode/vsce-sign-darwin-x64": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz", - "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==", - "cpu": [ - "x64" - ], + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@vscode/vsce-sign-linux-arm": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz", - "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/vsce-sign-linux-arm64": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz", - "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/vsce-sign-linux-x64": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", - "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/vsce-sign-win32-arm64": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz", - "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vscode/vsce-sign-win32-x64": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz", - "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vscode/vsce/node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } + "license": "MIT", + "engines": { + "node": ">= 14" + } }, "node_modules/ajv": { "version": "8.20.0", @@ -4791,9 +4415,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { @@ -5167,9 +4791,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -6243,153 +5867,6 @@ "lightningcss-win32-x64-msvc": "1.32.0" } }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/lightningcss-linux-x64-gnu": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", @@ -6432,48 +5909,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", @@ -9436,21 +8871,21 @@ } }, "node_modules/turbo": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-2.9.6.tgz", - "integrity": "sha512-+v2QJey7ZUeUiuigkU+uFfklvNUyPI2VO2vBpMYJA+a1hKFLFiKtUYlRHdb3P9CrAvMzi0upbjI4WT+zKtqkBg==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/turbo/-/turbo-2.9.14.tgz", + "integrity": "sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw==", "dev": true, "license": "MIT", "bin": { "turbo": "bin/turbo" }, "optionalDependencies": { - "@turbo/darwin-64": "2.9.6", - "@turbo/darwin-arm64": "2.9.6", - "@turbo/linux-64": "2.9.6", - "@turbo/linux-arm64": "2.9.6", - "@turbo/windows-64": "2.9.6", - "@turbo/windows-arm64": "2.9.6" + "@turbo/darwin-64": "2.9.14", + "@turbo/darwin-arm64": "2.9.14", + "@turbo/linux-64": "2.9.14", + "@turbo/linux-arm64": "2.9.14", + "@turbo/windows-64": "2.9.14", + "@turbo/windows-arm64": "2.9.14" } }, "node_modules/type-fest": { @@ -9605,29 +9040,6 @@ } } }, - "node_modules/unrun/node_modules/@emnapi/core": { - "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.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/unrun/node_modules/@emnapi/runtime": { - "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, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/unrun/node_modules/@oxc-project/types": { "version": "0.127.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", @@ -9638,160 +9050,7 @@ "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/unrun/node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", - "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-linux-x64-gnu": { + "node_modules/unrun/node_modules/@rolldown/binding-linux-x64-gnu": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", @@ -9825,76 +9084,6 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/unrun/node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", - "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/unrun/node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/unrun/node_modules/@rolldown/pluginutils": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", @@ -10065,29 +9254,6 @@ } } }, - "node_modules/vite/node_modules/@emnapi/core": { - "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.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/vite/node_modules/@emnapi/runtime": { - "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, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/vite/node_modules/@oxc-project/types": { "version": "0.127.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", @@ -10098,159 +9264,6 @@ "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/vite/node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", - "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/vite/node_modules/@rolldown/binding-linux-x64-gnu": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", @@ -10285,76 +9298,6 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/vite/node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", - "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/vite/node_modules/@rolldown/pluginutils": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", @@ -10728,9 +9671,9 @@ "optional": true }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", "dev": true, "license": "MIT", "engines": { @@ -10854,7 +9797,7 @@ "buffer-crc32": "~0.2.3" } }, - "packages/bridge-protocol": { + "packages/vscode-bridge-protocol": { "name": "@lemoncode/mongo-modeler-bridge-protocol", "version": "0.0.0", "devDependencies": { diff --git a/package.json b/package.json index eb55af9f..80edd84b 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "oxlint": "1.60.0", "prettier": "3.8.3", "tsx": "4.21.0", - "turbo": "2.9.6", + "turbo": "2.9.14", "typescript": "6.0.2" } } \ No newline at end of file diff --git a/packages/bridge-protocol/src/index.ts b/packages/bridge-protocol/src/index.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/packages/bridge-protocol/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/packages/bridge-protocol/package.json b/packages/vscode-bridge-protocol/package.json similarity index 100% rename from packages/bridge-protocol/package.json rename to packages/vscode-bridge-protocol/package.json diff --git a/packages/vscode-bridge-protocol/src/constant.ts b/packages/vscode-bridge-protocol/src/constant.ts new file mode 100644 index 00000000..ce5ae477 --- /dev/null +++ b/packages/vscode-bridge-protocol/src/constant.ts @@ -0,0 +1,11 @@ +export const HOST_MESSAGE_TYPE = { + SAVED: 'mm:saved', + LOAD_FILE: 'mm:load-file', + THEME: 'mm:theme', +} as const; + +export const APP_MESSAGE_TYPE = { + READY: 'mm:ready', + SAVE: 'mm:save', + WEBVIEW_READY: 'mm:webview-ready', +} as const; diff --git a/packages/vscode-bridge-protocol/src/index.ts b/packages/vscode-bridge-protocol/src/index.ts new file mode 100644 index 00000000..61dc567b --- /dev/null +++ b/packages/vscode-bridge-protocol/src/index.ts @@ -0,0 +1,2 @@ +export * from './constant'; +export * from './model'; diff --git a/packages/vscode-bridge-protocol/src/model.ts b/packages/vscode-bridge-protocol/src/model.ts new file mode 100644 index 00000000..eb66c1c2 --- /dev/null +++ b/packages/vscode-bridge-protocol/src/model.ts @@ -0,0 +1,25 @@ +import type { APP_MESSAGE_TYPE, HOST_MESSAGE_TYPE } from './constant'; + +export interface LoadFilePayload { + data: unknown; + fileName: string; +} + +export interface ThemePayload { + background: string; + backgroundSecondary: string; + foreground: string; +} + +export type HostMessage = + | { type: typeof HOST_MESSAGE_TYPE.SAVED } + | { type: typeof HOST_MESSAGE_TYPE.LOAD_FILE; payload: LoadFilePayload } + | { type: typeof HOST_MESSAGE_TYPE.THEME; payload: ThemePayload }; + +export type AppMessage = + | { type: typeof APP_MESSAGE_TYPE.READY } + | { type: typeof APP_MESSAGE_TYPE.WEBVIEW_READY } + | { type: typeof APP_MESSAGE_TYPE.SAVE; payload: { content: string } }; + +export type PayloadOf = + Extract extends { payload: infer P } ? P : undefined; diff --git a/packages/bridge-protocol/tsconfig.json b/packages/vscode-bridge-protocol/tsconfig.json similarity index 100% rename from packages/bridge-protocol/tsconfig.json rename to packages/vscode-bridge-protocol/tsconfig.json diff --git a/packages/vscode-extension/src/commands/index.ts b/packages/vscode-extension/src/commands/index.ts new file mode 100644 index 00000000..29ffc893 --- /dev/null +++ b/packages/vscode-extension/src/commands/index.ts @@ -0,0 +1,2 @@ +export * from './new-diagram'; +export * from './register'; diff --git a/packages/vscode-extension/src/commands/new-diagram.ts b/packages/vscode-extension/src/commands/new-diagram.ts new file mode 100644 index 00000000..b0b98659 --- /dev/null +++ b/packages/vscode-extension/src/commands/new-diagram.ts @@ -0,0 +1,52 @@ +import { logError } from '#core'; +import { writeFile } from '#editor'; +import * as vscode from 'vscode'; + +const VIEW_TYPE = 'mongo-modeler.editor'; +const FILE_EXTENSION = 'mml'; +const DEFAULT_FILENAME = `untitled.${FILE_EXTENSION}`; + +const DEFAULT_DIAGRAM_CONTENT = JSON.stringify( + { + version: '0.1', + tables: [], + relations: [], + notes: [], + selectedElementId: null, + isPristine: true, + }, + null, + 2 +); + +const getDefaultUri = (): vscode.Uri | undefined => { + const folder = vscode.workspace.workspaceFolders?.[0]; + return folder ? vscode.Uri.joinPath(folder.uri, DEFAULT_FILENAME) : undefined; +}; + +const createNewDiagram = async (): Promise => { + const target = await vscode.window.showSaveDialog({ + title: 'New Mongo Modeler diagram', + defaultUri: getDefaultUri(), + filters: { 'Mongo Modeler diagram': [FILE_EXTENSION] }, + }); + if (!target) return; + + try { + await writeFile(target, DEFAULT_DIAGRAM_CONTENT); + await vscode.commands.executeCommand('vscode.openWith', target, VIEW_TYPE); + } catch (error) { + logError('Failed to create new diagram:', error); + vscode.window.showErrorMessage( + `Failed to create new Mongo Modeler diagram: ${error instanceof Error ? error.message : String(error)}` + ); + } +}; + +export const registerNewDiagramCommand = ( + context: vscode.ExtensionContext +): void => { + context.subscriptions.push( + vscode.commands.registerCommand('mongo-modeler.newDiagram', createNewDiagram) + ); +}; diff --git a/packages/vscode-extension/src/commands/register.ts b/packages/vscode-extension/src/commands/register.ts new file mode 100644 index 00000000..8d40e475 --- /dev/null +++ b/packages/vscode-extension/src/commands/register.ts @@ -0,0 +1,6 @@ +import * as vscode from 'vscode'; +import { registerNewDiagramCommand } from './new-diagram'; + +export const registerCommands = (context: vscode.ExtensionContext): void => { + registerNewDiagramCommand(context); +}; diff --git a/packages/vscode-extension/src/core/config.ts b/packages/vscode-extension/src/core/config.ts new file mode 100644 index 00000000..6796f318 --- /dev/null +++ b/packages/vscode-extension/src/core/config.ts @@ -0,0 +1,29 @@ +import * as vscode from 'vscode'; + +const SECTION = 'mongo-modeler'; +const APP_URL_KEY = 'appUrl'; +const FULL_KEY = `${SECTION}.${APP_URL_KEY}`; +const DEFAULT_APP_URL = 'https://mongomodeler.com/editor.html'; + +const EDITOR_PARAMS = { env: 'vscode' } as const; + +const readRawAppUrl = (): string => { + const value = vscode.workspace + .getConfiguration(SECTION) + .get(APP_URL_KEY); + return value?.trim() || DEFAULT_APP_URL; +}; + +const withParams = (url: string, params: Record): string => { + const parsed = new URL(url); + for (const [k, v] of Object.entries(params)) parsed.searchParams.set(k, v); + return parsed.toString(); +}; + +export const getEditorAppUrl = (): string => + withParams(readRawAppUrl(), EDITOR_PARAMS); + +export const onAppUrlChange = (listener: () => void): vscode.Disposable => + vscode.workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(FULL_KEY)) listener(); + }); diff --git a/packages/vscode-extension/src/core/index.ts b/packages/vscode-extension/src/core/index.ts new file mode 100644 index 00000000..707452af --- /dev/null +++ b/packages/vscode-extension/src/core/index.ts @@ -0,0 +1,2 @@ +export * from './config'; +export * from './logger'; diff --git a/packages/vscode-extension/src/core/logger.ts b/packages/vscode-extension/src/core/logger.ts new file mode 100644 index 00000000..a2c5e2dc --- /dev/null +++ b/packages/vscode-extension/src/core/logger.ts @@ -0,0 +1,9 @@ +const PREFIX = '[MongoModeler]'; + +export const logInfo = (message: string, ...rest: unknown[]): void => { + console.info(`${PREFIX} ${message}`, ...rest); +}; + +export const logError = (message: string, ...rest: unknown[]): void => { + console.error(`${PREFIX} ${message}`, ...rest); +}; diff --git a/packages/vscode-extension/src/editor/document.ts b/packages/vscode-extension/src/editor/document.ts new file mode 100644 index 00000000..e89e0749 --- /dev/null +++ b/packages/vscode-extension/src/editor/document.ts @@ -0,0 +1,29 @@ +import * as vscode from 'vscode'; + +export type MongoModelerDocument = vscode.CustomDocument & { + readonly uri: vscode.Uri; + content: string; +}; + +export const openDocument = async ( + uri: vscode.Uri, + openContext: vscode.CustomDocumentOpenContext +): Promise => { + const source = openContext.backupId + ? vscode.Uri.parse(openContext.backupId) + : uri; + const content = await readFile(source); + return { uri, content, dispose: () => { } }; // no resources to release +}; + +export const readFile = async (uri: vscode.Uri): Promise => { + const bytes = await vscode.workspace.fs.readFile(uri); + return new TextDecoder().decode(bytes); +}; + +export const writeFile = async ( + uri: vscode.Uri, + content: string +): Promise => { + await vscode.workspace.fs.writeFile(uri, new TextEncoder().encode(content)); +}; diff --git a/packages/vscode-extension/src/editor/handlers.ts b/packages/vscode-extension/src/editor/handlers.ts new file mode 100644 index 00000000..0d1fab7d --- /dev/null +++ b/packages/vscode-extension/src/editor/handlers.ts @@ -0,0 +1,39 @@ +import { basename } from 'node:path'; +import { + APP_MESSAGE_TYPE, + type AppMessage, + HOST_MESSAGE_TYPE, + type HostMessage, +} from '@lemoncode/mongo-modeler-bridge-protocol'; +import { type MongoModelerDocument, writeFile } from './document'; + +type PostMessageFn = (msg: HostMessage) => void; + +export const handleWebviewMessage = async ( + msg: AppMessage, + doc: MongoModelerDocument, + postMessage: PostMessageFn +): Promise => { + switch (msg.type) { + case APP_MESSAGE_TYPE.WEBVIEW_READY: { + let data: unknown; + try { + data = JSON.parse(doc.content); + } catch { + data = doc.content; + } + postMessage({ + type: HOST_MESSAGE_TYPE.LOAD_FILE, + payload: { data, fileName: basename(doc.uri.fsPath) }, + }); + break; + } + + case APP_MESSAGE_TYPE.SAVE: + // This editor is auto-save driven, so SAVE writes directly to disk. + doc.content = msg.payload.content; + await writeFile(doc.uri, doc.content); + postMessage({ type: HOST_MESSAGE_TYPE.SAVED }); + break; + } +}; diff --git a/packages/vscode-extension/src/editor/index.ts b/packages/vscode-extension/src/editor/index.ts new file mode 100644 index 00000000..3951f00f --- /dev/null +++ b/packages/vscode-extension/src/editor/index.ts @@ -0,0 +1,4 @@ +export * from './document'; +export * from './handlers'; +export * from './panel'; +export * from './provider'; diff --git a/packages/vscode-extension/src/editor/panel.ts b/packages/vscode-extension/src/editor/panel.ts new file mode 100644 index 00000000..f943115f --- /dev/null +++ b/packages/vscode-extension/src/editor/panel.ts @@ -0,0 +1,33 @@ +import * as vscode from 'vscode'; + +const escapeAttr = (value: string): string => + value.replace(/&/g, '&').replace(/"/g, '"'); + +export const getHtml = ( + webview: vscode.Webview, + extensionUri: vscode.Uri, + appUrl: string +): string => { + const scriptUri = webview.asWebviewUri( + vscode.Uri.joinPath(extensionUri, 'dist', 'webview.js') + ); + const appOrigin = new URL(appUrl).origin; + const wsOrigin = appOrigin.replace(/^http/, 'ws'); + + return /* html */ ` + + + + + + + + + + +`; +}; diff --git a/packages/vscode-extension/src/editor/provider.ts b/packages/vscode-extension/src/editor/provider.ts new file mode 100644 index 00000000..391ef604 --- /dev/null +++ b/packages/vscode-extension/src/editor/provider.ts @@ -0,0 +1,146 @@ +import { getEditorAppUrl, onAppUrlChange } from '#core'; +import { + type AppMessage, + HOST_MESSAGE_TYPE, + type HostMessage, +} from '@lemoncode/mongo-modeler-bridge-protocol'; +import { basename } from 'node:path'; +import * as vscode from 'vscode'; +import { + type MongoModelerDocument, + openDocument, + readFile, + writeFile, +} from './document'; +import { handleWebviewMessage } from './handlers'; +import { getHtml } from './panel'; + +export class MongoModelerEditorProvider + implements vscode.CustomEditorProvider { + static register(context: vscode.ExtensionContext): vscode.Disposable { + const provider = new MongoModelerEditorProvider(context.extensionUri); + const editorRegistration = vscode.window.registerCustomEditorProvider( + 'mongo-modeler.editor', + provider, + { + supportsMultipleEditorsPerDocument: false, + webviewOptions: { retainContextWhenHidden: true }, + } + ); + const configListener = onAppUrlChange(() => provider.refreshAllPanels()); + return vscode.Disposable.from(editorRegistration, configListener); + } + + constructor(private readonly extensionUri: vscode.Uri) { } + + private readonly _onDidChangeCustomDocument = new vscode.EventEmitter< + vscode.CustomDocumentContentChangeEvent + >(); + readonly onDidChangeCustomDocument = this._onDidChangeCustomDocument.event; + + private readonly panels = new Map(); + + async openCustomDocument( + uri: vscode.Uri, + openContext: vscode.CustomDocumentOpenContext + ): Promise { + return openDocument(uri, openContext); + } + + async saveCustomDocument( + doc: MongoModelerDocument, + _cancel: vscode.CancellationToken + ): Promise { + await writeFile(doc.uri, doc.content); + } + + async saveCustomDocumentAs( + doc: MongoModelerDocument, + dest: vscode.Uri, + _cancel: vscode.CancellationToken + ): Promise { + await writeFile(dest, doc.content); + } + + async revertCustomDocument( + doc: MongoModelerDocument, + _cancel: vscode.CancellationToken + ): Promise { + doc.content = await readFile(doc.uri); + let data: unknown; + try { + data = JSON.parse(doc.content); + } catch { + data = doc.content; + } + this.broadcast(doc, { + type: HOST_MESSAGE_TYPE.LOAD_FILE, + payload: { data, fileName: basename(doc.uri.fsPath) }, + }); + } + + async backupCustomDocument( + doc: MongoModelerDocument, + context: vscode.CustomDocumentBackupContext, + _cancel: vscode.CancellationToken + ): Promise { + await writeFile(context.destination, doc.content); + return { + id: context.destination.toString(), + delete: () => { + vscode.workspace.fs + .delete(context.destination) + .then(undefined, () => { }); + }, + }; + } + + resolveCustomEditor( + doc: MongoModelerDocument, + panel: vscode.WebviewPanel, + _token: vscode.CancellationToken + ): void { + const key = doc.uri.toString(); + this.panels.set(key, [...(this.panels.get(key) ?? []), panel]); + panel.onDidDispose(() => { + const remaining = (this.panels.get(key) ?? []).filter(p => p !== panel); + if (remaining.length === 0) { + this.panels.delete(key); + } else { + this.panels.set(key, remaining); + } + }); + + panel.webview.options = { + enableScripts: true, + localResourceRoots: [this.extensionUri], + }; + + panel.webview.onDidReceiveMessage(async (msg: AppMessage) => { + await handleWebviewMessage(msg, doc, reply => + panel.webview.postMessage(reply satisfies HostMessage) + ); + }); + + panel.webview.html = getHtml( + panel.webview, + this.extensionUri, + getEditorAppUrl() + ); + } + + private broadcast(doc: MongoModelerDocument, msg: HostMessage): void { + for (const panel of this.panels.get(doc.uri.toString()) ?? []) { + panel.webview.postMessage(msg); + } + } + + refreshAllPanels(): void { + const url = getEditorAppUrl(); + for (const panels of this.panels.values()) { + for (const panel of panels) { + panel.webview.html = getHtml(panel.webview, this.extensionUri, url); + } + } + } +} diff --git a/packages/vscode-extension/src/index.ts b/packages/vscode-extension/src/index.ts index 95a1665d..972b8dde 100644 --- a/packages/vscode-extension/src/index.ts +++ b/packages/vscode-extension/src/index.ts @@ -1,7 +1,10 @@ +import { registerCommands } from '#commands'; +import { MongoModelerEditorProvider } from '#editor'; import * as vscode from 'vscode'; -export const activate = (_context: vscode.ExtensionContext) => { - // Extension activation entrypoint. Implementation will be added later. +export const activate = (context: vscode.ExtensionContext) => { + context.subscriptions.push(MongoModelerEditorProvider.register(context)); + registerCommands(context); }; -export const deactivate = () => { }; +export const deactivate = () => {}; diff --git a/packages/vscode-extension/src/webview/bridge.ts b/packages/vscode-extension/src/webview/bridge.ts new file mode 100644 index 00000000..fe605821 --- /dev/null +++ b/packages/vscode-extension/src/webview/bridge.ts @@ -0,0 +1,30 @@ +import { + type AppMessage, + HOST_MESSAGE_TYPE, + type HostMessage, +} from '@lemoncode/mongo-modeler-bridge-protocol'; + +declare function acquireVsCodeApi(): { postMessage(msg: AppMessage): void }; + +const vscode = acquireVsCodeApi(); + +const FORWARDED_TO_IFRAME: ReadonlySet = new Set([ + HOST_MESSAGE_TYPE.SAVED, + HOST_MESSAGE_TYPE.LOAD_FILE, +]); + +export const setupBridge = ( + iframe: HTMLIFrameElement, + appOrigin: string +): void => { + window.addEventListener('message', (event: MessageEvent) => { + if (event.origin === appOrigin) { + vscode.postMessage(event.data as AppMessage); + } else { + const msg = event.data as HostMessage; + if (FORWARDED_TO_IFRAME.has(msg.type)) { + iframe.contentWindow?.postMessage(msg, appOrigin); + } + } + }); +}; diff --git a/packages/vscode-extension/src/webview/main.ts b/packages/vscode-extension/src/webview/main.ts index 9daaf173..3bf20247 100644 --- a/packages/vscode-extension/src/webview/main.ts +++ b/packages/vscode-extension/src/webview/main.ts @@ -1,3 +1,23 @@ -// Webview bootstrap. Implementation will be added later. -export { }; +import { setupBridge } from './bridge'; +import { setupThemeSync } from './theme'; +const appUrl = document.body.dataset.appUrl; +if (!appUrl) { + throw new Error('[MongoModeler] Missing data-app-url attribute on '); +} + +const appOrigin = new URL(appUrl).origin; + +const iframe = document.createElement('iframe'); +iframe.src = appUrl; +// keep same-origin enabled so the hosted app can use its browser storage/session APIs. +iframe.setAttribute( + 'sandbox', + 'allow-scripts allow-same-origin allow-downloads' +); +iframe.allow = 'clipboard-read; clipboard-write'; +iframe.title = 'Mongo Modeler Application'; +document.body.appendChild(iframe); + +setupBridge(iframe, appOrigin); +setupThemeSync(iframe, appOrigin); diff --git a/packages/vscode-extension/src/webview/theme.ts b/packages/vscode-extension/src/webview/theme.ts new file mode 100644 index 00000000..95f1cc36 --- /dev/null +++ b/packages/vscode-extension/src/webview/theme.ts @@ -0,0 +1,53 @@ +import { + APP_MESSAGE_TYPE, + HOST_MESSAGE_TYPE, + type ThemePayload, +} from '@lemoncode/mongo-modeler-bridge-protocol'; + +const readVar = (style: CSSStyleDeclaration, name: string): string => + style.getPropertyValue(name).trim(); + +export const extractTheme = (): ThemePayload => { + const style = getComputedStyle(document.documentElement); + return { + background: readVar(style, '--vscode-editor-background'), + backgroundSecondary: readVar(style, '--vscode-sideBar-background'), + foreground: readVar(style, '--vscode-editor-foreground'), + }; +}; + +const IFRAME_READY_TYPES: ReadonlySet = new Set([ + APP_MESSAGE_TYPE.WEBVIEW_READY, + APP_MESSAGE_TYPE.READY, +]); + +export const setupThemeSync = ( + iframe: HTMLIFrameElement, + appOrigin: string +): void => { + const sendTheme = (): void => { + iframe.contentWindow?.postMessage( + { type: HOST_MESSAGE_TYPE.THEME, payload: extractTheme() }, + appOrigin + ); + }; + + const onIframeReady = (event: MessageEvent): void => { + if (event.origin !== appOrigin) return; + const type = (event.data as { type?: string } | undefined)?.type; + if (type && IFRAME_READY_TYPES.has(type)) sendTheme(); + }; + window.addEventListener('message', onIframeReady); + + let rafId = 0; + const sendThemeDebounced = (): void => { + cancelAnimationFrame(rafId); + rafId = requestAnimationFrame(sendTheme); + }; + + const observer = new MutationObserver(sendThemeDebounced); + observer.observe(document.body, { + attributes: true, + attributeFilter: ['class', 'style'], + }); +};