diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..e05e784a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,99 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +VaultLink is a self-hosted Obsidian plugin for real-time collaborative file syncing. The project consists of a Rust-based sync server and a TypeScript frontend with three main components: an Obsidian plugin, a sync client library, and a test client. + +## Architecture + +### Core Components + +- **sync-server/**: Rust-based WebSocket server with SQLite database for document versioning and real-time synchronization +- **frontend/sync-client/**: TypeScript library providing core sync functionality, WebSocket management, and file operations +- **frontend/obsidian-plugin/**: Obsidian plugin that integrates the sync client with Obsidian's API +- **frontend/test-client/**: CLI testing tool for the sync functionality + +### Key Technologies + +- **Backend**: Rust with Axum framework, SQLite with SQLx, WebSockets for real-time sync +- **Frontend**: TypeScript, Webpack for bundling, Jest for testing +- **Sync Algorithm**: Uses reconcile-text library for operational transformation + +## Development Commands + +### Server Development +```bash +cd sync-server +cargo run config-e2e.yml # Start development server +cargo test --verbose # Run Rust tests +cargo clippy --all-targets --all-features # Lint Rust code +cargo fmt --all -- --check # Check Rust formatting +``` + +### Frontend Development +```bash +cd frontend +npm run dev # Start development mode (watches sync-client and obsidian-plugin) +npm run build # Build all workspaces +npm run test # Run all tests +npm run lint # Lint and format TypeScript code +``` + +### Database Setup (Development) +```bash +cd sync-server +sqlx database create --database-url sqlite://db.sqlite3 +sqlx migrate run --source src/app_state/database/migrations --database-url sqlite://db.sqlite3 +cargo sqlx prepare --workspace +``` + +### Scripts +- `scripts/check.sh`: Full CI check (builds, lints, tests both server and frontend) +- `scripts/e2e.sh`: End-to-end testing +- `scripts/clean-up.sh`: Clean logs and database files +- `scripts/bump-version.sh patch`: Publish new version +- `scripts/update-api-types.sh`: Update TypeScript bindings from Rust types + +## Code Structure + +### Workspace Configuration +The frontend uses npm workspaces with three packages: +- `sync-client`: Core synchronization logic +- `obsidian-plugin`: Obsidian-specific integration +- `test-client`: Testing utilities + +### Type Generation +Rust structs generate TypeScript types via ts-rs crate, stored in `sync-server/bindings/` and used by frontend packages. + +### Key Files +- `sync-server/src/`: Rust server implementation with WebSocket handlers +- `frontend/sync-client/src/sync-client.ts`: Main sync client entry point +- `frontend/obsidian-plugin/src/vault-link-plugin.ts`: Main Obsidian plugin class +- `frontend/sync-client/src/services/sync-service.ts`: Core synchronization logic + +## Testing + +### Running Tests +- Server: `cargo test --verbose` +- Frontend: `npm run test` (runs Jest across all workspaces) +- E2E: `scripts/e2e.sh` + +### Test Structure +- Rust: Unit tests alongside source files +- TypeScript: `.test.ts` files using Jest +- E2E: Uses test-client to simulate multiple concurrent users + +## Code Style + +### Rust +- Uses extensive Clippy lints (see Cargo.toml) +- Follows pedantic linting rules +- Forbids unsafe code +- Uses cargo fmt with default settings + +### TypeScript +- Prettier configuration: 4-space tabs, trailing commas removed, LF line endings +- ESLint with unused imports plugin +- Consistent across all three frontend packages \ No newline at end of file diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs index ceba2eee..db648d46 100644 --- a/frontend/eslint.config.mjs +++ b/frontend/eslint.config.mjs @@ -20,7 +20,14 @@ export default [ "no-unused-vars": "off", "@typescript-eslint/restrict-template-expressions": "off", "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-floating-promises": "error", + "@typescript-eslint/no-floating-promises": [ + "error", + { + allowForKnownSafeCalls: [ + { from: "package", name: ["suite", "test"], package: "node:test" }, + ], + }, + ], "@typescript-eslint/parameter-properties": "off", "@typescript-eslint/require-await": "off", "@typescript-eslint/class-methods-use-this": "off", diff --git a/frontend/obsidian-plugin/jest.config.js b/frontend/obsidian-plugin/jest.config.js deleted file mode 100644 index d1cbaca2..00000000 --- a/frontend/obsidian-plugin/jest.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - preset: "ts-jest" -}; diff --git a/frontend/obsidian-plugin/manifest.json b/frontend/obsidian-plugin/manifest.json index a15afeab..b327da4f 100644 --- a/frontend/obsidian-plugin/manifest.json +++ b/frontend/obsidian-plugin/manifest.json @@ -1,7 +1,7 @@ { "id": "vault-link", "name": "VaultLink", - "version": "0.6.1", + "version": "0.6.3", "minAppVersion": "0.0.0", "description": "Self-hosted synchronization and collaboration for your Vault.", "author": "Andras Schmelczer", diff --git a/frontend/obsidian-plugin/package.json b/frontend/obsidian-plugin/package.json index ce8f8b1a..14b286c9 100644 --- a/frontend/obsidian-plugin/package.json +++ b/frontend/obsidian-plugin/package.json @@ -1,40 +1,38 @@ { "name": "vault-link-obsidian-plugin", - "version": "0.6.1", + "version": "0.6.3", "description": "This is a sample plugin for Obsidian (https://obsidian.md)", "main": "main.js", "scripts": { "dev": "webpack watch --mode development", "build": "webpack --mode production", - "test": "jest", + "test": "echo \"no tests defined\" && exit 0", "version": "node version-bump.mjs" }, "keywords": [], "author": "", "license": "MIT", "devDependencies": { - "@types/jest": "^29.5.14", "@types/node": "^22.15.30", "css-loader": "^7.1.2", "date-fns": "^4.1.0", "file-loader": "^6.2.0", "fs-extra": "^11.3.0", - "jest": "^29.7.0", "mini-css-extract-plugin": "^2.9.2", "obsidian": "1.8.7", + "reconcile-text": "^0.5.0", "resolve-url-loader": "^5.0.0", - "sass": "^1.89.1", + "sass": "^1.91.0", "sass-loader": "^16.0.5", "sync-client": "file:../sync-client", "terser-webpack-plugin": "^5.3.14", - "ts-jest": "^29.3.4", "ts-loader": "^9.5.2", "tslib": "2.8.1", + "tsx": "^4.20.5", "typescript": "5.8.3", "url": "^0.11.4", "virtual-scroller": "^1.13.1", "webpack": "^5.99.9", - "webpack-cli": "^6.0.1", - "reconcile-text": "^0.5.0" + "webpack-cli": "^6.0.1" } -} +} \ No newline at end of file diff --git a/frontend/obsidian-plugin/src/obsidian-file-system.ts b/frontend/obsidian-plugin/src/obsidian-file-system.ts index 9609e8b0..00a9acfb 100644 --- a/frontend/obsidian-plugin/src/obsidian-file-system.ts +++ b/frontend/obsidian-plugin/src/obsidian-file-system.ts @@ -1,7 +1,10 @@ import type { Stat, Vault, Workspace } from "obsidian"; import { MarkdownView, normalizePath } from "obsidian"; -import type { FileSystemOperations, RelativePath } from "sync-client"; -import { positionToLineAndColumn } from "./utils/position-to-line-and-column"; +import { + utils, + type FileSystemOperations, + type RelativePath +} from "sync-client"; import { getSelectionsFromEditor } from "./views/cursors/get-selections-from-editor"; import type { TextWithCursors, CursorPosition } from "reconcile-text"; @@ -105,10 +108,10 @@ export class ObsidianFileSystemOperations implements FileSystemOperations { const from = result.cursors[2 * i]; const to = result.cursors[2 * i + 1]; const { line: fromLine, column: fromColumn } = - positionToLineAndColumn(result.text, from.position); + utils.positionToLineAndColumn(result.text, from.position); const { line: toLine, column: toColumn } = - positionToLineAndColumn(result.text, to.position); + utils.positionToLineAndColumn(result.text, to.position); selections.push({ anchor: { line: fromLine, ch: fromColumn }, diff --git a/frontend/obsidian-plugin/src/utils/position-to-line-and-column.test.ts b/frontend/obsidian-plugin/src/utils/position-to-line-and-column.test.ts deleted file mode 100644 index d5533778..00000000 --- a/frontend/obsidian-plugin/src/utils/position-to-line-and-column.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { positionToLineAndColumn } from "./position-to-line-and-column"; - -describe("positionToLineAndColumn", () => { - test("converts position to line and column in multi-line text", () => { - const text = "ab\ncd\n"; - expect(positionToLineAndColumn(text, 0)).toEqual({ - line: 0, - column: 0 - }); - expect(positionToLineAndColumn(text, 1)).toEqual({ - line: 0, - column: 1 - }); - expect(positionToLineAndColumn(text, 2)).toEqual({ - line: 0, - column: 2 - }); - expect(positionToLineAndColumn(text, 3)).toEqual({ - line: 1, - column: 0 - }); - expect(positionToLineAndColumn(text, 4)).toEqual({ - line: 1, - column: 1 - }); - expect(positionToLineAndColumn(text, 6)).toEqual({ - line: 2, - column: 0 - }); - }); - - test("with carrige returns", () => { - expect(positionToLineAndColumn("a\nb", 3)).toEqual({ - line: 1, - column: 1 - }); - - expect(positionToLineAndColumn("a\r\nb", 3)).toEqual({ - line: 1, - column: 1 - }); - }); - - test("handles empty input", () => { - expect(positionToLineAndColumn("", 0)).toEqual({ line: 0, column: 0 }); - }); - - test("handles positions at the end of text", () => { - const text = "End"; - expect(positionToLineAndColumn(text, 3)).toEqual({ - line: 0, - column: 3 - }); - }); - - test("throws error for position out of range", () => { - const text = "Short text"; - expect(() => positionToLineAndColumn(text, 15)).toThrow(); - expect(() => positionToLineAndColumn(text, -1)).toThrow(); - }); -}); diff --git a/frontend/obsidian-plugin/src/utils/sleep.ts b/frontend/obsidian-plugin/src/utils/sleep.ts deleted file mode 100644 index 638fc019..00000000 --- a/frontend/obsidian-plugin/src/utils/sleep.ts +++ /dev/null @@ -1,3 +0,0 @@ -export async function sleep(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} diff --git a/frontend/obsidian-plugin/src/vault-link-plugin.ts b/frontend/obsidian-plugin/src/vault-link-plugin.ts index 7e0eff1b..b791ffb7 100644 --- a/frontend/obsidian-plugin/src/vault-link-plugin.ts +++ b/frontend/obsidian-plugin/src/vault-link-plugin.ts @@ -1,29 +1,33 @@ import type { + MarkdownView, Editor, MarkdownFileInfo, TAbstractFile, WorkspaceLeaf } from "obsidian"; -import type { MarkdownView } from "obsidian"; import { Platform, Plugin, TFile } from "obsidian"; import "../manifest.json"; import { HistoryView } from "./views/history/history-view"; import { StatusBar } from "./views/status-bar/status-bar"; import { LogsView } from "./views/logs/logs-view"; import { StatusDescription } from "./views/status-description/status-description"; -import { SyncClient, rateLimit, DEFAULT_SETTINGS, Logger } from "sync-client"; +import { + SyncClient, + rateLimit, + DEFAULT_SETTINGS, + Logger, + debugging +} from "sync-client"; import { ObsidianFileSystemOperations } from "./obsidian-file-system"; import { SyncSettingsTab } from "./views/settings/settings-tab"; -import { logToConsole } from "./utils/log-to-console"; -import { updateEditorStatusDisplay } from "./views/editor-sync-line/editor-sync-line"; +import { EditorStatusDisplayManager } from "./views/editor-status-display-manager/editor-status-display-manager"; import { remoteCursorsTheme } from "./views/cursors/remote-cursor-theme"; import { remoteCursorsPlugin, RemoteCursorsPluginValue } from "./views/cursors/remote-cursors-plugin"; import { LocalCursorUpdateListener } from "./views/cursors/local-cursor-update-listener"; -import { slowFetchFactory } from "./debugging/slow-fetch-factory"; -import { flakyWebSocketFactory } from "./debugging/flaky-websocket-factory"; +import { renderCursorsInFileExplorer } from "./views/cursors/file-explorer"; const MIN_WAIT_BETWEEN_UPDATES_IN_MS = 250; @@ -48,8 +52,8 @@ export default class VaultLinkPlugin extends Plugin { const debugOptions = isDebugBuild ? { - fetch: slowFetchFactory(1), - webSocket: flakyWebSocketFactory(1, new Logger()) + fetch: debugging.slowFetchFactory(1), + webSocket: debugging.slowWebSocketFactory(1, new Logger()) } : {}; @@ -66,7 +70,9 @@ export default class VaultLinkPlugin extends Plugin { ...debugOptions }); - logToConsole(this.client); + if (isDebugBuild) { + debugging.logToConsole(this.client); + } const statusDescription = new StatusDescription(this.client); @@ -94,6 +100,7 @@ export default class VaultLinkPlugin extends Plugin { this.client.addRemoteCursorsUpdateListener((cursors) => { RemoteCursorsPluginValue.setCursors(cursors, this.app); + renderCursorsInFileExplorer(cursors, this.app); }); const cursorListener = new LocalCursorUpdateListener( @@ -122,17 +129,23 @@ export default class VaultLinkPlugin extends Plugin { this.registerEditorEvents(); await this.client.start(); - const interval = setInterval(() => { - updateEditorStatusDisplay(this.app.workspace, this.client); - }, 200); + const editorStatusDisplayManager = new EditorStatusDisplayManager( + this, + this.app.workspace, + this.client + ); this.disposables.push(() => { - clearInterval(interval); + editorStatusDisplayManager.stop(); }); }); } public onunload(): void { - this.client.stop(); + this.client.waitAndStop().catch((err: unknown) => { + this.client.logger.error( + `Error while stopping the sync client: ${err}` + ); + }); this.disposables.forEach((disposable) => { disposable(); }); diff --git a/frontend/obsidian-plugin/src/views/cursors/file-explorer.scss b/frontend/obsidian-plugin/src/views/cursors/file-explorer.scss new file mode 100644 index 00000000..90918b55 --- /dev/null +++ b/frontend/obsidian-plugin/src/views/cursors/file-explorer.scss @@ -0,0 +1,15 @@ +.remote-users { + display: flex; + flex-wrap: wrap; + gap: var(--size-4-2); + margin-left: var(--size-4-2); + + span { + border-radius: var(--radius-l); + padding: 0 var(--size-4-1); + border-width: 1.4px; + border-style: solid; + font-size: var(--font-smallest); + font-style: italic; + } +} \ No newline at end of file diff --git a/frontend/obsidian-plugin/src/views/cursors/file-explorer.ts b/frontend/obsidian-plugin/src/views/cursors/file-explorer.ts new file mode 100644 index 00000000..be71c058 --- /dev/null +++ b/frontend/obsidian-plugin/src/views/cursors/file-explorer.ts @@ -0,0 +1,55 @@ +import "./file-explorer.scss"; + +import type { App, View } from "obsidian"; +import { + utils, + type MaybeOutdatedClientCursors, + type RelativePath +} from "sync-client"; + +const REMOTE_USER_CONTAINER_CLASS = "remote-users"; + +export function renderCursorsInFileExplorer( + cursors: MaybeOutdatedClientCursors[], + app: App +): void { + const fileExplorers = app.workspace.getLeavesOfType("file-explorer"); + if (fileExplorers.length == 0) return; + + const [fileExplorer] = fileExplorers; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const fileExplorerView: View & { + fileItems: Record; // it's an internal API + } = fileExplorer.view as any; // eslint-disable-line + + for (const key in fileExplorerView.fileItems) { + const element = + fileExplorerView.fileItems[key].el.querySelector(".tree-item-self"); + + const customElement = createDiv( + { + cls: REMOTE_USER_CONTAINER_CLASS + }, + (parent) => { + cursors.forEach((cursor) => { + cursor.documentsWithCursors.forEach((document) => { + if (document.relative_path === key) { + parent.appendChild( + createSpan({ + text: cursor.userName, + attr: { + style: `border-color: ${utils.getRandomColor(cursor.userName)}` + } + }) + ); + } + }); + }); + } + ); + + element?.querySelector("." + REMOTE_USER_CONTAINER_CLASS)?.remove(); + element?.appendChild(customElement); + } +} diff --git a/frontend/obsidian-plugin/src/views/cursors/get-selections-from-editor.ts b/frontend/obsidian-plugin/src/views/cursors/get-selections-from-editor.ts index 03cce4a8..1635b930 100644 --- a/frontend/obsidian-plugin/src/views/cursors/get-selections-from-editor.ts +++ b/frontend/obsidian-plugin/src/views/cursors/get-selections-from-editor.ts @@ -1,5 +1,5 @@ import type { Editor } from "obsidian"; -import { lineAndColumnToPosition } from "../../utils/line-and-column-to-position"; +import { utils } from "sync-client"; export interface Selection { id: number; @@ -11,7 +11,7 @@ export function getSelectionsFromEditor(editor: Editor): Selection[] { const text = editor.getValue(); return editor.listSelections().map(({ anchor, head }, i) => ({ id: i, - start: lineAndColumnToPosition(text, anchor.line, anchor.ch), - end: lineAndColumnToPosition(text, head.line, head.ch) + start: utils.lineAndColumnToPosition(text, anchor.line, anchor.ch), + end: utils.lineAndColumnToPosition(text, head.line, head.ch) })); } diff --git a/frontend/obsidian-plugin/src/views/cursors/remote-cursors-plugin.ts b/frontend/obsidian-plugin/src/views/cursors/remote-cursors-plugin.ts index 8801ecda..a0de390c 100644 --- a/frontend/obsidian-plugin/src/views/cursors/remote-cursors-plugin.ts +++ b/frontend/obsidian-plugin/src/views/cursors/remote-cursors-plugin.ts @@ -9,12 +9,15 @@ import type { ViewUpdate } from "@codemirror/view"; import { RemoteCursorWidget } from "./remote-cursor-widget"; -import type { CursorSpan, MaybeOutdatedClientCursors } from "sync-client"; +import { + utils, + type CursorSpan, + type MaybeOutdatedClientCursors +} from "sync-client"; import type { App } from "obsidian"; import { MarkdownView } from "obsidian"; import { StateEffect } from "@codemirror/state"; -import { getRandomColor } from "src/utils/get-random-color"; import type { SpanWithHistory } from "reconcile-text"; import { reconcileWithHistory } from "reconcile-text"; @@ -155,7 +158,7 @@ export class RemoteCursorsPluginValue implements PluginValue { RemoteCursorsPluginValue.cursors.forEach( ({ name, span: { start, end } }) => { - const color = getRandomColor(name); + const color = utils.getRandomColor(name); const startLine = update.view.state.doc.lineAt(start); const endLine = update.view.state.doc.lineAt(end); diff --git a/frontend/obsidian-plugin/src/views/editor-sync-line/editor-sync-line.scss b/frontend/obsidian-plugin/src/views/editor-status-display-manager/editor-status-display-manager.scss similarity index 100% rename from frontend/obsidian-plugin/src/views/editor-sync-line/editor-sync-line.scss rename to frontend/obsidian-plugin/src/views/editor-status-display-manager/editor-status-display-manager.scss diff --git a/frontend/obsidian-plugin/src/views/editor-status-display-manager/editor-status-display-manager.ts b/frontend/obsidian-plugin/src/views/editor-status-display-manager/editor-status-display-manager.ts new file mode 100644 index 00000000..5075b847 --- /dev/null +++ b/frontend/obsidian-plugin/src/views/editor-status-display-manager/editor-status-display-manager.ts @@ -0,0 +1,97 @@ +import type { Workspace } from "obsidian"; +import { FileView, setIcon } from "obsidian"; +import type { SyncClient } from "sync-client"; +import { DocumentSyncStatus } from "sync-client"; +import "./editor-status-display-manager.scss"; +import type VaultLinkPlugin from "src/vault-link-plugin"; +import { HistoryView } from "../history/history-view"; + +export class EditorStatusDisplayManager { + private static readonly UPDATE_INTERVAL_IN_MS = 100; + + private readonly intervalId: NodeJS.Timeout; + private readonly lastStatuses = new Map(); + + public constructor( + private readonly plugin: VaultLinkPlugin, + private readonly workspace: Workspace, + private readonly client: SyncClient + ) { + this.intervalId = setInterval(() => { + this.updateEditorStatusDisplay(); + }, EditorStatusDisplayManager.UPDATE_INTERVAL_IN_MS); + } + + public stop(): void { + clearInterval(this.intervalId); + } + + private updateEditorStatusDisplay(): void { + this.workspace.iterateAllLeaves((leaf) => { + if (leaf.view instanceof FileView) { + const filePath = leaf.view.file?.path; + if (filePath == null) { + return; + } + + const element = this.getElementFromLeaf(leaf.view); + if (element == null) { + return; + } + + const previousStatus = this.lastStatuses.get(filePath); + const currentStatus = + this.client.getDocumentSyncingStatus(filePath); + if (previousStatus === currentStatus) { + return; + } + this.lastStatuses.set(filePath, currentStatus); + + if (currentStatus == DocumentSyncStatus.SYNCING_IS_DISABLED) { + element.remove(); + return; + } + + if (currentStatus == DocumentSyncStatus.SYNCING) { + element.classList.add("loading"); + } else { + element.classList.remove("loading"); + } + + const iconContainer = element.querySelector(".icon"); + if (iconContainer != null) { + setIcon( + iconContainer as HTMLElement, // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion + currentStatus == DocumentSyncStatus.SYNCING + ? "loader" + : "circle-check" + ); + } + } + }); + } + + private getElementFromLeaf(fileView: FileView): Element | undefined { + const parent = fileView.contentEl.querySelector(".cm-editor"); + if (parent == null) { + return; + } + + return ( + parent.querySelector(".vault-link-sync-status") ?? + parent.createDiv( + { + cls: "vault-link-sync-status" + }, + (el) => { + el.createSpan({ text: "VaultLink sync state" }); + el.createDiv({ + cls: "icon" + }); + el.onclick = async (): Promise => + this.plugin.activateView(HistoryView.TYPE); + } + ) + ); + } +} diff --git a/frontend/obsidian-plugin/src/views/editor-sync-line/editor-sync-line.ts b/frontend/obsidian-plugin/src/views/editor-sync-line/editor-sync-line.ts deleted file mode 100644 index 78ef1bd8..00000000 --- a/frontend/obsidian-plugin/src/views/editor-sync-line/editor-sync-line.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { Workspace } from "obsidian"; -import { FileView, setIcon } from "obsidian"; -import type { SyncClient } from "sync-client"; -import { DocumentSyncStatus } from "sync-client"; -import "./editor-sync-line.scss"; - -export function updateEditorStatusDisplay( - workspace: Workspace, - client: SyncClient -): void { - workspace.iterateAllLeaves((leaf) => { - if (leaf.view instanceof FileView) { - const filePath = leaf.view.file?.path; - if (filePath == null) { - return; - } - const parent = leaf.view.contentEl.querySelector(".cm-editor"); - if (parent == null) { - return; - } - - const element = - parent.querySelector(".vault-link-sync-status") ?? - parent.createDiv( - { - cls: "vault-link-sync-status" - }, - (el) => { - el.createSpan({ text: "VaultLink sync state" }); - el.createDiv({ - cls: "icon" - }); - } - ); - - const isLoading = - client.getDocumentSyncingStatus(filePath) == - DocumentSyncStatus.SYNCING; - - if (isLoading) { - element.classList.add("loading"); - } else { - element.classList.remove("loading"); - } - - const iconContainer = element.querySelector(".icon"); - if (iconContainer != null) { - setIcon( - iconContainer as HTMLElement, // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion - isLoading ? "loader" : "circle-check" - ); - } - } - }); -} diff --git a/frontend/obsidian-plugin/tsconfig.json b/frontend/obsidian-plugin/tsconfig.json index 09dab427..4c39e97b 100644 --- a/frontend/obsidian-plugin/tsconfig.json +++ b/frontend/obsidian-plugin/tsconfig.json @@ -8,7 +8,7 @@ "allowSyntheticDefaultImports": true, "lib": [ "DOM", - "ESNext" + "ES2024" ] }, "exclude": [ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 73309f06..7876659b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15,464 +15,10 @@ "eslint": "9.28.0", "eslint-plugin-unused-imports": "^4.1.4", "npm-check-updates": "^18.0.1", - "prettier": "^3.5.3", - "typescript-eslint": "8.33.1" + "prettier": "^3.6.2", + "typescript-eslint": "8.41.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.26.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.26.8", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.26.10", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "dev": true, - "license": "MIT" - }, "node_modules/@codemirror/state": { "version": "6.5.2", "dev": true, @@ -501,6 +47,448 @@ "node": ">=14.17.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", "dev": true, @@ -611,17 +599,32 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.1", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.14.0", + "@eslint/core": "^0.15.2", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "dev": true, @@ -678,380 +681,15 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -1062,14 +700,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", "dev": true, @@ -1085,7 +715,9 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1101,6 +733,8 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", "dependencies": { @@ -1113,6 +747,8 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", "engines": { @@ -1121,6 +757,8 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { @@ -1204,64 +842,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.7", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, "node_modules/@types/codemirror": { "version": "5.60.8", "dev": true, @@ -1293,62 +873,21 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.14", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, "node_modules/@types/json-schema": { "version": "7.0.15", "dev": true, "license": "MIT" }, "node_modules/@types/node": { - "version": "22.15.30", + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", + "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.10.0" } }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "dev": true, - "license": "MIT" - }, "node_modules/@types/tern": { "version": "0.23.9", "dev": true, @@ -1357,29 +896,18 @@ "@types/estree": "*" } }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "dev": true, - "license": "MIT" - }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.41.0.tgz", + "integrity": "sha512-8fz6oa6wEKZrhXWro/S3n2eRJqlRcIa6SlDh59FXJ5Wp5XRZ8B9ixpJDcjadHq47hMx0u+HW6SNa6LjJQ6NLtw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.33.1", - "@typescript-eslint/type-utils": "8.33.1", - "@typescript-eslint/utils": "8.33.1", - "@typescript-eslint/visitor-keys": "8.33.1", + "@typescript-eslint/scope-manager": "8.41.0", + "@typescript-eslint/type-utils": "8.41.0", + "@typescript-eslint/utils": "8.41.0", + "@typescript-eslint/visitor-keys": "8.41.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -1393,9 +921,9 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.33.1", + "@typescript-eslint/parser": "^8.41.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { @@ -1407,14 +935,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.41.0.tgz", + "integrity": "sha512-gTtSdWX9xiMPA/7MV9STjJOOYtWwIJIYxkQxnSV1U3xcE+mnJSH3f6zI0RYP+ew66WSlZ5ed+h0VCxsvdC1jJg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.33.1", - "@typescript-eslint/types": "8.33.1", - "@typescript-eslint/typescript-estree": "8.33.1", - "@typescript-eslint/visitor-keys": "8.33.1", + "@typescript-eslint/scope-manager": "8.41.0", + "@typescript-eslint/types": "8.41.0", + "@typescript-eslint/typescript-estree": "8.41.0", + "@typescript-eslint/visitor-keys": "8.41.0", "debug": "^4.3.4" }, "engines": { @@ -1426,16 +956,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.41.0.tgz", + "integrity": "sha512-b8V9SdGBQzQdjJ/IO3eDifGpDBJfvrNTp2QD9P2BeqWTGrRibgfgIlBSw6z3b6R7dPzg752tOs4u/7yCLxksSQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.33.1", - "@typescript-eslint/types": "^8.33.1", + "@typescript-eslint/tsconfig-utils": "^8.41.0", + "@typescript-eslint/types": "^8.41.0", "debug": "^4.3.4" }, "engines": { @@ -1446,16 +978,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.41.0.tgz", + "integrity": "sha512-n6m05bXn/Cd6DZDGyrpXrELCPVaTnLdPToyhBoFkLIMznRUQUEQdSp96s/pcWSQdqOhrgR1mzJ+yItK7T+WPMQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.33.1", - "@typescript-eslint/visitor-keys": "8.33.1" + "@typescript-eslint/types": "8.41.0", + "@typescript-eslint/visitor-keys": "8.41.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1466,7 +1000,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.41.0.tgz", + "integrity": "sha512-TDhxYFPUYRFxFhuU5hTIJk+auzM/wKvWgoNYOPcOf6i4ReYlOoYN8q1dV5kOTjNQNJgzWN3TUUQMtlLOcUgdUw==", "dev": true, "license": "MIT", "engines": { @@ -1477,16 +1013,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.41.0.tgz", + "integrity": "sha512-63qt1h91vg3KsjVVonFJWjgSK7pZHSQFKH6uwqxAH9bBrsyRhO6ONoKyXxyVBzG1lJnFAJcKAcxLS54N1ee1OQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.33.1", - "@typescript-eslint/utils": "8.33.1", + "@typescript-eslint/types": "8.41.0", + "@typescript-eslint/typescript-estree": "8.41.0", + "@typescript-eslint/utils": "8.41.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -1499,11 +1038,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.41.0.tgz", + "integrity": "sha512-9EwxsWdVqh42afLbHP90n2VdHaWU/oWgbH2P0CfcNfdKL7CuKpwMQGjwev56vWu9cSKU7FWSu6r9zck6CVfnag==", "dev": true, "license": "MIT", "engines": { @@ -1515,14 +1056,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.41.0.tgz", + "integrity": "sha512-D43UwUYJmGhuwHfY7MtNKRZMmfd8+p/eNSfFe6tH5mbVDto+VQCayeAt35rOx3Cs6wxD16DQtIKw/YXxt5E0UQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.33.1", - "@typescript-eslint/tsconfig-utils": "8.33.1", - "@typescript-eslint/types": "8.33.1", - "@typescript-eslint/visitor-keys": "8.33.1", + "@typescript-eslint/project-service": "8.41.0", + "@typescript-eslint/tsconfig-utils": "8.41.0", + "@typescript-eslint/types": "8.41.0", + "@typescript-eslint/visitor-keys": "8.41.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1538,11 +1081,13 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1551,6 +1096,8 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -1564,14 +1111,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.41.0.tgz", + "integrity": "sha512-udbCVstxZ5jiPIXrdH+BZWnPatjlYwJuJkDA4Tbo3WyYLh8NvB+h/bKeSZHDOFKfphsZYJQqaFtLeXEqurQn1A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.33.1", - "@typescript-eslint/types": "8.33.1", - "@typescript-eslint/typescript-estree": "8.33.1" + "@typescript-eslint/scope-manager": "8.41.0", + "@typescript-eslint/types": "8.41.0", + "@typescript-eslint/typescript-estree": "8.41.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1582,16 +1131,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.41.0.tgz", + "integrity": "sha512-+GeGMebMCy0elMNg67LRNoVnUFPIm37iu5CmHESVx56/9Jsfdpsvbv605DQ81Pi/x11IdKUsS5nzgTYbCQU9fg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.33.1", - "eslint-visitor-keys": "^4.2.0" + "@typescript-eslint/types": "8.41.0", + "eslint-visitor-keys": "^4.2.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1873,20 +1424,6 @@ "ajv": "^6.9.1" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "dev": true, @@ -1909,140 +1446,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/argparse": { "version": "2.0.1", "dev": true, "license": "Python-2.0" }, - "node_modules/async": { - "version": "3.2.6", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "license": "MIT" @@ -2106,25 +1514,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/bs-logger": { - "version": "0.2.6", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "dev": true, @@ -2181,14 +1570,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001707", "dev": true, @@ -2234,14 +1615,6 @@ "node": ">=8" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/chokidar": { "version": "4.0.3", "dev": true, @@ -2264,25 +1637,6 @@ "node": ">=6.0" } }, - "node_modules/ci-info": { - "version": "3.9.0", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "dev": true, - "license": "MIT" - }, "node_modules/cliui": { "version": "8.0.1", "dev": true, @@ -2309,20 +1663,6 @@ "node": ">=6" } }, - "node_modules/co": { - "version": "4.6.0", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, "node_modules/color-convert": { "version": "2.0.1", "dev": true, @@ -2373,31 +1713,6 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/create-jest": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "dev": true, @@ -2481,32 +1796,11 @@ } } }, - "node_modules/dedent": { - "version": "1.5.3", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, "node_modules/deep-is": { "version": "0.1.4", "dev": true, "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/detect-libc": { "version": "1.0.3", "dev": true, @@ -2519,22 +1813,6 @@ "node": ">=0.10" } }, - "node_modules/detect-newline": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "dev": true, @@ -2548,36 +1826,11 @@ "node": ">= 0.4" } }, - "node_modules/ejs": { - "version": "3.1.10", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/electron-to-chromium": { "version": "1.5.127", "dev": true, "license": "ISC" }, - "node_modules/emittery": { - "version": "0.13.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, "node_modules/emoji-regex": { "version": "8.0.0", "dev": true, @@ -2614,14 +1867,6 @@ "node": ">=4" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, "node_modules/es-define-property": { "version": "1.0.1", "dev": true, @@ -2654,6 +1899,48 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, "node_modules/escalade": { "version": "3.2.0", "dev": true, @@ -2762,7 +2049,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "4.2.0", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2788,18 +2077,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/esquery": { "version": "1.6.0", "dev": true, @@ -2850,50 +2127,6 @@ "node": ">=0.8.x" } }, - "node_modules/execa": { - "version": "5.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "dev": true, @@ -2901,6 +2134,8 @@ }, "node_modules/fast-glob": { "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", "dependencies": { @@ -2916,6 +2151,8 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", "dependencies": { @@ -2960,20 +2197,14 @@ }, "node_modules/fastq": { "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "dev": true, @@ -3004,33 +2235,6 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/filelist": { - "version": "1.0.4", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fill-range": { "version": "7.1.1", "dev": true, @@ -3095,10 +2299,20 @@ "node": ">=14.14" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "license": "ISC" + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, "node_modules/function-bind": { "version": "1.1.2", @@ -3108,14 +2322,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "dev": true, @@ -3147,14 +2353,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/get-proto": { "version": "1.0.1", "dev": true, @@ -3167,34 +2365,17 @@ "node": ">= 0.4" } }, - "node_modules/get-stream": { - "version": "6.0.1", + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" + "resolve-pkg-maps": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, "node_modules/glob-parent": { @@ -3275,19 +2456,6 @@ "node": ">= 0.4" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/human-signals": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, "node_modules/icss-utils": { "version": "5.1.0", "dev": true, @@ -3353,20 +2521,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "license": "ISC" - }, "node_modules/interpret": { "version": "3.1.1", "dev": true, @@ -3375,11 +2529,6 @@ "node": ">=10.13.0" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "dev": true, - "license": "MIT" - }, "node_modules/is-core-module": { "version": "2.16.1", "dev": true, @@ -3410,14 +2559,6 @@ "node": ">=8" } }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/is-glob": { "version": "4.0.3", "dev": true, @@ -3448,17 +2589,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isexe": { "version": "2.0.0", "dev": true, @@ -3472,613 +2602,6 @@ "node": ">=0.10.0" } }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake": { - "version": "10.9.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/js-yaml": { "version": "4.1.0", "dev": true, @@ -4090,17 +2613,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/json-buffer": { "version": "3.0.1", "dev": true, @@ -4159,22 +2671,6 @@ "node": ">=0.10.0" } }, - "node_modules/kleur": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/levn": { "version": "0.4.1", "dev": true, @@ -4187,11 +2683,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "dev": true, - "license": "MIT" - }, "node_modules/loader-runner": { "version": "4.3.0", "dev": true, @@ -4232,51 +2723,11 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "dev": true, "license": "MIT" }, - "node_modules/lru-cache": { - "version": "5.1.1", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "dev": true, @@ -4292,6 +2743,8 @@ }, "node_modules/merge2": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "license": "MIT", "engines": { @@ -4329,14 +2782,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/mini-css-extract-plugin": { "version": "2.9.2", "dev": true, @@ -4472,24 +2917,11 @@ "node-gyp-build-test": "build-test.js" } }, - "node_modules/node-int64": { - "version": "0.4.0", - "dev": true, - "license": "MIT" - }, "node_modules/node-releases": { "version": "2.0.19", "dev": true, "license": "MIT" }, - "node_modules/normalize-path": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/npm-check-updates": { "version": "18.0.1", "dev": true, @@ -4503,17 +2935,6 @@ "npm": ">=8.12.1" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/object-inspect": { "version": "1.13.4", "dev": true, @@ -4538,28 +2959,6 @@ "@codemirror/view": "^6.0.0" } }, - "node_modules/once": { - "version": "1.4.0", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "dev": true, @@ -4647,23 +3046,6 @@ "node": ">=6" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/path-exists": { "version": "4.0.0", "dev": true, @@ -4672,14 +3054,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "dev": true, @@ -4709,14 +3083,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pirates": { - "version": "4.0.7", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/pkg-dir": { "version": "4.2.0", "dev": true, @@ -4884,7 +3250,9 @@ } }, "node_modules/prettier": { - "version": "3.5.3", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", "bin": { @@ -4897,42 +3265,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/punycode": { "version": "2.3.1", "dev": true, @@ -4941,21 +3273,6 @@ "node": ">=6" } }, - "node_modules/pure-rand": { - "version": "6.1.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, "node_modules/qs": { "version": "6.14.0", "dev": true, @@ -4972,6 +3289,8 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -4997,11 +3316,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/react-is": { - "version": "18.3.1", - "dev": true, - "license": "MIT" - }, "node_modules/readdirp": { "version": "4.1.2", "dev": true, @@ -5103,6 +3417,16 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/resolve-url-loader": { "version": "5.0.0", "dev": true, @@ -5123,16 +3447,10 @@ "dev": true, "license": "MIT" }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/reusify": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { @@ -5142,6 +3460,8 @@ }, "node_modules/run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -5190,7 +3510,9 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.89.1", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.91.0.tgz", + "integrity": "sha512-aFOZHGf+ur+bp1bCHZ+u8otKGh77ZtmFyXDo4tlYvT7PWql41Kwd8wdkPqhhT+h2879IVblcHFglIMofsFd1EA==", "dev": true, "license": "MIT", "dependencies": { @@ -5392,24 +3714,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "license": "ISC" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/source-map": { "version": "0.6.1", "dev": true, @@ -5426,51 +3730,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.13", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/string-width": { "version": "4.2.3", "dev": true, @@ -5495,22 +3754,6 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -5690,24 +3933,6 @@ "resolved": "test-client", "link": true }, - "node_modules/test-exclude": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/to-regex-range": { "version": "5.0.1", "dev": true, @@ -5729,6 +3954,8 @@ }, "node_modules/ts-api-utils": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, "license": "MIT", "engines": { @@ -5738,65 +3965,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-jest": { - "version": "29.3.4", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "^2.1.0", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.2", - "type-fest": "^4.41.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.41.0", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ts-loader": { "version": "9.5.2", "dev": true, @@ -5829,6 +3997,26 @@ "dev": true, "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.20.5", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.5.tgz", + "integrity": "sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/type-check": { "version": "0.4.0", "dev": true, @@ -5840,25 +4028,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { "version": "5.8.3", "dev": true, @@ -5872,13 +4041,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.33.1", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.41.0.tgz", + "integrity": "sha512-n66rzs5OBXW3SFSnZHr2T685q1i4ODm2nulFJhMZBotaTavsS8TrI3d7bDlRSs9yWo7HmyWrN9qDu14Qv7Y0Dw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.33.1", - "@typescript-eslint/parser": "8.33.1", - "@typescript-eslint/utils": "8.33.1" + "@typescript-eslint/eslint-plugin": "8.41.0", + "@typescript-eslint/parser": "8.41.0", + "@typescript-eslint/typescript-estree": "8.41.0", + "@typescript-eslint/utils": "8.41.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5889,11 +4061,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/undici-types": { - "version": "6.21.0", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", "dev": true, "license": "MIT" }, @@ -5989,19 +4163,6 @@ "uuid": "dist/esm/bin/uuid" } }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, "node_modules/vault-link-obsidian-plugin": { "resolved": "obsidian-plugin", "link": true @@ -6020,14 +4181,6 @@ "license": "MIT", "peer": true }, - "node_modules/walker": { - "version": "1.0.8", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, "node_modules/watchpack": { "version": "2.4.2", "dev": true, @@ -6273,25 +4426,10 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/ws": { - "version": "8.18.2", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "dev": true, "license": "MIT", "engines": { @@ -6318,11 +4456,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "3.1.1", - "dev": true, - "license": "ISC" - }, "node_modules/yargs": { "version": "17.7.2", "dev": true, @@ -6361,27 +4494,25 @@ }, "obsidian-plugin": { "name": "vault-link-obsidian-plugin", - "version": "0.6.1", + "version": "0.6.3", "license": "MIT", "devDependencies": { - "@types/jest": "^29.5.14", "@types/node": "^22.15.30", "css-loader": "^7.1.2", "date-fns": "^4.1.0", "file-loader": "^6.2.0", "fs-extra": "^11.3.0", - "jest": "^29.7.0", "mini-css-extract-plugin": "^2.9.2", "obsidian": "1.8.7", "reconcile-text": "^0.5.0", "resolve-url-loader": "^5.0.0", - "sass": "^1.89.1", + "sass": "^1.91.0", "sass-loader": "^16.0.5", "sync-client": "file:../sync-client", "terser-webpack-plugin": "^5.3.14", - "ts-jest": "^29.3.4", "ts-loader": "^9.5.2", "tslib": "2.8.1", + "tsx": "^4.20.5", "typescript": "5.8.3", "url": "^0.11.4", "virtual-scroller": "^1.13.1", @@ -6389,8 +4520,25 @@ "webpack-cli": "^6.0.1" } }, + "obsidian-plugin/node_modules/@types/node": { + "version": "22.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.0.tgz", + "integrity": "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "obsidian-plugin/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, "sync-client": { - "version": "0.6.1", + "version": "0.6.3", "dependencies": { "byte-base64": "^1.1.0", "minimatch": "^10.0.1", @@ -6399,17 +4547,25 @@ "uuid": "^11.1.0" }, "devDependencies": { - "@types/jest": "^29.5.14", "@types/node": "^22.15.30", - "jest": "^29.7.0", - "ts-jest": "^29.3.4", "ts-loader": "^9.5.2", "tslib": "2.8.1", + "tsx": "^4.20.5", "typescript": "5.8.3", "webpack": "^5.99.9", "webpack-cli": "^6.0.1", "webpack-merge": "^6.0.1", - "ws": "^8.18.2" + "ws": "^8.18.3" + } + }, + "sync-client/node_modules/@types/node": { + "version": "22.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.0.tgz", + "integrity": "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" } }, "sync-client/node_modules/brace-expansion": { @@ -6432,8 +4588,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "sync-client/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, "test-client": { - "version": "0.6.1", + "version": "0.6.3", "bin": { "test-client": "dist/cli.js" }, @@ -6443,11 +4606,29 @@ "sync-client": "file:../sync-client", "ts-loader": "^9.5.2", "tslib": "2.8.1", + "tsx": "^4.20.5", "typescript": "5.8.3", "uuid": "^11.1.0", "webpack": "^5.99.9", "webpack-cli": "^6.0.1" } + }, + "test-client/node_modules/@types/node": { + "version": "22.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.0.tgz", + "integrity": "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "test-client/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" } } } diff --git a/frontend/package.json b/frontend/package.json index 6c51ddcf..718efea1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,7 +24,7 @@ "eslint": "9.28.0", "eslint-plugin-unused-imports": "^4.1.4", "npm-check-updates": "^18.0.1", - "prettier": "^3.5.3", - "typescript-eslint": "8.33.1" + "prettier": "^3.6.2", + "typescript-eslint": "8.41.0" } } \ No newline at end of file diff --git a/frontend/sync-client/jest.config.js b/frontend/sync-client/jest.config.js deleted file mode 100644 index d1cbaca2..00000000 --- a/frontend/sync-client/jest.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - preset: "ts-jest" -}; diff --git a/frontend/sync-client/package.json b/frontend/sync-client/package.json index b44ac8cc..0046f5c2 100644 --- a/frontend/sync-client/package.json +++ b/frontend/sync-client/package.json @@ -1,6 +1,6 @@ { "name": "sync-client", - "version": "0.6.1", + "version": "0.6.3", "main": "dist/sync-client.node.js", "browser": "dist/sync-client.web.js", "types": "dist/types/index.d.ts", @@ -10,26 +10,24 @@ "scripts": { "dev": "webpack watch --mode development", "build": "webpack --mode production", - "test": "jest" + "test": "tsx --test src/**/*.test.ts" }, "dependencies": { "byte-base64": "^1.1.0", "minimatch": "^10.0.1", "p-queue": "^8.1.0", - "uuid": "^11.1.0", - "reconcile-text": "^0.5.0" + "reconcile-text": "^0.5.0", + "uuid": "^11.1.0" }, "devDependencies": { - "@types/jest": "^29.5.14", "@types/node": "^22.15.30", - "jest": "^29.7.0", - "ts-jest": "^29.3.4", "ts-loader": "^9.5.2", "tslib": "2.8.1", + "tsx": "^4.20.5", "typescript": "5.8.3", "webpack": "^5.99.9", "webpack-cli": "^6.0.1", "webpack-merge": "^6.0.1", - "ws": "^8.18.2" + "ws": "^8.18.3" } } diff --git a/frontend/obsidian-plugin/src/utils/log-to-console.ts b/frontend/sync-client/src/debugging/log-to-console.ts similarity index 77% rename from frontend/obsidian-plugin/src/utils/log-to-console.ts rename to frontend/sync-client/src/debugging/log-to-console.ts index 2579f6a5..ace58db0 100644 --- a/frontend/obsidian-plugin/src/utils/log-to-console.ts +++ b/frontend/sync-client/src/debugging/log-to-console.ts @@ -1,5 +1,6 @@ -import type { LogLine, SyncClient } from "sync-client"; -import { LogLevel } from "sync-client"; +import type { SyncClient } from "../sync-client"; +import type { LogLine } from "../tracing/logger"; +import { LogLevel } from "../tracing/logger"; export function logToConsole(client: SyncClient): void { client.logger.addOnMessageListener((logLine: LogLine) => { diff --git a/frontend/obsidian-plugin/src/debugging/slow-fetch-factory.ts b/frontend/sync-client/src/debugging/slow-fetch-factory.ts similarity index 89% rename from frontend/obsidian-plugin/src/debugging/slow-fetch-factory.ts rename to frontend/sync-client/src/debugging/slow-fetch-factory.ts index 5fe6c3ef..cd07dd1a 100644 --- a/frontend/obsidian-plugin/src/debugging/slow-fetch-factory.ts +++ b/frontend/sync-client/src/debugging/slow-fetch-factory.ts @@ -1,3 +1,5 @@ +import { sleep } from "../utils/sleep"; + export const slowFetchFactory = (jitterScaleInSeconds: number) => async ( diff --git a/frontend/obsidian-plugin/src/debugging/flaky-websocket-factory.ts b/frontend/sync-client/src/debugging/slow-web-socket-factory.ts similarity index 90% rename from frontend/obsidian-plugin/src/debugging/flaky-websocket-factory.ts rename to frontend/sync-client/src/debugging/slow-web-socket-factory.ts index f59cce19..51a27a5f 100644 --- a/frontend/obsidian-plugin/src/debugging/flaky-websocket-factory.ts +++ b/frontend/sync-client/src/debugging/slow-web-socket-factory.ts @@ -1,7 +1,8 @@ -import type { Logger } from "sync-client"; -import { helpers } from "sync-client"; +import { sleep } from "../utils/sleep"; +import { Locks } from "../utils/locks"; +import type { Logger } from "../tracing/logger"; -export function flakyWebSocketFactory( +export function slowWebSocketFactory( jitterScaleInSeconds: number, logger: Logger ): typeof WebSocket { @@ -10,7 +11,7 @@ export function flakyWebSocketFactory( private static readonly RECEIVE_KEY = "websocket-receive"; private static readonly SEND_KEY = "websocket-send"; - private readonly locks = new helpers.Locks(logger); + private readonly locks = new Locks(logger); public set onopen(callback: (event: Event) => void) { super.onopen = async (event: Event): Promise => { diff --git a/frontend/sync-client/src/file-operations/file-operations.test.ts b/frontend/sync-client/src/file-operations/file-operations.test.ts index 82a96f9d..64c02655 100644 --- a/frontend/sync-client/src/file-operations/file-operations.test.ts +++ b/frontend/sync-client/src/file-operations/file-operations.test.ts @@ -1,3 +1,4 @@ +import { describe, it } from "node:test"; import type { Database, DocumentRecord, diff --git a/frontend/sync-client/src/index.ts b/frontend/sync-client/src/index.ts index 00b19940..a73f63dd 100644 --- a/frontend/sync-client/src/index.ts +++ b/frontend/sync-client/src/index.ts @@ -1,3 +1,10 @@ +import { logToConsole } from "./debugging/log-to-console"; +import { slowFetchFactory } from "./debugging/slow-fetch-factory"; +import { slowWebSocketFactory } from "./debugging/slow-web-socket-factory"; +import { getRandomColor } from "./utils/get-random-color"; +import { lineAndColumnToPosition } from "./utils/line-and-column-to-position"; +import { positionToLineAndColumn } from "./utils/position-to-line-and-column"; + export { SyncType, SyncStatus, @@ -22,7 +29,14 @@ export type { MaybeOutdatedClientCursors } from "./types/maybe-outdated-client-c export { DocumentSyncStatus } from "./types/document-sync-status"; export { SyncClient } from "./sync-client"; -import { Locks } from "./utils/locks"; -export const helpers = { - Locks +export const debugging = { + slowFetchFactory, + slowWebSocketFactory, + logToConsole +}; + +export const utils = { + getRandomColor, + positionToLineAndColumn, + lineAndColumnToPosition }; diff --git a/frontend/sync-client/src/services/sync-service.ts b/frontend/sync-client/src/services/sync-service.ts index 5ac81d5b..8ce9c56a 100644 --- a/frontend/sync-client/src/services/sync-service.ts +++ b/frontend/sync-client/src/services/sync-service.ts @@ -70,7 +70,10 @@ export class SyncService { formData.append("document_id", documentId); } formData.append("relative_path", relativePath); - formData.append("content", new Blob([contentBytes])); + formData.append( + "content", + new Blob([new Uint8Array(contentBytes)]) + ); const response = await this.client(this.getUrl("/documents"), { method: "POST", @@ -117,7 +120,10 @@ export class SyncService { const formData = new FormData(); formData.append("parent_version_id", parentVersionId.toString()); formData.append("relative_path", relativePath); - formData.append("content", new Blob([contentBytes])); + formData.append( + "content", + new Blob([new Uint8Array(contentBytes)]) + ); const response = await this.client( this.getUrl(`/documents/${documentId}`), diff --git a/frontend/sync-client/src/services/websocket-manager.ts b/frontend/sync-client/src/services/websocket-manager.ts index dde8f068..a30774f4 100644 --- a/frontend/sync-client/src/services/websocket-manager.ts +++ b/frontend/sync-client/src/services/websocket-manager.ts @@ -13,10 +13,11 @@ export class WebSocketManager { cursors: ClientCursors[] ) => unknown)[] = []; - private refreshWebSocketInterval: NodeJS.Timeout | undefined; - private webSocket: WebSocket | undefined; + private isStopped = true; + private _isFirstSyncCompleted = false; + private readonly webSocketFactoryImplementation: typeof globalThis.WebSocket; public constructor( @@ -41,20 +42,15 @@ export class WebSocketManager { } } - this.updateWebSocket(settings.getSettings()); - settings.addOnSettingsChangeListener((newSettings, oldSettings) => { if ( newSettings.remoteUri !== oldSettings.remoteUri || newSettings.vaultName !== oldSettings.vaultName || - newSettings.token !== oldSettings.token || - newSettings.isSyncEnabled !== oldSettings.isSyncEnabled + newSettings.token !== oldSettings.token ) { - this.updateWebSocket(newSettings); + this.initializeWebSocket(newSettings); } }); - - this.setWebSocketRefreshInterval(); } public get isWebSocketConnected(): boolean { @@ -64,6 +60,10 @@ export class WebSocketManager { ); } + public get isFirstSyncCompleted(): boolean { + return this._isFirstSyncCompleted; + } + public addWebSocketStatusChangeListener(listener: () => unknown): void { this.webSocketStatusChangeListeners.push(listener); } @@ -74,19 +74,15 @@ export class WebSocketManager { this.remoteCursorsUpdateListeners.push(listener); } - public async reset(): Promise { - this.setWebSocketRefreshInterval(); - this.updateWebSocket(this.settings.getSettings()); + public start(): void { + this.isStopped = false; + this._isFirstSyncCompleted = false; + this.initializeWebSocket(this.settings.getSettings()); } public stop(): void { - clearInterval(this.refreshWebSocketInterval); - - try { - this.webSocket?.close(); - } catch (e) { - this.logger.warn(`Failed to close WebSocket: ${e}`); - } + this.isStopped = true; + this.webSocket?.close(1000, "WebSocketManager has been stopped"); } public updateLocalCursors(cursorPositions: CursorPositionFromClient): void { @@ -101,23 +97,22 @@ export class WebSocketManager { ...cursorPositions }; this.webSocket?.send(JSON.stringify(message)); - this.logger.info( + this.logger.debug( `Sent cursor positions: ${JSON.stringify(cursorPositions)}` ); } - private updateWebSocket(settings: SyncSettings): void { + private initializeWebSocket(settings: SyncSettings): void { + if (this.isStopped) { + return; + } + try { this.webSocket?.close(); } catch (e) { this.logger.warn(`Failed to close WebSocket: ${e}`); } - if (!settings.isSyncEnabled) { - this.webSocket = undefined; - return; - } - const wsUri = new URL(settings.remoteUri); wsUri.protocol = wsUri.protocol === "https" ? "wss" : "ws"; wsUri.pathname = `/vaults/${settings.vaultName}/ws`; @@ -126,55 +121,10 @@ export class WebSocketManager { this.webSocket = new this.webSocketFactoryImplementation(wsUri); - this.webSocket.onmessage = async (event): Promise => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion - const message = JSON.parse(event.data) as WebSocketServerMessage; - - if (message.type === "vaultUpdate") { - try { - await Promise.all( - message.documents.map(async (document) => - this.syncer.syncRemotelyUpdatedFile(document) - ) - ); - - if (message.isInitialSync && message.documents.length > 0) { - this.database.setLastSeenUpdateId( - message.documents - .map((document) => document.vaultUpdateId) - .reduce((a, b) => Math.max(a, b)) - ); - } - } catch (e) { - this.logger.error( - `Failed to sync remotely updated file: ${e}` - ); - } - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - } else if (message.type === "cursorPositions") { - this.logger.debug( - `Received cursor positions for ${JSON.stringify(message.clients)}` - ); - this.remoteCursorsUpdateListeners.forEach((listener) => { - listener( - message.clients.filter( - (client) => client.deviceId !== this.deviceId - ) - ); - }); - } else { - this.logger.warn( - `Received unknown message type: ${JSON.stringify(message)}` - ); - } - }; - // The JS WebSocket API doesn't support setting headers, so we have to send the token as a message this.webSocket.onopen = (): void => { this.logger.info("WebSocket connection opened"); - this.webSocketStatusChangeListeners.forEach((listener) => { - listener(); - }); + this.webSocketStatusChangeListeners.forEach((l) => l()); const message: WebSocketClientMessage = { type: "handshake", @@ -185,25 +135,65 @@ export class WebSocketManager { this.webSocket?.send(JSON.stringify(message)); }; + this.webSocket.onmessage = async (event): Promise => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion + const message = JSON.parse(event.data) as WebSocketServerMessage; + return this.handleWebSocketMessage(message); + }; + this.webSocket.onclose = (event): void => { this.logger.warn( `WebSocket closed with code ${event.code} (${event.reason == "" ? "unknown reason" : event.reason})` ); - this.webSocketStatusChangeListeners.forEach((listener) => { - listener(); - }); + this.webSocketStatusChangeListeners.forEach((l) => l()); + + if (!this.isStopped) { + setTimeout(() => { + this.initializeWebSocket(this.settings.getSettings()); + }, this.settings.getSettings().webSocketRetryIntervalMs); + } }; } - private setWebSocketRefreshInterval(): void { - this.refreshWebSocketInterval = setInterval(() => { - if ( - this.webSocket?.readyState === - this.webSocketFactoryImplementation.CLOSED - ) { - this.logger.info("WebSocket is closed, reconnecting..."); - this.updateWebSocket(this.settings.getSettings()); + private async handleWebSocketMessage( + message: WebSocketServerMessage + ): Promise { + if (message.type === "vaultUpdate") { + try { + await Promise.all( + message.documents.map(async (document) => + this.syncer.syncRemotelyUpdatedFile(document) + ) + ); + + if (message.isInitialSync && message.documents.length > 0) { + this.database.setLastSeenUpdateId( + message.documents + .map((document) => document.vaultUpdateId) + .reduce((a, b) => Math.max(a, b)) + ); + } + + this._isFirstSyncCompleted = true; + } catch (e) { + this.logger.error(`Failed to sync remotely updated file: ${e}`); } - }, this.settings.getSettings().webSocketRetryIntervalMs); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + } else if (message.type === "cursorPositions") { + this.logger.debug( + `Received cursor positions for ${JSON.stringify(message.clients)}` + ); + this.remoteCursorsUpdateListeners.forEach((listener) => { + listener( + message.clients.filter( + (client) => client.deviceId !== this.deviceId + ) + ); + }); + } else { + this.logger.warn( + `Received unknown message type: ${JSON.stringify(message)}` + ); + } } } diff --git a/frontend/sync-client/src/sync-client.ts b/frontend/sync-client/src/sync-client.ts index ddab8860..78beb910 100644 --- a/frontend/sync-client/src/sync-client.ts +++ b/frontend/sync-client/src/sync-client.ts @@ -24,6 +24,8 @@ import { FileChangeNotifier } from "./sync-operations/file-change-notifier"; export class SyncClient { private static readonly MINIMUM_SAVE_INTERVAL_MS = 1000; + private hasStartedOfflineSync = false; + private hasFinishedOfflineSync = false; // eslint-disable-next-line @typescript-eslint/max-params private constructor( @@ -43,6 +45,14 @@ export class SyncClient { if (newSettings.vaultName !== oldSettings.vaultName) { await this.reset(); } + + if (newSettings.isSyncEnabled !== oldSettings.isSyncEnabled) { + if (newSettings.isSyncEnabled) { + await this.start(); + } else { + this.stop(); + } + } } ); } @@ -197,10 +207,17 @@ export class SyncClient { } public async start(): Promise { - await this.syncer.scheduleSyncForOfflineChanges(); + if (!this.hasStartedOfflineSync) { + await this.syncer.scheduleSyncForOfflineChanges(); + this.hasStartedOfflineSync = true; + } + + this.hasFinishedOfflineSync = true; + this.webSocketManager.start(); } public stop(): void { + this.hasFinishedOfflineSync = false; this.webSocketManager.stop(); } @@ -216,7 +233,6 @@ export class SyncClient { this.stop(); this.connectionStatus.startReset(); await this.syncer.reset(); - await this.webSocketManager.reset(); this.history.reset(); this.database.reset(); this._logger.reset(); @@ -286,6 +302,17 @@ export class SyncClient { public getDocumentSyncingStatus( relativePath: RelativePath ): DocumentSyncStatus { + if (!this.settings.getSettings().isSyncEnabled) { + return DocumentSyncStatus.SYNCING_IS_DISABLED; + } + + if ( + !this.webSocketManager.isFirstSyncCompleted || + !this.hasFinishedOfflineSync + ) { + return DocumentSyncStatus.SYNCING; + } + const document = this.database.getLatestDocumentByRelativePath(relativePath); if (document === undefined) { diff --git a/frontend/sync-client/src/types/document-sync-status.ts b/frontend/sync-client/src/types/document-sync-status.ts index a2ec01c2..07a0e801 100644 --- a/frontend/sync-client/src/types/document-sync-status.ts +++ b/frontend/sync-client/src/types/document-sync-status.ts @@ -1,4 +1,5 @@ export enum DocumentSyncStatus { UP_TO_DATE = "UP_TO_DATE", - SYNCING = "SYNCING" + SYNCING = "SYNCING", + SYNCING_IS_DISABLED = "SYNCING_IS_DISABLED" } diff --git a/frontend/sync-client/src/utils/assert-set-contains-exactly.ts b/frontend/sync-client/src/utils/assert-set-contains-exactly.ts index 0532a3d3..502dca03 100644 --- a/frontend/sync-client/src/utils/assert-set-contains-exactly.ts +++ b/frontend/sync-client/src/utils/assert-set-contains-exactly.ts @@ -1,7 +1,7 @@ -import * as assert from "assert"; +import assert from "node:assert"; export function assertSetContainsExactly(set: Set, ...values: T[]): void { - assert( + assert.ok( set.size === values.length && Array.from(set).every((value) => values.includes(value)), `Expected set to contain only ${values.map((v) => '"' + v + '"').join(", ")}, but it contained ${Array.from( diff --git a/frontend/sync-client/src/utils/create-promise.ts b/frontend/sync-client/src/utils/create-promise.ts index 3099f0da..542a4013 100644 --- a/frontend/sync-client/src/utils/create-promise.ts +++ b/frontend/sync-client/src/utils/create-promise.ts @@ -16,10 +16,8 @@ export function createPromise(): [ const creationPromise = new Promise( (resolve_, reject_) => - ( - // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion - (resolve = resolve_ as ResolveFunction), (reject = reject_) - ) + // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion + ((resolve = resolve_ as ResolveFunction), (reject = reject_)) ); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion diff --git a/frontend/obsidian-plugin/src/utils/get-random-color.ts b/frontend/sync-client/src/utils/get-random-color.ts similarity index 77% rename from frontend/obsidian-plugin/src/utils/get-random-color.ts rename to frontend/sync-client/src/utils/get-random-color.ts index 5b2d33dc..543b943e 100644 --- a/frontend/obsidian-plugin/src/utils/get-random-color.ts +++ b/frontend/sync-client/src/utils/get-random-color.ts @@ -5,5 +5,5 @@ export function getRandomColor(name: string): string { hash |= 0; // Convert to 32bit integer } const normalised = hash / 0x7fffffff; - return `hsl(${Math.abs(normalised * 360)}, 55%, 55%)`; // HSL color + return `oklch(0.58 0.15 ${Math.round(Math.abs(normalised * 360))})`; } diff --git a/frontend/sync-client/src/utils/globs-to-regexes.test.ts b/frontend/sync-client/src/utils/globs-to-regexes.test.ts index 71639a38..3e986ca4 100644 --- a/frontend/sync-client/src/utils/globs-to-regexes.test.ts +++ b/frontend/sync-client/src/utils/globs-to-regexes.test.ts @@ -1,3 +1,5 @@ +import { describe, it } from "node:test"; +import assert from "node:assert"; import { Logger } from "../tracing/logger"; import { globsToRegexes } from "./globs-to-regexes"; @@ -5,7 +7,7 @@ describe("globsToRegexes", () => { it("basicExample", async () => { const [regex] = globsToRegexes([".git/**"], new Logger()); - expect(regex.test(".git/objects/object")).toBeTruthy(); - expect(regex.test(".git/objects/.object")).toBeTruthy(); + assert.ok(regex.test(".git/objects/object")); + assert.ok(regex.test(".git/objects/.object")); }); }); diff --git a/frontend/sync-client/src/utils/is-equal-bytes.test.ts b/frontend/sync-client/src/utils/is-equal-bytes.test.ts index e2394bfd..a887309f 100644 --- a/frontend/sync-client/src/utils/is-equal-bytes.test.ts +++ b/frontend/sync-client/src/utils/is-equal-bytes.test.ts @@ -1,27 +1,29 @@ +import { describe, it } from "node:test"; +import assert from "node:assert"; import { isEqualBytes } from "./is-equal-bytes"; describe("isEqualBytes", () => { it("should return true for equal byte arrays", () => { const bytes1 = new Uint8Array([1, 2, 3, 4]); const bytes2 = new Uint8Array([1, 2, 3, 4]); - expect(isEqualBytes(bytes1, bytes2)).toBe(true); + assert.strictEqual(isEqualBytes(bytes1, bytes2), true); }); it("should return false for byte arrays of different lengths", () => { const bytes1 = new Uint8Array([1, 2, 3, 4]); const bytes2 = new Uint8Array([1, 2, 3]); - expect(isEqualBytes(bytes1, bytes2)).toBe(false); + assert.strictEqual(isEqualBytes(bytes1, bytes2), false); }); it("should return true for empty byte arrays", () => { const bytes1 = new Uint8Array([]); const bytes2 = new Uint8Array([]); - expect(isEqualBytes(bytes1, bytes2)).toBe(true); + assert.strictEqual(isEqualBytes(bytes1, bytes2), true); }); it("should return false for byte arrays with same length but different content", () => { const bytes1 = new Uint8Array([1, 2, 3, 4]); const bytes2 = new Uint8Array([4, 3, 2, 1]); - expect(isEqualBytes(bytes1, bytes2)).toBe(false); + assert.strictEqual(isEqualBytes(bytes1, bytes2), false); }); }); diff --git a/frontend/sync-client/src/utils/is-file-type-mergable.test.ts b/frontend/sync-client/src/utils/is-file-type-mergable.test.ts index 1b3c6557..3f3fffbb 100644 --- a/frontend/sync-client/src/utils/is-file-type-mergable.test.ts +++ b/frontend/sync-client/src/utils/is-file-type-mergable.test.ts @@ -1,28 +1,42 @@ +import { describe, it } from "node:test"; +import assert from "node:assert"; import { isFileTypeMergable } from "./is-file-type-mergable"; describe("isFileTypeMergable", () => { it("should return true for .md files", () => { - expect(isFileTypeMergable(".md")).toBe(true); - expect(isFileTypeMergable("hi.md")).toBe(true); - expect(isFileTypeMergable("my/path/to/my/document.md")).toBe(true); + assert.strictEqual(isFileTypeMergable(".md"), true); + assert.strictEqual(isFileTypeMergable("hi.md"), true); + assert.strictEqual( + isFileTypeMergable("my/path/to/my/document.md"), + true + ); }); it("should return true for .txt files", () => { - expect(isFileTypeMergable(".txt")).toBe(true); - expect(isFileTypeMergable("hi.txt")).toBe(true); - expect(isFileTypeMergable("my/path/to/my/document.txt")).toBe(true); + assert.strictEqual(isFileTypeMergable(".txt"), true); + assert.strictEqual(isFileTypeMergable("hi.txt"), true); + assert.strictEqual( + isFileTypeMergable("my/path/to/my/document.txt"), + true + ); }); it("should be case insensitive", () => { - expect(isFileTypeMergable("hi.MD")).toBe(true); - expect(isFileTypeMergable("my/path/to/my/DOCUMENT.MD")).toBe(true); - expect(isFileTypeMergable("hi.TXT")).toBe(true); - expect(isFileTypeMergable("my/path/to/my/DOCUMENT.TXT")).toBe(true); + assert.strictEqual(isFileTypeMergable("hi.MD"), true); + assert.strictEqual( + isFileTypeMergable("my/path/to/my/DOCUMENT.MD"), + true + ); + assert.strictEqual(isFileTypeMergable("hi.TXT"), true); + assert.strictEqual( + isFileTypeMergable("my/path/to/my/DOCUMENT.TXT"), + true + ); }); it("should return false for non-mergable file types", () => { - expect(isFileTypeMergable(".json")).toBe(false); - expect(isFileTypeMergable("HELLO.JSON")).toBe(false); - expect(isFileTypeMergable("my/config.yml")).toBe(false); + assert.strictEqual(isFileTypeMergable(".json"), false); + assert.strictEqual(isFileTypeMergable("HELLO.JSON"), false); + assert.strictEqual(isFileTypeMergable("my/config.yml"), false); }); }); diff --git a/frontend/obsidian-plugin/src/utils/line-and-column-to-position.test.ts b/frontend/sync-client/src/utils/line-and-column-to-position.test.ts similarity index 68% rename from frontend/obsidian-plugin/src/utils/line-and-column-to-position.test.ts rename to frontend/sync-client/src/utils/line-and-column-to-position.test.ts index 9c02fbb5..82d752c9 100644 --- a/frontend/obsidian-plugin/src/utils/line-and-column-to-position.test.ts +++ b/frontend/sync-client/src/utils/line-and-column-to-position.test.ts @@ -1,42 +1,44 @@ +import { describe, it } from "node:test"; +import assert from "node:assert"; import { lineAndColumnToPosition } from "./line-and-column-to-position"; describe("lineAndColumnToPosition", () => { it("should return the correct position for the first line", () => { const text = "Hello\nWorld"; const position = lineAndColumnToPosition(text, 0, 3); - expect(position).toBe(3); + assert.strictEqual(position, 3); }); it("should return the correct position for the second line", () => { const text = "Hello\nWorld"; const position = lineAndColumnToPosition(text, 1, 2); - expect(position).toBe(8); + assert.strictEqual(position, 8); }); it("should return the correct position for an empty string", () => { const text = ""; const position = lineAndColumnToPosition(text, 0, 0); - expect(position).toBe(0); + assert.strictEqual(position, 0); }); it("with carrige return", () => { - expect(lineAndColumnToPosition("a\nb", 1, 1)).toBe(3); - expect(lineAndColumnToPosition("a\r\nb", 1, 1)).toBe(3); + assert.strictEqual(lineAndColumnToPosition("a\nb", 1, 1), 3); + assert.strictEqual(lineAndColumnToPosition("a\r\nb", 1, 1), 3); }); it("should handle multi-line strings with varying lengths", () => { const text = "Line1\nLongerLine2\nShort3"; const position = lineAndColumnToPosition(text, 2, 4); - expect(position).toBe(22); + assert.strictEqual(position, 22); }); it("should throw an error if the line number is out of range", () => { const text = "Line1\nLine2"; - expect(() => lineAndColumnToPosition(text, 3, 0)).toThrow(); + assert.throws(() => lineAndColumnToPosition(text, 3, 0)); }); it("should throw an error if the column number is out of range", () => { const text = "Line1\nLine2"; - expect(() => lineAndColumnToPosition(text, 1, 10)).toThrow(); + assert.throws(() => lineAndColumnToPosition(text, 1, 10)); }); }); diff --git a/frontend/obsidian-plugin/src/utils/line-and-column-to-position.ts b/frontend/sync-client/src/utils/line-and-column-to-position.ts similarity index 100% rename from frontend/obsidian-plugin/src/utils/line-and-column-to-position.ts rename to frontend/sync-client/src/utils/line-and-column-to-position.ts diff --git a/frontend/sync-client/src/utils/locks.test.ts b/frontend/sync-client/src/utils/locks.test.ts index 1e6bd38b..5626becc 100644 --- a/frontend/sync-client/src/utils/locks.test.ts +++ b/frontend/sync-client/src/utils/locks.test.ts @@ -1,3 +1,5 @@ +import { describe, it, beforeEach } from "node:test"; +import assert from "node:assert"; import { Logger } from "../tracing/logger"; import type { RelativePath } from "../persistence/database"; import { Locks } from "./locks"; @@ -14,18 +16,18 @@ describe("withLock", () => { locks = new Locks(logger); }); - test("should execute function with single key lock", async () => { + it("should execute function with single key lock", async () => { let executionCount = 0; const result = await locks.withLock(testPath, () => { executionCount++; return "success"; }); - expect(result).toBe("success"); - expect(executionCount).toBe(1); + assert.strictEqual(result, "success"); + assert.strictEqual(executionCount, 1); }); - test("should execute async function with single key lock", async () => { + it("should execute async function with single key lock", async () => { let executionCount = 0; const result = await locks.withLock(testPath, async () => { executionCount++; @@ -33,22 +35,22 @@ describe("withLock", () => { return "async-success"; }); - expect(result).toBe("async-success"); - expect(executionCount).toBe(1); + assert.strictEqual(result, "async-success"); + assert.strictEqual(executionCount, 1); }); - test("should execute function with multiple key locks", async () => { + it("should execute function with multiple key locks", async () => { let executionCount = 0; const result = await locks.withLock([testPath, testPath2], () => { executionCount++; return "multi-success"; }); - expect(result).toBe("multi-success"); - expect(executionCount).toBe(1); + assert.strictEqual(result, "multi-success"); + assert.strictEqual(executionCount, 1); }); - test("should sort multiple keys to prevent deadlocks", async () => { + it("should sort multiple keys to prevent deadlocks", async () => { const executionOrder: string[] = []; // Start two concurrent operations with keys in different orders @@ -68,10 +70,10 @@ describe("withLock", () => { const [result1, result2] = await Promise.all([promise1, promise2]); - expect(result1).toBe("result1"); - expect(result2).toBe("result2"); + assert.strictEqual(result1, "result1"); + assert.strictEqual(result2, "result2"); // One operation should complete entirely before the other starts - expect(executionOrder).toEqual([ + assert.deepStrictEqual(executionOrder, [ "operation1-start", "operation1-end", "operation2-start", @@ -79,7 +81,7 @@ describe("withLock", () => { ]); }); - test("should serialize access to same key", async () => { + it("should serialize access to same key", async () => { const executionOrder: string[] = []; const promise1 = locks.withLock(testPath, async () => { @@ -98,9 +100,9 @@ describe("withLock", () => { const [result1, result2] = await Promise.all([promise1, promise2]); - expect(result1).toBe("result1"); - expect(result2).toBe("result2"); - expect(executionOrder).toEqual([ + assert.strictEqual(result1, "result1"); + assert.strictEqual(result2, "result2"); + assert.deepStrictEqual(executionOrder, [ "operation1-start", "operation1-end", "operation2-start", @@ -108,7 +110,7 @@ describe("withLock", () => { ]); }); - test("should allow concurrent access to different keys", async () => { + it("should allow concurrent access to different keys", async () => { const executionOrder: string[] = []; const promise1 = locks.withLock(testPath, async () => { @@ -127,54 +129,56 @@ describe("withLock", () => { const [result1, result2] = await Promise.all([promise1, promise2]); - expect(result1).toBe("result1"); - expect(result2).toBe("result2"); + assert.strictEqual(result1, "result1"); + assert.strictEqual(result2, "result2"); // Both operations should run concurrently - expect(executionOrder[0]).toBe("operation1-start"); - expect(executionOrder[1]).toBe("operation2-start"); + assert.strictEqual(executionOrder[0], "operation1-start"); + assert.strictEqual(executionOrder[1], "operation2-start"); }); - test("should release locks even if function throws", async () => { + it("should release locks even if function throws", async () => { const error = new Error("test error"); - await expect( + await assert.rejects( locks.withLock(testPath, () => { throw error; - }) - ).rejects.toThrow("test error"); + }), + { message: "test error" } + ); // Lock should be released, allowing another operation const result = await locks.withLock( testPath, () => "success-after-error" ); - expect(result).toBe("success-after-error"); + assert.strictEqual(result, "success-after-error"); }); - test("should release locks even if async function throws", async () => { + it("should release locks even if async function throws", async () => { const error = new Error("async test error"); - await expect( + await assert.rejects( locks.withLock(testPath, async () => { await new Promise((resolve) => setTimeout(resolve, 10)); throw error; - }) - ).rejects.toThrow("async test error"); + }), + { message: "async test error" } + ); // Lock should be released, allowing another operation const result = await locks.withLock( testPath, () => "success-after-async-error" ); - expect(result).toBe("success-after-async-error"); + assert.strictEqual(result, "success-after-async-error"); }); - test("should handle empty array of keys", async () => { + it("should handle empty array of keys", async () => { const result = await locks.withLock([], () => "empty-keys"); - expect(result).toBe("empty-keys"); + assert.strictEqual(result, "empty-keys"); }); - test("should maintain FIFO order for multiple waiters", async () => { + it("should maintain FIFO order for multiple waiters", async () => { const executionOrder: string[] = []; // Start first operation that holds the lock @@ -209,10 +213,10 @@ describe("withLock", () => { thirdPromise ]); - expect(first).toBe("first"); - expect(second).toBe("second"); - expect(third).toBe("third"); - expect(executionOrder).toEqual([ + assert.strictEqual(first, "first"); + assert.strictEqual(second, "second"); + assert.strictEqual(third, "third"); + assert.deepStrictEqual(executionOrder, [ "first-start", "first-end", "second-start", diff --git a/frontend/sync-client/src/utils/min-covered.test.ts b/frontend/sync-client/src/utils/min-covered.test.ts index 429f7a63..82f792c3 100644 --- a/frontend/sync-client/src/utils/min-covered.test.ts +++ b/frontend/sync-client/src/utils/min-covered.test.ts @@ -1,60 +1,62 @@ +import { describe, it } from "node:test"; +import assert from "node:assert"; import { CoveredValues } from "./min-covered"; describe("CoveredValues", () => { - test("should initialize with the given min value", () => { + it("should initialize with the given min value", () => { const covered = new CoveredValues(5); - expect(covered.min).toBe(5); + assert.strictEqual(covered.min, 5); }); - test("should add values greater than min", () => { + it("should add values greater than min", () => { const covered = new CoveredValues(0); covered.add(3); - expect(covered.min).toBe(0); + assert.strictEqual(covered.min, 0); covered.add(1); - expect(covered.min).toBe(1); + assert.strictEqual(covered.min, 1); covered.add(4); - expect(covered.min).toBe(1); + assert.strictEqual(covered.min, 1); covered.add(2); - expect(covered.min).toBe(4); + assert.strictEqual(covered.min, 4); }); - test("should ignore duplicate values", () => { + it("should ignore duplicate values", () => { const covered = new CoveredValues(0); covered.add(3); covered.add(3); covered.add(3); - expect(covered.min).toBe(0); + assert.strictEqual(covered.min, 0); covered.add(1); covered.add(2); - expect(covered.min).toBe(3); + assert.strictEqual(covered.min, 3); }); - test("should handle multiple consecutive values", () => { + it("should handle multiple consecutive values", () => { const covered = new CoveredValues(132); for (let i = 250; i > 132; i--) { - expect(covered.min).toBe(132); + assert.strictEqual(covered.min, 132); covered.add(i); } - expect(covered.min).toBe(250); + assert.strictEqual(covered.min, 250); }); - test("should handle adding values lower than current min", () => { + it("should handle adding values lower than current min", () => { const covered = new CoveredValues(5); covered.add(3); - expect(covered.min).toBe(5); + assert.strictEqual(covered.min, 5); covered.add(6); - expect(covered.min).toBe(6); + assert.strictEqual(covered.min, 6); }); - test("should handle force setting min value", () => { + it("should handle force setting min value", () => { const covered = new CoveredValues(5); covered.add(7); covered.add(8); covered.add(9); - expect(covered.min).toBe(5); + assert.strictEqual(covered.min, 5); covered.min = 6; - expect(covered.min).toBe(6); + assert.strictEqual(covered.min, 6); covered.add(10); - expect(covered.min).toBe(10); + assert.strictEqual(covered.min, 10); }); }); diff --git a/frontend/sync-client/src/utils/position-to-line-and-column.test.ts b/frontend/sync-client/src/utils/position-to-line-and-column.test.ts new file mode 100644 index 00000000..bc21b983 --- /dev/null +++ b/frontend/sync-client/src/utils/position-to-line-and-column.test.ts @@ -0,0 +1,66 @@ +import { describe, test } from "node:test"; +import assert from "node:assert"; +import { positionToLineAndColumn } from "./position-to-line-and-column"; + +describe("positionToLineAndColumn", () => { + test("converts position to line and column in multi-line text", () => { + const text = "ab\ncd\n"; + assert.deepStrictEqual(positionToLineAndColumn(text, 0), { + line: 0, + column: 0 + }); + assert.deepStrictEqual(positionToLineAndColumn(text, 1), { + line: 0, + column: 1 + }); + assert.deepStrictEqual(positionToLineAndColumn(text, 2), { + line: 0, + column: 2 + }); + assert.deepStrictEqual(positionToLineAndColumn(text, 3), { + line: 1, + column: 0 + }); + assert.deepStrictEqual(positionToLineAndColumn(text, 4), { + line: 1, + column: 1 + }); + assert.deepStrictEqual(positionToLineAndColumn(text, 6), { + line: 2, + column: 0 + }); + }); + + test("with carrige returns", () => { + assert.deepStrictEqual(positionToLineAndColumn("a\nb", 3), { + line: 1, + column: 1 + }); + + assert.deepStrictEqual(positionToLineAndColumn("a\r\nb", 3), { + line: 1, + column: 1 + }); + }); + + test("handles empty input", () => { + assert.deepStrictEqual(positionToLineAndColumn("", 0), { + line: 0, + column: 0 + }); + }); + + test("handles positions at the end of text", () => { + const text = "End"; + assert.deepStrictEqual(positionToLineAndColumn(text, 3), { + line: 0, + column: 3 + }); + }); + + test("throws error for position out of range", () => { + const text = "Short text"; + assert.throws(() => positionToLineAndColumn(text, 15)); + assert.throws(() => positionToLineAndColumn(text, -1)); + }); +}); diff --git a/frontend/obsidian-plugin/src/utils/position-to-line-and-column.ts b/frontend/sync-client/src/utils/position-to-line-and-column.ts similarity index 100% rename from frontend/obsidian-plugin/src/utils/position-to-line-and-column.ts rename to frontend/sync-client/src/utils/position-to-line-and-column.ts diff --git a/frontend/sync-client/src/utils/rate-limit.test.ts b/frontend/sync-client/src/utils/rate-limit.test.ts index 577783f7..e0b77dc4 100644 --- a/frontend/sync-client/src/utils/rate-limit.test.ts +++ b/frontend/sync-client/src/utils/rate-limit.test.ts @@ -1,66 +1,64 @@ import { rateLimit } from "./rate-limit"; -import { jest } from "@jest/globals"; +import { describe, it, beforeEach, afterEach, mock } from "node:test"; +import assert from "node:assert"; describe("rateLimit", () => { beforeEach(() => { - jest.useFakeTimers(); + mock.timers.enable({ apis: ["setTimeout"] }); }); afterEach(() => { - jest.useRealTimers(); + mock.timers.reset(); }); it("should call the function immediately on first invocation", async () => { - const mockFn = jest - .fn<() => Promise>() - .mockResolvedValue("result"); + const mockFn = mock.fn<() => Promise>(); + mockFn.mock.mockImplementation(async () => "result"); const rateLimited = rateLimit(mockFn, 100); const promise = rateLimited(); - expect(mockFn).toHaveBeenCalledTimes(1); + assert.strictEqual(mockFn.mock.callCount(), 1); await promise; }); it("should call the function again after the interval has passed", async () => { - const mockFn = jest - .fn<(value: number) => Promise>() - .mockResolvedValue("result"); + const mockFn = mock.fn<(value: number) => Promise>(); + mockFn.mock.mockImplementation(async () => "result"); const rateLimited = rateLimit(mockFn, 100); const promise1 = rateLimited(1); await promise1; - jest.advanceTimersByTime(200); + mock.timers.tick(200); const promise2 = rateLimited(2); await promise2; - expect(mockFn).toHaveBeenCalledTimes(2); - expect(mockFn).toHaveBeenCalledWith(2); + assert.strictEqual(mockFn.mock.callCount(), 2); + assert.deepStrictEqual(mockFn.mock.calls[1].arguments, [2]); }); it("should use the most recent arguments if multiple calls are made within interval", async () => { - const mockFn = jest - .fn<(value: string) => Promise>() - .mockImplementation(async (val) => `${val}-result`); + const mockFn = mock.fn<(value: string) => Promise>(); + mockFn.mock.mockImplementation(async (val: string) => `${val}-result`); const rateLimited = rateLimit(mockFn, 100); const promise1 = rateLimited("first"); - jest.advanceTimersByTime(10); + mock.timers.tick(10); const promise2 = rateLimited("second"); - jest.advanceTimersByTime(10); + mock.timers.tick(10); const promise3 = rateLimited("third"); - jest.advanceTimersByTime(1000); + mock.timers.tick(1000); - expect(await promise1).toEqual("first-result"); - expect(await promise2).toEqual("third-result"); - expect(await promise3).toBeUndefined(); + assert.strictEqual(await promise1, "first-result"); + assert.strictEqual(await promise2, "third-result"); + assert.strictEqual(await promise3, undefined); - expect(mockFn).toHaveBeenCalledTimes(2); - expect(mockFn).toHaveBeenNthCalledWith(1, "first"); - expect(mockFn).toHaveBeenNthCalledWith(2, "third"); + assert.strictEqual(mockFn.mock.callCount(), 2); + assert.deepStrictEqual(mockFn.mock.calls[0].arguments, ["first"]); + assert.deepStrictEqual(mockFn.mock.calls[1].arguments, ["third"]); }); }); diff --git a/frontend/sync-client/tsconfig.json b/frontend/sync-client/tsconfig.json index 024e7b99..c49baa45 100644 --- a/frontend/sync-client/tsconfig.json +++ b/frontend/sync-client/tsconfig.json @@ -6,7 +6,8 @@ "allowSyntheticDefaultImports": true, "moduleResolution": "bundler", "lib": [ - "DOM" // to get `fetch` & `WebSocket` + "DOM", // to get `fetch` & `WebSocket` + "ES2024" ], "declaration": true, "declarationDir": "./dist/types" diff --git a/frontend/test-client/jest.config.js b/frontend/test-client/jest.config.js deleted file mode 100644 index d1cbaca2..00000000 --- a/frontend/test-client/jest.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - preset: "ts-jest" -}; diff --git a/frontend/test-client/package.json b/frontend/test-client/package.json index dc5d2d44..ba40bd48 100644 --- a/frontend/test-client/package.json +++ b/frontend/test-client/package.json @@ -1,6 +1,6 @@ { "name": "test-client", - "version": "0.6.1", + "version": "0.6.3", "private": true, "bin": { "test-client": "./dist/cli.js" @@ -8,17 +8,18 @@ "scripts": { "dev": "webpack watch --mode development", "build": "webpack --mode production", - "test": "jest" + "test": "tsx --test src/**/*.test.ts" }, "devDependencies": { "@types/node": "^22.15.30", + "bufferutil": "^4.0.9", "sync-client": "file:../sync-client", "ts-loader": "^9.5.2", "tslib": "2.8.1", + "tsx": "^4.20.5", "typescript": "5.8.3", "uuid": "^11.1.0", "webpack": "^5.99.9", - "webpack-cli": "^6.0.1", - "bufferutil": "^4.0.9" + "webpack-cli": "^6.0.1" } } diff --git a/frontend/test-client/src/agent/mock-agent.ts b/frontend/test-client/src/agent/mock-agent.ts index b4d1a62e..9e7806ab 100644 --- a/frontend/test-client/src/agent/mock-agent.ts +++ b/frontend/test-client/src/agent/mock-agent.ts @@ -2,12 +2,10 @@ import { choose } from "../utils/choose"; import { v4 as uuidv4 } from "uuid"; import { assert } from "../utils/assert"; import type { RelativePath, SyncSettings } from "sync-client"; -import { Logger, LogLevel } from "sync-client"; +import { debugging, Logger, LogLevel } from "sync-client"; import { MockClient } from "./mock-client"; import { sleep } from "../utils/sleep"; import type { LogLine } from "sync-client/dist/types/tracing/logger"; -import { flakyFetchFactory } from "../utils/flaky-fetch"; -import { flakyWebSocketFactory } from "../utils/flaky-websocket-factory"; export class MockAgent extends MockClient { private readonly writtenContents: string[] = []; @@ -28,8 +26,8 @@ export class MockAgent extends MockClient { public async init(): Promise { await super.init( - flakyFetchFactory(this.jitterScaleInSeconds), - flakyWebSocketFactory( + debugging.slowFetchFactory(this.jitterScaleInSeconds), + debugging.slowWebSocketFactory( this.jitterScaleInSeconds, new Logger() // this logger isn't wired anywhere, so messages to it will be ignored ) diff --git a/frontend/test-client/src/utils/flaky-fetch.ts b/frontend/test-client/src/utils/flaky-fetch.ts deleted file mode 100644 index 6a2c8817..00000000 --- a/frontend/test-client/src/utils/flaky-fetch.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { sleep } from "./sleep"; - -export const flakyFetchFactory = - (jitterScaleInSeconds: number) => - async ( - input: string | URL | globalThis.Request, - init?: RequestInit - ): Promise => { - if (jitterScaleInSeconds > 0) { - await sleep(Math.random() * jitterScaleInSeconds * 1000); - } - - const response = await fetch(input, init); - - if (jitterScaleInSeconds > 0) { - await sleep(Math.random() * jitterScaleInSeconds * 1000); - } - - return response; - }; diff --git a/frontend/test-client/src/utils/flaky-websocket-factory.ts b/frontend/test-client/src/utils/flaky-websocket-factory.ts deleted file mode 100644 index c2c13525..00000000 --- a/frontend/test-client/src/utils/flaky-websocket-factory.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { Logger } from "sync-client"; -import { helpers } from "sync-client"; -import { sleep } from "./sleep"; - -export function flakyWebSocketFactory( - jitterScaleInSeconds: number, - logger: Logger -): typeof WebSocket { - // eslint-disable-next-line - return class FlakyWebSocket extends WebSocket { - private static readonly RECEIVE_KEY = "websocket-receive"; - private static readonly SEND_KEY = "websocket-send"; - - private readonly locks = new helpers.Locks(logger); - - public set onopen(callback: (event: Event) => void) { - super.onopen = async (event: Event): Promise => { - if (jitterScaleInSeconds > 0) { - await sleep(Math.random() * jitterScaleInSeconds * 1000); - } - - callback(event); - }; - } - - public set onmessage(callback: (event: MessageEvent) => void) { - super.onmessage = async (event: MessageEvent): Promise => { - return this.locks.withLock( - FlakyWebSocket.RECEIVE_KEY, - async () => { - if (jitterScaleInSeconds > 0) { - await sleep( - Math.random() * jitterScaleInSeconds * 1000 - ); - } - - callback(event); - } - ); - }; - } - - public set onclose(callback: (event: CloseEvent) => void) { - super.onclose = async (event: CloseEvent): Promise => { - if (jitterScaleInSeconds > 0) { - await sleep(Math.random() * jitterScaleInSeconds * 1000); - } - callback(event); - }; - } - - public set onerror(callback: (event: Event) => void) { - super.onerror = async (event: Event): Promise => { - if (jitterScaleInSeconds > 0) { - await sleep(Math.random() * jitterScaleInSeconds * 1000); - } - callback(event); - }; - } - - public send( - data: string | ArrayBufferLike | Blob | ArrayBufferView - ): void { - this.waitingSend(data).catch((error: unknown) => { - logger.error(`Error sending WebSocket message: ${error}`); - }); - } - - private async waitingSend( - data: string | ArrayBufferLike | Blob | ArrayBufferView - ): Promise { - // maintain message order - return this.locks.withLock(FlakyWebSocket.SEND_KEY, async () => { - if (jitterScaleInSeconds > 0) { - await sleep(Math.random() * jitterScaleInSeconds * 1000); - } - - super.send(data); - }); - } - } as unknown as typeof WebSocket; -} diff --git a/frontend/test-client/src/utils/random-casing.test.ts b/frontend/test-client/src/utils/random-casing.test.ts index c6f1aafa..67033305 100644 --- a/frontend/test-client/src/utils/random-casing.test.ts +++ b/frontend/test-client/src/utils/random-casing.test.ts @@ -1,3 +1,5 @@ +import { describe, it } from "node:test"; +import assert from "node:assert"; import { randomCasing } from "./random-casing"; describe("randomCasing", () => { @@ -5,7 +7,7 @@ describe("randomCasing", () => { const input = "hello, this is a really long string with a lot of characters"; const result = randomCasing(input); - expect(result.toLowerCase()).toBe(input.toLowerCase()); - expect(result).not.toBe(input); + assert.strictEqual(result.toLowerCase(), input.toLowerCase()); + assert.notStrictEqual(result, input); }); }); diff --git a/frontend/test-client/tsconfig.json b/frontend/test-client/tsconfig.json index 4995a2bc..7b38e409 100644 --- a/frontend/test-client/tsconfig.json +++ b/frontend/test-client/tsconfig.json @@ -7,7 +7,7 @@ "esModuleInterop": true, "lib": [ "DOM", - "ESNext" + "ES2024", ], "moduleResolution": "node" }, diff --git a/manifest.json b/manifest.json index a15afeab..b327da4f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "vault-link", "name": "VaultLink", - "version": "0.6.1", + "version": "0.6.3", "minAppVersion": "0.0.0", "description": "Self-hosted synchronization and collaboration for your Vault.", "author": "Andras Schmelczer", diff --git a/scripts/check.sh b/scripts/check.sh index f807d2c8..03bb35fe 100755 --- a/scripts/check.sh +++ b/scripts/check.sh @@ -4,17 +4,17 @@ set -e echo "Running checks in sync-server" cd sync-server +cargo test --verbose cargo clippy --all-targets --all-features cargo fmt --all -- --check cargo machete -cargo test --verbose echo "Running checks in frontend" cd ../frontend npm ci npm run build -npm run lint npm run test +npm run lint if [[ $(git status --porcelain) ]]; then git status --porcelain diff --git a/sync-server/Cargo.lock b/sync-server/Cargo.lock index 7bcdcb6b..26669e0a 100644 --- a/sync-server/Cargo.lock +++ b/sync-server/Cargo.lock @@ -2205,7 +2205,7 @@ dependencies = [ [[package]] name = "sync_server" -version = "0.6.1" +version = "0.6.3" dependencies = [ "anyhow", "axum", diff --git a/sync-server/Cargo.toml b/sync-server/Cargo.toml index 7565adde..550a0998 100644 --- a/sync-server/Cargo.toml +++ b/sync-server/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Andras Schmelczer "] edition = "2024" license = "MIT" repository = "https://github.com/schmelczer/vault-link" -version = "0.6.1" +version = "0.6.3" [dependencies] serde = { version = "1.0.219", default-features = false, features = ["derive"] } diff --git a/sync-server/Dockerfile b/sync-server/Dockerfile index abd9aa6e..e1c04973 100644 --- a/sync-server/Dockerfile +++ b/sync-server/Dockerfile @@ -30,7 +30,7 @@ RUN . /tmp/rust_env && \ cargo build --release --target $RUST_TARGET # Runtime image -FROM alpine:3.22.0 +FROM alpine:3.22.1 LABEL org.opencontainers.image.authors="andras@schmelczer.dev"