From 91bc4e2d24ca45948e14b5b499219b8349b9a935 Mon Sep 17 00:00:00 2001 From: "ctcx@163.com" Date: Wed, 20 May 2026 07:57:01 +0800 Subject: [PATCH] feat: add iframe embed API --- .gitignore | 3 +- index.ts | 2 + lib/converter.ts | 18 +- lib/document-converter.ts | 29 +- lib/document-types.ts | 3 + lib/document.ts | 18 +- lib/embed-api.ts | 214 ++++ lib/onlyoffice-editor.ts | 243 ++++- pnpm-lock.yaml | 1730 ++++++++++++++++--------------- public/embed-demo.html | 344 ++++++ public/sdkjs/cell/sdk-all.js | 2 +- public/sdkjs/common/AllFonts.js | 10 + readme.md | 217 ++++ styles/base.css | 6 + types/editor.d.ts | 12 + 15 files changed, 1982 insertions(+), 869 deletions(-) create mode 100644 lib/embed-api.ts create mode 100644 public/embed-demo.html diff --git a/.gitignore b/.gitignore index b7e76093..b4e71a05 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ cache # vite vite.config.ts.timestamp* config.ts.timestamp* -dist \ No newline at end of file +dist +public/fonts/__fallback__/ diff --git a/index.ts b/index.ts index b69d003d..9c30cefd 100644 --- a/index.ts +++ b/index.ts @@ -1,4 +1,5 @@ import { getAllQueryString } from 'ranuts/utils'; +import { initEmbedApi } from './lib/embed-api'; import { initEvents, setEventUICallbacks } from './lib/events'; import { onCreateNew, openDocumentFromUrl, setUICallbacks } from './lib/document'; import { @@ -25,6 +26,7 @@ declare global { // Initialize events initEvents(); +initEmbedApi(); // Set up UI callbacks to avoid circular dependency setUICallbacks({ diff --git a/lib/converter.ts b/lib/converter.ts index a4c0823a..f0de9466 100644 --- a/lib/converter.ts +++ b/lib/converter.ts @@ -2,7 +2,7 @@ import { getExtensions } from 'ranuts/utils'; import { g_sEmpty_bin } from './empty_bin'; import { t } from './i18n'; import { X2TConverter } from './document-converter'; -import { createEditorInstance, loadEditorApi, setConverterCallback } from './onlyoffice-editor'; +import { createEditorInstance, loadEditorApi, setConverterCallbacks } from './onlyoffice-editor'; import { getDocumentType } from './document-utils'; import type { BinConversionResult, ConversionResult, EmscriptenModule } from './document-types'; @@ -28,6 +28,11 @@ const x2tConverter = new X2TConverter(); export const loadScript = (): Promise => x2tConverter.loadScript(); export const initX2T = (): Promise => x2tConverter.initialize(); export const convertDocument = (file: File): Promise => x2tConverter.convertDocument(file); +export const convertBinToDocument = ( + bin: Uint8Array, + fileName: string, + targetExt?: string, +): Promise => x2tConverter.convertBinToDocument(bin, fileName, targetExt); export const convertBinToDocumentAndDownload = ( bin: Uint8Array, fileName: string, @@ -38,17 +43,21 @@ export const convertBinToDocumentAndDownload = ( export { createEditorInstance, loadEditorApi }; // Set up converter callback for editor -setConverterCallback(convertBinToDocumentAndDownload); +setConverterCallbacks({ + convert: convertBinToDocument, + convertAndDownload: convertBinToDocumentAndDownload, +}); // Merged file operation method export async function handleDocumentOperation(options: { isNew: boolean; fileName: string; file?: File; + readonly?: boolean; }): Promise { try { - const { isNew, fileName, file } = options; - const fileType = getExtensions(file?.type || '')[0] || fileName.split('.').pop() || ''; + const { isNew, fileName, file, readonly = false } = options; + const fileType = fileName.split('.').pop() || getExtensions(file?.type || '')[0] || ''; const _docType = getDocumentType(fileType); // Get document content @@ -77,6 +86,7 @@ export async function handleDocumentOperation(options: { fileType, binData: documentData.bin, media: documentData.media, + readonly, }); } catch (error: any) { console.error(`${t('documentOperationFailed')}`, error); diff --git a/lib/document-converter.ts b/lib/document-converter.ts index c4c0e4ba..e26c1130 100644 --- a/lib/document-converter.ts +++ b/lib/document-converter.ts @@ -299,7 +299,7 @@ export class X2TConverter { await this.initialize(); const fileName = file.name; - const fileExt = getExtensions(file?.type)[0] || fileName.split('.').pop() || ''; + const fileExt = fileName.split('.').pop() || getExtensions(file?.type)[0] || ''; const documentType = this.getDocumentType(fileExt); try { @@ -436,9 +436,9 @@ export class X2TConverter { } /** - * Convert bin format to specified format and download + * Convert bin format to specified document format. */ - async convertBinToDocumentAndDownload( + async convertBinToDocument( bin: Uint8Array, originalFileName: string, targetExt = 'DOCX', @@ -483,9 +483,6 @@ export class X2TConverter { csvArray.set(csvBOM, 0); csvArray.set(csvTextBytes, csvBOM.length); - // Save CSV file - await this.saveWithFileSystemAPI(csvArray, outputFileName); - return { fileName: outputFileName, data: csvArray, @@ -519,10 +516,6 @@ export class X2TConverter { // Ensure result is Uint8Array type const resultArray = result instanceof Uint8Array ? result : new Uint8Array(result as ArrayBuffer); - // Download file - // TODO: Improve print functionality - await this.saveWithFileSystemAPI(resultArray, outputFileName); - return { fileName: outputFileName, data: result, @@ -532,6 +525,22 @@ export class X2TConverter { } } + /** + * Convert bin format to specified format and save it locally. + */ + async convertBinToDocumentAndDownload( + bin: Uint8Array, + originalFileName: string, + targetExt = 'DOCX', + ): Promise { + const result = await this.convertBinToDocument(bin, originalFileName, targetExt); + const data = result.data instanceof Uint8Array ? result.data : new Uint8Array(result.data as ArrayBuffer); + + // TODO: Improve print functionality + await this.saveWithFileSystemAPI(data, result.fileName); + return result; + } + /** * Download file */ diff --git a/lib/document-types.ts b/lib/document-types.ts index 3cd3c4a3..6173ad57 100644 --- a/lib/document-types.ts +++ b/lib/document-types.ts @@ -55,8 +55,11 @@ declare global { buf?: ArrayBuffer; success?: boolean; error?: string; + enabled?: boolean; + message?: string; }; }) => void; + downloadAs?: (data?: string) => void; destroyEditor: () => void; }; } diff --git a/lib/document.ts b/lib/document.ts index 8c4e5814..ed1705b5 100644 --- a/lib/document.ts +++ b/lib/document.ts @@ -116,7 +116,14 @@ export const onOpenDocument = (): void => { fileInput.click(); }; -export const openDocumentFromUrl = async (url: string, fileName?: string): Promise => { +export const openDocumentFromUrl = async ( + url: string, + fileName?: string, + options?: { + readonly?: boolean; + fetchOptions?: RequestInit; + }, +): Promise => { const { removeLoading } = showLoading(); try { if (hideControlPanelFn) { @@ -126,7 +133,7 @@ export const openDocumentFromUrl = async (url: string, fileName?: string): Promi // Fetch the file from URL console.log('Fetching document from URL:', url); // eslint-disable-next-line n/no-unsupported-features/node-builtins - const response = await fetch(url); + const response = await fetch(url, options?.fetchOptions); if (!response.ok) { throw new Error(`Failed to fetch document: ${response.status} ${response.statusText}`); @@ -172,7 +179,12 @@ export const openDocumentFromUrl = async (url: string, fileName?: string): Promi // Initialize and open document await initX2T(); const { fileName: docFileName, file: fileBlob } = getDocmentObj(); - await handleDocumentOperation({ file: fileBlob, fileName: docFileName, isNew: !fileBlob }); + await handleDocumentOperation({ + file: fileBlob, + fileName: docFileName, + isNew: !fileBlob, + readonly: options?.readonly, + }); // Show menu guide after document is loaded if (showMenuGuideFn) { diff --git a/lib/embed-api.ts b/lib/embed-api.ts new file mode 100644 index 00000000..c0bf2645 --- /dev/null +++ b/lib/embed-api.ts @@ -0,0 +1,214 @@ +import { setDocmentObj } from '../store'; +import { handleDocumentOperation, loadEditorApi } from './converter'; +import { openDocumentFromUrl } from './document'; +import { getReadonlyMode, requestSaveDocument, setReadonlyMode } from './onlyoffice-editor'; + +type EmbedMessageType = + | 'document:open' + | 'document:open-url' + | 'document:open-file' + | 'document:open-buffer' + | 'document:set-readonly' + | 'document:save' + | 'document:get-state'; + +type EmbedMessage = { + id?: string; + type?: EmbedMessageType; + payload?: Record; +}; + +type EmbedResponsePayload = Record; + +const EMBED_QUERY_KEYS = ['embed', 'embedded']; + +let initialized = false; +let parentOrigin = '*'; +let isEmbedMode = false; + +function getQueryValue(key: string): string | null { + return new URLSearchParams(window.location.search).get(key); +} + +function detectEmbedMode(): boolean { + if (window.parent !== window) { + return true; + } + + return EMBED_QUERY_KEYS.some((key) => { + const value = getQueryValue(key); + return value === '' || value === '1' || value === 'true'; + }); +} + +function normalizeTargetOrigin(origin: string): string { + return origin && origin !== 'null' ? origin : '*'; +} + +function shouldAcceptMessage(event: MessageEvent): boolean { + const allowedOrigin = getQueryValue('embedOrigin'); + if (!allowedOrigin) { + return true; + } + + return event.origin === allowedOrigin; +} + +function postToParent(type: string, payload: EmbedResponsePayload = {}, id?: string): void { + if (!isEmbedMode) { + return; + } + + window.parent.postMessage( + { + id, + type, + payload, + }, + parentOrigin, + ); +} + +function makeFileFromPayload(payload: Record): File { + const fileName = payload.fileName || payload.name || 'document.xlsx'; + + if (payload.file instanceof File) { + return payload.file; + } + + if (payload.blob instanceof Blob) { + return new File([payload.blob], fileName, { + type: payload.blob.type || payload.mimeType || 'application/octet-stream', + }); + } + + const buffer = payload.buffer || payload.arrayBuffer || payload.bytes || payload.data; + if (buffer instanceof ArrayBuffer) { + return new File([buffer], fileName, { + type: payload.mimeType || 'application/octet-stream', + }); + } + + if (buffer instanceof Uint8Array) { + const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer; + return new File([arrayBuffer], fileName, { + type: payload.mimeType || 'application/octet-stream', + }); + } + + throw new Error('document:open requires url, file, blob, buffer, arrayBuffer, bytes, or data'); +} + +async function openFile(file: File, readonly = false): Promise { + await loadEditorApi(); + setDocmentObj({ + fileName: file.name, + file, + url: URL.createObjectURL(file), + }); + await handleDocumentOperation({ + fileName: file.name, + file, + isNew: false, + readonly, + }); +} + +async function handleOpen(payload: Record): Promise { + const readonly = Boolean(payload.readonly); + + if (payload.url) { + await openDocumentFromUrl(String(payload.url), payload.fileName, { + readonly, + fetchOptions: payload.fetchOptions, + }); + return; + } + + await openFile(makeFileFromPayload(payload), readonly); +} + +async function handleMessage(event: MessageEvent): Promise { + const message = event.data as EmbedMessage; + if (!message || typeof message !== 'object' || !message.type?.startsWith('document:')) { + return; + } + + if (!shouldAcceptMessage(event)) { + return; + } + + parentOrigin = normalizeTargetOrigin(event.origin); + const payload = message.payload || {}; + + try { + switch (message.type) { + case 'document:open': + case 'document:open-url': + case 'document:open-file': + case 'document:open-buffer': + await handleOpen(payload); + postToParent('document:opened', { readonly: getReadonlyMode() }, message.id); + break; + + case 'document:set-readonly': + setReadonlyMode(Boolean(payload.readonly)); + postToParent('document:readonly-changed', { readonly: getReadonlyMode() }, message.id); + break; + + case 'document:save': { + const file = await requestSaveDocument(payload.targetExt || 'XLSX', { + returnOriginalOnTimeout: Boolean(payload.returnOriginalOnTimeout), + }); + postToParent( + 'document:saved', + { + file, + fileName: file.name, + mimeType: file.type, + size: file.size, + }, + message.id, + ); + break; + } + + case 'document:get-state': + postToParent('document:state', { readonly: getReadonlyMode(), hasDocument: Boolean(window.editor) }, message.id); + break; + + default: + break; + } + } catch (error) { + postToParent( + 'document:error', + { + message: error instanceof Error ? error.message : String(error), + }, + message.id, + ); + } +} + +export function initEmbedApi(): void { + if (initialized) { + return; + } + + initialized = true; + isEmbedMode = detectEmbedMode(); + + if (!isEmbedMode) { + return; + } + + document.body.classList.add('embed-mode'); + window.addEventListener('message', (event) => { + void handleMessage(event); + }); + + window.addEventListener('load', () => { + postToParent('document:ready'); + }); +} diff --git a/lib/onlyoffice-editor.ts b/lib/onlyoffice-editor.ts index 0040f961..14338368 100644 --- a/lib/onlyoffice-editor.ts +++ b/lib/onlyoffice-editor.ts @@ -3,18 +3,22 @@ import { createObjectURL } from 'ranuts/utils'; import { getDocmentObj } from '../store'; import { getOnlyOfficeLang, t } from './i18n'; import { c_oAscFileType2 } from './file-types'; -import type { SaveEvent } from './document-types'; +import type { BinConversionResult, SaveEvent } from './document-types'; import { getMimeTypeFromExtension } from './document-utils'; // Import converter function to avoid circular dependency +let convertBinToDocumentFn: ((bin: Uint8Array, fileName: string, targetExt?: string) => Promise) | null = + null; let convertBinToDocumentAndDownloadFn: - | ((bin: Uint8Array, fileName: string, targetExt?: string) => Promise) + | ((bin: Uint8Array, fileName: string, targetExt?: string) => Promise) | null = null; -export function setConverterCallback( - callback: (bin: Uint8Array, fileName: string, targetExt?: string) => Promise, -): void { - convertBinToDocumentAndDownloadFn = callback; +export function setConverterCallbacks(callbacks: { + convert: (bin: Uint8Array, fileName: string, targetExt?: string) => Promise; + convertAndDownload: (bin: Uint8Array, fileName: string, targetExt?: string) => Promise; +}): void { + convertBinToDocumentFn = callbacks.convert; + convertBinToDocumentAndDownloadFn = callbacks.convertAndDownload; } // Global media mapping object @@ -22,6 +26,90 @@ const media: Record = {}; // Editor operation queue to prevent concurrent operations let editorOperationQueue: Promise = Promise.resolve(); +let isReadonlyMode = false; + +type EmbeddedSaveRequest = { + targetExt?: string; + resolve: (file: File) => void; + reject: (error: Error) => void; + timeoutId: number; + fallbackId: number; + settled: boolean; +}; + +let embeddedSaveRequest: EmbeddedSaveRequest | null = null; + +function getSavedFileMimeType(fileName: string): string { + const extension = fileName.split('.').pop()?.toLowerCase() || ''; + const mimeMap: Record = { + docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + doc: 'application/msword', + xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + xls: 'application/vnd.ms-excel', + csv: 'text/csv', + pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + ppt: 'application/vnd.ms-powerpoint', + pdf: 'application/pdf', + }; + return mimeMap[extension] || 'application/octet-stream'; +} + +function getNormalizedFile(file: File): File { + const mimeType = !file.type || file.type === 'application/octet-stream' ? getSavedFileMimeType(file.name) : file.type; + return new File([file], file.name, { type: mimeType }); +} + +function toUint8Array(data: BlobPart): Uint8Array { + if (data instanceof Uint8Array) { + return data; + } + if (data instanceof ArrayBuffer) { + return new Uint8Array(data); + } + if (ArrayBuffer.isView(data)) { + const arrayBuffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer; + return new Uint8Array(arrayBuffer); + } + throw new Error('Unsupported saved data type'); +} + +function getFileExtension(fileName: string): string { + return fileName.split('.').pop()?.toUpperCase() || ''; +} + +function isEmbedMode(): boolean { + if (typeof window === 'undefined') { + return false; + } + + const params = new URLSearchParams(window.location.search); + const embed = params.get('embed') || params.get('embedded'); + return window.parent !== window || embed === '' || embed === '1' || embed === 'true'; +} + +function resolveEmbeddedSaveRequest(request: EmbeddedSaveRequest, file: File): void { + if (request.settled) { + return; + } + request.settled = true; + request.resolve(file); +} + +function rejectEmbeddedSaveRequest(request: EmbeddedSaveRequest, error: Error): void { + if (request.settled) { + return; + } + request.settled = true; + request.reject(error); +} + +function cleanupEmbeddedSaveRequest(request: EmbeddedSaveRequest): void { + window.clearTimeout(request.timeoutId); + window.clearTimeout(request.fallbackId); + if (embeddedSaveRequest === request) { + embeddedSaveRequest = null; + } +} /** * Queue editor operations to prevent concurrent editor creation/destruction @@ -166,8 +254,26 @@ async function handleSaveDocument(event: SaveEvent) { console.log(`Saving as ${targetFormat} format (original file: ${fileName})`); } - // Create download - if (convertBinToDocumentAndDownloadFn) { + if (embeddedSaveRequest) { + if (!convertBinToDocumentFn) { + throw new Error('Converter callback not set'); + } + + const request = embeddedSaveRequest; + cleanupEmbeddedSaveRequest(request); + + try { + const result = await convertBinToDocumentFn(data.data, fileName, request.targetExt || targetFormat); + const bytes = toUint8Array(result.data); + const file = new File([bytes as BlobPart], result.fileName, { type: getSavedFileMimeType(result.fileName) }); + resolveEmbeddedSaveRequest(request, file); + } catch (error) { + rejectEmbeddedSaveRequest(request, error instanceof Error ? error : new Error(String(error))); + throw error; + } + } else if (isEmbedMode()) { + console.warn('Local save is disabled in iframe embed mode. Use document:save from the parent page.'); + } else if (convertBinToDocumentAndDownloadFn) { await convertBinToDocumentAndDownloadFn(data.data, fileName, targetFormat); } else { throw new Error('Converter callback not set'); @@ -181,15 +287,49 @@ async function handleSaveDocument(event: SaveEvent) { }); } +async function handleDownloadAs(event: { data?: { url?: string; fileType?: string } }): Promise { + if (!embeddedSaveRequest) { + console.warn('Local download is disabled in iframe embed mode. Use document:save from the parent page.'); + return; + } + + const request = embeddedSaveRequest; + cleanupEmbeddedSaveRequest(request); + + try { + const url = event.data?.url; + if (!url) { + throw new Error('Download URL is empty'); + } + + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch exported file: ${response.status} ${response.statusText}`); + } + + const blob = await response.blob(); + const { fileName } = getDocmentObj() || {}; + const baseName = (fileName || 'document').replace(/\.[^/.]+$/, ''); + const ext = (request.targetExt || event.data?.fileType || 'XLSX').toLowerCase(); + const savedFileName = `${baseName}.${ext}`; + const file = new File([blob], savedFileName, { type: blob.type || getSavedFileMimeType(savedFileName) }); + resolveEmbeddedSaveRequest(request, file); + } catch (error) { + rejectEmbeddedSaveRequest(request, error instanceof Error ? error : new Error(String(error))); + } +} + // Public editor creation method export function createEditorInstance(config: { fileName: string; fileType: string; binData: ArrayBuffer | string; media?: any; + readonly?: boolean; }): Promise { return queueEditorOperation(async () => { - const { fileName, fileType, binData, media: mediaUrls } = config; + const { fileName, fileType, binData, media: mediaUrls, readonly = false } = config; + isReadonlyMode = readonly; // Check if there's an existing editor that needs cleanup const hasExistingEditor = !!window.editor; @@ -240,7 +380,8 @@ export function createEditorInstance(config: { url: fileName, // Use file name as identifier fileType: fileType, permissions: { - edit: true, + edit: !readonly, + download: !readonly, chat: false, protect: false, }, @@ -285,6 +426,7 @@ export function createEditorInstance(config: { // but the actual save will be forced to CSV format in handleSaveDocument }, onSave: handleSaveDocument, + onDownloadAs: handleDownloadAs, // writeFile // TODO: writeFile - handle when pasting images from external sources writeFile: handleWriteFile, @@ -297,6 +439,87 @@ export function createEditorInstance(config: { }); } +export function setReadonlyMode(readonly: boolean): void { + isReadonlyMode = readonly; + window.editor?.sendCommand({ + command: 'processRightsChange', + data: { + enabled: !readonly, + message: readonly ? 'Readonly mode' : '', + } as any, + }); +} + +export function getReadonlyMode(): boolean { + return isReadonlyMode; +} + +export function requestSaveDocument( + targetExt = 'XLSX', + options: { + returnOriginalOnTimeout?: boolean; + } = {}, +): Promise { + if (!window.editor) { + return Promise.reject(new Error('No document is open')); + } + + if (isReadonlyMode) { + return Promise.reject(new Error('Current document is readonly')); + } + + if (embeddedSaveRequest) { + return Promise.reject(new Error('A save request is already in progress')); + } + + return new Promise((resolve, reject) => { + const normalizedTargetExt = targetExt.toUpperCase(); + + const fallbackId = window.setTimeout(() => { + if (!embeddedSaveRequest || embeddedSaveRequest.settled) { + return; + } + + const { file, fileName } = getDocmentObj() || {}; + const originalExt = getFileExtension(fileName || file?.name || ''); + + if (options.returnOriginalOnTimeout && file && originalExt === normalizedTargetExt) { + const request = embeddedSaveRequest; + cleanupEmbeddedSaveRequest(request); + resolveEmbeddedSaveRequest(request, getNormalizedFile(file)); + } + }, 8000); + + const timeoutId = window.setTimeout(() => { + if (!embeddedSaveRequest) { + return; + } + const request = embeddedSaveRequest; + cleanupEmbeddedSaveRequest(request); + rejectEmbeddedSaveRequest(request, new Error('Save request timed out before receiving edited file data')); + }, 60000); + + embeddedSaveRequest = { + targetExt: normalizedTargetExt, + resolve, + reject, + timeoutId, + fallbackId, + settled: false, + }; + + const editor = window.editor; + if (!editor || typeof editor.downloadAs !== 'function') { + const request = embeddedSaveRequest; + cleanupEmbeddedSaveRequest(request); + rejectEmbeddedSaveRequest(request, new Error('The current editor does not support downloadAs export')); + return; + } + + editor.downloadAs(normalizedTargetExt); + }); +} + export function loadEditorApi(): Promise { return new Promise((resolve, reject) => { // Check if already loaded diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 232b9001..c7b5cfe7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,471 +1,819 @@ -lockfileVersion: '9.0' +lockfileVersion: '6.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -importers: - - .: - dependencies: - '@khmyznikov/pwa-install': - specifier: ^0.6.3 - version: 0.6.3(@lit/react@1.0.8(@types/react@19.2.14))(@types/dom-chromium-installation-events@101.0.4)(@types/web-app-manifest@1.0.9)(lit@3.3.2) - ranui: - specifier: 0.1.10-alpha-27 - version: 0.1.10-alpha-27 - ranuts: - specifier: 0.1.0-alpha-23 - version: 0.1.0-alpha-23 - devDependencies: - '@tailwindcss/postcss': - specifier: ^4.1.18 - version: 4.1.18 - '@types/node': - specifier: ^25.0.5 - version: 25.0.5 - oxlint: - specifier: ^1.38.0 - version: 1.38.0 - postcss: - specifier: ^8.5.6 - version: 8.5.6 - prettier: - specifier: ^3.7.4 - version: 3.7.4 - tailwindcss: - specifier: ^4.1.18 - version: 4.1.18 - typescript: - specifier: ^5.9.3 - version: 5.9.3 - vite: - specifier: ^7.3.2 - version: 7.3.2(@types/node@25.0.5)(jiti@2.6.1)(lightningcss@1.30.2) +dependencies: + '@khmyznikov/pwa-install': + specifier: ^0.6.3 + version: 0.6.3(@lit/react@1.0.8)(@types/dom-chromium-installation-events@101.0.4)(@types/web-app-manifest@1.0.9)(lit@3.3.3) + ranui: + specifier: 0.1.10-alpha-27 + version: 0.1.10-alpha-27 + ranuts: + specifier: 0.1.0-alpha-23 + version: 0.1.0-alpha-23 + +devDependencies: + '@tailwindcss/postcss': + specifier: ^4.1.18 + version: 4.3.0 + '@types/node': + specifier: ^25.0.5 + version: 25.9.0 + oxlint: + specifier: ^1.38.0 + version: 1.65.0 + postcss: + specifier: ^8.5.6 + version: 8.5.14 + prettier: + specifier: ^3.7.4 + version: 3.8.3 + tailwindcss: + specifier: ^4.1.18 + version: 4.3.0 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vite: + specifier: ^7.3.2 + version: 7.3.3(@types/node@25.9.0) packages: - '@alloc/quick-lru@5.2.0': + /@alloc/quick-lru@5.2.0: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + dev: true - '@esbuild/aix-ppc64@0.27.7': + /@esbuild/aix-ppc64@0.27.7: resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm64@0.27.7': + /@esbuild/android-arm64@0.27.7: resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm@0.27.7': + /@esbuild/android-arm@0.27.7: resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-x64@0.27.7': + /@esbuild/android-x64@0.27.7: resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-arm64@0.27.7': + /@esbuild/darwin-arm64@0.27.7: resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-x64@0.27.7': + /@esbuild/darwin-x64@0.27.7: resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-arm64@0.27.7': + /@esbuild/freebsd-arm64@0.27.7: resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-x64@0.27.7': + /@esbuild/freebsd-x64@0.27.7: resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm64@0.27.7': + /@esbuild/linux-arm64@0.27.7: resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm@0.27.7': + /@esbuild/linux-arm@0.27.7: resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ia32@0.27.7': + /@esbuild/linux-ia32@0.27.7: resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-loong64@0.27.7': + /@esbuild/linux-loong64@0.27.7: resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-mips64el@0.27.7': + /@esbuild/linux-mips64el@0.27.7: resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ppc64@0.27.7': + /@esbuild/linux-ppc64@0.27.7: resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-riscv64@0.27.7': + /@esbuild/linux-riscv64@0.27.7: resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-s390x@0.27.7': + /@esbuild/linux-s390x@0.27.7: resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-x64@0.27.7': + /@esbuild/linux-x64@0.27.7: resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/netbsd-arm64@0.27.7': + /@esbuild/netbsd-arm64@0.27.7: resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/netbsd-x64@0.27.7': + /@esbuild/netbsd-x64@0.27.7: resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openbsd-arm64@0.27.7': + /@esbuild/openbsd-arm64@0.27.7: resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openbsd-x64@0.27.7': + /@esbuild/openbsd-x64@0.27.7: resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openharmony-arm64@0.27.7': + /@esbuild/openharmony-arm64@0.27.7: resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + requiresBuild: true + dev: true + optional: true - '@esbuild/sunos-x64@0.27.7': + /@esbuild/sunos-x64@0.27.7: resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-arm64@0.27.7': + /@esbuild/win32-arm64@0.27.7: resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-ia32@0.27.7': + /@esbuild/win32-ia32@0.27.7: resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-x64@0.27.7': + /@esbuild/win32-x64@0.27.7: resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@jridgewell/gen-mapping@0.3.13': + /@jridgewell/gen-mapping@0.3.13: resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + dev: true - '@jridgewell/remapping@2.3.5': + /@jridgewell/remapping@2.3.5: resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + dev: true - '@jridgewell/resolve-uri@3.1.2': + /@jridgewell/resolve-uri@3.1.2: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + dev: true - '@jridgewell/sourcemap-codec@1.5.5': + /@jridgewell/sourcemap-codec@1.5.5: resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.31': + /@jridgewell/trace-mapping@0.3.31: resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + dev: true - '@khmyznikov/pwa-install@0.6.3': + /@khmyznikov/pwa-install@0.6.3(@lit/react@1.0.8)(@types/dom-chromium-installation-events@101.0.4)(@types/web-app-manifest@1.0.9)(lit@3.3.3): resolution: {integrity: sha512-1GoPVcltXCZgXa7kovAYqodSWNmUW26RaNoF6KbSGfEZ6r6OLwHrUm/+vYFlDUBaIgYHo5Xi301bN4mG51KZRA==} peerDependencies: '@lit/react': ^1.0.8 '@types/dom-chromium-installation-events': ^101.0.4 '@types/web-app-manifest': ^1.0.9 lit: ^3.3.1 + dependencies: + '@lit/react': 1.0.8(@types/react@19.2.14) + '@types/dom-chromium-installation-events': 101.0.4 + '@types/web-app-manifest': 1.0.9 + lit: 3.3.3 + dev: false - '@lit-labs/ssr-dom-shim@1.5.1': - resolution: {integrity: sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==} + /@lit-labs/ssr-dom-shim@1.6.0: + resolution: {integrity: sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==} + dev: false - '@lit/react@1.0.8': + /@lit/react@1.0.8(@types/react@19.2.14): resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==} peerDependencies: '@types/react': 17 || 18 || 19 + dependencies: + '@types/react': 19.2.14 + dev: false - '@lit/reactive-element@2.1.2': + /@lit/reactive-element@2.1.2: resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.6.0 + dev: false + + /@oxlint/binding-android-arm-eabi@1.65.0: + resolution: {integrity: sha512-jDVaGNURT5pEA9qcabh6WusIoBNybOMMDPCx+EFt+gxo6rVvoUf0+73Xy5x81+ZrxU+ewk5uRBYifjy5pgkcnA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-android-arm64@1.65.0: + resolution: {integrity: sha512-v0z80IWNA7c9RhUydq9YprBxCVZrQ6Ixls2tdxUC1F/1FFqSfa7xTX+EJf0mj6+BKRg2zWXqWfcbJUnETlLlIw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true - '@oxlint/darwin-arm64@1.38.0': - resolution: {integrity: sha512-9rN3047QTyA4i73FKikDUBdczRcLtOsIwZ5TsEx5Q7jr5nBjolhYQOFQf9QdhBLdInxw1iX4+lgdMCf1g74zjg==} + /@oxlint/binding-darwin-arm64@1.65.0: + resolution: {integrity: sha512-pL/mG/5gMzBwp1gdc5+Cwi87F9j3XRnPxHGyVj5Zd+dCEV5YkKt0L70PB3EGmEEHxgn4H+jnMS3xLuXs6mZW/Q==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@oxlint/darwin-x64@1.38.0': - resolution: {integrity: sha512-Y1UHW4KOlg5NvyrSn/bVBQP8/LRuid7Pnu+BWGbAVVsFcK0b565YgMSO3Eu9nU3w8ke91dr7NFpUmS+bVkdkbw==} + /@oxlint/binding-darwin-x64@1.65.0: + resolution: {integrity: sha512-jVTneaeuHtqTrKYnhrdH1buhnSorinvpy1sv43ayclfWx/e/DfdRWv+h1fopJcHQbYr5WMcZMmDvnfEBkPZ+1A==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-freebsd-x64@1.65.0: + resolution: {integrity: sha512-8lJQ7B6RloYDUhwVdbSpwT2eKsCN5KP1Scn18ly1tytCuhXhbs0nkfKHT4jWWZBJqmynWuzd+78bF7wILrj6pw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@oxlint/linux-arm64-gnu@1.38.0': - resolution: {integrity: sha512-ZiVxPZizlXSnAMdkEFWX/mAj7U3bNiku8p6I9UgLrXzgGSSAhFobx8CaFGwVoKyWOd+gQgZ/ogCrunvx2k0CFg==} + /@oxlint/binding-linux-arm-gnueabihf@1.65.0: + resolution: {integrity: sha512-EgmZY+DeWhLLEnNl70/49j3ltA8I6X9kxMfexupWi2Vwfp6RonGsBaHtGoedLolaU37ne7eDUgoxa3CFB95GZA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-linux-arm-musleabihf@1.65.0: + resolution: {integrity: sha512-OJMWmAYRVBCPPxnYr3j5sXRwHPh1bAuMlTStGco1Z8q3HkvSH4h+A10E9MiRNYmLhUuli5a2P5wmfj8cagiF5Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-linux-arm64-gnu@1.65.0: + resolution: {integrity: sha512-D8uNi50LsYKgS0vGARZDRx05TBZeSxAVdLGddSEqQLSU7xsiqdImHPEw55xq8sKA5rCc/4au/5uS7FQALWdLCg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@oxlint/linux-arm64-musl@1.38.0': - resolution: {integrity: sha512-ELtlCIGZ72A65ATZZHFxHMFrkRtY+DYDCKiNKg6v7u5PdeOFey+OlqRXgXtXlxWjCL+g7nivwI2FPVsWqf05Qw==} + /@oxlint/binding-linux-arm64-musl@1.65.0: + resolution: {integrity: sha512-IpbA8QGbwFehQhO+YaHwmoI81f93xvywpspf8HrdPCWOIeKwYfM1dhVhO4YKfZewTRRQEPY/JFjTOXTgkwhKrA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-linux-ppc64-gnu@1.65.0: + resolution: {integrity: sha512-ZSe8HgaZdgyHSv2+/pTG68z10+OarB18CkFKQOhRs3lmmP/p2vuigedK2e9d0ztoG2DU/duJzhxXBSjy/492HQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-linux-riscv64-gnu@1.65.0: + resolution: {integrity: sha512-DcTERf++v6HyPHukKAr0JFTRqB+YeDEvqzRgNDMaz7jITPf+tlJIwRxodlAqoXMYhNVEZhXdQM5RAAYH8/oPuw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-linux-riscv64-musl@1.65.0: + resolution: {integrity: sha512-xjhMwuFJwRh40NOBzol4gM5gqAa0xPCJU+GQLM6BydV8TbfkIA7JeyCFNhyfbE9Q/5EWcKYTx62R0cRcjP7DAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-linux-s390x-gnu@1.65.0: + resolution: {integrity: sha512-lrWSXb8JzboPWYBG6Kunt/eemvjo2oCFXktShsm3yMToY7HjzKLjxh7CljSvGnnZH9oohNFHOKc9xYpGKCPm6w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true - '@oxlint/linux-x64-gnu@1.38.0': - resolution: {integrity: sha512-E1OcDh30qyng1m0EIlsOuapYkqk5QB6o6IMBjvDKqIoo6IrjlVAasoJfS/CmSH998gXRL3BcAJa6Qg9IxPFZnQ==} + /@oxlint/binding-linux-x64-gnu@1.65.0: + resolution: {integrity: sha512-A7xfghw250m4a1sPV+q44Mow2G5bhiC9FBvhAuIhJS6QovWnqzuL5AFQPEuwOB+PM4DhABkqxVa3Iwe3Y/nFlQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@oxlint/linux-x64-musl@1.38.0': - resolution: {integrity: sha512-4AfpbM/4sQnr6S1dMijEPfsq4stQbN5vJ2jsahSy/QTcvIVbFkgY+RIhrA5UWlC6eb0rD5CdaPQoKGMJGeXpYw==} + /@oxlint/binding-linux-x64-musl@1.65.0: + resolution: {integrity: sha512-reqOun1+pWO3fW6cv7bsa8hHG0TN3t/82qPdaoJo90FwugXiMjKhZMChmH5Z01cFNRHmxN4+543Fy8478cM/iA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-openharmony-arm64@1.65.0: + resolution: {integrity: sha512-KQpqOb/juDBO0xyloDkVDhOVxDUgAfZ2OAAVq99TJScJDzT319xry1QzB9LQohV9QGnA7p6m/XATZkMXc84lwA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: true + optional: true - '@oxlint/win32-arm64@1.38.0': - resolution: {integrity: sha512-OvUVYdI68OwXh3d1RjH9N/okCxb6PrOGtEtzXyqGA7Gk+IxyZcX0/QCTBwV8FNbSSzDePSSEHOKpoIB+VXdtvg==} + /@oxlint/binding-win32-arm64-msvc@1.65.0: + resolution: {integrity: sha512-xfqcOc3nJFeAd1kDY4T9d3XeJIhr00twaaW0kOAzGPyUHkruXtNJv6zz1Ra9fRtSek5VpW2Yoj5AcwPIlT0ZiQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true + + /@oxlint/binding-win32-ia32-msvc@1.65.0: + resolution: {integrity: sha512-JV+pXm45p8sdgs3c7LOPAohW23optCNZETFOXUcjn6cS4PYZhEU/RI54Z5dHdMudab3nw7T48PZILthM+Q0COQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true - '@oxlint/win32-x64@1.38.0': - resolution: {integrity: sha512-7IuZMYiZiOcgg5zHvpJY6jRlEwh8EB/uq7GsoQJO9hANq96TIjyntGByhIjFSsL4asyZmhTEki+MO/u5Fb/WQA==} + /@oxlint/binding-win32-x64-msvc@1.65.0: + resolution: {integrity: sha512-D7L/oBbskLss21bYrRbFuIs81AiSQV+wRzwck54dOkHIlq2qu1xjLz8u6jCqGH8Fltk8bB5DLBpVhE7v/fA8XQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-android-arm-eabi@4.60.1': - resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} + /@rollup/rollup-android-arm-eabi@4.60.4: + resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} cpu: [arm] os: [android] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-android-arm64@4.60.1': - resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==} + /@rollup/rollup-android-arm64@4.60.4: + resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-darwin-arm64@4.60.1': - resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==} + /@rollup/rollup-darwin-arm64@4.60.4: + resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-darwin-x64@4.60.1': - resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==} + /@rollup/rollup-darwin-x64@4.60.4: + resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-freebsd-arm64@4.60.1': - resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==} + /@rollup/rollup-freebsd-arm64@4.60.4: + resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-freebsd-x64@4.60.1': - resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==} + /@rollup/rollup-freebsd-x64@4.60.4: + resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.1': - resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==} + /@rollup/rollup-linux-arm-gnueabihf@4.60.4: + resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.1': - resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==} + /@rollup/rollup-linux-arm-musleabihf@4.60.4: + resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.1': - resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==} + /@rollup/rollup-linux-arm64-gnu@4.60.4: + resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm64-musl@4.60.1': - resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==} + /@rollup/rollup-linux-arm64-musl@4.60.4: + resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.1': - resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==} + /@rollup/rollup-linux-loong64-gnu@4.60.4: + resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-loong64-musl@4.60.1': - resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==} + /@rollup/rollup-linux-loong64-musl@4.60.4: + resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.1': - resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==} + /@rollup/rollup-linux-ppc64-gnu@4.60.4: + resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.1': - resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==} + /@rollup/rollup-linux-ppc64-musl@4.60.4: + resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.1': - resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==} + /@rollup/rollup-linux-riscv64-gnu@4.60.4: + resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.1': - resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==} + /@rollup/rollup-linux-riscv64-musl@4.60.4: + resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.1': - resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==} + /@rollup/rollup-linux-s390x-gnu@4.60.4: + resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} cpu: [s390x] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-x64-gnu@4.60.1': - resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==} + /@rollup/rollup-linux-x64-gnu@4.60.4: + resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-x64-musl@4.60.1': - resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==} + /@rollup/rollup-linux-x64-musl@4.60.4: + resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-openbsd-x64@4.60.1': - resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==} + /@rollup/rollup-openbsd-x64@4.60.4: + resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-openharmony-arm64@4.60.1': - resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==} + /@rollup/rollup-openharmony-arm64@4.60.4: + resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} cpu: [arm64] os: [openharmony] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.1': - resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==} + /@rollup/rollup-win32-arm64-msvc@4.60.4: + resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.1': - resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==} + /@rollup/rollup-win32-ia32-msvc@4.60.4: + resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-x64-gnu@4.60.1': - resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==} + /@rollup/rollup-win32-x64-gnu@4.60.4: + resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-x64-msvc@4.60.1': - resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==} + /@rollup/rollup-win32-x64-msvc@4.60.4: + resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/node@4.1.18': - resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + /@tailwindcss/node@4.3.0: + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.4 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.0 + dev: true - '@tailwindcss/oxide-android-arm64@4.1.18': - resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-android-arm64@4.3.0: + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} + engines: {node: '>= 20'} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.18': - resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-darwin-arm64@4.3.0: + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} + engines: {node: '>= 20'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-darwin-x64@4.1.18': - resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-darwin-x64@4.3.0: + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} + engines: {node: '>= 20'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.18': - resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-freebsd-x64@4.3.0: + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} + engines: {node: '>= 20'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0: + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} + engines: {node: '>= 20'} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-linux-arm64-gnu@4.3.0: + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-linux-arm64-musl@4.3.0: + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-linux-x64-gnu@4.3.0: + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-linux-x64-musl@4.3.0: + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + /@tailwindcss/oxide-wasm32-wasi@4.3.0: + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} engines: {node: '>=14.0.0'} cpu: [wasm32] + requiresBuild: true + dev: true + optional: true bundledDependencies: - '@napi-rs/wasm-runtime' - '@emnapi/core' @@ -474,66 +822,140 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-win32-arm64-msvc@4.3.0: + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} + engines: {node: '>= 20'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} - engines: {node: '>= 10'} + /@tailwindcss/oxide-win32-x64-msvc@4.3.0: + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} + engines: {node: '>= 20'} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@tailwindcss/oxide@4.1.18': - resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} - engines: {node: '>= 10'} - - '@tailwindcss/postcss@4.1.18': - resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==} + /@tailwindcss/oxide@4.3.0: + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} + engines: {node: '>= 20'} + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 + dev: true + + /@tailwindcss/postcss@4.3.0: + resolution: {integrity: sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==} + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + postcss: 8.5.14 + tailwindcss: 4.3.0 + dev: true - '@types/dom-chromium-installation-events@101.0.4': + /@types/dom-chromium-installation-events@101.0.4: resolution: {integrity: sha512-jV4HXmW5D18bpndzAPF1REGE5xagQqrAexHgX9WoWIPpNaaHtsHQgu5uFbL2z0NIc9fOD0TIC1TRpJhYA1OPxw==} + dev: false - '@types/estree@1.0.8': + /@types/estree@1.0.8: resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + dev: true - '@types/node@25.0.5': - resolution: {integrity: sha512-FuLxeLuSVOqHPxSN1fkcD8DLU21gAP7nCKqGRJ/FglbCUBs0NYN6TpHcdmyLeh8C0KwGIaZQJSv+OYG+KZz+Gw==} + /@types/node@25.9.0: + resolution: {integrity: sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==} + dependencies: + undici-types: 7.24.6 + dev: true - '@types/react@19.2.14': + /@types/react@19.2.14: resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + dependencies: + csstype: 3.2.3 + dev: false - '@types/trusted-types@2.0.7': + /@types/trusted-types@2.0.7: resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + dev: false - '@types/web-app-manifest@1.0.9': + /@types/web-app-manifest@1.0.9: resolution: {integrity: sha512-aVz1aXTubyL6nvVRyz9W7QR60zHLTiCGAafqYRc/RYUjA1GFc4npUUr7RlfO1+yP6gVvxzFmIVp8ULLYqhBRdA==} + dev: false - bmp-js@0.1.0: + /bmp-js@0.1.0: resolution: {integrity: sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==} + dev: false - csstype@3.2.3: + /csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + dev: false - detect-libc@2.1.2: + /detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + dev: true - earcut@3.0.2: + /earcut@3.0.2: resolution: {integrity: sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==} + dev: false - enhanced-resolve@5.18.4: - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + /enhanced-resolve@5.21.4: + resolution: {integrity: sha512-wE4fDO8OjJhrPFH69HUQStq5oKvGRTNXEyW+k5C/pUQLASSsTu7obd2V3GvCDgPcY9AWjhJ4jz9Kh7iRvrxhJg==} engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + dev: true - esbuild@0.27.7: + /esbuild@0.27.7: resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + dev: true - fdir@6.5.0: + /fdir@6.5.0(picomatch@4.0.4): resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} peerDependencies: @@ -541,117 +963,192 @@ packages: peerDependenciesMeta: picomatch: optional: true + dependencies: + picomatch: 4.0.4 + dev: true - fsevents@2.3.3: + /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + requiresBuild: true + dev: true + optional: true - graceful-fs@4.2.11: + /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true - idb-keyval@6.2.2: + /idb-keyval@6.2.2: resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} + dev: false - is-url@1.2.4: + /is-url@1.2.4: resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} + dev: false - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + /jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true + dev: true - jschardet@3.1.4: + /jschardet@3.1.4: resolution: {integrity: sha512-/kmVISmrwVwtyYU40iQUOp3SUPk2dhNCMsZBQX0R1/jZ8maaXJ/oZIzUOiyOqcgtLnETFKYChbJ5iDC/eWmFHg==} engines: {node: '>=0.1.90'} + dev: false - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + /lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + /lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + /lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + /lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + /lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + /lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + /lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + /lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + /lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + /lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + /lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + /lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} - - lit-element@4.2.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + dev: true + + /lit-element@4.2.2: resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.6.0 + '@lit/reactive-element': 2.1.2 + lit-html: 3.3.3 + dev: false - lit-html@3.3.2: - resolution: {integrity: sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw==} + /lit-html@3.3.3: + resolution: {integrity: sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==} + dependencies: + '@types/trusted-types': 2.0.7 + dev: false - lit@3.3.2: - resolution: {integrity: sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==} + /lit@3.3.3: + resolution: {integrity: sha512-fycuvZg/hkpozL00lm1pEJH5nN/lr9ZXd6mJI2HSN4+Bzc+LDNdEApJ6HFbPkdFNHLvOplIIuJvxkS4XUxqirw==} + dependencies: + '@lit/reactive-element': 2.1.2 + lit-element: 4.2.2 + lit-html: 3.3.3 + dev: false - magic-string@0.30.21: + /magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + /nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + dev: true - node-fetch@2.7.0: + /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} peerDependencies: @@ -659,87 +1156,189 @@ packages: peerDependenciesMeta: encoding: optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false - opencollective-postinstall@2.0.3: + /opencollective-postinstall@2.0.3: resolution: {integrity: sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==} hasBin: true + dev: false - oxlint@1.38.0: - resolution: {integrity: sha512-XT7tBinQS+hVLxtfJOnokJ9qVBiQvZqng40tDgR6qEJMRMnpVq/JwYfbYyGntSq8MO+Y+N9M1NG4bAMFUtCJiw==} + /oxlint@1.65.0: + resolution: {integrity: sha512-ChUuE3Q7XnAbscvT4XLMsH7HFJmLgLVv9lu+RRgFL5wSXnDqUOzTp5IS8qWDBGd/ZDSzQ2tbX8fjAmijlGLC7A==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - oxlint-tsgolint: '>=0.10.0' + oxlint-tsgolint: '>=0.22.1' peerDependenciesMeta: oxlint-tsgolint: optional: true - - picocolors@1.1.1: + optionalDependencies: + '@oxlint/binding-android-arm-eabi': 1.65.0 + '@oxlint/binding-android-arm64': 1.65.0 + '@oxlint/binding-darwin-arm64': 1.65.0 + '@oxlint/binding-darwin-x64': 1.65.0 + '@oxlint/binding-freebsd-x64': 1.65.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.65.0 + '@oxlint/binding-linux-arm-musleabihf': 1.65.0 + '@oxlint/binding-linux-arm64-gnu': 1.65.0 + '@oxlint/binding-linux-arm64-musl': 1.65.0 + '@oxlint/binding-linux-ppc64-gnu': 1.65.0 + '@oxlint/binding-linux-riscv64-gnu': 1.65.0 + '@oxlint/binding-linux-riscv64-musl': 1.65.0 + '@oxlint/binding-linux-s390x-gnu': 1.65.0 + '@oxlint/binding-linux-x64-gnu': 1.65.0 + '@oxlint/binding-linux-x64-musl': 1.65.0 + '@oxlint/binding-openharmony-arm64': 1.65.0 + '@oxlint/binding-win32-arm64-msvc': 1.65.0 + '@oxlint/binding-win32-ia32-msvc': 1.65.0 + '@oxlint/binding-win32-x64-msvc': 1.65.0 + dev: true + + /picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + dev: true - picomatch@4.0.4: + /picomatch@4.0.4: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + dev: true - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + /postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + dev: true - prettier@3.7.4: - resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + /prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true + dev: true - ranui@0.1.10-alpha-27: + /ranui@0.1.10-alpha-27: resolution: {integrity: sha512-UtS2m0ipKG4Pqe5B/Ta5XcTMx2gOBIpEcwTeuZ9P/cQqkk0uf5MDUF4LVIoOUzVEU83ROXw1oWOzibt/sW4E5A==} engines: {node: '>=23.10.0'} + dependencies: + ranuts: 0.1.0-alpha-23 + transitivePeerDependencies: + - encoding + dev: false - ranuts@0.1.0-alpha-23: + /ranuts@0.1.0-alpha-23: resolution: {integrity: sha512-E6IlFEO2Ya07nPDOIOMe56cL/J6Rs2mHczzSN18GYJTKJS8p9EA054ef3MECcdtoKSlBodbMJZrO+in3u+cBEg==} engines: {node: '>=23.10.0'} + dependencies: + earcut: 3.0.2 + jschardet: 3.1.4 + magic-string: 0.30.21 + tesseract.js: 6.0.1 + transitivePeerDependencies: + - encoding + dev: false - regenerator-runtime@0.13.11: + /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: false - rollup@4.60.1: - resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==} + /rollup@4.60.4: + resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.4 + '@rollup/rollup-android-arm64': 4.60.4 + '@rollup/rollup-darwin-arm64': 4.60.4 + '@rollup/rollup-darwin-x64': 4.60.4 + '@rollup/rollup-freebsd-arm64': 4.60.4 + '@rollup/rollup-freebsd-x64': 4.60.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 + '@rollup/rollup-linux-arm-musleabihf': 4.60.4 + '@rollup/rollup-linux-arm64-gnu': 4.60.4 + '@rollup/rollup-linux-arm64-musl': 4.60.4 + '@rollup/rollup-linux-loong64-gnu': 4.60.4 + '@rollup/rollup-linux-loong64-musl': 4.60.4 + '@rollup/rollup-linux-ppc64-gnu': 4.60.4 + '@rollup/rollup-linux-ppc64-musl': 4.60.4 + '@rollup/rollup-linux-riscv64-gnu': 4.60.4 + '@rollup/rollup-linux-riscv64-musl': 4.60.4 + '@rollup/rollup-linux-s390x-gnu': 4.60.4 + '@rollup/rollup-linux-x64-gnu': 4.60.4 + '@rollup/rollup-linux-x64-musl': 4.60.4 + '@rollup/rollup-openbsd-x64': 4.60.4 + '@rollup/rollup-openharmony-arm64': 4.60.4 + '@rollup/rollup-win32-arm64-msvc': 4.60.4 + '@rollup/rollup-win32-ia32-msvc': 4.60.4 + '@rollup/rollup-win32-x64-gnu': 4.60.4 + '@rollup/rollup-win32-x64-msvc': 4.60.4 + fsevents: 2.3.3 + dev: true - source-map-js@1.2.1: + /source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + dev: true - tailwindcss@4.1.18: - resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + /tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + dev: true - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + /tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + dev: true - tesseract.js-core@6.1.2: + /tesseract.js-core@6.1.2: resolution: {integrity: sha512-pv4GjmramjdObhDyR1q85Td8X60Puu/lGQn7Kw2id05LLgHhAcWgnz6xSdMCSxBMWjQDmMyDXPTC2aqADdpiow==} + dev: false - tesseract.js@6.0.1: + /tesseract.js@6.0.1: resolution: {integrity: sha512-/sPvMvrCtgxnNRCjbTYbr7BRu0yfWDsMZQ2a/T5aN/L1t8wUQN6tTWv6p6FwzpoEBA0jrN2UD2SX4QQFRdoDbA==} + requiresBuild: true + dependencies: + bmp-js: 0.1.0 + idb-keyval: 6.2.2 + is-url: 1.2.4 + node-fetch: 2.7.0 + opencollective-postinstall: 2.0.3 + regenerator-runtime: 0.13.11 + tesseract.js-core: 6.1.2 + wasm-feature-detect: 1.8.0 + zlibjs: 0.3.1 + transitivePeerDependencies: + - encoding + dev: false - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + /tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + dev: true - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - typescript@5.9.3: + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false + + /typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true + dev: true - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + /undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + dev: true - vite@7.3.2: - resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} + /vite@7.3.3(@types/node@25.9.0): + resolution: {integrity: sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -777,582 +1376,33 @@ packages: optional: true yaml: optional: true - - wasm-feature-detect@1.8.0: - resolution: {integrity: sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - zlibjs@0.3.1: - resolution: {integrity: sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==} - -snapshots: - - '@alloc/quick-lru@5.2.0': {} - - '@esbuild/aix-ppc64@0.27.7': - optional: true - - '@esbuild/android-arm64@0.27.7': - optional: true - - '@esbuild/android-arm@0.27.7': - optional: true - - '@esbuild/android-x64@0.27.7': - optional: true - - '@esbuild/darwin-arm64@0.27.7': - optional: true - - '@esbuild/darwin-x64@0.27.7': - optional: true - - '@esbuild/freebsd-arm64@0.27.7': - optional: true - - '@esbuild/freebsd-x64@0.27.7': - optional: true - - '@esbuild/linux-arm64@0.27.7': - optional: true - - '@esbuild/linux-arm@0.27.7': - optional: true - - '@esbuild/linux-ia32@0.27.7': - optional: true - - '@esbuild/linux-loong64@0.27.7': - optional: true - - '@esbuild/linux-mips64el@0.27.7': - optional: true - - '@esbuild/linux-ppc64@0.27.7': - optional: true - - '@esbuild/linux-riscv64@0.27.7': - optional: true - - '@esbuild/linux-s390x@0.27.7': - optional: true - - '@esbuild/linux-x64@0.27.7': - optional: true - - '@esbuild/netbsd-arm64@0.27.7': - optional: true - - '@esbuild/netbsd-x64@0.27.7': - optional: true - - '@esbuild/openbsd-arm64@0.27.7': - optional: true - - '@esbuild/openbsd-x64@0.27.7': - optional: true - - '@esbuild/openharmony-arm64@0.27.7': - optional: true - - '@esbuild/sunos-x64@0.27.7': - optional: true - - '@esbuild/win32-arm64@0.27.7': - optional: true - - '@esbuild/win32-ia32@0.27.7': - optional: true - - '@esbuild/win32-x64@0.27.7': - optional: true - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@khmyznikov/pwa-install@0.6.3(@lit/react@1.0.8(@types/react@19.2.14))(@types/dom-chromium-installation-events@101.0.4)(@types/web-app-manifest@1.0.9)(lit@3.3.2)': - dependencies: - '@lit/react': 1.0.8(@types/react@19.2.14) - '@types/dom-chromium-installation-events': 101.0.4 - '@types/web-app-manifest': 1.0.9 - lit: 3.3.2 - - '@lit-labs/ssr-dom-shim@1.5.1': {} - - '@lit/react@1.0.8(@types/react@19.2.14)': - dependencies: - '@types/react': 19.2.14 - - '@lit/reactive-element@2.1.2': - dependencies: - '@lit-labs/ssr-dom-shim': 1.5.1 - - '@oxlint/darwin-arm64@1.38.0': - optional: true - - '@oxlint/darwin-x64@1.38.0': - optional: true - - '@oxlint/linux-arm64-gnu@1.38.0': - optional: true - - '@oxlint/linux-arm64-musl@1.38.0': - optional: true - - '@oxlint/linux-x64-gnu@1.38.0': - optional: true - - '@oxlint/linux-x64-musl@1.38.0': - optional: true - - '@oxlint/win32-arm64@1.38.0': - optional: true - - '@oxlint/win32-x64@1.38.0': - optional: true - - '@rollup/rollup-android-arm-eabi@4.60.1': - optional: true - - '@rollup/rollup-android-arm64@4.60.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.60.1': - optional: true - - '@rollup/rollup-darwin-x64@4.60.1': - optional: true - - '@rollup/rollup-freebsd-arm64@4.60.1': - optional: true - - '@rollup/rollup-freebsd-x64@4.60.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.60.1': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.60.1': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.60.1': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.60.1': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.60.1': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.60.1': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.60.1': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.60.1': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.60.1': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.60.1': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.60.1': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.60.1': - optional: true - - '@rollup/rollup-linux-x64-musl@4.60.1': - optional: true - - '@rollup/rollup-openbsd-x64@4.60.1': - optional: true - - '@rollup/rollup-openharmony-arm64@4.60.1': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.60.1': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.60.1': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.60.1': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.60.1': - optional: true - - '@tailwindcss/node@4.1.18': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.4 - jiti: 2.6.1 - lightningcss: 1.30.2 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.1.18 - - '@tailwindcss/oxide-android-arm64@4.1.18': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.1.18': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.1.18': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide@4.1.18': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-x64': 4.1.18 - '@tailwindcss/oxide-freebsd-x64': 4.1.18 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-x64-musl': 4.1.18 - '@tailwindcss/oxide-wasm32-wasi': 4.1.18 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - - '@tailwindcss/postcss@4.1.18': - dependencies: - '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.1.18 - '@tailwindcss/oxide': 4.1.18 - postcss: 8.5.6 - tailwindcss: 4.1.18 - - '@types/dom-chromium-installation-events@101.0.4': {} - - '@types/estree@1.0.8': {} - - '@types/node@25.0.5': - dependencies: - undici-types: 7.16.0 - - '@types/react@19.2.14': - dependencies: - csstype: 3.2.3 - - '@types/trusted-types@2.0.7': {} - - '@types/web-app-manifest@1.0.9': {} - - bmp-js@0.1.0: {} - - csstype@3.2.3: {} - - detect-libc@2.1.2: {} - - earcut@3.0.2: {} - - enhanced-resolve@5.18.4: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - - esbuild@0.27.7: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.7 - '@esbuild/android-arm': 0.27.7 - '@esbuild/android-arm64': 0.27.7 - '@esbuild/android-x64': 0.27.7 - '@esbuild/darwin-arm64': 0.27.7 - '@esbuild/darwin-x64': 0.27.7 - '@esbuild/freebsd-arm64': 0.27.7 - '@esbuild/freebsd-x64': 0.27.7 - '@esbuild/linux-arm': 0.27.7 - '@esbuild/linux-arm64': 0.27.7 - '@esbuild/linux-ia32': 0.27.7 - '@esbuild/linux-loong64': 0.27.7 - '@esbuild/linux-mips64el': 0.27.7 - '@esbuild/linux-ppc64': 0.27.7 - '@esbuild/linux-riscv64': 0.27.7 - '@esbuild/linux-s390x': 0.27.7 - '@esbuild/linux-x64': 0.27.7 - '@esbuild/netbsd-arm64': 0.27.7 - '@esbuild/netbsd-x64': 0.27.7 - '@esbuild/openbsd-arm64': 0.27.7 - '@esbuild/openbsd-x64': 0.27.7 - '@esbuild/openharmony-arm64': 0.27.7 - '@esbuild/sunos-x64': 0.27.7 - '@esbuild/win32-arm64': 0.27.7 - '@esbuild/win32-ia32': 0.27.7 - '@esbuild/win32-x64': 0.27.7 - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - fsevents@2.3.3: - optional: true - - graceful-fs@4.2.11: {} - - idb-keyval@6.2.2: {} - - is-url@1.2.4: {} - - jiti@2.6.1: {} - - jschardet@3.1.4: {} - - lightningcss-android-arm64@1.30.2: - optional: true - - lightningcss-darwin-arm64@1.30.2: - optional: true - - lightningcss-darwin-x64@1.30.2: - optional: true - - lightningcss-freebsd-x64@1.30.2: - optional: true - - lightningcss-linux-arm-gnueabihf@1.30.2: - optional: true - - lightningcss-linux-arm64-gnu@1.30.2: - optional: true - - lightningcss-linux-arm64-musl@1.30.2: - optional: true - - lightningcss-linux-x64-gnu@1.30.2: - optional: true - - lightningcss-linux-x64-musl@1.30.2: - optional: true - - lightningcss-win32-arm64-msvc@1.30.2: - optional: true - - lightningcss-win32-x64-msvc@1.30.2: - optional: true - - lightningcss@1.30.2: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 - - lit-element@4.2.2: - dependencies: - '@lit-labs/ssr-dom-shim': 1.5.1 - '@lit/reactive-element': 2.1.2 - lit-html: 3.3.2 - - lit-html@3.3.2: - dependencies: - '@types/trusted-types': 2.0.7 - - lit@3.3.2: - dependencies: - '@lit/reactive-element': 2.1.2 - lit-element: 4.2.2 - lit-html: 3.3.2 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - nanoid@3.3.11: {} - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - opencollective-postinstall@2.0.3: {} - - oxlint@1.38.0: - optionalDependencies: - '@oxlint/darwin-arm64': 1.38.0 - '@oxlint/darwin-x64': 1.38.0 - '@oxlint/linux-arm64-gnu': 1.38.0 - '@oxlint/linux-arm64-musl': 1.38.0 - '@oxlint/linux-x64-gnu': 1.38.0 - '@oxlint/linux-x64-musl': 1.38.0 - '@oxlint/win32-arm64': 1.38.0 - '@oxlint/win32-x64': 1.38.0 - - picocolors@1.1.1: {} - - picomatch@4.0.4: {} - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prettier@3.7.4: {} - - ranui@0.1.10-alpha-27: - dependencies: - ranuts: 0.1.0-alpha-23 - transitivePeerDependencies: - - encoding - - ranuts@0.1.0-alpha-23: - dependencies: - earcut: 3.0.2 - jschardet: 3.1.4 - magic-string: 0.30.21 - tesseract.js: 6.0.1 - transitivePeerDependencies: - - encoding - - regenerator-runtime@0.13.11: {} - - rollup@4.60.1: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.1 - '@rollup/rollup-android-arm64': 4.60.1 - '@rollup/rollup-darwin-arm64': 4.60.1 - '@rollup/rollup-darwin-x64': 4.60.1 - '@rollup/rollup-freebsd-arm64': 4.60.1 - '@rollup/rollup-freebsd-x64': 4.60.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.1 - '@rollup/rollup-linux-arm-musleabihf': 4.60.1 - '@rollup/rollup-linux-arm64-gnu': 4.60.1 - '@rollup/rollup-linux-arm64-musl': 4.60.1 - '@rollup/rollup-linux-loong64-gnu': 4.60.1 - '@rollup/rollup-linux-loong64-musl': 4.60.1 - '@rollup/rollup-linux-ppc64-gnu': 4.60.1 - '@rollup/rollup-linux-ppc64-musl': 4.60.1 - '@rollup/rollup-linux-riscv64-gnu': 4.60.1 - '@rollup/rollup-linux-riscv64-musl': 4.60.1 - '@rollup/rollup-linux-s390x-gnu': 4.60.1 - '@rollup/rollup-linux-x64-gnu': 4.60.1 - '@rollup/rollup-linux-x64-musl': 4.60.1 - '@rollup/rollup-openbsd-x64': 4.60.1 - '@rollup/rollup-openharmony-arm64': 4.60.1 - '@rollup/rollup-win32-arm64-msvc': 4.60.1 - '@rollup/rollup-win32-ia32-msvc': 4.60.1 - '@rollup/rollup-win32-x64-gnu': 4.60.1 - '@rollup/rollup-win32-x64-msvc': 4.60.1 - fsevents: 2.3.3 - - source-map-js@1.2.1: {} - - tailwindcss@4.1.18: {} - - tapable@2.3.0: {} - - tesseract.js-core@6.1.2: {} - - tesseract.js@6.0.1: - dependencies: - bmp-js: 0.1.0 - idb-keyval: 6.2.2 - is-url: 1.2.4 - node-fetch: 2.7.0 - opencollective-postinstall: 2.0.3 - regenerator-runtime: 0.13.11 - tesseract.js-core: 6.1.2 - wasm-feature-detect: 1.8.0 - zlibjs: 0.3.1 - transitivePeerDependencies: - - encoding - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - tr46@0.0.3: {} - - typescript@5.9.3: {} - - undici-types@7.16.0: {} - - vite@7.3.2(@types/node@25.0.5)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: + '@types/node': 25.9.0 esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.6 - rollup: 4.60.1 - tinyglobby: 0.2.15 + postcss: 8.5.14 + rollup: 4.60.4 + tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.0.5 fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 + dev: true - wasm-feature-detect@1.8.0: {} + /wasm-feature-detect@1.8.0: + resolution: {integrity: sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==} + dev: false - webidl-conversions@3.0.1: {} + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false - whatwg-url@5.0.0: + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 + dev: false - zlibjs@0.3.1: {} + /zlibjs@0.3.1: + resolution: {integrity: sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==} + dev: false diff --git a/public/embed-demo.html b/public/embed-demo.html new file mode 100644 index 00000000..4cc4043e --- /dev/null +++ b/public/embed-demo.html @@ -0,0 +1,344 @@ + + + + + + + Document Editor iframe Demo + + + + + +
+ + +
+
+ Document Editor + loading +
+ +
+
+ + + + + diff --git a/public/sdkjs/cell/sdk-all.js b/public/sdkjs/cell/sdk-all.js index 9bc3ead9..6b91aa3c 100644 --- a/public/sdkjs/cell/sdk-all.js +++ b/public/sdkjs/cell/sdk-all.js @@ -18783,7 +18783,7 @@ this.$s = new n.$Nf(); this.$s.load(this.Jha); if (0 == this.$s.aBc) { - var U = q[B.jb ?? 'ASC.ttf']; + var U = q[B.jb ?? 'ASC.ttf'] || q['ASC.ttf']; this.$s.Sjc = !0; this.$s.aBc = U.units_per_EM; this.$s.s8a = U.ascender; diff --git a/public/sdkjs/common/AllFonts.js b/public/sdkjs/common/AllFonts.js index ab7c175c..a24dfc39 100644 --- a/public/sdkjs/common/AllFonts.js +++ b/public/sdkjs/common/AllFonts.js @@ -353,6 +353,16 @@ 'C:\\Windows\\Fonts\\webdings.ttf', 'C:\\Windows\\Fonts\\wingding.ttf', ]), + (window.__document_font_base_path = window.location.pathname.startsWith('/document/') ? '/document/' : '/'), + (window.__document_font_fallback = function (fontPath) { + if (!/^c:\\windows\\fonts\\/i.test(fontPath)) return fontPath; + + const fileName = fontPath.split('\\').pop().toLowerCase(); + const cjkFontPattern = /^(deng|dengb|dengl|fz|javanese|malgun|mingliu|msgothic|msyh|msyhbd|msyhl|sim|st|yu|yugoth|yumin)/i; + const fallbackFile = cjkFontPattern.test(fileName) ? 'NotoSansTC-VF.ttf' : 'LiberationSans-Bold.ttf'; + return window.__document_font_base_path + 'fonts/' + fallbackFile; + }), + (window.__fonts_files = window.__fonts_files.map(window.__document_font_fallback)), (window.__fonts_infos = [ ['Agency FB', 1, 0, -1, -1, 0, 0, -1, -1], ['Algerian', 2, 0, -1, -1, -1, -1, -1, -1], diff --git a/readme.md b/readme.md index 398436b1..d2078f0d 100644 --- a/readme.md +++ b/readme.md @@ -79,6 +79,223 @@ This project provides foundational services for document preview components in t 📚 **Preview Component Documentation**: [https://chaxus.github.io/ran/src/ranui/preview/](https://chaxus.github.io/ran/src/ranui/preview/) +## 🧩 iframe 嵌入使用方式 + +本项目支持通过 iframe 嵌入到其他业务系统中。推荐架构是:**父系统负责鉴权、下载文件和上传保存结果;iframe 只负责文档编辑**。这样 token、cookie、业务接口都留在父系统内,编辑器不需要知道业务系统的授权细节。 + +项目内置了一个示例页面: + +```text +/embed-demo.html +``` + +本地启动后可以访问: + +```text +http://127.0.0.1:8082/embed-demo.html +``` + +### 1. 嵌入编辑器 + +```html + +``` + +如果需要限制只接收指定父页面来源,可以增加 `embedOrigin`: + +```html + +``` + +### 2. 发送命令 + +建议每条命令带上 `id`,便于父页面匹配响应: + +```js +const iframe = document.getElementById('documentEditor'); +const editorOrigin = 'http://127.0.0.1:8082'; + +function sendEditorCommand(type, payload = {}) { + const id = `${Date.now()}-${Math.random().toString(16).slice(2)}`; + iframe.contentWindow.postMessage({ id, type, payload }, editorOrigin); + return id; +} +``` + +监听 iframe 响应: + +```js +window.addEventListener('message', (event) => { + if (event.origin !== editorOrigin) return; + + const { id, type, payload } = event.data || {}; + if (!type || !type.startsWith('document:')) return; + + if (type === 'document:ready') { + console.log('编辑器已就绪'); + } + + if (type === 'document:opened') { + console.log('文档已打开', id, payload); + } + + if (type === 'document:saved') { + console.log('保存完成', payload.fileName, payload.file); + } + + if (type === 'document:error') { + console.error('编辑器错误', payload.message); + } +}); +``` + +### 3. 打开文档 + +通过 URL 打开: + +```js +sendEditorCommand('document:open-url', { + url: 'https://example.com/files/demo.xlsx', + fileName: 'demo.xlsx', + readonly: false, +}); +``` + +如果 URL 接口需要授权,可以传 `fetchOptions`,但更推荐由父系统自己 `fetch` 后传入文件对象: + +```js +sendEditorCommand('document:open-url', { + url: 'https://example.com/api/files/1', + fileName: 'demo.xlsx', + readonly: false, + fetchOptions: { + headers: { + Authorization: `Bearer ${token}`, + }, + }, +}); +``` + +通过本地文件对话框打开: + +```js +const input = document.createElement('input'); +input.type = 'file'; +input.accept = '.xlsx,.xls,.csv,.docx,.doc,.pptx,.ppt'; +input.onchange = () => { + const file = input.files[0]; + sendEditorCommand('document:open-file', { + file, + readonly: false, + }); +}; +input.click(); +``` + +通过父系统授权请求后打开二进制数据: + +```js +const response = await fetch('/api/files/1', { + headers: { + Authorization: `Bearer ${token}`, + }, +}); + +const buffer = await response.arrayBuffer(); + +sendEditorCommand('document:open-buffer', { + fileName: 'demo.xlsx', + buffer, + readonly: false, +}); +``` + +### 4. 设置只读 + +打开文档时可以直接设置: + +```js +sendEditorCommand('document:open-buffer', { + fileName: 'demo.xlsx', + buffer, + readonly: true, +}); +``` + +文档打开后也可以切换: + +```js +sendEditorCommand('document:set-readonly', { + readonly: true, +}); +``` + +只读模式下编辑权限会关闭,保存命令会返回 `document:error`。 + +### 5. 保存并上传到服务端 + +保存命令会触发编辑器导出当前正在编辑的内容,并通过 `document:saved` 返回一个新的 `File` 对象。默认保存为 `XLSX`,也可以传入其他格式,例如 `DOCX`、`PPTX`、`CSV`。 + +```js +sendEditorCommand('document:save', { + targetExt: 'XLSX', +}); +``` + +默认情况下,保存命令必须等到编辑器返回当前编辑后的文件数据;如果超时会返回 `document:error`,避免误把原始文件上传到服务端。如果你的业务确实希望“没有修改时也回传原文件”,可以显式开启: + +```js +sendEditorCommand('document:save', { + targetExt: 'XLSX', + returnOriginalOnTimeout: true, +}); +``` + +父页面拿到文件后自行上传: + +```js +window.addEventListener('message', async (event) => { + if (event.origin !== editorOrigin) return; + + const { type, payload } = event.data || {}; + if (type !== 'document:saved') return; + + await fetch('/api/files/1', { + method: 'POST', + headers: { + Authorization: `Bearer ${token}`, + }, + body: payload.file, + }); +}); +``` + +注意:不要只用 `size` 判断文件是否变化,`xlsx` 是压缩包格式,轻微编辑后文件大小可能刚好不变。建议在调试时对返回的 `File` 计算 hash,项目内置的 `/embed-demo.html` 已经会在保存日志里打印 `sha256`。 + +### 6. 支持的消息 + +| 方向 | 类型 | 说明 | +| ---- | ---- | ---- | +| 父页面 → iframe | `document:open-url` | 通过 URL 打开文档 | +| 父页面 → iframe | `document:open-file` | 通过 `File` / `Blob` 打开文档 | +| 父页面 → iframe | `document:open-buffer` | 通过 `ArrayBuffer` / `Uint8Array` 打开文档 | +| 父页面 → iframe | `document:set-readonly` | 设置只读或可编辑 | +| 父页面 → iframe | `document:save` | 保存并返回 `File` | +| 父页面 → iframe | `document:get-state` | 获取当前状态 | +| iframe → 父页面 | `document:ready` | iframe 初始化完成 | +| iframe → 父页面 | `document:opened` | 文档打开完成 | +| iframe → 父页面 | `document:readonly-changed` | 只读状态已切换 | +| iframe → 父页面 | `document:saved` | 保存完成,返回文件 | +| iframe → 父页面 | `document:state` | 返回当前状态 | +| iframe → 父页面 | `document:error` | 操作失败 | + ## 🛠️ Technical Architecture - **OnlyOffice SDK**: Provides powerful document editing capabilities diff --git a/styles/base.css b/styles/base.css index 6c631779..a140e283 100644 --- a/styles/base.css +++ b/styles/base.css @@ -22,6 +22,12 @@ h2 { font-size: 1.5rem; } +body.embed-mode #control-panel-container, +body.embed-mode #fab-container, +body.embed-mode #menu-guide { + display: none !important; +} + /* Style for r-button webcomponent using ::part */ r-button[type='text']::part(ran-btn) { font-size: 18px; diff --git a/types/editor.d.ts b/types/editor.d.ts index 8020dd56..1cc2d367 100644 --- a/types/editor.d.ts +++ b/types/editor.d.ts @@ -13,6 +13,7 @@ interface DocEditorConfig { edit: boolean; chat: boolean; protect: boolean; + download?: boolean; }; }; editorConfig: { @@ -42,6 +43,7 @@ interface DocEditorConfig { onAppReady: () => void; onDocumentReady: () => void; onSave: (event: SaveEvent) => void; + onDownloadAs?: (event: DownloadAsEvent) => void; writeFile: (event: WriteFileEvent) => void; /** Handle external messages from plugins */ onExternalPluginMessage?: (event: { type: string; data: any; pluginName?: string }) => void; @@ -70,6 +72,13 @@ interface WriteFileEvent { callback?: (result: { success: boolean; error?: string }) => void; } +interface DownloadAsEvent { + data?: { + url?: string; + fileType?: string | number; + }; +} + interface DocEditor { sendCommand: (params: { command: string; @@ -81,8 +90,11 @@ interface DocEditor { buf?: ArrayBuffer; success?: boolean; error?: string; + enabled?: boolean; + message?: string; }; }) => void; + downloadAs?: (data?: string) => void; destroyEditor: () => void; }