From 8683fdbca0f58d30b1fee5627a90f9d9a32808ed Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Mon, 4 May 2026 11:13:21 +0200 Subject: [PATCH 01/13] feat: add VSCode launch and settings configuration for Mongo Modeler extension --- .vscode/launch.json | 14 ++++++++++++++ .vscode/settings.json | 3 +++ 2 files changed, 17 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json 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" +} From 89203a1fd643b2ba80d61b33cabf35899fbb22da Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Mon, 4 May 2026 11:18:01 +0200 Subject: [PATCH 02/13] feat: implement VSCode bridge to web --- apps/web/src/core/vscode/env.helpers.ts | 2 + apps/web/src/core/vscode/index.ts | 1 + .../core/vscode/use-vscode-auto-save.hook.ts | 46 ++++++++++++++++ .../core/vscode/use-vscode-file-load.hook.ts | 50 ++++++++++++++++++ .../src/core/vscode/use-vscode-sync.hook.ts | 11 ++++ .../src/core/vscode/vscode-bridge.helpers.ts | 52 +++++++++++++++++++ .../src/core/vscode/vscode-sync.helpers.ts | 8 +++ apps/web/src/scenes/main.scene.tsx | 12 +++-- 8 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 apps/web/src/core/vscode/env.helpers.ts create mode 100644 apps/web/src/core/vscode/index.ts create mode 100644 apps/web/src/core/vscode/use-vscode-auto-save.hook.ts create mode 100644 apps/web/src/core/vscode/use-vscode-file-load.hook.ts create mode 100644 apps/web/src/core/vscode/use-vscode-sync.hook.ts create mode 100644 apps/web/src/core/vscode/vscode-bridge.helpers.ts create mode 100644 apps/web/src/core/vscode/vscode-sync.helpers.ts 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..97d3a06a --- /dev/null +++ b/apps/web/src/core/vscode/use-vscode-sync.hook.ts @@ -0,0 +1,11 @@ +import { useVSCodeAutoSave } from './use-vscode-auto-save.hook'; +import { useVSCodeFileLoad } from './use-vscode-file-load.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); +}; 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..9253eb86 --- /dev/null +++ b/apps/web/src/core/vscode/vscode-bridge.helpers.ts @@ -0,0 +1,52 @@ +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; + 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..bcef9668 --- /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); 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 ( <>
From 4c4570da4e20e57c389caa16a71800ba303d1148 Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Mon, 4 May 2026 11:19:53 +0200 Subject: [PATCH 03/13] feat: implement core functionality for Mongo Modeler VSCode extension --- packages/bridge-protocol/src/constant.ts | 11 ++ packages/bridge-protocol/src/index.ts | 3 +- packages/bridge-protocol/src/model.ts | 22 +++ .../vscode-extension/src/commands/index.ts | 2 + .../src/commands/new-diagram.ts | 52 +++++++ .../vscode-extension/src/commands/register.ts | 6 + packages/vscode-extension/src/core/config.ts | 29 ++++ packages/vscode-extension/src/core/index.ts | 2 + packages/vscode-extension/src/core/logger.ts | 9 ++ .../vscode-extension/src/editor/document.ts | 29 ++++ .../vscode-extension/src/editor/handlers.ts | 45 ++++++ packages/vscode-extension/src/editor/index.ts | 4 + packages/vscode-extension/src/editor/panel.ts | 33 +++++ .../vscode-extension/src/editor/provider.ts | 136 ++++++++++++++++++ packages/vscode-extension/src/index.ts | 9 +- .../vscode-extension/src/webview/bridge.ts | 31 ++++ packages/vscode-extension/src/webview/main.ts | 21 ++- 17 files changed, 438 insertions(+), 6 deletions(-) create mode 100644 packages/bridge-protocol/src/constant.ts create mode 100644 packages/bridge-protocol/src/model.ts create mode 100644 packages/vscode-extension/src/commands/index.ts create mode 100644 packages/vscode-extension/src/commands/new-diagram.ts create mode 100644 packages/vscode-extension/src/commands/register.ts create mode 100644 packages/vscode-extension/src/core/config.ts create mode 100644 packages/vscode-extension/src/core/index.ts create mode 100644 packages/vscode-extension/src/core/logger.ts create mode 100644 packages/vscode-extension/src/editor/document.ts create mode 100644 packages/vscode-extension/src/editor/handlers.ts create mode 100644 packages/vscode-extension/src/editor/index.ts create mode 100644 packages/vscode-extension/src/editor/panel.ts create mode 100644 packages/vscode-extension/src/editor/provider.ts create mode 100644 packages/vscode-extension/src/webview/bridge.ts diff --git a/packages/bridge-protocol/src/constant.ts b/packages/bridge-protocol/src/constant.ts new file mode 100644 index 00000000..3cff235c --- /dev/null +++ b/packages/bridge-protocol/src/constant.ts @@ -0,0 +1,11 @@ +export const HOST_MESSAGE_TYPE = { + LOAD: 'mm:load', + SAVED: 'mm:saved', + LOAD_FILE: 'LOAD_FILE', +} as const; + +export const APP_MESSAGE_TYPE = { + READY: 'mm:ready', + SAVE: 'mm:save', + WEBVIEW_READY: 'WEBVIEW_READY', +} as const; diff --git a/packages/bridge-protocol/src/index.ts b/packages/bridge-protocol/src/index.ts index cb0ff5c3..61dc567b 100644 --- a/packages/bridge-protocol/src/index.ts +++ b/packages/bridge-protocol/src/index.ts @@ -1 +1,2 @@ -export {}; +export * from './constant'; +export * from './model'; diff --git a/packages/bridge-protocol/src/model.ts b/packages/bridge-protocol/src/model.ts new file mode 100644 index 00000000..32a34c91 --- /dev/null +++ b/packages/bridge-protocol/src/model.ts @@ -0,0 +1,22 @@ +import type { APP_MESSAGE_TYPE, HOST_MESSAGE_TYPE } from './constant'; + +export interface LoadFilePayload { + data: unknown; + fileName: string; +} + +export type HostMessage = + | { + type: typeof HOST_MESSAGE_TYPE.LOAD; + payload: { content: string; fileName: string }; + } + | { type: typeof HOST_MESSAGE_TYPE.SAVED } + | { type: typeof HOST_MESSAGE_TYPE.LOAD_FILE; payload: LoadFilePayload }; + +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/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..c7b07205 --- /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: () => {} }; +}; + +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..d8987997 --- /dev/null +++ b/packages/vscode-extension/src/editor/handlers.ts @@ -0,0 +1,45 @@ +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.READY: + postMessage({ + type: HOST_MESSAGE_TYPE.LOAD, + payload: { content: doc.content, fileName: basename(doc.uri.fsPath) }, + }); + break; + + 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: + 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..f7ab36e4 --- /dev/null +++ b/packages/vscode-extension/src/editor/provider.ts @@ -0,0 +1,136 @@ +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); + this.broadcast(doc, { + type: HOST_MESSAGE_TYPE.LOAD, + payload: { content: doc.content, 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); + this.panels.set(key, remaining); + }); + + panel.webview.options = { + enableScripts: true, + localResourceRoots: [this.extensionUri], + }; + panel.webview.html = getHtml( + panel.webview, + this.extensionUri, + getEditorAppUrl() + ); + + panel.webview.onDidReceiveMessage(async (msg: AppMessage) => { + await handleWebviewMessage(msg, doc, reply => + panel.webview.postMessage(reply satisfies HostMessage) + ); + }); + } + + 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..e81070a4 --- /dev/null +++ b/packages/vscode-extension/src/webview/bridge.ts @@ -0,0 +1,31 @@ +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.LOAD, + 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..cc199da5 100644 --- a/packages/vscode-extension/src/webview/main.ts +++ b/packages/vscode-extension/src/webview/main.ts @@ -1,3 +1,20 @@ -// Webview bootstrap. Implementation will be added later. -export { }; +import { setupBridge } from './bridge'; +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; +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); From ae4e3c1a764e64abd260cd7a1847e085923db3a4 Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Mon, 4 May 2026 11:49:05 +0200 Subject: [PATCH 04/13] feat: implement theme synchronization for VSCode extension --- .../src/core/vscode/use-vscode-sync.hook.ts | 2 + .../src/core/vscode/use-vscode-theme.hook.ts | 39 ++++++++++++++ apps/web/src/pods/toolbar/toolbar.pod.tsx | 27 +++++----- packages/bridge-protocol/src/constant.ts | 1 + packages/bridge-protocol/src/model.ts | 9 +++- packages/vscode-extension/src/webview/main.ts | 2 + .../vscode-extension/src/webview/theme.ts | 52 +++++++++++++++++++ 7 files changed, 119 insertions(+), 13 deletions(-) create mode 100644 apps/web/src/core/vscode/use-vscode-theme.hook.ts create mode 100644 packages/vscode-extension/src/webview/theme.ts diff --git a/apps/web/src/core/vscode/use-vscode-sync.hook.ts b/apps/web/src/core/vscode/use-vscode-sync.hook.ts index 97d3a06a..ab933994 100644 --- a/apps/web/src/core/vscode/use-vscode-sync.hook.ts +++ b/apps/web/src/core/vscode/use-vscode-sync.hook.ts @@ -1,5 +1,6 @@ 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 @@ -8,4 +9,5 @@ import { useVSCodeFileLoad } from './use-vscode-file-load.hook'; 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..551ca5ae --- /dev/null +++ b/apps/web/src/core/vscode/use-vscode-theme.hook.ts @@ -0,0 +1,39 @@ +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 = { + 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/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/packages/bridge-protocol/src/constant.ts b/packages/bridge-protocol/src/constant.ts index 3cff235c..d7128da3 100644 --- a/packages/bridge-protocol/src/constant.ts +++ b/packages/bridge-protocol/src/constant.ts @@ -2,6 +2,7 @@ export const HOST_MESSAGE_TYPE = { LOAD: 'mm:load', SAVED: 'mm:saved', LOAD_FILE: 'LOAD_FILE', + THEME: 'mm:theme', } as const; export const APP_MESSAGE_TYPE = { diff --git a/packages/bridge-protocol/src/model.ts b/packages/bridge-protocol/src/model.ts index 32a34c91..308a9798 100644 --- a/packages/bridge-protocol/src/model.ts +++ b/packages/bridge-protocol/src/model.ts @@ -5,13 +5,20 @@ export interface LoadFilePayload { fileName: string; } +export interface ThemePayload { + background: string; + backgroundSecondary: string; + foreground: string; +} + export type HostMessage = | { type: typeof HOST_MESSAGE_TYPE.LOAD; payload: { content: string; fileName: string }; } | { type: typeof HOST_MESSAGE_TYPE.SAVED } - | { type: typeof HOST_MESSAGE_TYPE.LOAD_FILE; payload: LoadFilePayload }; + | { 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 } diff --git a/packages/vscode-extension/src/webview/main.ts b/packages/vscode-extension/src/webview/main.ts index cc199da5..73a2f904 100644 --- a/packages/vscode-extension/src/webview/main.ts +++ b/packages/vscode-extension/src/webview/main.ts @@ -1,4 +1,5 @@ import { setupBridge } from './bridge'; +import { setupThemeSync } from './theme'; const appUrl = document.body.dataset.appUrl; if (!appUrl) { @@ -18,3 +19,4 @@ 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..ce705ac0 --- /dev/null +++ b/packages/vscode-extension/src/webview/theme.ts @@ -0,0 +1,52 @@ +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); + + const observer = new MutationObserver(sendTheme); + observer.observe(document.body, { + attributes: true, + attributeFilter: ['class', 'style'], + }); + + return () => { + window.removeEventListener('message', onIframeReady); + observer.disconnect(); + }; +}; From e4dbfad84ab382fe8a25afc56be62a4296938e72 Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Tue, 5 May 2026 12:28:43 +0200 Subject: [PATCH 05/13] feat: update message types and payload structure for VSCode extension --- packages/bridge-protocol/src/constant.ts | 5 ++--- packages/bridge-protocol/src/model.ts | 4 ---- packages/vscode-extension/src/editor/handlers.ts | 7 ------- packages/vscode-extension/src/editor/provider.ts | 10 ++++++++-- packages/vscode-extension/src/webview/bridge.ts | 1 - 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/packages/bridge-protocol/src/constant.ts b/packages/bridge-protocol/src/constant.ts index d7128da3..ce5ae477 100644 --- a/packages/bridge-protocol/src/constant.ts +++ b/packages/bridge-protocol/src/constant.ts @@ -1,12 +1,11 @@ export const HOST_MESSAGE_TYPE = { - LOAD: 'mm:load', SAVED: 'mm:saved', - LOAD_FILE: 'LOAD_FILE', + LOAD_FILE: 'mm:load-file', THEME: 'mm:theme', } as const; export const APP_MESSAGE_TYPE = { READY: 'mm:ready', SAVE: 'mm:save', - WEBVIEW_READY: 'WEBVIEW_READY', + WEBVIEW_READY: 'mm:webview-ready', } as const; diff --git a/packages/bridge-protocol/src/model.ts b/packages/bridge-protocol/src/model.ts index 308a9798..eb66c1c2 100644 --- a/packages/bridge-protocol/src/model.ts +++ b/packages/bridge-protocol/src/model.ts @@ -12,10 +12,6 @@ export interface ThemePayload { } export type HostMessage = - | { - type: typeof HOST_MESSAGE_TYPE.LOAD; - payload: { content: string; fileName: string }; - } | { type: typeof HOST_MESSAGE_TYPE.SAVED } | { type: typeof HOST_MESSAGE_TYPE.LOAD_FILE; payload: LoadFilePayload } | { type: typeof HOST_MESSAGE_TYPE.THEME; payload: ThemePayload }; diff --git a/packages/vscode-extension/src/editor/handlers.ts b/packages/vscode-extension/src/editor/handlers.ts index d8987997..bf2c6c87 100644 --- a/packages/vscode-extension/src/editor/handlers.ts +++ b/packages/vscode-extension/src/editor/handlers.ts @@ -15,13 +15,6 @@ export const handleWebviewMessage = async ( postMessage: PostMessageFn ): Promise => { switch (msg.type) { - case APP_MESSAGE_TYPE.READY: - postMessage({ - type: HOST_MESSAGE_TYPE.LOAD, - payload: { content: doc.content, fileName: basename(doc.uri.fsPath) }, - }); - break; - case APP_MESSAGE_TYPE.WEBVIEW_READY: { let data: unknown; try { diff --git a/packages/vscode-extension/src/editor/provider.ts b/packages/vscode-extension/src/editor/provider.ts index f7ab36e4..22295aec 100644 --- a/packages/vscode-extension/src/editor/provider.ts +++ b/packages/vscode-extension/src/editor/provider.ts @@ -68,9 +68,15 @@ export class MongoModelerEditorProvider _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, - payload: { content: doc.content, fileName: basename(doc.uri.fsPath) }, + type: HOST_MESSAGE_TYPE.LOAD_FILE, + payload: { data, fileName: basename(doc.uri.fsPath) }, }); } diff --git a/packages/vscode-extension/src/webview/bridge.ts b/packages/vscode-extension/src/webview/bridge.ts index e81070a4..fe605821 100644 --- a/packages/vscode-extension/src/webview/bridge.ts +++ b/packages/vscode-extension/src/webview/bridge.ts @@ -9,7 +9,6 @@ declare function acquireVsCodeApi(): { postMessage(msg: AppMessage): void }; const vscode = acquireVsCodeApi(); const FORWARDED_TO_IFRAME: ReadonlySet = new Set([ - HOST_MESSAGE_TYPE.LOAD, HOST_MESSAGE_TYPE.SAVED, HOST_MESSAGE_TYPE.LOAD_FILE, ]); From 3ef9a71f052a0af6b3fbcba1fab9f15da659eb11 Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Tue, 5 May 2026 12:36:51 +0200 Subject: [PATCH 06/13] chore: change bridge-protocol to vscode-bridge-protocol package name --- package-lock.json | 10 +++++++++- .../package.json | 0 .../src/constant.ts | 0 .../src/index.ts | 0 .../src/model.ts | 0 .../tsconfig.json | 0 6 files changed, 9 insertions(+), 1 deletion(-) rename packages/{bridge-protocol => vscode-bridge-protocol}/package.json (100%) rename packages/{bridge-protocol => vscode-bridge-protocol}/src/constant.ts (100%) rename packages/{bridge-protocol => vscode-bridge-protocol}/src/index.ts (100%) rename packages/{bridge-protocol => vscode-bridge-protocol}/src/model.ts (100%) rename packages/{bridge-protocol => vscode-bridge-protocol}/tsconfig.json (100%) diff --git a/package-lock.json b/package-lock.json index a61e65ee..e6b464fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1415,7 +1415,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": { @@ -10855,6 +10855,14 @@ } }, "packages/bridge-protocol": { + "name": "@lemoncode/mongo-modeler-bridge-protocol", + "version": "0.0.0", + "extraneous": true, + "devDependencies": { + "@lemoncode/typescript-config": "*" + } + }, + "packages/vscode-bridge-protocol": { "name": "@lemoncode/mongo-modeler-bridge-protocol", "version": "0.0.0", "devDependencies": { 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/bridge-protocol/src/constant.ts b/packages/vscode-bridge-protocol/src/constant.ts similarity index 100% rename from packages/bridge-protocol/src/constant.ts rename to packages/vscode-bridge-protocol/src/constant.ts diff --git a/packages/bridge-protocol/src/index.ts b/packages/vscode-bridge-protocol/src/index.ts similarity index 100% rename from packages/bridge-protocol/src/index.ts rename to packages/vscode-bridge-protocol/src/index.ts diff --git a/packages/bridge-protocol/src/model.ts b/packages/vscode-bridge-protocol/src/model.ts similarity index 100% rename from packages/bridge-protocol/src/model.ts rename to packages/vscode-bridge-protocol/src/model.ts 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 From eee9b7e6acc77a87772bbcb5a938a7ff6a3a0085 Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Wed, 6 May 2026 08:56:05 +0200 Subject: [PATCH 07/13] fix(vscode-extension): register webview listener before assigning html --- .../vscode-extension/src/editor/provider.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/vscode-extension/src/editor/provider.ts b/packages/vscode-extension/src/editor/provider.ts index 22295aec..917f5293 100644 --- a/packages/vscode-extension/src/editor/provider.ts +++ b/packages/vscode-extension/src/editor/provider.ts @@ -16,8 +16,7 @@ import { handleWebviewMessage } from './handlers'; import { getHtml } from './panel'; export class MongoModelerEditorProvider - implements vscode.CustomEditorProvider -{ + implements vscode.CustomEditorProvider { static register(context: vscode.ExtensionContext): vscode.Disposable { const provider = new MongoModelerEditorProvider(context.extensionUri); const editorRegistration = vscode.window.registerCustomEditorProvider( @@ -32,7 +31,7 @@ export class MongoModelerEditorProvider return vscode.Disposable.from(editorRegistration, configListener); } - constructor(private readonly extensionUri: vscode.Uri) {} + constructor(private readonly extensionUri: vscode.Uri) { } private readonly _onDidChangeCustomDocument = new vscode.EventEmitter< vscode.CustomDocumentContentChangeEvent @@ -91,7 +90,7 @@ export class MongoModelerEditorProvider delete: () => { vscode.workspace.fs .delete(context.destination) - .then(undefined, () => {}); + .then(undefined, () => { }); }, }; } @@ -112,17 +111,18 @@ export class MongoModelerEditorProvider enableScripts: true, localResourceRoots: [this.extensionUri], }; - panel.webview.html = getHtml( - panel.webview, - this.extensionUri, - getEditorAppUrl() - ); 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 { From d117c13502a7c3dff15d1735ef0d5420a9a97e0f Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Wed, 20 May 2026 12:20:58 +0200 Subject: [PATCH 08/13] refactor(vscode-extension): simplify setupThemeSync by removing return function and debouncing theme updates --- packages/vscode-extension/src/webview/theme.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/vscode-extension/src/webview/theme.ts b/packages/vscode-extension/src/webview/theme.ts index ce705ac0..95f1cc36 100644 --- a/packages/vscode-extension/src/webview/theme.ts +++ b/packages/vscode-extension/src/webview/theme.ts @@ -24,7 +24,7 @@ const IFRAME_READY_TYPES: ReadonlySet = new Set([ export const setupThemeSync = ( iframe: HTMLIFrameElement, appOrigin: string -): (() => void) => { +): void => { const sendTheme = (): void => { iframe.contentWindow?.postMessage( { type: HOST_MESSAGE_TYPE.THEME, payload: extractTheme() }, @@ -39,14 +39,15 @@ export const setupThemeSync = ( }; window.addEventListener('message', onIframeReady); - const observer = new MutationObserver(sendTheme); + 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'], }); - - return () => { - window.removeEventListener('message', onIframeReady); - observer.disconnect(); - }; }; From 2dd83816df7a706d6cc74a02889e9a8c7fe74313 Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Wed, 20 May 2026 12:25:11 +0200 Subject: [PATCH 09/13] fix(vscode-extension): format serialized schema output with indentation --- apps/web/src/core/vscode/vscode-sync.helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/core/vscode/vscode-sync.helpers.ts b/apps/web/src/core/vscode/vscode-sync.helpers.ts index bcef9668..33949dbd 100644 --- a/apps/web/src/core/vscode/vscode-sync.helpers.ts +++ b/apps/web/src/core/vscode/vscode-sync.helpers.ts @@ -5,4 +5,4 @@ export const deserializeSchema = (data: unknown): DatabaseSchemaVm => mapSchemaToLatestVersion(data); export const serializeSchema = (schema: DatabaseSchemaVm): string => - JSON.stringify(schema); + JSON.stringify(schema, null, 2); From 2dd9cc546e8855d868f06877b092f8c120057ed4 Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Wed, 20 May 2026 12:29:47 +0200 Subject: [PATCH 10/13] chore: update turbo to version 2.9.14 in package.json --- package-lock.json | 1181 +++------------------------------------------ package.json | 2 +- 2 files changed, 59 insertions(+), 1124 deletions(-) diff --git a/package-lock.json b/package-lock.json index e6b464fe..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", @@ -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,14 +9797,6 @@ "buffer-crc32": "~0.2.3" } }, - "packages/bridge-protocol": { - "name": "@lemoncode/mongo-modeler-bridge-protocol", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "@lemoncode/typescript-config": "*" - } - }, "packages/vscode-bridge-protocol": { "name": "@lemoncode/mongo-modeler-bridge-protocol", "version": "0.0.0", 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 From cf24220e1ebf2651a22340e2e27ae9750eed6df1 Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Wed, 20 May 2026 12:34:29 +0200 Subject: [PATCH 11/13] fix(vscode-extension): improve panel disposal logic to delete empty entries from the panels map --- packages/vscode-extension/src/editor/provider.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/vscode-extension/src/editor/provider.ts b/packages/vscode-extension/src/editor/provider.ts index 917f5293..391ef604 100644 --- a/packages/vscode-extension/src/editor/provider.ts +++ b/packages/vscode-extension/src/editor/provider.ts @@ -104,7 +104,11 @@ export class MongoModelerEditorProvider this.panels.set(key, [...(this.panels.get(key) ?? []), panel]); panel.onDidDispose(() => { const remaining = (this.panels.get(key) ?? []).filter(p => p !== panel); - this.panels.set(key, remaining); + if (remaining.length === 0) { + this.panels.delete(key); + } else { + this.panels.set(key, remaining); + } }); panel.webview.options = { From 4fc938cc45c022399c33ae09fbf1bdf707e0aba7 Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Wed, 20 May 2026 12:43:46 +0200 Subject: [PATCH 12/13] fix(vscode-extension): add comments for clarity --- apps/web/src/core/vscode/use-vscode-theme.hook.ts | 1 + packages/vscode-extension/src/editor/document.ts | 2 +- packages/vscode-extension/src/editor/handlers.ts | 1 + packages/vscode-extension/src/webview/main.ts | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/web/src/core/vscode/use-vscode-theme.hook.ts b/apps/web/src/core/vscode/use-vscode-theme.hook.ts index 551ca5ae..cd20ca13 100644 --- a/apps/web/src/core/vscode/use-vscode-theme.hook.ts +++ b/apps/web/src/core/vscode/use-vscode-theme.hook.ts @@ -7,6 +7,7 @@ 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', diff --git a/packages/vscode-extension/src/editor/document.ts b/packages/vscode-extension/src/editor/document.ts index c7b07205..e89e0749 100644 --- a/packages/vscode-extension/src/editor/document.ts +++ b/packages/vscode-extension/src/editor/document.ts @@ -13,7 +13,7 @@ export const openDocument = async ( ? vscode.Uri.parse(openContext.backupId) : uri; const content = await readFile(source); - return { uri, content, dispose: () => {} }; + return { uri, content, dispose: () => { } }; // no resources to release }; export const readFile = async (uri: vscode.Uri): Promise => { diff --git a/packages/vscode-extension/src/editor/handlers.ts b/packages/vscode-extension/src/editor/handlers.ts index bf2c6c87..0d1fab7d 100644 --- a/packages/vscode-extension/src/editor/handlers.ts +++ b/packages/vscode-extension/src/editor/handlers.ts @@ -30,6 +30,7 @@ export const handleWebviewMessage = async ( } 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 }); diff --git a/packages/vscode-extension/src/webview/main.ts b/packages/vscode-extension/src/webview/main.ts index 73a2f904..3bf20247 100644 --- a/packages/vscode-extension/src/webview/main.ts +++ b/packages/vscode-extension/src/webview/main.ts @@ -10,6 +10,7 @@ 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' From 4c6573de7075134a47a1609675c5e312a30d2d1a Mon Sep 17 00:00:00 2001 From: Ivanruii Date: Wed, 20 May 2026 12:53:42 +0200 Subject: [PATCH 13/13] docs(vscode-extension): add comments for clarity in sendToExtension and onMessage functions --- apps/web/src/core/vscode/vscode-bridge.helpers.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/web/src/core/vscode/vscode-bridge.helpers.ts b/apps/web/src/core/vscode/vscode-bridge.helpers.ts index 9253eb86..62cc2f63 100644 --- a/apps/web/src/core/vscode/vscode-bridge.helpers.ts +++ b/apps/web/src/core/vscode/vscode-bridge.helpers.ts @@ -15,6 +15,8 @@ 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, '*'); }; @@ -22,7 +24,7 @@ export const onMessage = ( type: T, handler: HandlerFor ): (() => void) => { - if (!isVSCodeEnv()) return () => {}; + if (!isVSCodeEnv()) return () => { }; const existing = handlers.get(type) ?? new Set(); existing.add(handler as AnyHandler);