web based infinite canvas
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: eslint setup

+829 -276
+24 -2
apps/web/eslint.config.js
··· 5 5 import { defineConfig } from "eslint/config"; 6 6 import globals from "globals"; 7 7 import { fileURLToPath } from "node:url"; 8 + import { dirname } from "node:path"; 8 9 import ts from "typescript-eslint"; 9 10 import svelteConfig from "./svelte.config.js"; 10 11 12 + const __dirname = dirname(fileURLToPath(import.meta.url)); 11 13 const gitignorePath = fileURLToPath(new URL("./.gitignore", import.meta.url)); 12 14 13 15 export default defineConfig( ··· 18 20 prettier, 19 21 ...svelte.configs.prettier, 20 22 { 21 - languageOptions: { globals: { ...globals.browser, ...globals.node } }, 23 + languageOptions: { 24 + globals: { ...globals.browser, ...globals.node }, 25 + parserOptions: { 26 + tsconfigRootDir: __dirname, 27 + }, 28 + }, 22 29 23 30 rules: { 24 31 // typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects. 25 32 // see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors 26 33 "no-undef": "off", 34 + // Allow unused vars that start with _ 35 + "@typescript-eslint/no-unused-vars": [ 36 + "error", 37 + { 38 + argsIgnorePattern: "^_", 39 + varsIgnorePattern: "^_", 40 + caughtErrorsIgnorePattern: "^_", 41 + }, 42 + ], 27 43 }, 28 44 }, 29 45 { 30 46 files: ["**/*.svelte", "**/*.svelte.ts", "**/*.svelte.js"], 31 47 languageOptions: { 32 - parserOptions: { projectService: true, extraFileExtensions: [".svelte"], parser: ts.parser, svelteConfig }, 48 + parserOptions: { 49 + projectService: true, 50 + extraFileExtensions: [".svelte"], 51 + parser: ts.parser, 52 + svelteConfig, 53 + tsconfigRootDir: __dirname, 54 + }, 33 55 }, 34 56 }, 35 57 );
+72 -49
apps/web/src/lib/canvas/Canvas.svelte
··· 4 4 import TitleBar from '$lib/components/TitleBar.svelte'; 5 5 import Toolbar from '$lib/components/Toolbar.svelte'; 6 6 import { createInputAdapter, type InputAdapter } from '$lib/input'; 7 + import { createPlatformRepo, detectPlatform } from '$lib/platform'; 7 8 import { 8 9 createPersistenceManager, 9 10 createSnapStore, ··· 17 18 CursorStore, 18 19 EditorState, 19 20 EllipseTool, 20 - InkfiniteDB, 21 21 LineTool, 22 22 RectTool, 23 23 SelectTool, ··· 26 26 Store, 27 27 TextTool, 28 28 createToolMap, 29 - createWebDocRepo, 30 29 diffDoc, 31 30 getShapesOnCurrentPage, 32 31 routeAction, ··· 34 33 switchTool, 35 34 type Action, 36 35 type CommandKind, 36 + type DocRepo, 37 37 type LoadedDoc, 38 38 type PersistenceSink, 39 39 type ToolId, ··· 42 42 import { createRenderer, type Renderer } from 'inkfinite-renderer'; 43 43 import { onDestroy, onMount } from 'svelte'; 44 44 45 - let repo: ReturnType<typeof createWebDocRepo> | null = null; 45 + let repo: DocRepo | null = null; 46 46 let sink: PersistenceSink | null = null; 47 47 let persistenceManager: ReturnType<typeof createPersistenceManager> | null = null; 48 + const platform = detectPlatform(); 48 49 const fallbackStatusStore = createStatusStore({ 49 - backend: 'indexeddb', 50 + backend: platform === 'desktop' ? 'filesystem' : 'indexeddb', 50 51 state: 'saved', 51 52 pendingWrites: 0 52 53 }); ··· 752 753 } 753 754 754 755 onMount(() => { 755 - const db = new InkfiniteDB(); 756 - repo = createWebDocRepo(db); 757 - persistenceManager = createPersistenceManager(db, repo, { sink: { debounceMs: 200 } }); 758 - sink = persistenceManager.sink; 759 - persistenceStatusStore = persistenceManager.status; 760 756 let disposed = false; 761 757 762 - const hydrate = async () => { 763 - const repoInstance = repo; 764 - if (!repoInstance) { 765 - return; 758 + const initialize = async () => { 759 + const { repo: platformRepo, platform: detectedPlatform, db } = await createPlatformRepo(); 760 + repo = platformRepo; 761 + 762 + if (detectedPlatform === 'web' && db) { 763 + persistenceManager = createPersistenceManager(db, repo, { sink: { debounceMs: 200 } }); 764 + sink = persistenceManager.sink; 765 + persistenceStatusStore = persistenceManager.status; 766 + } else { 767 + const { createPersistenceSink } = await import('inkfinite-core'); 768 + sink = createPersistenceSink(repo, { debounceMs: 500 }); 766 769 } 767 - try { 768 - const boards = await repoInstance.listBoards(); 769 - const id = boards[0]?.id ?? (await repoInstance.createBoard('My board')); 770 - if (disposed) { 770 + 771 + const hydrate = async () => { 772 + const repoInstance = repo; 773 + if (!repoInstance) { 771 774 return; 772 775 } 773 - activeBoardId = id; 774 - const loaded = await repoInstance.loadDoc(id); 775 - if (!disposed) { 776 - persistenceManager?.setActiveBoard(id); 777 - applyLoadedDoc(loaded); 776 + try { 777 + if (detectedPlatform === 'web') { 778 + const boards = await repoInstance.listBoards(); 779 + const id = boards[0]?.id ?? (await repoInstance.createBoard('My board')); 780 + if (disposed) { 781 + return; 782 + } 783 + activeBoardId = id; 784 + const loaded = await repoInstance.loadDoc(id); 785 + if (!disposed) { 786 + persistenceManager?.setActiveBoard(id); 787 + applyLoadedDoc(loaded); 788 + } 789 + } else { 790 + const id = await repoInstance.createBoard('Untitled'); 791 + if (disposed) { 792 + return; 793 + } 794 + activeBoardId = id; 795 + const loaded = await repoInstance.loadDoc(id); 796 + if (!disposed) { 797 + applyLoadedDoc(loaded); 798 + } 799 + } 800 + } catch (error) { 801 + console.error('Failed to load board', error); 778 802 } 779 - } catch (error) { 780 - console.error('Failed to load board', error); 781 - } 782 - }; 803 + }; 783 804 784 - hydrate(); 805 + await hydrate(); 785 806 786 - function getCamera() { 787 - return store.getState().camera; 788 - } 807 + function getCamera() { 808 + return store.getState().camera; 809 + } 789 810 790 - renderer = createRenderer(canvas!, store, { 791 - snapProvider, 792 - cursorProvider, 793 - pointerStateProvider, 794 - handleProvider 795 - }); 796 - inputAdapter = createInputAdapter({ 797 - canvas: canvas!, 798 - getCamera, 799 - getViewport, 800 - onAction: handleAction, 801 - onCursorUpdate: (world, screen) => cursorStore.updateCursor(world, screen) 802 - }); 811 + renderer = createRenderer(canvas!, store, { 812 + snapProvider, 813 + cursorProvider, 814 + pointerStateProvider, 815 + handleProvider 816 + }); 817 + inputAdapter = createInputAdapter({ 818 + canvas: canvas!, 819 + getCamera, 820 + getViewport, 821 + onAction: handleAction, 822 + onCursorUpdate: (world, screen) => cursorStore.updateCursor(world, screen) 823 + }); 803 824 804 - function handleBeforeUnload() { 805 - if (sink) { 806 - void sink.flush(); 825 + function handleBeforeUnload() { 826 + if (sink) { 827 + void sink.flush(); 828 + } 807 829 } 808 - } 830 + 831 + window.addEventListener('beforeunload', handleBeforeUnload); 832 + }; 809 833 810 - window.addEventListener('beforeunload', handleBeforeUnload); 834 + initialize(); 811 835 812 836 return () => { 813 837 disposed = true; 814 - window.removeEventListener('beforeunload', handleBeforeUnload); 815 838 }; 816 839 }); 817 840
+2 -2
apps/web/src/lib/components/HistoryViewer.svelte
··· 53 53 <p class="empty-state">No actions to undo</p> 54 54 {:else} 55 55 <ul class="history-list"> 56 - {#each history.undoStack as entry, index} 56 + {#each history.undoStack as entry, index (`UNDO:${entry.command.kind}:${entry.timestamp}`)} 57 57 <li class="history-entry"> 58 58 <div class="entry-info"> 59 59 <span class="entry-name">{entry.command.name}</span> ··· 72 72 <p class="empty-state">No actions to redo</p> 73 73 {:else} 74 74 <ul class="history-list"> 75 - {#each history.redoStack as entry, index} 75 + {#each history.redoStack as entry, index (`REDO:${entry.command.kind}:${entry.timestamp}`)} 76 76 <li class="history-entry redo"> 77 77 <div class="entry-info"> 78 78 <span class="entry-name">{entry.command.name}</span>
+95
apps/web/src/lib/fileops.ts
··· 1 + /** 2 + * Desktop file operations using Tauri plugins 3 + */ 4 + 5 + import { open, save } from "@tauri-apps/plugin-dialog"; 6 + import { readTextFile, writeTextFile } from "@tauri-apps/plugin-fs"; 7 + import { load } from "@tauri-apps/plugin-store"; 8 + import type { DesktopFileOps, FileHandle } from "inkfinite-core"; 9 + 10 + export type { DesktopFileOps }; 11 + 12 + const STORE_NAME = "inkfinite-desktop.json"; 13 + const RECENT_FILES_KEY = "recentFiles"; 14 + const MAX_RECENT_FILES = 10; 15 + 16 + /** 17 + * Create desktop file operations using Tauri APIs 18 + */ 19 + export function createDesktopFileOps(): DesktopFileOps { 20 + let storePromise: Promise<Awaited<ReturnType<typeof load>>> | null = null; 21 + 22 + async function getStore() { 23 + if (!storePromise) { 24 + storePromise = load(STORE_NAME); 25 + } 26 + return storePromise; 27 + } 28 + 29 + async function showOpenDialog(): Promise<string | null> { 30 + const result = await open({ 31 + multiple: false, 32 + directory: false, 33 + filters: [{ name: "Inkfinite Files", extensions: ["inkfinite.json", "json"] }], 34 + }); 35 + 36 + return result; 37 + } 38 + 39 + async function showSaveDialog(defaultName?: string): Promise<string | null> { 40 + const result = await save({ 41 + defaultPath: defaultName || "Untitled.inkfinite.json", 42 + filters: [{ name: "Inkfinite Files", extensions: ["inkfinite.json"] }], 43 + }); 44 + 45 + return result; 46 + } 47 + 48 + async function readFile(path: string): Promise<string> { 49 + return readTextFile(path); 50 + } 51 + 52 + async function writeFile(path: string, content: string): Promise<void> { 53 + await writeTextFile(path, content); 54 + } 55 + 56 + async function getRecentFiles(): Promise<FileHandle[]> { 57 + const store = await getStore(); 58 + const recent = (await store.get<FileHandle[]>(RECENT_FILES_KEY)) || []; 59 + return recent; 60 + } 61 + 62 + async function addRecentFile(handle: FileHandle): Promise<void> { 63 + const store = await getStore(); 64 + const recent = (await store.get<FileHandle[]>(RECENT_FILES_KEY)) || []; 65 + const filtered = recent.filter((f) => f.path !== handle.path); 66 + const updated = [handle, ...filtered].slice(0, MAX_RECENT_FILES); 67 + await store.set(RECENT_FILES_KEY, updated); 68 + await store.save(); 69 + } 70 + 71 + async function removeRecentFile(path: string): Promise<void> { 72 + const store = await getStore(); 73 + const recent = (await store.get<FileHandle[]>(RECENT_FILES_KEY)) || []; 74 + const filtered = recent.filter((f) => f.path !== path); 75 + await store.set(RECENT_FILES_KEY, filtered); 76 + await store.save(); 77 + } 78 + 79 + async function clearRecentFiles(): Promise<void> { 80 + const store = await getStore(); 81 + await store.set(RECENT_FILES_KEY, []); 82 + await store.save(); 83 + } 84 + 85 + return { 86 + showOpenDialog, 87 + showSaveDialog, 88 + readFile, 89 + writeFile, 90 + getRecentFiles, 91 + addRecentFile, 92 + removeRecentFile, 93 + clearRecentFiles, 94 + }; 95 + }
+228
apps/web/src/lib/persistence/desktop.ts
··· 1 + /** 2 + * Desktop (Tauri) file-based DocRepo implementation 3 + * Used when the web app is running inside Tauri 4 + */ 5 + 6 + import type { BoardExport, BoardMeta, DocPatch, DocRepo, LoadedDoc } from "inkfinite-core"; 7 + import { 8 + createFileData, 9 + createId, 10 + type DesktopFileData, 11 + type FileHandle, 12 + loadedDocFromFileData, 13 + PageRecord, 14 + parseDesktopFile, 15 + serializeDesktopFile, 16 + } from "inkfinite-core"; 17 + import type { DesktopFileOps } from "../fileops"; 18 + 19 + /** 20 + * Create a desktop file-based DocRepo 21 + * This implementation manages a single document loaded from disk 22 + */ 23 + export function createDesktopDocRepo(fileOps: DesktopFileOps): DocRepo { 24 + let currentFile: FileHandle | null = null; 25 + let currentBoard: BoardMeta | null = null; 26 + let currentDoc: LoadedDoc | null = null; 27 + 28 + async function listBoards(): Promise<BoardMeta[]> { 29 + // TODO: cache metadata or read it from files 30 + // const recent = await fileOps.getRecentFiles(); 31 + return []; 32 + } 33 + 34 + async function createBoard(name: string): Promise<string> { 35 + const boardId = createId("board"); 36 + const timestamp = Date.now(); 37 + const page = PageRecord.create("Page 1"); 38 + 39 + const board: BoardMeta = { 40 + id: boardId, 41 + name: name || "Untitled Board", 42 + createdAt: timestamp, 43 + updatedAt: timestamp, 44 + }; 45 + 46 + const fileData = createFileData(board, { [page.id]: page }, {}, {}, { 47 + pageIds: [page.id], 48 + shapeOrder: { [page.id]: [] }, 49 + }); 50 + 51 + const path = await fileOps.showSaveDialog(`${name || "Untitled"}.inkfinite.json`); 52 + if (!path) { 53 + throw new Error("Save cancelled"); 54 + } 55 + 56 + await fileOps.writeFile(path, serializeDesktopFile(fileData)); 57 + 58 + currentFile = { path, name: path.split("/").pop() || name }; 59 + currentBoard = board; 60 + currentDoc = loadedDocFromFileData(fileData); 61 + 62 + await fileOps.addRecentFile(currentFile); 63 + return boardId; 64 + } 65 + 66 + async function renameBoard(boardId: string, name: string): Promise<void> { 67 + if (!currentBoard || !currentDoc || !currentFile) { 68 + throw new Error("No board loaded"); 69 + } 70 + 71 + currentBoard = { ...currentBoard, name, updatedAt: Date.now() }; 72 + 73 + const fileData = createFileData( 74 + currentBoard, 75 + currentDoc.pages, 76 + currentDoc.shapes, 77 + currentDoc.bindings, 78 + currentDoc.order, 79 + ); 80 + 81 + await fileOps.writeFile(currentFile.path, serializeDesktopFile(fileData)); 82 + } 83 + 84 + async function deleteBoard(_boardId: string): Promise<void> { 85 + if (currentFile) { 86 + await fileOps.removeRecentFile(currentFile.path); 87 + currentFile = null; 88 + currentBoard = null; 89 + currentDoc = null; 90 + } 91 + } 92 + 93 + async function loadDoc(boardId: string): Promise<LoadedDoc> { 94 + if (currentDoc && currentBoard?.id === boardId) { 95 + return currentDoc; 96 + } 97 + 98 + const path = await fileOps.showOpenDialog(); 99 + if (!path) { 100 + throw new Error("Open cancelled"); 101 + } 102 + 103 + const content = await fileOps.readFile(path); 104 + const fileData = parseDesktopFile(content); 105 + 106 + currentFile = { path, name: path.split("/").pop() || "Untitled" }; 107 + currentBoard = fileData.board; 108 + currentDoc = loadedDocFromFileData(fileData); 109 + 110 + await fileOps.addRecentFile(currentFile); 111 + 112 + return currentDoc; 113 + } 114 + 115 + async function applyDocPatch(boardId: string, patch: DocPatch): Promise<void> { 116 + if (!currentBoard || !currentDoc || !currentFile) { 117 + throw new Error("No board loaded"); 118 + } 119 + 120 + if (patch.deletes) { 121 + if (patch.deletes.pageIds) { 122 + for (const id of patch.deletes.pageIds) { 123 + delete currentDoc.pages[id]; 124 + } 125 + } 126 + if (patch.deletes.shapeIds) { 127 + for (const id of patch.deletes.shapeIds) { 128 + delete currentDoc.shapes[id]; 129 + } 130 + } 131 + if (patch.deletes.bindingIds) { 132 + for (const id of patch.deletes.bindingIds) { 133 + delete currentDoc.bindings[id]; 134 + } 135 + } 136 + } 137 + 138 + if (patch.upserts) { 139 + if (patch.upserts.pages) { 140 + for (const page of patch.upserts.pages) { 141 + currentDoc.pages[page.id] = page; 142 + } 143 + } 144 + if (patch.upserts.shapes) { 145 + for (const shape of patch.upserts.shapes) { 146 + currentDoc.shapes[shape.id] = shape; 147 + } 148 + } 149 + if (patch.upserts.bindings) { 150 + for (const binding of patch.upserts.bindings) { 151 + currentDoc.bindings[binding.id] = binding; 152 + } 153 + } 154 + } 155 + 156 + if (patch.order) { 157 + if (patch.order.pageIds) { 158 + currentDoc.order.pageIds = patch.order.pageIds; 159 + } 160 + if (patch.order.shapeOrder) { 161 + currentDoc.order.shapeOrder = patch.order.shapeOrder; 162 + } 163 + } 164 + 165 + currentBoard = { ...currentBoard, updatedAt: Date.now() }; 166 + 167 + const fileData = createFileData( 168 + currentBoard, 169 + currentDoc.pages, 170 + currentDoc.shapes, 171 + currentDoc.bindings, 172 + currentDoc.order, 173 + ); 174 + 175 + await fileOps.writeFile(currentFile.path, serializeDesktopFile(fileData)); 176 + } 177 + 178 + async function exportBoard(_boardId: string): Promise<BoardExport> { 179 + if (!currentBoard || !currentDoc) { 180 + throw new Error("No board loaded"); 181 + } 182 + 183 + return { 184 + board: currentBoard, 185 + doc: { pages: currentDoc.pages, shapes: currentDoc.shapes, bindings: currentDoc.bindings }, 186 + order: currentDoc.order, 187 + }; 188 + } 189 + 190 + async function importBoard(snapshot: BoardExport): Promise<string> { 191 + const boardId = snapshot.board.id ?? createId("board"); 192 + const timestamp = Date.now(); 193 + 194 + const board: BoardMeta = { 195 + id: boardId, 196 + name: snapshot.board.name || "Imported Board", 197 + createdAt: snapshot.board.createdAt ?? timestamp, 198 + updatedAt: timestamp, 199 + }; 200 + 201 + const fileData: DesktopFileData = { board, doc: snapshot.doc, order: snapshot.order }; 202 + 203 + const path = await fileOps.showSaveDialog(`${board.name}.inkfinite.json`); 204 + if (!path) { 205 + throw new Error("Save cancelled"); 206 + } 207 + 208 + await fileOps.writeFile(path, serializeDesktopFile(fileData)); 209 + 210 + currentFile = { path, name: path.split("/").pop() || board.name }; 211 + currentBoard = board; 212 + currentDoc = loadedDocFromFileData(fileData); 213 + 214 + await fileOps.addRecentFile(currentFile); 215 + 216 + return boardId; 217 + } 218 + 219 + return { listBoards, createBoard, renameBoard, deleteBoard, loadDoc, applyDocPatch, exportBoard, importBoard }; 220 + } 221 + 222 + /** 223 + * Get current file handle (for showing in title bar, etc.) 224 + */ 225 + export function getCurrentFile(_repo: unknown): FileHandle | null { 226 + // TODO: expose this properly 227 + return null; 228 + }
+33
apps/web/src/lib/platform.ts
··· 1 + import type { DocRepo } from "inkfinite-core"; 2 + import { createWebDocRepo, InkfiniteDB } from "inkfinite-core"; 3 + import { createDesktopFileOps } from "./fileops"; 4 + import { createDesktopDocRepo } from "./persistence/desktop"; 5 + 6 + export type Platform = "web" | "desktop"; 7 + 8 + /** 9 + * Detect if we're running in Tauri 10 + */ 11 + export function detectPlatform(): Platform { 12 + if (typeof window !== "undefined" && "__TAURI__" in window) { 13 + return "desktop"; 14 + } 15 + return "web"; 16 + } 17 + 18 + /** 19 + * Create the appropriate DocRepo based on platform 20 + */ 21 + export async function createPlatformRepo(): Promise<{ repo: DocRepo; platform: Platform; db?: InkfiniteDB }> { 22 + const platform = detectPlatform(); 23 + 24 + if (platform === "desktop") { 25 + const fileOps = createDesktopFileOps(); 26 + const repo = createDesktopDocRepo(fileOps); 27 + return { repo, platform }; 28 + } else { 29 + const db = new InkfiniteDB(); 30 + const repo = createWebDocRepo(db); 31 + return { repo, platform, db }; 32 + } 33 + }
-32
eslint.config.js
··· 1 - // @ts-check 2 - 3 - import eslint from "@eslint/js"; 4 - import eslintPluginUnicorn from "eslint-plugin-unicorn"; 5 - import { defineConfig } from "eslint/config"; 6 - import tseslint from "typescript-eslint"; 7 - 8 - export default defineConfig( 9 - eslint.configs.recommended, 10 - tseslint.configs.recommended, 11 - eslintPluginUnicorn.configs.recommended, 12 - [{ 13 - rules: { 14 - "@typescript-eslint/no-unused-vars": ["error", { 15 - "args": "all", 16 - "argsIgnorePattern": "^_", 17 - "caughtErrors": "all", 18 - "caughtErrorsIgnorePattern": "^_", 19 - "destructuredArrayIgnorePattern": "^_", 20 - "varsIgnorePattern": "^_", 21 - "ignoreRestSiblings": true, 22 - }], 23 - "unicorn/prefer-ternary": "off", 24 - "unicorn/no-null": "off", 25 - "unicorn/no-array-reverse": "off", 26 - "unicorn/prefer-structured-clone": "off", 27 - "unicorn/prevent-abbreviations": ["error", { 28 - "replacements": { "i": false, "props": false, "doc": false, "db": false }, 29 - }], 30 - }, 31 - }], 32 - );
+1 -9
package.json
··· 5 5 "type": "module", 6 6 "workspaces": ["packages/*", "apps/*"], 7 7 "scripts": {}, 8 - "devDependencies": { 9 - "@eslint/js": "^9.39.2", 10 - "dprint": "^0.50.2", 11 - "eslint": "^9.39.2", 12 - "eslint-plugin-unicorn": "^62.0.0", 13 - "globals": "^16.5.0", 14 - "typescript": "^5.9.3", 15 - "typescript-eslint": "^8.50.0" 16 - }, 8 + "devDependencies": { "dprint": "^0.50.2", "typescript": "^5.9.3" }, 17 9 "engines": { "node": ">=18.0.0", "pnpm": ">=8.0.0" }, 18 10 "packageManager": "pnpm@10.26.1" 19 11 }
+32
packages/core/eslint.config.js
··· 1 + import js from "@eslint/js"; 2 + import { defineConfig } from "eslint/config"; 3 + import globals from "globals"; 4 + import { dirname } from "node:path"; 5 + import { fileURLToPath } from "node:url"; 6 + import ts from "typescript-eslint"; 7 + 8 + const __dirname = dirname(fileURLToPath(import.meta.url)); 9 + 10 + export default defineConfig( 11 + { 12 + ignores: ["dist/**", "*.config.js"], 13 + }, 14 + js.configs.recommended, 15 + ...ts.configs.recommended, 16 + { 17 + languageOptions: { 18 + globals: { ...globals.node }, 19 + parserOptions: { tsconfigRootDir: __dirname, project: "./tsconfig.json" }, 20 + }, 21 + rules: { 22 + "@typescript-eslint/no-unused-vars": [ 23 + "error", 24 + { 25 + argsIgnorePattern: "^_", 26 + varsIgnorePattern: "^_", 27 + caughtErrorsIgnorePattern: "^_", 28 + }, 29 + ], 30 + }, 31 + }, 32 + );
+24 -6
packages/core/package.json
··· 6 6 "author": "Owais J. <desertthunder.dev@gmail.com>", 7 7 "license": "MIT", 8 8 "homepage": "https://github.com/stormlightlabs/inkfinite#readme", 9 - "repository": { "type": "git", "url": "git+https://github.com/stormlightlabs/inkfinite.git" }, 10 - "bugs": { "url": "https://github.com/stormlightlabs/inkfinite/issues" }, 11 - "exports": { ".": "./dist/index.mjs", "./package.json": "./package.json" }, 9 + "repository": { 10 + "type": "git", 11 + "url": "git+https://github.com/stormlightlabs/inkfinite.git" 12 + }, 13 + "bugs": { 14 + "url": "https://github.com/stormlightlabs/inkfinite/issues" 15 + }, 16 + "exports": { 17 + ".": "./dist/index.mjs", 18 + "./package.json": "./package.json" 19 + }, 12 20 "main": "./dist/index.mjs", 13 21 "module": "./dist/index.mjs", 14 22 "types": "./dist/index.d.mts", 15 - "files": ["dist"], 23 + "files": [ 24 + "dist" 25 + ], 16 26 "scripts": { 17 27 "build": "tsdown", 18 28 "dev": "tsdown --watch", ··· 21 31 "prepublishOnly": "pnpm run build" 22 32 }, 23 33 "devDependencies": { 34 + "@eslint/js": "^9.39.2", 24 35 "@types/node": "^25.0.3", 25 36 "@vitest/coverage-v8": "^4.0.16", 26 - "fake-indexeddb": "^6.0.0", 27 37 "bumpp": "^10.3.2", 38 + "eslint": "^9.39.2", 39 + "eslint-config-prettier": "^10.1.8", 40 + "fake-indexeddb": "^6.0.0", 28 41 "tsdown": "^0.18.1", 29 42 "typescript": "^5.9.3", 43 + "typescript-eslint": "^8.50.1", 30 44 "vitest": "^4.0.16" 31 45 }, 32 - "dependencies": { "dexie": "^4.2.1", "rxjs": "^7.8.2", "uuid": "^13.0.0" } 46 + "dependencies": { 47 + "dexie": "^4.2.1", 48 + "rxjs": "^7.8.2", 49 + "uuid": "^13.0.0" 50 + } 33 51 }
+92
packages/core/src/persistence/desktop.ts
··· 1 + import type { BindingRecord, Document, PageRecord, ShapeRecord } from "../model"; 2 + import type { BoardMeta, DocOrder, LoadedDoc } from "./web"; 3 + 4 + /** 5 + * Desktop file representation - combines board metadata with document content 6 + */ 7 + export type DesktopFileData = { board: BoardMeta; doc: Document; order: DocOrder }; 8 + 9 + /** 10 + * File handle for desktop - just the path 11 + */ 12 + export type FileHandle = { path: string; name: string }; 13 + 14 + /** 15 + * Desktop-specific operations interface. 16 + * Implementation lives in apps/desktop using @tauri-apps/plugin-* APIs. 17 + */ 18 + export interface DesktopFileOps { 19 + /** 20 + * Show open dialog and return selected file path 21 + */ 22 + showOpenDialog(): Promise<string | null>; 23 + 24 + /** 25 + * Show save dialog and return selected file path 26 + */ 27 + showSaveDialog(defaultName?: string): Promise<string | null>; 28 + 29 + /** 30 + * Read a file from disk 31 + */ 32 + readFile(path: string): Promise<string>; 33 + 34 + /** 35 + * Write a file to disk 36 + */ 37 + writeFile(path: string, content: string): Promise<void>; 38 + 39 + /** 40 + * Get recent files list 41 + */ 42 + getRecentFiles(): Promise<FileHandle[]>; 43 + 44 + /** 45 + * Add a file to recent files list 46 + */ 47 + addRecentFile(handle: FileHandle): Promise<void>; 48 + 49 + /** 50 + * Remove a file from recent files list 51 + */ 52 + removeRecentFile(path: string): Promise<void>; 53 + 54 + /** 55 + * Clear all recent files 56 + */ 57 + clearRecentFiles(): Promise<void>; 58 + } 59 + 60 + /** 61 + * Create a loaded document from desktop file data 62 + */ 63 + export function loadedDocFromFileData(data: DesktopFileData): LoadedDoc { 64 + return { pages: data.doc.pages, shapes: data.doc.shapes, bindings: data.doc.bindings, order: data.order }; 65 + } 66 + 67 + /** 68 + * Create file data from document parts 69 + */ 70 + export function createFileData( 71 + board: BoardMeta, 72 + pages: Record<string, PageRecord>, 73 + shapes: Record<string, ShapeRecord>, 74 + bindings: Record<string, BindingRecord>, 75 + order: DocOrder, 76 + ): DesktopFileData { 77 + return { board, doc: { pages, shapes, bindings }, order }; 78 + } 79 + 80 + export function parseDesktopFile(content: string): DesktopFileData { 81 + const data = JSON.parse(content) as DesktopFileData; 82 + 83 + if (!data.board || !data.doc || !data.order) { 84 + throw new Error("Invalid file format: missing required fields"); 85 + } 86 + 87 + return data; 88 + } 89 + 90 + export function serializeDesktopFile(data: DesktopFileData): string { 91 + return JSON.stringify(data, null, 2); 92 + }
+1 -1
packages/core/src/ui/statusbar.ts
··· 9 9 export type SnapSummary = { enabled: boolean; gridSize?: number; angleStepDeg?: number }; 10 10 11 11 export type PersistenceStatus = { 12 - backend: "indexeddb"; 12 + backend: "indexeddb" | "filesystem"; 13 13 state: "saved" | "saving" | "error"; 14 14 lastSavedAt?: number; 15 15 pendingWrites?: number;
+27
packages/renderer/eslint.config.js
··· 1 + import js from "@eslint/js"; 2 + import { defineConfig } from "eslint/config"; 3 + import globals from "globals"; 4 + import { dirname } from "node:path"; 5 + import { fileURLToPath } from "node:url"; 6 + import ts from "typescript-eslint"; 7 + 8 + const __dirname = dirname(fileURLToPath(import.meta.url)); 9 + 10 + export default defineConfig( 11 + { ignores: ["dist/**", "*.config.js"] }, 12 + js.configs.recommended, 13 + ...ts.configs.recommended, 14 + { 15 + languageOptions: { 16 + globals: { ...globals.node }, 17 + parserOptions: { tsconfigRootDir: __dirname, project: "./tsconfig.json" }, 18 + }, 19 + rules: { 20 + "@typescript-eslint/no-unused-vars": ["error", { 21 + argsIgnorePattern: "^_", 22 + varsIgnorePattern: "^_", 23 + caughtErrorsIgnorePattern: "^_", 24 + }], 25 + }, 26 + }, 27 + );
+4
packages/renderer/package.json
··· 21 21 "prepublishOnly": "pnpm run build" 22 22 }, 23 23 "devDependencies": { 24 + "@eslint/js": "^9.39.2", 24 25 "@types/jsdom": "^27.0.0", 25 26 "@types/node": "^25.0.3", 26 27 "bumpp": "^10.3.2", 28 + "eslint": "^9.39.2", 29 + "eslint-config-prettier": "^10.1.8", 27 30 "jsdom": "^27.3.0", 28 31 "tsdown": "^0.18.1", 29 32 "typescript": "^5.9.3", 33 + "typescript-eslint": "^8.50.1", 30 34 "vitest": "^4.0.16" 31 35 }, 32 36 "dependencies": { "inkfinite-core": "workspace:*" }
+194 -175
pnpm-lock.yaml
··· 8 8 9 9 .: 10 10 devDependencies: 11 - '@eslint/js': 12 - specifier: ^9.39.2 13 - version: 9.39.2 14 11 dprint: 15 12 specifier: ^0.50.2 16 13 version: 0.50.2 17 - eslint: 18 - specifier: ^9.39.2 19 - version: 9.39.2(jiti@2.6.1) 20 - eslint-plugin-unicorn: 21 - specifier: ^62.0.0 22 - version: 62.0.0(eslint@9.39.2(jiti@2.6.1)) 23 - globals: 24 - specifier: ^16.5.0 25 - version: 16.5.0 26 14 typescript: 27 15 specifier: ^5.9.3 28 16 version: 5.9.3 29 - typescript-eslint: 30 - specifier: ^8.50.0 31 - version: 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 32 17 33 18 apps/desktop: 34 19 devDependencies: ··· 139 124 specifier: ^13.0.0 140 125 version: 13.0.0 141 126 devDependencies: 127 + '@eslint/js': 128 + specifier: ^9.39.2 129 + version: 9.39.2 142 130 '@types/node': 143 131 specifier: ^25.0.3 144 132 version: 25.0.3 ··· 148 136 bumpp: 149 137 specifier: ^10.3.2 150 138 version: 10.3.2(magicast@0.5.1) 139 + eslint: 140 + specifier: ^9.39.2 141 + version: 9.39.2(jiti@2.6.1) 142 + eslint-config-prettier: 143 + specifier: ^10.1.8 144 + version: 10.1.8(eslint@9.39.2(jiti@2.6.1)) 151 145 fake-indexeddb: 152 146 specifier: ^6.0.0 153 147 version: 6.2.5 ··· 157 151 typescript: 158 152 specifier: ^5.9.3 159 153 version: 5.9.3 154 + typescript-eslint: 155 + specifier: ^8.50.1 156 + version: 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 160 157 vitest: 161 158 specifier: ^4.0.16 162 159 version: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@27.3.0)(yaml@2.8.2) ··· 167 164 specifier: workspace:* 168 165 version: link:../core 169 166 devDependencies: 167 + '@eslint/js': 168 + specifier: ^9.39.2 169 + version: 9.39.2 170 170 '@types/jsdom': 171 171 specifier: ^27.0.0 172 172 version: 27.0.0 ··· 176 176 bumpp: 177 177 specifier: ^10.3.2 178 178 version: 10.3.2(magicast@0.5.1) 179 + eslint: 180 + specifier: ^9.39.2 181 + version: 9.39.2(jiti@2.6.1) 182 + eslint-config-prettier: 183 + specifier: ^10.1.8 184 + version: 10.1.8(eslint@9.39.2(jiti@2.6.1)) 179 185 jsdom: 180 186 specifier: ^27.3.0 181 187 version: 27.3.0 ··· 185 191 typescript: 186 192 specifier: ^5.9.3 187 193 version: 5.9.3 194 + typescript-eslint: 195 + specifier: ^8.50.1 196 + version: 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 188 197 vitest: 189 198 specifier: ^4.0.16 190 199 version: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@27.3.0)(yaml@2.8.2) ··· 913 922 eslint: ^8.57.0 || ^9.0.0 914 923 typescript: '>=4.8.4 <6.0.0' 915 924 925 + '@typescript-eslint/eslint-plugin@8.50.1': 926 + resolution: {integrity: sha512-PKhLGDq3JAg0Jk/aK890knnqduuI/Qj+udH7wCf0217IGi4gt+acgCyPVe79qoT+qKUvHMDQkwJeKW9fwl8Cyw==} 927 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 928 + peerDependencies: 929 + '@typescript-eslint/parser': ^8.50.1 930 + eslint: ^8.57.0 || ^9.0.0 931 + typescript: '>=4.8.4 <6.0.0' 932 + 916 933 '@typescript-eslint/parser@8.50.0': 917 934 resolution: {integrity: sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==} 918 935 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} ··· 920 937 eslint: ^8.57.0 || ^9.0.0 921 938 typescript: '>=4.8.4 <6.0.0' 922 939 940 + '@typescript-eslint/parser@8.50.1': 941 + resolution: {integrity: sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==} 942 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 943 + peerDependencies: 944 + eslint: ^8.57.0 || ^9.0.0 945 + typescript: '>=4.8.4 <6.0.0' 946 + 923 947 '@typescript-eslint/project-service@8.50.0': 924 948 resolution: {integrity: sha512-Cg/nQcL1BcoTijEWyx4mkVC56r8dj44bFDvBdygifuS20f3OZCHmFbjF34DPSi07kwlFvqfv/xOLnJ5DquxSGQ==} 949 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 950 + peerDependencies: 951 + typescript: '>=4.8.4 <6.0.0' 952 + 953 + '@typescript-eslint/project-service@8.50.1': 954 + resolution: {integrity: sha512-E1ur1MCVf+YiP89+o4Les/oBAVzmSbeRB0MQLfSlYtbWU17HPxZ6Bhs5iYmKZRALvEuBoXIZMOIRRc/P++Ortg==} 925 955 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 926 956 peerDependencies: 927 957 typescript: '>=4.8.4 <6.0.0' ··· 930 960 resolution: {integrity: sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A==} 931 961 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 932 962 963 + '@typescript-eslint/scope-manager@8.50.1': 964 + resolution: {integrity: sha512-mfRx06Myt3T4vuoHaKi8ZWNTPdzKPNBhiblze5N50//TSHOAQQevl/aolqA/BcqqbJ88GUnLqjjcBc8EWdBcVw==} 965 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 966 + 933 967 '@typescript-eslint/tsconfig-utils@8.50.0': 934 968 resolution: {integrity: sha512-vxd3G/ybKTSlm31MOA96gqvrRGv9RJ7LGtZCn2Vrc5htA0zCDvcMqUkifcjrWNNKXHUU3WCkYOzzVSFBd0wa2w==} 935 969 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 936 970 peerDependencies: 937 971 typescript: '>=4.8.4 <6.0.0' 938 972 973 + '@typescript-eslint/tsconfig-utils@8.50.1': 974 + resolution: {integrity: sha512-ooHmotT/lCWLXi55G4mvaUF60aJa012QzvLK0Y+Mp4WdSt17QhMhWOaBWeGTFVkb2gDgBe19Cxy1elPXylslDw==} 975 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 976 + peerDependencies: 977 + typescript: '>=4.8.4 <6.0.0' 978 + 939 979 '@typescript-eslint/type-utils@8.50.0': 940 980 resolution: {integrity: sha512-7OciHT2lKCewR0mFoBrvZJ4AXTMe/sYOe87289WAViOocEmDjjv8MvIOT2XESuKj9jp8u3SZYUSh89QA4S1kQw==} 941 981 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} ··· 943 983 eslint: ^8.57.0 || ^9.0.0 944 984 typescript: '>=4.8.4 <6.0.0' 945 985 986 + '@typescript-eslint/type-utils@8.50.1': 987 + resolution: {integrity: sha512-7J3bf022QZE42tYMO6SL+6lTPKFk/WphhRPe9Tw/el+cEwzLz1Jjz2PX3GtGQVxooLDKeMVmMt7fWpYRdG5Etg==} 988 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 989 + peerDependencies: 990 + eslint: ^8.57.0 || ^9.0.0 991 + typescript: '>=4.8.4 <6.0.0' 992 + 946 993 '@typescript-eslint/types@8.50.0': 947 994 resolution: {integrity: sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w==} 948 995 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 949 996 997 + '@typescript-eslint/types@8.50.1': 998 + resolution: {integrity: sha512-v5lFIS2feTkNyMhd7AucE/9j/4V9v5iIbpVRncjk/K0sQ6Sb+Np9fgYS/63n6nwqahHQvbmujeBL7mp07Q9mlA==} 999 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1000 + 950 1001 '@typescript-eslint/typescript-estree@8.50.0': 951 1002 resolution: {integrity: sha512-W7SVAGBR/IX7zm1t70Yujpbk+zdPq/u4soeFSknWFdXIFuWsBGBOUu/Tn/I6KHSKvSh91OiMuaSnYp3mtPt5IQ==} 1003 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1004 + peerDependencies: 1005 + typescript: '>=4.8.4 <6.0.0' 1006 + 1007 + '@typescript-eslint/typescript-estree@8.50.1': 1008 + resolution: {integrity: sha512-woHPdW+0gj53aM+cxchymJCrh0cyS7BTIdcDxWUNsclr9VDkOSbqC13juHzxOmQ22dDkMZEpZB+3X1WpUvzgVQ==} 952 1009 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 953 1010 peerDependencies: 954 1011 typescript: '>=4.8.4 <6.0.0' ··· 960 1017 eslint: ^8.57.0 || ^9.0.0 961 1018 typescript: '>=4.8.4 <6.0.0' 962 1019 1020 + '@typescript-eslint/utils@8.50.1': 1021 + resolution: {integrity: sha512-lCLp8H1T9T7gPbEuJSnHwnSuO9mDf8mfK/Nion5mZmiEaQD9sWf9W4dfeFqRyqRjF06/kBuTmAqcs9sewM2NbQ==} 1022 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1023 + peerDependencies: 1024 + eslint: ^8.57.0 || ^9.0.0 1025 + typescript: '>=4.8.4 <6.0.0' 1026 + 963 1027 '@typescript-eslint/visitor-keys@8.50.0': 964 1028 resolution: {integrity: sha512-Xzmnb58+Db78gT/CCj/PVCvK+zxbnsw6F+O1oheYszJbBSdEjVhQi3C/Xttzxgi/GLmpvOggRs1RFpiJ8+c34Q==} 1029 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1030 + 1031 + '@typescript-eslint/visitor-keys@8.50.1': 1032 + resolution: {integrity: sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==} 965 1033 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 966 1034 967 1035 '@vitest/browser-playwright@4.0.16': ··· 1066 1134 balanced-match@1.0.2: 1067 1135 resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 1068 1136 1069 - baseline-browser-mapping@2.9.11: 1070 - resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} 1071 - hasBin: true 1072 - 1073 1137 bidi-js@1.0.3: 1074 1138 resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} 1075 1139 ··· 1082 1146 brace-expansion@2.0.2: 1083 1147 resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} 1084 1148 1085 - browserslist@4.28.1: 1086 - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} 1087 - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 1088 - hasBin: true 1089 - 1090 - builtin-modules@5.0.0: 1091 - resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} 1092 - engines: {node: '>=18.20'} 1093 - 1094 1149 bumpp@10.3.2: 1095 1150 resolution: {integrity: sha512-yUUkVx5zpTywLNX97MlrqtpanI7eMMwFwLntWR2EBVDw3/Pm3aRIzCoDEGHATLIiHK9PuJC7xWI4XNWqXItSPg==} 1096 1151 engines: {node: '>=18'} ··· 1112 1167 resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 1113 1168 engines: {node: '>=6'} 1114 1169 1115 - caniuse-lite@1.0.30001761: 1116 - resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==} 1117 - 1118 1170 chai@6.2.1: 1119 1171 resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} 1120 1172 engines: {node: '>=18'} ··· 1123 1175 resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 1124 1176 engines: {node: '>=10'} 1125 1177 1126 - change-case@5.4.4: 1127 - resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} 1128 - 1129 1178 chokidar@4.0.3: 1130 1179 resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 1131 1180 engines: {node: '>= 14.16.0'} ··· 1133 1182 chokidar@5.0.0: 1134 1183 resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} 1135 1184 engines: {node: '>= 20.19.0'} 1136 - 1137 - ci-info@4.3.1: 1138 - resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} 1139 - engines: {node: '>=8'} 1140 1185 1141 1186 citty@0.1.6: 1142 1187 resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} 1143 - 1144 - clean-regexp@1.0.0: 1145 - resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} 1146 - engines: {node: '>=4'} 1147 1188 1148 1189 clsx@2.1.1: 1149 1190 resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} ··· 1169 1210 cookie@0.6.0: 1170 1211 resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} 1171 1212 engines: {node: '>= 0.6'} 1172 - 1173 - core-js-compat@3.47.0: 1174 - resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} 1175 1213 1176 1214 cross-spawn@7.0.6: 1177 1215 resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} ··· 1242 1280 oxc-resolver: 1243 1281 optional: true 1244 1282 1245 - electron-to-chromium@1.5.267: 1246 - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} 1247 - 1248 1283 empathic@2.0.0: 1249 1284 resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} 1250 1285 engines: {node: '>=14'} ··· 1265 1300 resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 1266 1301 engines: {node: '>=6'} 1267 1302 1268 - escape-string-regexp@1.0.5: 1269 - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 1270 - engines: {node: '>=0.8.0'} 1271 - 1272 1303 escape-string-regexp@4.0.0: 1273 1304 resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 1274 1305 engines: {node: '>=10'} ··· 1289 1320 svelte: 1290 1321 optional: true 1291 1322 1292 - eslint-plugin-unicorn@62.0.0: 1293 - resolution: {integrity: sha512-HIlIkGLkvf29YEiS/ImuDZQbP12gWyx5i3C6XrRxMvVdqMroCI9qoVYCoIl17ChN+U89pn9sVwLxhIWj5nEc7g==} 1294 - engines: {node: ^20.10.0 || >=21.0.0} 1295 - peerDependencies: 1296 - eslint: '>=9.38.0' 1297 - 1298 1323 eslint-scope@8.4.0: 1299 1324 resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} 1300 1325 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} ··· 1378 1403 file-entry-cache@8.0.0: 1379 1404 resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 1380 1405 engines: {node: '>=16.0.0'} 1381 - 1382 - find-up-simple@1.0.1: 1383 - resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} 1384 - engines: {node: '>=18'} 1385 1406 1386 1407 find-up@5.0.0: 1387 1408 resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} ··· 1469 1490 resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1470 1491 engines: {node: '>=0.8.19'} 1471 1492 1472 - indent-string@5.0.0: 1473 - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} 1474 - engines: {node: '>=12'} 1475 - 1476 - is-builtin-module@5.0.0: 1477 - resolution: {integrity: sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==} 1478 - engines: {node: '>=18.20'} 1479 - 1480 1493 is-extglob@2.1.1: 1481 1494 resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1482 1495 engines: {node: '>=0.10.0'} ··· 1621 1634 node-fetch-native@1.6.7: 1622 1635 resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} 1623 1636 1624 - node-releases@2.0.27: 1625 - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} 1626 - 1627 1637 nypm@0.6.2: 1628 1638 resolution: {integrity: sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==} 1629 1639 engines: {node: ^14.16.0 || >=16.10.0} ··· 1698 1708 engines: {node: '>=18'} 1699 1709 hasBin: true 1700 1710 1701 - pluralize@8.0.0: 1702 - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} 1703 - engines: {node: '>=4'} 1704 - 1705 1711 pngjs@7.0.0: 1706 1712 resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} 1707 1713 engines: {node: '>=14.19.0'} ··· 1771 1777 resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} 1772 1778 engines: {node: '>= 20.19.0'} 1773 1779 1774 - regexp-tree@0.1.27: 1775 - resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} 1776 - hasBin: true 1777 - 1778 - regjsparser@0.13.0: 1779 - resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} 1780 - hasBin: true 1781 - 1782 1780 require-from-string@2.0.2: 1783 1781 resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 1784 1782 engines: {node: '>=0.10.0'} ··· 1865 1863 1866 1864 std-env@3.10.0: 1867 1865 resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} 1868 - 1869 - strip-indent@4.1.1: 1870 - resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} 1871 - engines: {node: '>=12'} 1872 1866 1873 1867 strip-json-comments@3.1.1: 1874 1868 resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} ··· 1985 1979 eslint: ^8.57.0 || ^9.0.0 1986 1980 typescript: '>=4.8.4 <6.0.0' 1987 1981 1982 + typescript-eslint@8.50.1: 1983 + resolution: {integrity: sha512-ytTHO+SoYSbhAH9CrYnMhiLx8To6PSSvqnvXyPUgPETCvB6eBKmTI9w6XMPS3HsBRGkwTVBX+urA8dYQx6bHfQ==} 1984 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1985 + peerDependencies: 1986 + eslint: ^8.57.0 || ^9.0.0 1987 + typescript: '>=4.8.4 <6.0.0' 1988 + 1988 1989 typescript@5.9.3: 1989 1990 resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} 1990 1991 engines: {node: '>=14.17'} ··· 2005 2006 peerDependenciesMeta: 2006 2007 synckit: 2007 2008 optional: true 2008 - 2009 - update-browserslist-db@1.2.3: 2010 - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} 2011 - hasBin: true 2012 - peerDependencies: 2013 - browserslist: '>= 4.21.0' 2014 2009 2015 2010 uri-js@4.4.1: 2016 2011 resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} ··· 2743 2738 transitivePeerDependencies: 2744 2739 - supports-color 2745 2740 2741 + '@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 2742 + dependencies: 2743 + '@eslint-community/regexpp': 4.12.2 2744 + '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 2745 + '@typescript-eslint/scope-manager': 8.50.1 2746 + '@typescript-eslint/type-utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 2747 + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 2748 + '@typescript-eslint/visitor-keys': 8.50.1 2749 + eslint: 9.39.2(jiti@2.6.1) 2750 + ignore: 7.0.5 2751 + natural-compare: 1.4.0 2752 + ts-api-utils: 2.1.0(typescript@5.9.3) 2753 + typescript: 5.9.3 2754 + transitivePeerDependencies: 2755 + - supports-color 2756 + 2746 2757 '@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 2747 2758 dependencies: 2748 2759 '@typescript-eslint/scope-manager': 8.50.0 ··· 2755 2766 transitivePeerDependencies: 2756 2767 - supports-color 2757 2768 2769 + '@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 2770 + dependencies: 2771 + '@typescript-eslint/scope-manager': 8.50.1 2772 + '@typescript-eslint/types': 8.50.1 2773 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) 2774 + '@typescript-eslint/visitor-keys': 8.50.1 2775 + debug: 4.4.3 2776 + eslint: 9.39.2(jiti@2.6.1) 2777 + typescript: 5.9.3 2778 + transitivePeerDependencies: 2779 + - supports-color 2780 + 2758 2781 '@typescript-eslint/project-service@8.50.0(typescript@5.9.3)': 2759 2782 dependencies: 2760 - '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@5.9.3) 2761 - '@typescript-eslint/types': 8.50.0 2783 + '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) 2784 + '@typescript-eslint/types': 8.50.1 2785 + debug: 4.4.3 2786 + typescript: 5.9.3 2787 + transitivePeerDependencies: 2788 + - supports-color 2789 + 2790 + '@typescript-eslint/project-service@8.50.1(typescript@5.9.3)': 2791 + dependencies: 2792 + '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) 2793 + '@typescript-eslint/types': 8.50.1 2762 2794 debug: 4.4.3 2763 2795 typescript: 5.9.3 2764 2796 transitivePeerDependencies: ··· 2768 2800 dependencies: 2769 2801 '@typescript-eslint/types': 8.50.0 2770 2802 '@typescript-eslint/visitor-keys': 8.50.0 2803 + 2804 + '@typescript-eslint/scope-manager@8.50.1': 2805 + dependencies: 2806 + '@typescript-eslint/types': 8.50.1 2807 + '@typescript-eslint/visitor-keys': 8.50.1 2771 2808 2772 2809 '@typescript-eslint/tsconfig-utils@8.50.0(typescript@5.9.3)': 2773 2810 dependencies: 2774 2811 typescript: 5.9.3 2775 2812 2813 + '@typescript-eslint/tsconfig-utils@8.50.1(typescript@5.9.3)': 2814 + dependencies: 2815 + typescript: 5.9.3 2816 + 2776 2817 '@typescript-eslint/type-utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 2777 2818 dependencies: 2778 2819 '@typescript-eslint/types': 8.50.0 ··· 2785 2826 transitivePeerDependencies: 2786 2827 - supports-color 2787 2828 2829 + '@typescript-eslint/type-utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 2830 + dependencies: 2831 + '@typescript-eslint/types': 8.50.1 2832 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) 2833 + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 2834 + debug: 4.4.3 2835 + eslint: 9.39.2(jiti@2.6.1) 2836 + ts-api-utils: 2.1.0(typescript@5.9.3) 2837 + typescript: 5.9.3 2838 + transitivePeerDependencies: 2839 + - supports-color 2840 + 2788 2841 '@typescript-eslint/types@8.50.0': {} 2842 + 2843 + '@typescript-eslint/types@8.50.1': {} 2789 2844 2790 2845 '@typescript-eslint/typescript-estree@8.50.0(typescript@5.9.3)': 2791 2846 dependencies: ··· 2802 2857 transitivePeerDependencies: 2803 2858 - supports-color 2804 2859 2860 + '@typescript-eslint/typescript-estree@8.50.1(typescript@5.9.3)': 2861 + dependencies: 2862 + '@typescript-eslint/project-service': 8.50.1(typescript@5.9.3) 2863 + '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) 2864 + '@typescript-eslint/types': 8.50.1 2865 + '@typescript-eslint/visitor-keys': 8.50.1 2866 + debug: 4.4.3 2867 + minimatch: 9.0.5 2868 + semver: 7.7.3 2869 + tinyglobby: 0.2.15 2870 + ts-api-utils: 2.1.0(typescript@5.9.3) 2871 + typescript: 5.9.3 2872 + transitivePeerDependencies: 2873 + - supports-color 2874 + 2805 2875 '@typescript-eslint/utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 2806 2876 dependencies: 2807 2877 '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) ··· 2813 2883 transitivePeerDependencies: 2814 2884 - supports-color 2815 2885 2886 + '@typescript-eslint/utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': 2887 + dependencies: 2888 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) 2889 + '@typescript-eslint/scope-manager': 8.50.1 2890 + '@typescript-eslint/types': 8.50.1 2891 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) 2892 + eslint: 9.39.2(jiti@2.6.1) 2893 + typescript: 5.9.3 2894 + transitivePeerDependencies: 2895 + - supports-color 2896 + 2816 2897 '@typescript-eslint/visitor-keys@8.50.0': 2817 2898 dependencies: 2818 2899 '@typescript-eslint/types': 8.50.0 2819 2900 eslint-visitor-keys: 4.2.1 2820 2901 2902 + '@typescript-eslint/visitor-keys@8.50.1': 2903 + dependencies: 2904 + '@typescript-eslint/types': 8.50.1 2905 + eslint-visitor-keys: 4.2.1 2906 + 2821 2907 '@vitest/browser-playwright@4.0.16(playwright@1.57.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(yaml@2.8.2))(vitest@4.0.16)': 2822 2908 dependencies: 2823 2909 '@vitest/browser': 4.0.16(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(yaml@2.8.2))(vitest@4.0.16) ··· 2990 3076 2991 3077 balanced-match@1.0.2: {} 2992 3078 2993 - baseline-browser-mapping@2.9.11: {} 2994 - 2995 3079 bidi-js@1.0.3: 2996 3080 dependencies: 2997 3081 require-from-string: 2.0.2 ··· 3007 3091 dependencies: 3008 3092 balanced-match: 1.0.2 3009 3093 3010 - browserslist@4.28.1: 3011 - dependencies: 3012 - baseline-browser-mapping: 2.9.11 3013 - caniuse-lite: 1.0.30001761 3014 - electron-to-chromium: 1.5.267 3015 - node-releases: 2.0.27 3016 - update-browserslist-db: 1.2.3(browserslist@4.28.1) 3017 - 3018 - builtin-modules@5.0.0: {} 3019 - 3020 3094 bumpp@10.3.2(magicast@0.5.1): 3021 3095 dependencies: 3022 3096 ansis: 4.2.0 ··· 3054 3128 3055 3129 callsites@3.1.0: {} 3056 3130 3057 - caniuse-lite@1.0.30001761: {} 3058 - 3059 3131 chai@6.2.1: {} 3060 3132 3061 3133 chalk@4.1.2: 3062 3134 dependencies: 3063 3135 ansi-styles: 4.3.0 3064 3136 supports-color: 7.2.0 3065 - 3066 - change-case@5.4.4: {} 3067 3137 3068 3138 chokidar@4.0.3: 3069 3139 dependencies: ··· 3073 3143 dependencies: 3074 3144 readdirp: 5.0.0 3075 3145 3076 - ci-info@4.3.1: {} 3077 - 3078 3146 citty@0.1.6: 3079 3147 dependencies: 3080 3148 consola: 3.4.2 3081 3149 3082 - clean-regexp@1.0.0: 3083 - dependencies: 3084 - escape-string-regexp: 1.0.5 3085 - 3086 3150 clsx@2.1.1: {} 3087 3151 3088 3152 color-convert@2.0.1: ··· 3098 3162 consola@3.4.2: {} 3099 3163 3100 3164 cookie@0.6.0: {} 3101 - 3102 - core-js-compat@3.47.0: 3103 - dependencies: 3104 - browserslist: 4.28.1 3105 3165 3106 3166 cross-spawn@7.0.6: 3107 3167 dependencies: ··· 3161 3221 3162 3222 dts-resolver@2.1.3: {} 3163 3223 3164 - electron-to-chromium@1.5.267: {} 3165 - 3166 3224 empathic@2.0.0: {} 3167 3225 3168 3226 entities@6.0.1: {} ··· 3200 3258 3201 3259 escalade@3.2.0: {} 3202 3260 3203 - escape-string-regexp@1.0.5: {} 3204 - 3205 3261 escape-string-regexp@4.0.0: {} 3206 3262 3207 3263 eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)): ··· 3226 3282 transitivePeerDependencies: 3227 3283 - ts-node 3228 3284 3229 - eslint-plugin-unicorn@62.0.0(eslint@9.39.2(jiti@2.6.1)): 3230 - dependencies: 3231 - '@babel/helper-validator-identifier': 7.28.5 3232 - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) 3233 - '@eslint/plugin-kit': 0.4.1 3234 - change-case: 5.4.4 3235 - ci-info: 4.3.1 3236 - clean-regexp: 1.0.0 3237 - core-js-compat: 3.47.0 3238 - eslint: 9.39.2(jiti@2.6.1) 3239 - esquery: 1.6.0 3240 - find-up-simple: 1.0.1 3241 - globals: 16.5.0 3242 - indent-string: 5.0.0 3243 - is-builtin-module: 5.0.0 3244 - jsesc: 3.1.0 3245 - pluralize: 8.0.0 3246 - regexp-tree: 0.1.27 3247 - regjsparser: 0.13.0 3248 - semver: 7.7.3 3249 - strip-indent: 4.1.1 3250 - 3251 3285 eslint-scope@8.4.0: 3252 3286 dependencies: 3253 3287 esrecurse: 4.3.0 ··· 3346 3380 dependencies: 3347 3381 flat-cache: 4.0.1 3348 3382 3349 - find-up-simple@1.0.1: {} 3350 - 3351 3383 find-up@5.0.0: 3352 3384 dependencies: 3353 3385 locate-path: 6.0.0 ··· 3428 3460 3429 3461 imurmurhash@0.1.4: {} 3430 3462 3431 - indent-string@5.0.0: {} 3432 - 3433 - is-builtin-module@5.0.0: 3434 - dependencies: 3435 - builtin-modules: 5.0.0 3436 - 3437 3463 is-extglob@2.1.1: {} 3438 3464 3439 3465 is-glob@4.0.3: ··· 3575 3601 3576 3602 node-fetch-native@1.6.7: {} 3577 3603 3578 - node-releases@2.0.27: {} 3579 - 3580 3604 nypm@0.6.2: 3581 3605 dependencies: 3582 3606 citty: 0.1.6 ··· 3650 3674 optionalDependencies: 3651 3675 fsevents: 2.3.2 3652 3676 3653 - pluralize@8.0.0: {} 3654 - 3655 3677 pngjs@7.0.0: {} 3656 3678 3657 3679 postcss-load-config@3.1.4(postcss@8.5.6): ··· 3702 3724 3703 3725 readdirp@5.0.0: {} 3704 3726 3705 - regexp-tree@0.1.27: {} 3706 - 3707 - regjsparser@0.13.0: 3708 - dependencies: 3709 - jsesc: 3.1.0 3710 - 3711 3727 require-from-string@2.0.2: {} 3712 3728 3713 3729 resolve-from@4.0.0: {} ··· 3814 3830 stackback@0.0.2: {} 3815 3831 3816 3832 std-env@3.10.0: {} 3817 - 3818 - strip-indent@4.1.1: {} 3819 3833 3820 3834 strip-json-comments@3.1.1: {} 3821 3835 ··· 3943 3957 transitivePeerDependencies: 3944 3958 - supports-color 3945 3959 3960 + typescript-eslint@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): 3961 + dependencies: 3962 + '@typescript-eslint/eslint-plugin': 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 3963 + '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 3964 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) 3965 + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 3966 + eslint: 9.39.2(jiti@2.6.1) 3967 + typescript: 5.9.3 3968 + transitivePeerDependencies: 3969 + - supports-color 3970 + 3946 3971 typescript@5.9.3: {} 3947 3972 3948 3973 unconfig-core@7.4.2: ··· 3955 3980 unrun@0.2.20: 3956 3981 dependencies: 3957 3982 rolldown: 1.0.0-beta.55 3958 - 3959 - update-browserslist-db@1.2.3(browserslist@4.28.1): 3960 - dependencies: 3961 - browserslist: 4.28.1 3962 - escalade: 3.2.0 3963 - picocolors: 1.1.1 3964 3983 3965 3984 uri-js@4.4.1: 3966 3985 dependencies: