diff --git a/.github/workflows/desktop-release-guard.yml b/.github/workflows/desktop-release-guard.yml
new file mode 100644
index 000000000..e3d0a569d
--- /dev/null
+++ b/.github/workflows/desktop-release-guard.yml
@@ -0,0 +1,71 @@
+name: Desktop Release Guard
+
+on:
+ pull_request:
+ paths:
+ - '.github/workflows/desktop-release-guard.yml'
+ - 'apps/desktop/**'
+ - 'package.json'
+ - 'package-lock.json'
+ - 'packages/client/**'
+ - 'packages/shared/**'
+ - 'propr-ui/**'
+ push:
+ tags:
+ - 'v*'
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+concurrency:
+ group: desktop-release-guard-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ verify:
+ name: Audit and package desktop app
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
+
+ - name: Set up Node.js
+ uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
+ with:
+ node-version-file: '.nvmrc'
+ cache: npm
+ cache-dependency-path: package-lock.json
+
+ # Audit the committed resolution before npm lifecycle or packaging code can run.
+ - name: Audit production runtime dependencies (low threshold)
+ run: npm run audit:runtime
+
+ - name: Audit desktop packaging toolchain (high threshold)
+ run: npm run desktop:audit:packaging
+
+ - name: Install locked dependencies
+ run: npm ci
+
+ - name: Package desktop app from clean checkout
+ run: |
+ test ! -e packages/shared/dist
+ test ! -e packages/client/dist
+ test ! -e apps/desktop/out
+ npm run desktop:package
+
+ - name: Typecheck desktop and renderer
+ run: npm run desktop:typecheck
+
+ - name: Test desktop runtime
+ run: npm run desktop:test
+
+ - name: Configure Chromium sandbox helper
+ run: |
+ sudo chown root:root apps/desktop/out/propr-desktop-linux-x64/chrome-sandbox
+ sudo chmod 4755 apps/desktop/out/propr-desktop-linux-x64/chrome-sandbox
+
+ - name: Launch packaged desktop app with sandboxing
+ run: xvfb-run --auto-servernum npm run desktop:smoke
diff --git a/.gitignore b/.gitignore
index 57baa45eb..5c9139815 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,3 +37,7 @@ apps/release-site-videos/
# Standalone publish staging (scripts/build-publish.mjs)
dist-publish/
+
+# Electron Forge build and package output
+apps/desktop/.vite/
+apps/desktop/out/
diff --git a/apps/desktop/README.md b/apps/desktop/README.md
new file mode 100644
index 000000000..265883486
--- /dev/null
+++ b/apps/desktop/README.md
@@ -0,0 +1,51 @@
+# ProPR Desktop
+
+This workspace packages the existing `propr-ui` React source as a sandboxed Electron renderer. The desktop entry is
+`propr-ui/src/desktop.tsx`; the normal web entry, service worker, CLI, API, and self-hosted deployment remain unchanged.
+
+## Commands
+
+Run these from the repository root:
+
+```sh
+npm run desktop:dev
+npm run desktop:typecheck
+npm run desktop:test
+npm run desktop:package
+npm run desktop:smoke # Run under xvfb-run on a headless Linux host.
+npm run desktop:make
+npm run desktop:audit
+# On Linux hosts with the corresponding native packaging tools installed:
+npm run make:deb -w @propr/desktop
+npm run make:rpm -w @propr/desktop
+```
+
+Desktop development, typecheck, package, and make commands build required renderer workspace dependencies through
+`desktop:prepare`, in dependency order (`@propr/shared` then `@propr/client`). They do not depend on previously
+generated workspace `dist` directories.
+
+Development renderer URLs are accepted only when Electron Forge supplies an HTTP loopback URL. Packaged builds load
+the generated renderer from the application ASAR through an app-owned protocol.
+
+The packaged-binary smoke test verifies the hardened fuse states, launches the Linux artifact without a
+sandbox-disabling flag, rejects main-process uncaught exceptions, and requires proof that `window.proprDesktop` is
+exposed before accepting renderer-ready and a clean exit.
+
+`desktop:audit` deliberately applies separate policies to the two dependency surfaces: low-or-higher advisories fail
+the production-runtime audit, while high and critical advisories fail the desktop development/build-tool audit. Release
+CI runs both checks directly from the committed lockfile before installing or executing the packaging toolchain.
+
+## Security boundary
+
+The renderer has no Node.js integration and receives only the typed `window.proprDesktop` bridge. It exposes metadata,
+validated external-browser opening, profiles, encrypted credentials, lifecycle placeholders, and validated deep-link
+events. It never exposes a shell, command runner, arbitrary IPC call, or filesystem path/API.
+
+Profile metadata is stored in an app-owned, permission-restricted JSON file. Credential values are encrypted with
+Electron `safeStorage` before they are written separately. If OS encryption is unavailable—or Linux selects the
+`basic_text` backend—the app reports that state and refuses to persist or return credentials; there is no plaintext
+fallback. Profiles remain usable because they contain only a display label and validated API endpoint.
+
+`propr://connect` and `propr://open` are the only accepted deep-link actions. A single-instance lock routes later
+activations to the existing window. Local lifecycle methods intentionally return `not-implemented`; this scaffold does
+not download, install, start, or execute ProPR runtime components.
diff --git a/apps/desktop/forge.config.ts b/apps/desktop/forge.config.ts
new file mode 100644
index 000000000..a2d291851
--- /dev/null
+++ b/apps/desktop/forge.config.ts
@@ -0,0 +1,56 @@
+import type { ForgeConfig } from '@electron-forge/shared-types';
+import { MakerDeb } from '@electron-forge/maker-deb';
+import { MakerRpm } from '@electron-forge/maker-rpm';
+import { MakerSquirrel } from '@electron-forge/maker-squirrel';
+import { MakerZIP } from '@electron-forge/maker-zip';
+import { VitePlugin } from '@electron-forge/plugin-vite';
+import { flipFuses, FuseV1Options, FuseVersion } from '@electron/fuses';
+import { resolve } from 'node:path';
+
+const config: ForgeConfig = {
+ packagerConfig: {
+ asar: true,
+ name: 'propr-desktop',
+ executableName: 'propr-desktop',
+ },
+ rebuildConfig: {},
+ hooks: {
+ packageAfterCopy: async (_forgeConfig, resourcesPath, _electronVersion, platform, arch) => {
+ const applePlatform = platform === 'darwin' || platform === 'mas';
+ const executableName = applePlatform ? 'Electron' : `electron${platform === 'win32' ? '.exe' : ''}`;
+ await flipFuses(resolve(resourcesPath, '..', '..', applePlatform ? 'MacOS' : '', executableName), {
+ version: FuseVersion.V1,
+ resetAdHocDarwinSignature: applePlatform && arch === 'arm64',
+ strictlyRequireAllFuses: true,
+ [FuseV1Options.RunAsNode]: false,
+ [FuseV1Options.EnableCookieEncryption]: true,
+ [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
+ [FuseV1Options.EnableNodeCliInspectArguments]: false,
+ [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
+ [FuseV1Options.OnlyLoadAppFromAsar]: true,
+ [FuseV1Options.LoadBrowserProcessSpecificV8Snapshot]: false,
+ [FuseV1Options.GrantFileProtocolExtraPrivileges]: false,
+ [FuseV1Options.WasmTrapHandlers]: true,
+ });
+ },
+ },
+ makers: [
+ new MakerSquirrel({ name: 'propr_desktop' }),
+ new MakerZIP({}, ['darwin', 'linux']),
+ ...(process.env.PROPR_DESKTOP_ENABLE_DEB === '1' ? [new MakerDeb({})] : []),
+ ...(process.env.PROPR_DESKTOP_ENABLE_RPM === '1' ? [new MakerRpm({})] : []),
+ ],
+ plugins: [
+ new VitePlugin({
+ build: [
+ { entry: 'src/main.ts', config: 'vite.main.config.ts' },
+ { entry: 'src/preload.ts', config: 'vite.preload.config.ts' },
+ ],
+ renderer: [
+ { name: 'main_window', config: 'vite.renderer.config.ts' },
+ ],
+ }),
+ ],
+};
+
+export default config;
diff --git a/apps/desktop/package.json b/apps/desktop/package.json
new file mode 100644
index 000000000..c82d40083
--- /dev/null
+++ b/apps/desktop/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@propr/desktop",
+ "productName": "ProPR Desktop",
+ "version": "0.8.15",
+ "private": true,
+ "description": "Secure ProPR desktop application",
+ "author": "Unchained Development OÜ / Rinalds Uzkalns",
+ "license": "Apache-2.0",
+ "homepage": "https://github.com/integry/propr",
+ "type": "module",
+ "main": ".vite/build/main.cjs",
+ "scripts": {
+ "prepare:renderer": "npm run build -w @propr/shared && npm run build -w @propr/client",
+ "predev": "npm run prepare:renderer",
+ "dev": "electron-forge start",
+ "pretypecheck": "npm run prepare:renderer",
+ "typecheck": "tsc --noEmit",
+ "test": "tsx --test src/**/*.test.ts",
+ "prepackage": "npm run prepare:renderer",
+ "package": "electron-forge package",
+ "smoke:package": "node scripts/smoke-packaged.mjs",
+ "premake": "npm run prepare:renderer",
+ "make": "electron-forge make",
+ "premake:deb": "npm run prepare:renderer",
+ "make:deb": "PROPR_DESKTOP_ENABLE_DEB=1 electron-forge make --targets @electron-forge/maker-deb",
+ "premake:rpm": "npm run prepare:renderer",
+ "make:rpm": "PROPR_DESKTOP_ENABLE_RPM=1 electron-forge make --targets @electron-forge/maker-rpm"
+ },
+ "devDependencies": {
+ "@electron-forge/cli": "8.0.0-alpha.10",
+ "@electron-forge/maker-deb": "8.0.0-alpha.10",
+ "@electron-forge/maker-rpm": "8.0.0-alpha.10",
+ "@electron-forge/maker-squirrel": "8.0.0-alpha.10",
+ "@electron-forge/maker-zip": "8.0.0-alpha.10",
+ "@electron-forge/plugin-vite": "8.0.0-alpha.10",
+ "@electron-forge/shared-types": "8.0.0-alpha.10",
+ "@electron/fuses": "^2.1.3",
+ "@types/node": "^22.10.0",
+ "@vitejs/plugin-react": "^4.6.0",
+ "electron": "^44.0.0",
+ "tsx": "^4.21.0",
+ "typescript": "^5.9.3",
+ "vite": "^7.3.5"
+ }
+}
diff --git a/apps/desktop/renderer.html b/apps/desktop/renderer.html
new file mode 100644
index 000000000..374512fdf
--- /dev/null
+++ b/apps/desktop/renderer.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ ProPR Desktop
+
+
+
+
+
+
diff --git a/apps/desktop/scripts/smoke-packaged.mjs b/apps/desktop/scripts/smoke-packaged.mjs
new file mode 100644
index 000000000..ed36bb5a3
--- /dev/null
+++ b/apps/desktop/scripts/smoke-packaged.mjs
@@ -0,0 +1,146 @@
+import { spawn } from 'node:child_process';
+import { once } from 'node:events';
+import { access, mkdtemp, rm } from 'node:fs/promises';
+import { createServer } from 'node:http';
+import { tmpdir } from 'node:os';
+import { resolve } from 'node:path';
+import { DESKTOP_RENDERER_ORIGIN } from '@propr/shared';
+import {
+ FuseState,
+ FuseV1Options,
+ FuseVersion,
+ getCurrentFuseWire,
+} from '@electron/fuses';
+
+const READY_EVENT = 'desktop.renderer.ready';
+const PRELOAD_BRIDGE_PROOF = '"preloadBridgeExposed":true';
+const PROFILE_API_PROOF = 'desktop.renderer.profile_api.ready';
+const MAIN_PROCESS_ERROR_MARKERS = [
+ 'desktop.main_process.uncaught_exception',
+ 'A JavaScript error occurred in the main process',
+ 'Uncaught Exception:',
+];
+const TIMEOUT_MS = 30_000;
+const binaryPath = resolve('out', `propr-desktop-linux-${process.arch}`, 'propr-desktop');
+
+if (process.platform !== 'linux') {
+ throw new Error('The packaged-binary smoke test currently targets the Linux artifact');
+}
+
+await access(binaryPath);
+
+const expectedFuses = new Map([
+ [FuseV1Options.RunAsNode, FuseState.DISABLE],
+ [FuseV1Options.EnableCookieEncryption, FuseState.ENABLE],
+ [FuseV1Options.EnableNodeOptionsEnvironmentVariable, FuseState.DISABLE],
+ [FuseV1Options.EnableNodeCliInspectArguments, FuseState.DISABLE],
+ [FuseV1Options.EnableEmbeddedAsarIntegrityValidation, FuseState.ENABLE],
+ [FuseV1Options.OnlyLoadAppFromAsar, FuseState.ENABLE],
+ [FuseV1Options.LoadBrowserProcessSpecificV8Snapshot, FuseState.DISABLE],
+ [FuseV1Options.GrantFileProtocolExtraPrivileges, FuseState.DISABLE],
+ [FuseV1Options.WasmTrapHandlers, FuseState.ENABLE],
+]);
+const actualFuses = await getCurrentFuseWire(binaryPath);
+
+if (actualFuses.version !== FuseVersion.V1) {
+ throw new Error(`Expected fuse wire version ${FuseVersion.V1}, received ${actualFuses.version}`);
+}
+for (const [fuse, expectedState] of expectedFuses) {
+ const actualState = actualFuses[fuse];
+ if (actualState !== expectedState) {
+ throw new Error(
+ `Unexpected ${FuseV1Options[fuse]} fuse state: expected ${FuseState[expectedState]}, received ${FuseState[actualState] ?? actualState}`,
+ );
+ }
+}
+
+const userDataPath = await mkdtemp(resolve(tmpdir(), 'propr-desktop-smoke-'));
+const launchArguments = ['--disable-gpu', `--user-data-dir=${userDataPath}`];
+if (launchArguments.some(argument => argument === '--no-sandbox' || argument === '--disable-sandbox')) {
+ throw new Error('The packaged-binary smoke test must not disable Electron sandboxing');
+}
+
+let output = '';
+let receivedProfileApiOrigin;
+const profileApiServer = createServer((request, response) => {
+ receivedProfileApiOrigin = request.headers.origin;
+ if (
+ request.method !== 'GET'
+ || request.url !== '/api/compatibility'
+ || receivedProfileApiOrigin !== DESKTOP_RENDERER_ORIGIN
+ ) {
+ response.writeHead(403, { 'Content-Type': 'application/json' });
+ response.end('{"error":"CORS origin rejected"}');
+ return;
+ }
+ response.writeHead(200, {
+ 'Access-Control-Allow-Credentials': 'true',
+ 'Access-Control-Allow-Origin': DESKTOP_RENDERER_ORIGIN,
+ 'Content-Type': 'application/json',
+ });
+ response.end('{"profileEndpoint":true}');
+});
+profileApiServer.listen(0, '127.0.0.1');
+await once(profileApiServer, 'listening');
+const profileApiAddress = profileApiServer.address();
+if (!profileApiAddress || typeof profileApiAddress === 'string') {
+ throw new Error('Packaged desktop smoke profile API did not bind to a TCP port');
+}
+const profileApiUrl = `http://127.0.0.1:${profileApiAddress.port}`;
+
+try {
+ const child = spawn(binaryPath, launchArguments, {
+ env: {
+ ...process.env,
+ PROPR_DESKTOP_SMOKE_PROFILE_API_URL: profileApiUrl,
+ PROPR_DESKTOP_SMOKE_TEST: '1',
+ },
+ stdio: ['ignore', 'pipe', 'pipe'],
+ });
+
+ const capture = chunk => {
+ const text = chunk.toString();
+ output += text;
+ process.stdout.write(text);
+ };
+ child.stdout.on('data', capture);
+ child.stderr.on('data', capture);
+
+ const result = await new Promise((resolveResult, reject) => {
+ const timeout = setTimeout(() => {
+ child.kill('SIGKILL');
+ reject(new Error(`Packaged desktop did not reach renderer-ready within ${TIMEOUT_MS / 1000} seconds`));
+ }, TIMEOUT_MS);
+ child.once('error', error => {
+ clearTimeout(timeout);
+ reject(error);
+ });
+ child.once('close', (code, signal) => {
+ clearTimeout(timeout);
+ resolveResult({ code, signal });
+ });
+ });
+
+ const mainProcessError = MAIN_PROCESS_ERROR_MARKERS.find(marker => output.includes(marker));
+ if (mainProcessError) {
+ throw new Error(`Packaged desktop reported a main-process uncaught exception (${mainProcessError})`);
+ }
+ if (result.code !== 0) {
+ throw new Error(`Packaged desktop exited with code ${result.code ?? 'null'} (signal ${result.signal ?? 'none'})`);
+ }
+ if (!output.includes(READY_EVENT)) {
+ throw new Error('Packaged desktop exited without reporting renderer-ready');
+ }
+ if (!output.includes(PRELOAD_BRIDGE_PROOF)) {
+ throw new Error('Packaged desktop reported renderer-ready without proving window.proprDesktop is exposed');
+ }
+ if (!output.includes(PROFILE_API_PROOF) || receivedProfileApiOrigin !== DESKTOP_RENDERER_ORIGIN) {
+ throw new Error('Packaged desktop did not complete a profile API request from its exact renderer origin');
+ }
+
+ console.log('Packaged Linux desktop reached renderer-ready and completed a profile API request with sandboxing enabled.');
+} finally {
+ profileApiServer.closeAllConnections();
+ await new Promise(resolveClose => profileApiServer.close(resolveClose));
+ await rm(userDataPath, { recursive: true, force: true });
+}
diff --git a/apps/desktop/src/deep-link-delivery.test.ts b/apps/desktop/src/deep-link-delivery.test.ts
new file mode 100644
index 000000000..171209700
--- /dev/null
+++ b/apps/desktop/src/deep-link-delivery.test.ts
@@ -0,0 +1,26 @@
+import assert from 'node:assert/strict';
+import { describe, it } from 'node:test';
+import { DeepLinkDelivery, type DeepLinkWindow } from './deep-link-delivery';
+
+describe('desktop deep-link delivery', () => {
+ it('delivers a link received after did-finish-load but before global window assignment', () => {
+ const sent: Array<{ channel: string; value: string }> = [];
+ const window: DeepLinkWindow = {
+ isDestroyed: () => false,
+ webContents: {
+ isLoading: () => false,
+ send: (channel, value) => sent.push({ channel, value }),
+ },
+ };
+ const delivery = new DeepLinkDelivery('desktop:deep-link', ['propr://open?task=initial']);
+
+ delivery.didFinishLoad(window);
+ delivery.deliver('propr://open?task=between');
+ delivery.setWindow(window);
+
+ assert.deepEqual(sent, [
+ { channel: 'desktop:deep-link', value: 'propr://open?task=initial' },
+ { channel: 'desktop:deep-link', value: 'propr://open?task=between' },
+ ]);
+ });
+});
diff --git a/apps/desktop/src/deep-link-delivery.ts b/apps/desktop/src/deep-link-delivery.ts
new file mode 100644
index 000000000..99c124632
--- /dev/null
+++ b/apps/desktop/src/deep-link-delivery.ts
@@ -0,0 +1,44 @@
+export interface DeepLinkWindow {
+ isDestroyed(): boolean;
+ webContents: {
+ isLoading(): boolean;
+ send(channel: string, value: string): void;
+ };
+}
+
+/** Coordinates protocol delivery across the window creation/load boundary. */
+export class DeepLinkDelivery {
+ private window: TWindow | null = null;
+
+ constructor(
+ private readonly channel: string,
+ private readonly pending: string[] = [],
+ ) {}
+
+ deliver(value: string): void {
+ if (!this.window || this.window.isDestroyed() || this.window.webContents.isLoading()) {
+ this.pending.push(value);
+ return;
+ }
+ this.window.webContents.send(this.channel, value);
+ }
+
+ didFinishLoad(window: TWindow): void {
+ this.flush(window);
+ }
+
+ setWindow(window: TWindow): void {
+ this.window = window;
+ this.flush(window);
+ }
+
+ clearWindow(window: TWindow): void {
+ if (this.window === window) this.window = null;
+ }
+
+ private flush(window: TWindow): void {
+ if (window.isDestroyed() || window.webContents.isLoading()) return;
+ const linksToDeliver = this.pending.splice(0);
+ linksToDeliver.forEach(value => window.webContents.send(this.channel, value));
+ }
+}
diff --git a/apps/desktop/src/desktop-session.ts b/apps/desktop/src/desktop-session.ts
new file mode 100644
index 000000000..1beb2fd79
--- /dev/null
+++ b/apps/desktop/src/desktop-session.ts
@@ -0,0 +1,18 @@
+import type { Session } from 'electron';
+import { normalizeApiBaseUrl } from './security';
+
+export const logoutDesktopSession = async (
+ desktopSession: Pick,
+ apiBaseUrl: unknown,
+): Promise => {
+ if (typeof apiBaseUrl !== 'string') throw new Error('Invalid desktop API URL');
+ const normalizedApiBaseUrl = normalizeApiBaseUrl(apiBaseUrl);
+ if (!normalizedApiBaseUrl || normalizedApiBaseUrl !== apiBaseUrl) throw new Error('Invalid desktop API URL');
+ const response = await desktopSession.fetch(`${normalizedApiBaseUrl}/api/auth/logout`, {
+ credentials: 'include',
+ redirect: 'manual',
+ });
+ if (!response.ok && (response.status < 300 || response.status >= 400)) {
+ throw new Error(`Desktop logout failed with HTTP ${response.status}`);
+ }
+};
diff --git a/apps/desktop/src/global.d.ts b/apps/desktop/src/global.d.ts
new file mode 100644
index 000000000..ad7963f08
--- /dev/null
+++ b/apps/desktop/src/global.d.ts
@@ -0,0 +1,2 @@
+declare const MAIN_WINDOW_VITE_DEV_SERVER_URL: string | undefined;
+declare const MAIN_WINDOW_VITE_NAME: string;
diff --git a/apps/desktop/src/ipc.test.ts b/apps/desktop/src/ipc.test.ts
new file mode 100644
index 000000000..8ac15b68b
--- /dev/null
+++ b/apps/desktop/src/ipc.test.ts
@@ -0,0 +1,37 @@
+import assert from 'node:assert/strict';
+import { describe, it } from 'node:test';
+import type { Session } from 'electron';
+import { logoutDesktopSession } from './desktop-session';
+
+describe('desktop session IPC operations', () => {
+ it('logs out through the active Electron session with credentials and without following redirects', async () => {
+ const requests: Array<{ url: string; init: RequestInit | undefined }> = [];
+ const desktopSession: Pick = {
+ fetch: async (input, init) => {
+ requests.push({ url: input.toString(), init });
+ return new Response(null, { status: 302 });
+ },
+ };
+
+ await logoutDesktopSession(desktopSession, 'https://propr.example.com');
+
+ assert.deepEqual(requests, [{
+ url: 'https://propr.example.com/api/auth/logout',
+ init: { credentials: 'include', redirect: 'manual' },
+ }]);
+ });
+
+ it('rejects untrusted logout endpoints before making a session request', async () => {
+ let requested = false;
+ const desktopSession: Pick = {
+ fetch: async () => {
+ requested = true;
+ return new Response(null, { status: 200 });
+ },
+ };
+
+ await assert.rejects(logoutDesktopSession(desktopSession, 'https://propr.example.com/base'), /Invalid desktop API URL/);
+ await assert.rejects(logoutDesktopSession(desktopSession, 'https://user:secret@example.com'), /Invalid desktop API URL/);
+ assert.equal(requested, false);
+ });
+});
diff --git a/apps/desktop/src/ipc.ts b/apps/desktop/src/ipc.ts
new file mode 100644
index 000000000..93245534b
--- /dev/null
+++ b/apps/desktop/src/ipc.ts
@@ -0,0 +1,67 @@
+import type { App, IpcMain, IpcMainInvokeEvent, Session } from 'electron';
+import { shell } from 'electron';
+import { logoutDesktopSession } from './desktop-session';
+import type { DesktopLogger } from './logger';
+import type { LocalLifecycleController } from './lifecycle';
+import type { ProfileStore } from './profile-store';
+import { isSafeExternalUrl, isTrustedRendererUrl } from './security';
+import { IPC_CHANNELS } from './shared/contract';
+
+interface RegisterIpcOptions {
+ app: App;
+ ipcMain: IpcMain;
+ profiles: ProfileStore;
+ lifecycle: LocalLifecycleController;
+ logger: DesktopLogger;
+ desktopSession: Session;
+ devServerUrl: string | undefined;
+ packagedRendererUrl: string;
+}
+
+type Handler = (event: IpcMainInvokeEvent, ...args: any[]) => unknown;
+
+export const registerIpcHandlers = (options: RegisterIpcOptions): void => {
+ const trusted = (event: IpcMainInvokeEvent): boolean => {
+ const senderUrl = event.senderFrame?.url ?? '';
+ return isTrustedRendererUrl(senderUrl, options.devServerUrl, options.packagedRendererUrl);
+ };
+ const handle = (channel: string, handler: Handler): void => {
+ options.ipcMain.handle(channel, async (event, ...args) => {
+ if (!trusted(event)) {
+ options.logger.log('warn', 'desktop.ipc.rejected', { channel });
+ throw new Error('Untrusted desktop IPC sender');
+ }
+ try {
+ return await handler(event, ...args);
+ } catch (error) {
+ options.logger.log('error', 'desktop.ipc.failed', { channel, error });
+ throw error;
+ }
+ });
+ };
+
+ handle(IPC_CHANNELS.appMetadata, () => ({
+ name: options.app.getName(),
+ version: options.app.getVersion(),
+ platform: process.platform,
+ arch: process.arch,
+ packaged: options.app.isPackaged,
+ }));
+ handle(IPC_CHANNELS.authLogout, (_event, apiBaseUrl) => logoutDesktopSession(options.desktopSession, apiBaseUrl));
+ handle(IPC_CHANNELS.openExternal, async (_event, value: unknown) => {
+ if (typeof value !== 'string' || !isSafeExternalUrl(value)) throw new Error('External URL is not allowed');
+ await shell.openExternal(value);
+ });
+ handle(IPC_CHANNELS.storageSecurity, () => options.profiles.security());
+ handle(IPC_CHANNELS.profilesList, () => options.profiles.list());
+ handle(IPC_CHANNELS.profilesSave, (_event, input) => options.profiles.save(input));
+ handle(IPC_CHANNELS.profilesRemove, (_event, profileId) => options.profiles.remove(profileId));
+ handle(IPC_CHANNELS.profilesSetActive, (_event, profileId) => options.profiles.setActive(profileId));
+ handle(IPC_CHANNELS.credentialsRead, (_event, profileId) => options.profiles.readCredential(profileId));
+ handle(IPC_CHANNELS.credentialsWrite, (_event, profileId, value) => options.profiles.writeCredential(profileId, value));
+ handle(IPC_CHANNELS.credentialsRemove, (_event, profileId) => options.profiles.removeCredential(profileId));
+ handle(IPC_CHANNELS.lifecycleStatus, () => options.lifecycle.status());
+ handle(IPC_CHANNELS.lifecycleStart, () => options.lifecycle.start());
+ handle(IPC_CHANNELS.lifecycleStop, () => options.lifecycle.stop());
+ handle(IPC_CHANNELS.lifecycleRestart, () => options.lifecycle.restart());
+};
diff --git a/apps/desktop/src/lifecycle.ts b/apps/desktop/src/lifecycle.ts
new file mode 100644
index 000000000..a302635fc
--- /dev/null
+++ b/apps/desktop/src/lifecycle.ts
@@ -0,0 +1,40 @@
+import type { LocalLifecycleOperationResult, LocalLifecycleStatus } from './shared/contract';
+
+/**
+ * Stable renderer-facing lifecycle boundary. Runtime installation and process
+ * control are deliberately absent until the user-approved setup work lands.
+ */
+export class LocalLifecycleController {
+ #status: LocalLifecycleStatus = { state: 'disconnected' };
+
+ status(): LocalLifecycleStatus {
+ return { ...this.#status };
+ }
+
+ start(): LocalLifecycleOperationResult {
+ return this.#unsupported();
+ }
+
+ stop(): LocalLifecycleOperationResult {
+ return this.#unsupported();
+ }
+
+ restart(): LocalLifecycleOperationResult {
+ return this.#unsupported();
+ }
+
+ async shutdown(): Promise {
+ this.#status = { state: 'disconnected' };
+ }
+
+ #unsupported(): LocalLifecycleOperationResult {
+ return {
+ ok: false,
+ code: 'not-implemented',
+ status: {
+ ...this.#status,
+ detail: 'Local runtime management is not available in this desktop scaffold.',
+ },
+ };
+ }
+}
diff --git a/apps/desktop/src/logger.ts b/apps/desktop/src/logger.ts
new file mode 100644
index 000000000..a50fd9bbe
--- /dev/null
+++ b/apps/desktop/src/logger.ts
@@ -0,0 +1,33 @@
+import { appendFile, mkdir } from 'node:fs/promises';
+import { dirname } from 'node:path';
+
+export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
+
+export interface DesktopLogger {
+ log(level: LogLevel, event: string, fields?: Record): void;
+}
+
+const serializeError = (value: unknown): unknown => value instanceof Error
+ ? { name: value.name, message: value.message, stack: value.stack }
+ : value;
+
+export const createDesktopLogger = (logPath: string): DesktopLogger => {
+ let pending = Promise.resolve();
+ const log = (level: LogLevel, event: string, fields: Record = {}) => {
+ const record = JSON.stringify({
+ timestamp: new Date().toISOString(),
+ level,
+ event,
+ ...Object.fromEntries(Object.entries(fields).map(([key, value]) => [key, serializeError(value)])),
+ });
+ const consoleMethod = level === 'error' ? console.error : level === 'warn' ? console.warn : console.log;
+ consoleMethod(record);
+ pending = pending
+ .then(async () => {
+ await mkdir(dirname(logPath), { recursive: true, mode: 0o700 });
+ await appendFile(logPath, `${record}\n`, { encoding: 'utf8', mode: 0o600 });
+ })
+ .catch(error => console.error(JSON.stringify({ level: 'error', event: 'desktop.log.write_failed', error: serializeError(error) })));
+ };
+ return { log };
+};
diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts
new file mode 100644
index 000000000..d121bd8d8
--- /dev/null
+++ b/apps/desktop/src/main.ts
@@ -0,0 +1,261 @@
+import { isAbsolute, join, relative, resolve } from 'node:path';
+import { pathToFileURL } from 'node:url';
+import { app, BrowserWindow, ipcMain, net, protocol, safeStorage, session, shell } from 'electron';
+import { DESKTOP_RENDERER_ORIGIN } from '@propr/shared';
+import { DeepLinkDelivery } from './deep-link-delivery';
+import { registerIpcHandlers } from './ipc';
+import { LocalLifecycleController } from './lifecycle';
+import { createDesktopLogger, type DesktopLogger } from './logger';
+import { ProfileStore, type EncryptionProvider } from './profile-store';
+import {
+ deepLinkFromArguments,
+ isSafeExternalUrl,
+ isTrustedRendererUrl,
+ normalizeApiBaseUrl,
+ normalizeDeepLink,
+ rendererContentSecurityPolicy,
+ validatedDevServerUrl,
+} from './security';
+import { DESKTOP_PROTOCOL, IPC_CHANNELS } from './shared/contract';
+import { createBrowserWindowOptions } from './window-options';
+
+const devServerUrl = typeof MAIN_WINDOW_VITE_DEV_SERVER_URL === 'string'
+ ? MAIN_WINDOW_VITE_DEV_SERVER_URL
+ : undefined;
+const PACKAGED_RENDERER_SCHEME = 'propr-app';
+const PACKAGED_RENDERER_HOST = 'renderer';
+const packagedRendererRoot = join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}`);
+const packagedRendererUrl = `${DESKTOP_RENDERER_ORIGIN}/renderer.html`;
+let mainWindow: BrowserWindow | null = null;
+const initialDeepLink = deepLinkFromArguments(process.argv);
+const deepLinkDelivery = new DeepLinkDelivery(
+ IPC_CHANNELS.deepLink,
+ initialDeepLink ? [initialDeepLink] : [],
+);
+let logger: DesktopLogger | null = null;
+let shutdownStarted = false;
+
+const log = (level: 'debug' | 'info' | 'warn' | 'error', event: string, fields?: Record) =>
+ logger
+ ? logger.log(level, event, fields)
+ : console.error(JSON.stringify({ timestamp: new Date().toISOString(), level, event, ...fields }));
+
+process.on('uncaughtExceptionMonitor', error => {
+ log('error', 'desktop.main_process.uncaught_exception', { error });
+});
+
+protocol.registerSchemesAsPrivileged([{
+ scheme: PACKAGED_RENDERER_SCHEME,
+ privileges: {
+ standard: true,
+ secure: true,
+ supportFetchAPI: true,
+ corsEnabled: true,
+ },
+}]);
+
+const registerProtocolClient = (): void => {
+ if (process.defaultApp && process.argv[1]) {
+ app.setAsDefaultProtocolClient(DESKTOP_PROTOCOL, process.execPath, [process.argv[1]]);
+ return;
+ }
+ app.setAsDefaultProtocolClient(DESKTOP_PROTOCOL);
+};
+
+const deliverDeepLink = (value: string): void => {
+ deepLinkDelivery.deliver(value);
+};
+
+const configureSessionSecurity = (): void => {
+ const desktopSession = session.defaultSession;
+ desktopSession.setPermissionCheckHandler(() => false);
+ desktopSession.setPermissionRequestHandler((_webContents, _permission, callback) => callback(false));
+ desktopSession.webRequest.onHeadersReceived((details, callback) => {
+ callback({
+ responseHeaders: {
+ ...details.responseHeaders,
+ 'Content-Security-Policy': [rendererContentSecurityPolicy(!app.isPackaged)],
+ },
+ });
+ });
+};
+
+const configurePackagedRendererProtocol = (): void => {
+ protocol.handle(PACKAGED_RENDERER_SCHEME, request => {
+ const requestUrl = new URL(request.url);
+ if (requestUrl.hostname !== PACKAGED_RENDERER_HOST) {
+ return new Response(null, { status: 404 });
+ }
+
+ let requestedPath: string;
+ try {
+ requestedPath = decodeURIComponent(requestUrl.pathname).replace(/^\/+/, '');
+ } catch {
+ return new Response(null, { status: 400 });
+ }
+ const filePath = resolve(packagedRendererRoot, requestedPath);
+ const relativePath = relative(packagedRendererRoot, filePath);
+ if (relativePath.startsWith('..') || isAbsolute(relativePath)) {
+ return new Response(null, { status: 403 });
+ }
+ return net.fetch(pathToFileURL(filePath).href);
+ });
+};
+
+const openAllowedExternalUrl = async (url: string): Promise => {
+ if (!isSafeExternalUrl(url)) {
+ log('warn', 'desktop.external_url.rejected');
+ return;
+ }
+ await shell.openExternal(url);
+};
+
+const createMainWindow = async (): Promise => {
+ const window = new BrowserWindow(createBrowserWindowOptions(join(__dirname, 'preload.cjs'), !app.isPackaged));
+ const readyToShow = new Promise(resolveReady => window.once('ready-to-show', resolveReady));
+
+ window.webContents.setWindowOpenHandler(({ url }) => {
+ void openAllowedExternalUrl(url);
+ return { action: 'deny' };
+ });
+ window.webContents.on('will-navigate', (event, url) => {
+ if (isTrustedRendererUrl(url, devServerUrl, packagedRendererUrl)) return;
+ event.preventDefault();
+ void openAllowedExternalUrl(url);
+ });
+ window.webContents.on('will-attach-webview', (event) => event.preventDefault());
+ window.webContents.on('render-process-gone', (_event, details) => {
+ log('error', 'desktop.renderer.gone', { reason: details.reason, exitCode: details.exitCode });
+ });
+ window.webContents.on('did-finish-load', () => {
+ deepLinkDelivery.didFinishLoad(window);
+ });
+ window.on('closed', () => {
+ if (mainWindow === window) {
+ mainWindow = null;
+ deepLinkDelivery.clearWindow(window);
+ }
+ });
+
+ const validatedDevUrl = validatedDevServerUrl(devServerUrl);
+ if (devServerUrl && !validatedDevUrl) throw new Error('Electron Forge supplied an unsafe renderer development URL');
+ if (validatedDevUrl) {
+ await window.loadURL(new URL('renderer.html', validatedDevUrl).href);
+ } else {
+ await window.loadURL(packagedRendererUrl);
+ }
+
+ await readyToShow;
+ const preloadBridgeExposed = await window.webContents.executeJavaScript(
+ "typeof window.proprDesktop === 'object' && window.proprDesktop !== null",
+ );
+ if (preloadBridgeExposed !== true) {
+ throw new Error('Desktop preload bridge was not exposed to the renderer');
+ }
+ const smokeProfileApiUrl = process.env.PROPR_DESKTOP_SMOKE_PROFILE_API_URL;
+ if (app.isPackaged && process.env.PROPR_DESKTOP_SMOKE_TEST === '1' && smokeProfileApiUrl) {
+ const normalizedSmokeApiUrl = normalizeApiBaseUrl(smokeProfileApiUrl);
+ if (!normalizedSmokeApiUrl || normalizedSmokeApiUrl !== smokeProfileApiUrl) {
+ throw new Error('Packaged desktop smoke profile API URL is invalid');
+ }
+ const endpoint = `${normalizedSmokeApiUrl}/api/compatibility`;
+ const result = await window.webContents.executeJavaScript(`(async () => {
+ const response = await fetch(${JSON.stringify(endpoint)}, { credentials: 'include' });
+ return { ok: response.ok, status: response.status, body: await response.json() };
+ })()`);
+ if (result?.ok !== true || result?.body?.profileEndpoint !== true) {
+ throw new Error(`Packaged renderer profile API request failed with HTTP ${result?.status ?? 'unknown'}`);
+ }
+ log('info', 'desktop.renderer.profile_api.ready', { origin: DESKTOP_RENDERER_ORIGIN });
+ }
+ log('info', 'desktop.renderer.ready', { preloadBridgeExposed: true });
+ if (app.isPackaged && process.env.PROPR_DESKTOP_SMOKE_TEST === '1') {
+ app.quit();
+ } else {
+ window.show();
+ }
+ return window;
+};
+
+app.on('open-url', (event, url) => {
+ event.preventDefault();
+ const normalized = normalizeDeepLink(url);
+ if (normalized) deliverDeepLink(normalized);
+});
+
+const hasSingleInstanceLock = app.requestSingleInstanceLock();
+if (!hasSingleInstanceLock) {
+ app.quit();
+} else {
+ app.on('second-instance', (_event, argv) => {
+ const deepLink = deepLinkFromArguments(argv);
+ if (deepLink) deliverDeepLink(deepLink);
+ if (mainWindow) {
+ if (mainWindow.isMinimized()) mainWindow.restore();
+ mainWindow.show();
+ mainWindow.focus();
+ }
+ });
+
+ registerProtocolClient();
+ void app.whenReady().then(async () => {
+ logger = createDesktopLogger(join(app.getPath('logs'), 'desktop.jsonl'));
+ log('info', 'desktop.app.ready', { version: app.getVersion(), platform: process.platform });
+ configureSessionSecurity();
+ configurePackagedRendererProtocol();
+
+ const encryption: EncryptionProvider = {
+ isEncryptionAvailable: () => safeStorage.isEncryptionAvailable(),
+ backend: () => {
+ if (process.platform !== 'linux') return 'os-protected';
+ try {
+ return safeStorage.getSelectedStorageBackend();
+ } catch {
+ return 'unavailable';
+ }
+ },
+ encrypt: value => safeStorage.encryptString(value),
+ decrypt: value => safeStorage.decryptString(value),
+ };
+ const profiles = new ProfileStore(app.getPath('userData'), encryption);
+ const lifecycle = new LocalLifecycleController();
+ registerIpcHandlers({
+ app,
+ ipcMain,
+ profiles,
+ lifecycle,
+ logger,
+ desktopSession: session.defaultSession,
+ devServerUrl,
+ packagedRendererUrl,
+ });
+ mainWindow = await createMainWindow();
+ deepLinkDelivery.setWindow(mainWindow);
+
+ app.on('activate', () => {
+ if (BrowserWindow.getAllWindows().length === 0) {
+ void createMainWindow().then(window => {
+ mainWindow = window;
+ deepLinkDelivery.setWindow(window);
+ });
+ }
+ });
+
+ app.on('before-quit', event => {
+ if (shutdownStarted) return;
+ event.preventDefault();
+ shutdownStarted = true;
+ void lifecycle.shutdown().finally(() => {
+ log('info', 'desktop.app.shutdown');
+ app.quit();
+ });
+ });
+ }).catch(error => {
+ log('error', 'desktop.app.start_failed', { error });
+ app.exit(1);
+ });
+}
+
+app.on('window-all-closed', () => {
+ if (process.platform !== 'darwin') app.quit();
+});
diff --git a/apps/desktop/src/preload-bridge.test.ts b/apps/desktop/src/preload-bridge.test.ts
new file mode 100644
index 000000000..81db36bef
--- /dev/null
+++ b/apps/desktop/src/preload-bridge.test.ts
@@ -0,0 +1,79 @@
+import assert from 'node:assert/strict';
+import { describe, it } from 'node:test';
+import { createDesktopBridge, type PreloadIpc } from './preload-bridge';
+import { IPC_CHANNELS } from './shared/contract';
+
+class FakeIpc implements PreloadIpc {
+ readonly invocations: Array<{ channel: string; args: unknown[] }> = [];
+ readonly listeners = new Map void>();
+
+ async invoke(channel: string, ...args: unknown[]): Promise {
+ this.invocations.push({ channel, args });
+ return undefined;
+ }
+
+ on(channel: string, listener: (event: unknown, value: string) => void): void {
+ this.listeners.set(channel, listener);
+ }
+
+ removeListener(channel: string, listener: (event: unknown, value: string) => void): void {
+ if (this.listeners.get(channel) === listener) this.listeners.delete(channel);
+ }
+}
+
+describe('desktop preload bridge', () => {
+ it('exposes only the narrow frozen namespaces', () => {
+ const bridge = createDesktopBridge(new FakeIpc());
+ assert.deepEqual(Object.keys(bridge).sort(), ['app', 'auth', 'credentials', 'external', 'lifecycle', 'profiles', 'storage']);
+ assert.equal(Object.isFrozen(bridge), true);
+ assert.equal(Object.values(bridge).every(Object.isFrozen), true);
+ assert.equal('fs' in bridge, false);
+ assert.equal('exec' in bridge, false);
+ });
+
+ it('maps profile and credential operations to fixed channels', async () => {
+ const ipc = new FakeIpc();
+ const bridge = createDesktopBridge(ipc);
+ await bridge.auth.logout('http://localhost:4000');
+ await bridge.profiles.save({ label: 'Local', apiBaseUrl: 'http://localhost:4000' });
+ await bridge.credentials.write('profile-1', 'secret');
+ await bridge.lifecycle.start();
+ assert.deepEqual(ipc.invocations, [
+ { channel: IPC_CHANNELS.authLogout, args: ['http://localhost:4000'] },
+ {
+ channel: IPC_CHANNELS.profilesSave,
+ args: [{ label: 'Local', apiBaseUrl: 'http://localhost:4000' }],
+ },
+ { channel: IPC_CHANNELS.credentialsWrite, args: ['profile-1', 'secret'] },
+ { channel: IPC_CHANNELS.lifecycleStart, args: [] },
+ ]);
+ });
+
+ it('does not expose Electron event objects to deep-link listeners', () => {
+ const ipc = new FakeIpc();
+ const bridge = createDesktopBridge(ipc);
+ const received: string[] = [];
+ const unsubscribe = bridge.app.onDeepLink(value => received.push(value));
+ ipc.listeners.get(IPC_CHANNELS.deepLink)?.({ sender: 'must-not-leak' }, 'propr://open?path=%2Ftasks');
+ assert.deepEqual(received, ['propr://open?path=%2Ftasks']);
+ unsubscribe();
+ assert.equal(ipc.listeners.has(IPC_CHANNELS.deepLink), true);
+ });
+
+ it('buffers startup and second-instance deep links until the renderer subscribes', () => {
+ const ipc = new FakeIpc();
+ const bridge = createDesktopBridge(ipc);
+ const receiveDeepLink = ipc.listeners.get(IPC_CHANNELS.deepLink);
+ assert.ok(receiveDeepLink, 'preload must register its IPC listener eagerly');
+
+ receiveDeepLink({}, 'propr://connect?api=http%3A%2F%2Flocalhost%3A4000');
+ receiveDeepLink({}, 'propr://open?path=%2Ftasks');
+
+ const received: string[] = [];
+ bridge.app.onDeepLink(value => received.push(value));
+ assert.deepEqual(received, [
+ 'propr://connect?api=http%3A%2F%2Flocalhost%3A4000',
+ 'propr://open?path=%2Ftasks',
+ ]);
+ });
+});
diff --git a/apps/desktop/src/preload-bridge.ts b/apps/desktop/src/preload-bridge.ts
new file mode 100644
index 000000000..3bba8300e
--- /dev/null
+++ b/apps/desktop/src/preload-bridge.ts
@@ -0,0 +1,63 @@
+import type { DesktopBridge } from './shared/contract';
+import { IPC_CHANNELS } from './shared/contract';
+
+export interface PreloadIpc {
+ invoke(channel: string, ...args: unknown[]): Promise;
+ on(channel: string, listener: (event: unknown, value: string) => void): void;
+ removeListener(channel: string, listener: (event: unknown, value: string) => void): void;
+}
+
+const invoke = (ipc: PreloadIpc, channel: string, ...args: unknown[]): Promise =>
+ ipc.invoke(channel, ...args) as Promise;
+
+export const createDesktopBridge = (ipc: PreloadIpc): DesktopBridge => {
+ const deepLinkListeners = new Set<(url: string) => void>();
+ const pendingDeepLinks: string[] = [];
+ ipc.on(IPC_CHANNELS.deepLink, (_event, value) => {
+ if (deepLinkListeners.size === 0) {
+ pendingDeepLinks.push(value);
+ return;
+ }
+ deepLinkListeners.forEach(listener => listener(value));
+ });
+
+ const bridge: DesktopBridge = {
+ app: {
+ getMetadata: () => invoke(ipc, IPC_CHANNELS.appMetadata),
+ onDeepLink: (listener) => {
+ deepLinkListeners.add(listener);
+ pendingDeepLinks.splice(0).forEach(value => listener(value));
+ return () => deepLinkListeners.delete(listener);
+ },
+ },
+ auth: {
+ logout: (apiBaseUrl) => invoke(ipc, IPC_CHANNELS.authLogout, apiBaseUrl),
+ },
+ external: {
+ open: (url) => invoke(ipc, IPC_CHANNELS.openExternal, url),
+ },
+ storage: {
+ security: () => invoke(ipc, IPC_CHANNELS.storageSecurity),
+ },
+ profiles: {
+ list: () => invoke(ipc, IPC_CHANNELS.profilesList),
+ save: (profile) => invoke(ipc, IPC_CHANNELS.profilesSave, profile),
+ remove: (profileId) => invoke(ipc, IPC_CHANNELS.profilesRemove, profileId),
+ setActive: (profileId) => invoke(ipc, IPC_CHANNELS.profilesSetActive, profileId),
+ },
+ credentials: {
+ read: (profileId) => invoke(ipc, IPC_CHANNELS.credentialsRead, profileId),
+ write: (profileId, value) => invoke(ipc, IPC_CHANNELS.credentialsWrite, profileId, value),
+ remove: (profileId) => invoke(ipc, IPC_CHANNELS.credentialsRemove, profileId),
+ },
+ lifecycle: {
+ status: () => invoke(ipc, IPC_CHANNELS.lifecycleStatus),
+ start: () => invoke(ipc, IPC_CHANNELS.lifecycleStart),
+ stop: () => invoke(ipc, IPC_CHANNELS.lifecycleStop),
+ restart: () => invoke(ipc, IPC_CHANNELS.lifecycleRestart),
+ },
+ };
+
+ Object.values(bridge).forEach(Object.freeze);
+ return Object.freeze(bridge);
+};
diff --git a/apps/desktop/src/preload.ts b/apps/desktop/src/preload.ts
new file mode 100644
index 000000000..ba4f4d45b
--- /dev/null
+++ b/apps/desktop/src/preload.ts
@@ -0,0 +1,4 @@
+import { contextBridge, ipcRenderer } from 'electron';
+import { createDesktopBridge } from './preload-bridge';
+
+contextBridge.exposeInMainWorld('proprDesktop', createDesktopBridge(ipcRenderer));
diff --git a/apps/desktop/src/profile-store.test.ts b/apps/desktop/src/profile-store.test.ts
new file mode 100644
index 000000000..c4807df05
--- /dev/null
+++ b/apps/desktop/src/profile-store.test.ts
@@ -0,0 +1,106 @@
+import assert from 'node:assert/strict';
+import { mkdtemp, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterEach, describe, it } from 'node:test';
+import { ProfileStore, type EncryptionProvider } from './profile-store';
+
+const temporaryDirectories: string[] = [];
+
+const createDirectory = async (): Promise => {
+ const directory = await mkdtemp(join(tmpdir(), 'propr-desktop-test-'));
+ temporaryDirectories.push(directory);
+ return directory;
+};
+
+const encryption = (available = true, backend = 'keychain'): EncryptionProvider => ({
+ isEncryptionAvailable: () => available,
+ backend: () => backend,
+ encrypt: value => Buffer.from(Buffer.from(value, 'utf8').toString('base64url'), 'utf8'),
+ decrypt: value => Buffer.from(value.toString(), 'base64url').toString('utf8'),
+});
+
+afterEach(async () => {
+ await Promise.all(temporaryDirectories.splice(0).map(directory => rm(directory, { recursive: true, force: true })));
+});
+
+describe('desktop profile store', () => {
+ it('persists validated profiles and active selection', async () => {
+ const directory = await createDirectory();
+ const store = new ProfileStore(directory, encryption());
+ const profile = await store.save({ label: ' Local ', apiBaseUrl: 'http://localhost:4000///' });
+ const ipv6Profile = await store.save({ label: 'IPv6', apiBaseUrl: 'http://[::1]:4000/' });
+ await store.setActive(profile.id);
+ assert.deepEqual(await store.list(), { profiles: [profile, ipv6Profile], activeProfileId: profile.id });
+ assert.equal(profile.label, 'Local');
+ assert.equal(profile.apiBaseUrl, 'http://localhost:4000');
+ assert.equal(ipv6Profile.apiBaseUrl, 'http://[::1]:4000');
+ });
+
+ it('encrypts credentials before writing app-owned storage', async () => {
+ const directory = await createDirectory();
+ const store = new ProfileStore(directory, encryption());
+ const profile = await store.save({ label: 'Secure', apiBaseUrl: 'https://propr.example.com' });
+ assert.deepEqual(await store.writeCredential(profile.id, 'top-secret'), { stored: true });
+ assert.deepEqual(await store.readCredential(profile.id), { available: true, value: 'top-secret' });
+ const onDisk = await readFile(join(directory, 'desktop', 'credentials', `${profile.id}.bin`), 'utf8');
+ assert.equal(onDisk, Buffer.from('top-secret', 'utf8').toString('base64url'));
+ assert.equal(onDisk.includes('top-secret'), false);
+ assert.notEqual(onDisk, 'top-secret');
+ });
+
+ it('serializes concurrent credential writes with last-write semantics', async () => {
+ const store = new ProfileStore(await createDirectory(), encryption());
+
+ const first = store.writeCredential('profile-1', 'first');
+ const second = store.writeCredential('profile-1', 'second');
+ assert.deepEqual(await Promise.all([first, second]), [{ stored: true }, { stored: true }]);
+ assert.deepEqual(await store.readCredential('profile-1'), { available: true, value: 'second' });
+ });
+
+ it('orders concurrent credential writes and removals by invocation', async () => {
+ const store = new ProfileStore(await createDirectory(), encryption());
+
+ await Promise.all([
+ store.writeCredential('profile-1', 'remove-me'),
+ store.removeCredential('profile-1'),
+ ]);
+ assert.deepEqual(await store.readCredential('profile-1'), { available: true, value: null });
+
+ await Promise.all([
+ store.removeCredential('profile-1'),
+ store.writeCredential('profile-1', 'keep-me'),
+ ]);
+ assert.deepEqual(await store.readCredential('profile-1'), { available: true, value: 'keep-me' });
+ });
+
+ it('refuses plaintext fallback when encryption is unavailable or basic_text', async () => {
+ for (const provider of [encryption(false, 'unavailable'), encryption(true, 'basic_text')]) {
+ const directory = await createDirectory();
+ const store = new ProfileStore(directory, provider);
+ assert.equal(store.security().available, false);
+ assert.deepEqual(await store.writeCredential('profile-1', 'secret'), {
+ stored: false,
+ reason: 'encryption-unavailable',
+ });
+ assert.deepEqual(await store.readCredential('profile-1'), { available: false, value: null });
+ }
+ });
+
+ it('rejects unsafe endpoints and path-like profile identifiers', async () => {
+ const directory = await createDirectory();
+ const store = new ProfileStore(directory, encryption());
+ const profile = await store.save({ label: 'Remote', apiBaseUrl: 'https://propr.example.com/' });
+ await assert.rejects(
+ store.save({ label: 'Remote HTTP', apiBaseUrl: 'http://example.com' }),
+ /HTTPS/,
+ );
+ await assert.rejects(
+ store.save({ id: profile.id, label: 'Path bearing', apiBaseUrl: 'https://propr.example.com/base' }),
+ /HTTPS/,
+ );
+ assert.deepEqual((await store.list()).profiles, [profile]);
+ assert.doesNotMatch(await readFile(join(directory, 'desktop', 'profiles.json'), 'utf8'), /\/base/);
+ await assert.rejects(store.writeCredential('../escape', 'secret'), /Invalid desktop profile id/);
+ });
+});
diff --git a/apps/desktop/src/profile-store.ts b/apps/desktop/src/profile-store.ts
new file mode 100644
index 000000000..4115c1f92
--- /dev/null
+++ b/apps/desktop/src/profile-store.ts
@@ -0,0 +1,250 @@
+import { randomUUID } from 'node:crypto';
+import { chmod, mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises';
+import { join } from 'node:path';
+import type {
+ CredentialReadResult,
+ CredentialWriteResult,
+ DesktopProfile,
+ DesktopProfileInput,
+ DesktopProfileList,
+ StorageSecurity,
+} from './shared/contract';
+import { normalizeApiBaseUrl } from './security';
+
+const PROFILE_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
+const MAX_CREDENTIAL_LENGTH = 65_536;
+
+interface PersistedState {
+ version: 1;
+ activeProfileId: string | null;
+ profiles: DesktopProfile[];
+}
+
+export interface EncryptionProvider {
+ isEncryptionAvailable(): boolean;
+ backend(): string;
+ encrypt(value: string): Buffer;
+ decrypt(value: Buffer): string;
+}
+
+const emptyState = (): PersistedState => ({
+ version: 1,
+ activeProfileId: null,
+ profiles: [],
+});
+
+const validDate = (value: unknown): value is string =>
+ typeof value === 'string' && !Number.isNaN(Date.parse(value));
+
+const validProfile = (value: unknown): value is DesktopProfile => {
+ if (!value || typeof value !== 'object') return false;
+ const profile = value as Record;
+ return typeof profile.id === 'string'
+ && PROFILE_ID_PATTERN.test(profile.id)
+ && typeof profile.label === 'string'
+ && profile.label.length > 0
+ && profile.label.length <= 80
+ && typeof profile.apiBaseUrl === 'string'
+ && normalizeApiBaseUrl(profile.apiBaseUrl) === profile.apiBaseUrl
+ && validDate(profile.createdAt)
+ && validDate(profile.updatedAt);
+};
+
+const parseState = (contents: string): PersistedState => {
+ const value = JSON.parse(contents) as unknown;
+ if (!value || typeof value !== 'object') throw new Error('Desktop profile store is invalid');
+ const state = value as Record;
+ if (state.version !== 1 || !Array.isArray(state.profiles) || !state.profiles.every(validProfile)) {
+ throw new Error('Desktop profile store is invalid');
+ }
+ if (state.activeProfileId !== null && (
+ typeof state.activeProfileId !== 'string'
+ || !state.profiles.some((profile: DesktopProfile) => profile.id === state.activeProfileId)
+ )) {
+ throw new Error('Desktop active profile is invalid');
+ }
+ return state as unknown as PersistedState;
+};
+
+const encryptionStatus = (encryption: EncryptionProvider): StorageSecurity => {
+ const backend = encryption.backend();
+ if (!encryption.isEncryptionAvailable()) {
+ return { available: false, backend, reason: 'os-encryption-unavailable' };
+ }
+ if (backend === 'basic_text') {
+ return { available: false, backend, reason: 'insecure-basic-text-backend' };
+ }
+ return { available: true, backend };
+};
+
+const assertProfileId: (profileId: unknown) => asserts profileId is string = (profileId) => {
+ if (typeof profileId !== 'string' || !PROFILE_ID_PATTERN.test(profileId)) {
+ throw new Error('Invalid desktop profile id');
+ }
+};
+
+const normalizedProfileInput = (input: DesktopProfileInput): Omit => {
+ if (!input || typeof input !== 'object') throw new Error('Invalid desktop profile');
+ const label = input.label?.trim();
+ const apiBaseUrl = normalizeApiBaseUrl(input.apiBaseUrl ?? '');
+ if (!label || label.length > 80) throw new Error('Profile label must contain 1 to 80 characters');
+ if (!apiBaseUrl) throw new Error('Use HTTPS, or HTTP on localhost, for the ProPR API URL');
+ const id = input.id ?? randomUUID();
+ assertProfileId(id);
+ return { id, label, apiBaseUrl };
+};
+
+export class ProfileStore {
+ readonly #directory: string;
+ readonly #statePath: string;
+ readonly #credentialsDirectory: string;
+ readonly #encryption: EncryptionProvider;
+ #mutation = Promise.resolve();
+ readonly #credentialMutations = new Map>();
+
+ constructor(userDataPath: string, encryption: EncryptionProvider) {
+ this.#directory = join(userDataPath, 'desktop');
+ this.#statePath = join(this.#directory, 'profiles.json');
+ this.#credentialsDirectory = join(this.#directory, 'credentials');
+ this.#encryption = encryption;
+ }
+
+ security(): StorageSecurity {
+ return encryptionStatus(this.#encryption);
+ }
+
+ async list(): Promise {
+ const state = await this.#readState();
+ return {
+ profiles: state.profiles.map(profile => ({ ...profile })),
+ activeProfileId: state.activeProfileId,
+ };
+ }
+
+ save(input: DesktopProfileInput): Promise {
+ return this.#mutate(async () => {
+ const normalized = normalizedProfileInput(input);
+ const state = await this.#readState();
+ const existing = state.profiles.find(profile => profile.id === normalized.id);
+ const now = new Date().toISOString();
+ const profile: DesktopProfile = {
+ ...normalized,
+ createdAt: existing?.createdAt ?? now,
+ updatedAt: now,
+ };
+ state.profiles = [...state.profiles.filter(item => item.id !== profile.id), profile];
+ await this.#writeState(state);
+ return { ...profile };
+ });
+ }
+
+ remove(profileId: string): Promise {
+ assertProfileId(profileId);
+ const stateMutation = this.#mutate(async () => {
+ const state = await this.#readState();
+ state.profiles = state.profiles.filter(profile => profile.id !== profileId);
+ if (state.activeProfileId === profileId) state.activeProfileId = null;
+ await this.#writeState(state);
+ });
+ return this.#mutateCredential(profileId, async () => {
+ await stateMutation;
+ await this.#removeCredentialFile(profileId);
+ });
+ }
+
+ setActive(profileId: string | null): Promise {
+ if (profileId !== null) assertProfileId(profileId);
+ return this.#mutate(async () => {
+ const state = await this.#readState();
+ if (profileId !== null && !state.profiles.some(profile => profile.id === profileId)) {
+ throw new Error('Desktop profile does not exist');
+ }
+ state.activeProfileId = profileId;
+ await this.#writeState(state);
+ });
+ }
+
+ async readCredential(profileId: string): Promise {
+ assertProfileId(profileId);
+ if (!this.security().available) return { available: false, value: null };
+ try {
+ const encrypted = await readFile(this.#credentialPath(profileId));
+ return { available: true, value: this.#encryption.decrypt(encrypted) };
+ } catch (error) {
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { available: true, value: null };
+ throw error;
+ }
+ }
+
+ async writeCredential(profileId: string, value: string): Promise {
+ assertProfileId(profileId);
+ if (typeof value !== 'string' || value.length === 0 || value.length > MAX_CREDENTIAL_LENGTH) {
+ throw new Error('Credential must contain 1 to 65536 characters');
+ }
+ if (!this.security().available) return { stored: false, reason: 'encryption-unavailable' };
+ return this.#mutateCredential(profileId, async () => {
+ await this.#ensureDirectories();
+ const target = this.#credentialPath(profileId);
+ const temporary = `${target}.${process.pid}.tmp`;
+ await writeFile(temporary, this.#encryption.encrypt(value), { mode: 0o600 });
+ await rename(temporary, target);
+ await chmod(target, 0o600).catch(() => undefined);
+ return { stored: true };
+ });
+ }
+
+ removeCredential(profileId: string): Promise {
+ assertProfileId(profileId);
+ return this.#mutateCredential(profileId, () => this.#removeCredentialFile(profileId));
+ }
+
+ async #removeCredentialFile(profileId: string): Promise {
+ await unlink(this.#credentialPath(profileId)).catch(error => {
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
+ });
+ }
+
+ async #readState(): Promise {
+ try {
+ return parseState(await readFile(this.#statePath, 'utf8'));
+ } catch (error) {
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return emptyState();
+ throw error;
+ }
+ }
+
+ async #writeState(state: PersistedState): Promise {
+ await this.#ensureDirectories();
+ const temporary = `${this.#statePath}.${process.pid}.tmp`;
+ await writeFile(temporary, `${JSON.stringify(state, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
+ await rename(temporary, this.#statePath);
+ await chmod(this.#statePath, 0o600).catch(() => undefined);
+ }
+
+ async #ensureDirectories(): Promise {
+ await mkdir(this.#credentialsDirectory, { recursive: true, mode: 0o700 });
+ await chmod(this.#directory, 0o700).catch(() => undefined);
+ await chmod(this.#credentialsDirectory, 0o700).catch(() => undefined);
+ }
+
+ #credentialPath(profileId: string): string {
+ return join(this.#credentialsDirectory, `${profileId}.bin`);
+ }
+
+ #mutate(operation: () => Promise): Promise {
+ const result = this.#mutation.then(operation, operation);
+ this.#mutation = result.then(() => undefined, () => undefined);
+ return result;
+ }
+
+ #mutateCredential(profileId: string, operation: () => Promise): Promise {
+ const previous = this.#credentialMutations.get(profileId) ?? Promise.resolve();
+ const result = previous.then(operation, operation);
+ const settled = result.then(() => undefined, () => undefined);
+ this.#credentialMutations.set(profileId, settled);
+ void settled.then(() => {
+ if (this.#credentialMutations.get(profileId) === settled) this.#credentialMutations.delete(profileId);
+ });
+ return result;
+ }
+}
diff --git a/apps/desktop/src/security.test.ts b/apps/desktop/src/security.test.ts
new file mode 100644
index 000000000..aecda058a
--- /dev/null
+++ b/apps/desktop/src/security.test.ts
@@ -0,0 +1,96 @@
+import assert from 'node:assert/strict';
+import { describe, it } from 'node:test';
+import {
+ deepLinkFromArguments,
+ applyDevelopmentRendererCsp,
+ isSafeExternalUrl,
+ isTrustedRendererUrl,
+ normalizeApiBaseUrl,
+ normalizeDeepLink,
+ rendererContentSecurityPolicy,
+ validatedDevServerUrl,
+} from './security';
+
+describe('desktop URL security', () => {
+ it('only accepts HTTPS and loopback HTTP API endpoints', () => {
+ assert.equal(normalizeApiBaseUrl('https://propr.example.com///'), 'https://propr.example.com');
+ assert.equal(normalizeApiBaseUrl('http://localhost:4000/'), 'http://localhost:4000');
+ assert.equal(normalizeApiBaseUrl('http://127.0.0.1:4000'), 'http://127.0.0.1:4000');
+ assert.equal(normalizeApiBaseUrl('http://[::1]:4000/'), 'http://[::1]:4000');
+ assert.equal(normalizeApiBaseUrl('https://propr.example.com/base'), null);
+ assert.equal(normalizeApiBaseUrl('http://[::1]:4000/api'), null);
+ assert.equal(normalizeApiBaseUrl('http://propr.example.com'), null);
+ assert.equal(normalizeApiBaseUrl('http://[2001:db8::1]:4000'), null);
+ assert.equal(normalizeApiBaseUrl('https://user:secret@propr.example.com'), null);
+ assert.equal(normalizeApiBaseUrl('file:///tmp/propr'), null);
+ });
+
+ it('denies unsafe external browser schemes and credential-bearing URLs', () => {
+ assert.equal(isSafeExternalUrl('https://github.com/integry/propr'), true);
+ assert.equal(isSafeExternalUrl('http://localhost:4000/docs'), true);
+ assert.equal(isSafeExternalUrl('http://[::1]:4000/docs'), true);
+ assert.equal(isSafeExternalUrl('http://example.com'), false);
+ assert.equal(isSafeExternalUrl('http://[2001:db8::1]:4000/docs'), false);
+ assert.equal(isSafeExternalUrl('javascript:alert(1)'), false);
+ assert.equal(isSafeExternalUrl('file://[::1]/tmp/propr'), false);
+ assert.equal(isSafeExternalUrl('https://token@example.com'), false);
+ });
+
+ it('requires an exact loopback development origin', () => {
+ assert.equal(validatedDevServerUrl('http://localhost:5173/')?.origin, 'http://localhost:5173');
+ assert.equal(validatedDevServerUrl('http://[::1]:5173/')?.origin, 'http://[::1]:5173');
+ assert.equal(validatedDevServerUrl('https://localhost:5173/'), null);
+ assert.equal(validatedDevServerUrl('http://0.0.0.0:5173/'), null);
+ assert.equal(validatedDevServerUrl('http://[2001:db8::1]:5173/'), null);
+ assert.equal(validatedDevServerUrl('ws://[::1]:5173/'), null);
+ assert.equal(validatedDevServerUrl('http://localhost:5173/path'), null);
+ assert.equal(
+ isTrustedRendererUrl('http://localhost:5173/renderer.html', 'http://localhost:5173/', '/unused'),
+ true,
+ );
+ assert.equal(
+ isTrustedRendererUrl('http://127.0.0.1:5173/renderer.html', 'http://localhost:5173/', '/unused'),
+ false,
+ );
+ });
+
+ it('retains IPC trust for hash-routed packaged renderer URLs only', () => {
+ const renderer = 'propr-app://renderer/renderer.html';
+ assert.equal(isTrustedRendererUrl(renderer, undefined, renderer), true);
+ assert.equal(isTrustedRendererUrl(`${renderer}#/plans/123`, undefined, renderer), true);
+ assert.equal(isTrustedRendererUrl(`${renderer}?profile=123#/plans/123`, undefined, renderer), false);
+ assert.equal(isTrustedRendererUrl('propr-app://renderer/other.html', undefined, renderer), false);
+ assert.equal(isTrustedRendererUrl('propr-app://other/renderer.html#/plans/123', undefined, renderer), false);
+ assert.equal(isTrustedRendererUrl('https://propr.example.com', undefined, renderer), false);
+ });
+
+ it('allowlists custom protocol actions and extracts them from argv', () => {
+ const link = 'propr://connect?api=https%3A%2F%2Fpropr.example.com';
+ assert.equal(normalizeDeepLink(link), link);
+ assert.equal(deepLinkFromArguments(['electron', '.', link]), link);
+ assert.equal(normalizeDeepLink('propr://delete-everything'), null);
+ assert.equal(normalizeDeepLink('https://propr.example.com'), null);
+ assert.equal(normalizeDeepLink('propr://user:secret@connect'), null);
+ });
+
+ it('publishes a restrictive production policy', () => {
+ const policy = rendererContentSecurityPolicy();
+ assert.match(policy, /default-src 'self'/);
+ assert.match(policy, /object-src 'none'/);
+ assert.match(policy, /frame-src 'none'/);
+ assert.doesNotMatch(policy, /unsafe-eval/);
+ assert.match(policy, /script-src 'self'(?:;|$)/);
+ assert.match(policy, /http:\/\/\[::1\]:\*/);
+ assert.match(policy, /ws:\/\/\[::1\]:\*/);
+ });
+
+ it('relaxes inline scripts only while Vite serves the development renderer', () => {
+ const packagedPolicy = rendererContentSecurityPolicy();
+ const source = ``;
+ const transformed = applyDevelopmentRendererCsp(source);
+
+ assert.match(transformed, /script-src 'self' 'unsafe-inline'/);
+ assert.equal(applyDevelopmentRendererCsp(source).includes(rendererContentSecurityPolicy(true)), true);
+ assert.match(packagedPolicy, /script-src 'self'(?:;|$)/);
+ });
+});
diff --git a/apps/desktop/src/security.ts b/apps/desktop/src/security.ts
new file mode 100644
index 000000000..ab6ad6f73
--- /dev/null
+++ b/apps/desktop/src/security.ts
@@ -0,0 +1,92 @@
+import { DESKTOP_PROTOCOL } from './shared/contract';
+
+// WHATWG URL.hostname retains brackets around IPv6 literals.
+const LOOPBACK_HOSTS = new Set(['127.0.0.1', '[::1]', 'localhost']);
+const DEEP_LINK_ACTIONS = new Set(['connect', 'open']);
+
+const parseUrl = (value: string): URL | null => {
+ try {
+ return new URL(value);
+ } catch {
+ return null;
+ }
+};
+
+const hasCredentials = (url: URL): boolean => Boolean(url.username || url.password);
+
+export const normalizeApiBaseUrl = (value: string): string | null => {
+ const url = parseUrl(value.trim());
+ if (!url || hasCredentials(url) || url.hash || url.search) return null;
+ if (url.protocol === 'http:' && !LOOPBACK_HOSTS.has(url.hostname)) return null;
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') return null;
+ if (url.pathname.replace(/\//g, '') !== '') return null;
+ return url.origin;
+};
+
+export const isSafeExternalUrl = (value: string): boolean => {
+ const url = parseUrl(value);
+ if (!url || hasCredentials(url)) return false;
+ return url.protocol === 'https:'
+ || (url.protocol === 'http:' && LOOPBACK_HOSTS.has(url.hostname));
+};
+
+export const validatedDevServerUrl = (value: string | undefined): URL | null => {
+ if (!value) return null;
+ const url = parseUrl(value);
+ if (!url || url.protocol !== 'http:' || !LOOPBACK_HOSTS.has(url.hostname) || hasCredentials(url)) return null;
+ if (url.pathname !== '/' || url.search || url.hash) return null;
+ return url;
+};
+
+export const isTrustedRendererUrl = (
+ candidate: string,
+ devServerUrl: string | undefined,
+ packagedRendererUrl: string,
+): boolean => {
+ const candidateUrl = parseUrl(candidate);
+ if (!candidateUrl) return false;
+ const devUrl = validatedDevServerUrl(devServerUrl);
+ if (devUrl) return candidateUrl.origin === devUrl.origin;
+ const packagedUrl = parseUrl(packagedRendererUrl);
+ if (!packagedUrl || hasCredentials(candidateUrl) || candidateUrl.search) return false;
+ return candidateUrl.protocol === packagedUrl.protocol
+ && candidateUrl.host === packagedUrl.host
+ && candidateUrl.pathname === packagedUrl.pathname;
+};
+
+export const normalizeDeepLink = (value: string): string | null => {
+ if (value.length > 2_048) return null;
+ const url = parseUrl(value);
+ if (!url || url.protocol !== `${DESKTOP_PROTOCOL}:` || hasCredentials(url)) return null;
+ if (!DEEP_LINK_ACTIONS.has(url.hostname) || url.port || url.hash) return null;
+ return url.href;
+};
+
+export const deepLinkFromArguments = (argv: readonly string[]): string | null => {
+ for (const argument of argv) {
+ const normalized = normalizeDeepLink(argument);
+ if (normalized) return normalized;
+ }
+ return null;
+};
+
+export const rendererContentSecurityPolicy = (development = false): string => [
+ "default-src 'self'",
+ `script-src 'self'${development ? " 'unsafe-inline'" : ''}`,
+ "style-src 'self' 'unsafe-inline'",
+ "img-src 'self' data: blob: https:",
+ "font-src 'self' data:",
+ "connect-src 'self' https: http://127.0.0.1:* http://[::1]:* http://localhost:* ws://127.0.0.1:* ws://[::1]:* ws://localhost:* wss:",
+ "object-src 'none'",
+ "base-uri 'none'",
+ "form-action 'none'",
+ "frame-src 'none'",
+].join('; ');
+
+export const applyDevelopmentRendererCsp = (html: string): string => {
+ const packagedPolicy = rendererContentSecurityPolicy();
+ if (!html.includes(packagedPolicy)) {
+ throw new Error('renderer.html is missing the packaged content security policy');
+ }
+ return html.replace(packagedPolicy, rendererContentSecurityPolicy(true));
+};
diff --git a/apps/desktop/src/shared/contract.ts b/apps/desktop/src/shared/contract.ts
new file mode 100644
index 000000000..f34d23298
--- /dev/null
+++ b/apps/desktop/src/shared/contract.ts
@@ -0,0 +1,111 @@
+export const DESKTOP_PROTOCOL = 'propr';
+
+export const IPC_CHANNELS = Object.freeze({
+ appMetadata: 'desktop:app-metadata',
+ authLogout: 'desktop:auth-logout',
+ openExternal: 'desktop:open-external',
+ storageSecurity: 'desktop:storage-security',
+ profilesList: 'desktop:profiles-list',
+ profilesSave: 'desktop:profiles-save',
+ profilesRemove: 'desktop:profiles-remove',
+ profilesSetActive: 'desktop:profiles-set-active',
+ credentialsRead: 'desktop:credentials-read',
+ credentialsWrite: 'desktop:credentials-write',
+ credentialsRemove: 'desktop:credentials-remove',
+ lifecycleStatus: 'desktop:lifecycle-status',
+ lifecycleStart: 'desktop:lifecycle-start',
+ lifecycleStop: 'desktop:lifecycle-stop',
+ lifecycleRestart: 'desktop:lifecycle-restart',
+ deepLink: 'desktop:deep-link',
+} as const);
+
+export type DesktopPlatform = 'aix' | 'android' | 'darwin' | 'freebsd' | 'haiku'
+ | 'linux' | 'openbsd' | 'sunos' | 'win32' | 'cygwin' | 'netbsd';
+
+export interface DesktopAppMetadata {
+ name: string;
+ version: string;
+ platform: DesktopPlatform;
+ arch: string;
+ packaged: boolean;
+}
+
+export interface DesktopProfile {
+ id: string;
+ label: string;
+ apiBaseUrl: string;
+ createdAt: string;
+ updatedAt: string;
+}
+
+export interface DesktopProfileInput {
+ id?: string;
+ label: string;
+ apiBaseUrl: string;
+}
+
+export interface DesktopProfileList {
+ profiles: DesktopProfile[];
+ activeProfileId: string | null;
+}
+
+export type StorageSecurity = {
+ available: true;
+ backend: string;
+} | {
+ available: false;
+ backend: string;
+ reason: 'os-encryption-unavailable' | 'insecure-basic-text-backend';
+};
+
+export type CredentialReadResult =
+ | { available: false; value: null }
+ | { available: true; value: string | null };
+
+export type CredentialWriteResult =
+ | { stored: true }
+ | { stored: false; reason: 'encryption-unavailable' };
+
+export type LocalLifecycleState = 'disconnected' | 'starting' | 'connected' | 'stopping' | 'error';
+
+export interface LocalLifecycleStatus {
+ state: LocalLifecycleState;
+ detail?: string;
+}
+
+export type LocalLifecycleOperationResult =
+ | { ok: true; status: LocalLifecycleStatus }
+ | { ok: false; code: 'not-implemented'; status: LocalLifecycleStatus };
+
+export interface DesktopBridge {
+ app: {
+ getMetadata(): Promise;
+ onDeepLink(listener: (url: string) => void): () => void;
+ };
+ auth: {
+ logout(apiBaseUrl: string): Promise;
+ };
+ external: {
+ open(url: string): Promise;
+ };
+ storage: {
+ security(): Promise;
+ };
+ profiles: {
+ list(): Promise;
+ save(profile: DesktopProfileInput): Promise;
+ remove(profileId: string): Promise;
+ setActive(profileId: string | null): Promise;
+ };
+ credentials: {
+ read(profileId: string): Promise;
+ write(profileId: string, value: string): Promise;
+ remove(profileId: string): Promise;
+ };
+ lifecycle: {
+ status(): Promise;
+ start(): Promise;
+ stop(): Promise;
+ restart(): Promise;
+ };
+}
diff --git a/apps/desktop/src/vite-file-system-url.test.ts b/apps/desktop/src/vite-file-system-url.test.ts
new file mode 100644
index 000000000..9d2bddc75
--- /dev/null
+++ b/apps/desktop/src/vite-file-system-url.test.ts
@@ -0,0 +1,19 @@
+import assert from 'node:assert/strict';
+import { describe, it } from 'node:test';
+import { viteFileSystemUrl } from './vite-file-system-url';
+
+describe('Vite filesystem renderer URLs', () => {
+ it('preserves an absolute POSIX path after the /@fs/ prefix', () => {
+ assert.equal(
+ viteFileSystemUrl('/home/propr/propr-ui/src/desktop.tsx'),
+ '/@fs/home/propr/propr-ui/src/desktop.tsx',
+ );
+ });
+
+ it('normalizes a Windows drive-letter path and separators', () => {
+ assert.equal(
+ viteFileSystemUrl('C:\\propr\\propr-ui\\src\\desktop.tsx'),
+ '/@fs/C:/propr/propr-ui/src/desktop.tsx',
+ );
+ });
+});
diff --git a/apps/desktop/src/vite-file-system-url.ts b/apps/desktop/src/vite-file-system-url.ts
new file mode 100644
index 000000000..4d6b1fed0
--- /dev/null
+++ b/apps/desktop/src/vite-file-system-url.ts
@@ -0,0 +1,5 @@
+/** Convert an absolute native path into Vite's cross-platform /@fs/ URL form. */
+export const viteFileSystemUrl = (absolutePath: string): string => {
+ const normalizedPath = absolutePath.replace(/\\/g, '/').replace(/^\/+/, '');
+ return `/@fs/${normalizedPath}`;
+};
diff --git a/apps/desktop/src/window-options.test.ts b/apps/desktop/src/window-options.test.ts
new file mode 100644
index 000000000..240c66740
--- /dev/null
+++ b/apps/desktop/src/window-options.test.ts
@@ -0,0 +1,25 @@
+import assert from 'node:assert/strict';
+import { describe, it } from 'node:test';
+import { createBrowserWindowOptions } from './window-options';
+
+describe('desktop BrowserWindow security', () => {
+ it('isolates and sandboxes the renderer without Node or webviews', () => {
+ const options = createBrowserWindowOptions('/app/preload.cjs', true, 'linux');
+ assert.deepEqual(options.webPreferences, {
+ preload: '/app/preload.cjs',
+ contextIsolation: true,
+ nodeIntegration: false,
+ sandbox: true,
+ webSecurity: true,
+ allowRunningInsecureContent: false,
+ webviewTag: false,
+ devTools: true,
+ });
+ assert.equal('enableRemoteModule' in (options.webPreferences ?? {}), false);
+ });
+
+ it('uses the native inset title bar only on macOS', () => {
+ assert.equal(createBrowserWindowOptions('/preload.cjs', false, 'darwin').titleBarStyle, 'hiddenInset');
+ assert.equal(createBrowserWindowOptions('/preload.cjs', false, 'win32').titleBarStyle, undefined);
+ });
+});
diff --git a/apps/desktop/src/window-options.ts b/apps/desktop/src/window-options.ts
new file mode 100644
index 000000000..797f9d3be
--- /dev/null
+++ b/apps/desktop/src/window-options.ts
@@ -0,0 +1,26 @@
+import type { BrowserWindowConstructorOptions } from 'electron';
+
+export const createBrowserWindowOptions = (
+ preloadPath: string,
+ allowDevTools: boolean,
+ platform: NodeJS.Platform = process.platform,
+): BrowserWindowConstructorOptions => ({
+ title: 'ProPR Desktop',
+ width: 1280,
+ height: 820,
+ minWidth: 880,
+ minHeight: 620,
+ backgroundColor: '#f8fafc',
+ show: false,
+ ...(platform === 'darwin' ? { titleBarStyle: 'hiddenInset' as const } : {}),
+ webPreferences: {
+ preload: preloadPath,
+ contextIsolation: true,
+ nodeIntegration: false,
+ sandbox: true,
+ webSecurity: true,
+ allowRunningInsecureContent: false,
+ webviewTag: false,
+ devTools: allowDevTools,
+ },
+});
diff --git a/apps/desktop/tsconfig.json b/apps/desktop/tsconfig.json
new file mode 100644
index 000000000..1cd5d0235
--- /dev/null
+++ b/apps/desktop/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "lib": ["ES2022", "DOM"],
+ "types": ["node"],
+ "strict": true,
+ "noEmit": true,
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "jsx": "react-jsx"
+ },
+ "include": [
+ "src/**/*.ts",
+ "src/**/*.tsx",
+ "forge.config.ts",
+ "vite.*.config.ts"
+ ]
+}
diff --git a/apps/desktop/vite.main.config.ts b/apps/desktop/vite.main.config.ts
new file mode 100644
index 000000000..3fac6a497
--- /dev/null
+++ b/apps/desktop/vite.main.config.ts
@@ -0,0 +1,14 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+ build: {
+ sourcemap: true,
+ minify: false,
+ rollupOptions: {
+ output: {
+ format: 'cjs',
+ entryFileNames: 'main.cjs',
+ },
+ },
+ },
+});
diff --git a/apps/desktop/vite.preload.config.ts b/apps/desktop/vite.preload.config.ts
new file mode 100644
index 000000000..d5353c7db
--- /dev/null
+++ b/apps/desktop/vite.preload.config.ts
@@ -0,0 +1,14 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+ build: {
+ sourcemap: true,
+ minify: false,
+ rollupOptions: {
+ output: {
+ format: 'cjs',
+ entryFileNames: 'preload.cjs',
+ },
+ },
+ },
+});
diff --git a/apps/desktop/vite.renderer.config.ts b/apps/desktop/vite.renderer.config.ts
new file mode 100644
index 000000000..c8de93b75
--- /dev/null
+++ b/apps/desktop/vite.renderer.config.ts
@@ -0,0 +1,54 @@
+import { readFileSync } from 'node:fs';
+import { fileURLToPath } from 'node:url';
+import react from '@vitejs/plugin-react';
+import { defineConfig, type Plugin } from 'vite';
+import { applyDevelopmentRendererCsp } from './src/security';
+import { viteFileSystemUrl } from './src/vite-file-system-url';
+
+const rootPackage = JSON.parse(
+ readFileSync(fileURLToPath(new URL('../../package.json', import.meta.url)), 'utf8'),
+) as { version: string };
+const rendererEntrySource = '../../propr-ui/src/desktop.tsx';
+const rendererEntryDevelopmentUrl = viteFileSystemUrl(
+ fileURLToPath(new URL(rendererEntrySource, import.meta.url)),
+);
+
+const transformDevelopmentRendererHtml = (html: string): string => {
+ if (!html.includes(rendererEntrySource)) {
+ throw new Error('renderer.html is missing the shared desktop renderer entry');
+ }
+ return applyDevelopmentRendererCsp(html).replace(rendererEntrySource, rendererEntryDevelopmentUrl);
+};
+
+const developmentCspPlugin: Plugin = {
+ name: 'propr-desktop-development-csp',
+ apply: 'serve',
+ transformIndexHtml: {
+ order: 'pre',
+ handler: transformDevelopmentRendererHtml,
+ },
+};
+
+export default defineConfig({
+ base: './',
+ define: {
+ __APP_VERSION__: JSON.stringify(rootPackage.version),
+ __PROPR_DESKTOP__: 'true',
+ },
+ plugins: [developmentCspPlugin, react()],
+ publicDir: '../../propr-ui/public',
+ build: {
+ sourcemap: true,
+ rollupOptions: {
+ input: 'renderer.html',
+ output: {
+ manualChunks: {
+ 'charts-vendor': ['recharts'],
+ 'markdown-vendor': ['react-markdown', 'remark-breaks', 'remark-gfm'],
+ 'motion-vendor': ['framer-motion'],
+ 'react-vendor': ['react', 'react-dom', 'react-router-dom'],
+ },
+ },
+ },
+ },
+});
diff --git a/package-lock.json b/package-lock.json
index b160a739f..88956cb9d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -71,540 +71,1148 @@
"node": ">=22.12.0"
}
},
- "node_modules/@adobe/css-tools": {
- "version": "4.4.4",
- "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz",
- "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==",
- "dev": true,
- "license": "MIT"
+ "apps/desktop": {
+ "name": "@propr/desktop",
+ "version": "0.8.15",
+ "license": "Apache-2.0",
+ "devDependencies": {
+ "@electron-forge/cli": "8.0.0-alpha.10",
+ "@electron-forge/maker-deb": "8.0.0-alpha.10",
+ "@electron-forge/maker-rpm": "8.0.0-alpha.10",
+ "@electron-forge/maker-squirrel": "8.0.0-alpha.10",
+ "@electron-forge/maker-zip": "8.0.0-alpha.10",
+ "@electron-forge/plugin-vite": "8.0.0-alpha.10",
+ "@electron-forge/shared-types": "8.0.0-alpha.10",
+ "@electron/fuses": "^2.1.3",
+ "@types/node": "^22.10.0",
+ "@vitejs/plugin-react": "^4.6.0",
+ "electron": "^44.0.0",
+ "tsx": "^4.21.0",
+ "typescript": "^5.9.3",
+ "vite": "^7.3.5"
+ }
},
- "node_modules/@alcalzone/ansi-tokenize": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.3.0.tgz",
- "integrity": "sha512-p+CMKJ93HFmLkjXKlXiVGlMQEuRb6H0MokBSwUsX+S6BRX8eV5naFZpQJFfJHjRZY0Hmnqy1/r6UWl3x+19zYA==",
+ "apps/desktop/node_modules/@electron-forge/cli": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/cli/-/cli-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-3fkKH50xTVN1A+UhsX6BzwFfP7JVTadIrA3Cs4jpR7Yl/PChH4w/cyi99LNnZnVAypiywkOkqrQU9t+1SZy1YA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/malept"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/subscription/pkg/npm-.electron-forge-cli?utm_medium=referral&utm_source=npm_fund"
+ }
+ ],
"license": "MIT",
"dependencies": {
- "ansi-styles": "^6.2.1",
- "is-fullwidth-code-point": "^5.0.0"
+ "@electron-forge/core": "8.0.0-alpha.10",
+ "@electron-forge/core-utils": "8.0.0-alpha.10",
+ "@electron-forge/shared-types": "8.0.0-alpha.10",
+ "@electron/get": "^5.0.0",
+ "commander": "^11.1.0",
+ "debug": "^4.3.1",
+ "listr2": "^7.0.2",
+ "semver": "^7.2.1"
+ },
+ "bin": {
+ "electron-forge": "dist/electron-forge.js",
+ "electron-forge-vscode-nix": "script/vscode.sh",
+ "electron-forge-vscode-win": "script/vscode.cmd"
},
"engines": {
- "node": ">=18"
+ "node": ">= 22.12.0"
}
},
- "node_modules/@alcalzone/ansi-tokenize/node_modules/ansi-styles": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
- "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "apps/desktop/node_modules/@electron-forge/core": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/core/-/core-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-sg52Ay0vy9ShC7G4CL9fsfzcUC4yAI9HdP7D18tdmbPwZJ6DLqDLKT/pFw297V7IjX4AYlpsW/71yPEqadDm3w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/malept"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/subscription/pkg/npm-.electron-forge-core?utm_medium=referral&utm_source=npm_fund"
+ }
+ ],
"license": "MIT",
- "engines": {
- "node": ">=12"
+ "dependencies": {
+ "@electron-forge/core-utils": "8.0.0-alpha.10",
+ "@electron-forge/maker-base": "8.0.0-alpha.10",
+ "@electron-forge/plugin-base": "8.0.0-alpha.10",
+ "@electron-forge/publisher-base": "8.0.0-alpha.10",
+ "@electron-forge/shared-types": "8.0.0-alpha.10",
+ "@electron-forge/tracer": "8.0.0-alpha.10",
+ "@electron/get": "^5.0.0",
+ "@electron/packager": "^20.0.1",
+ "debug": "^4.3.1",
+ "graceful-fs": "^4.2.11",
+ "jiti": "^2.4.2",
+ "listr2": "^7.0.2"
},
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ "engines": {
+ "node": ">= 22.12.0"
}
},
- "node_modules/@alloc/quick-lru": {
- "version": "5.2.0",
+ "apps/desktop/node_modules/@electron-forge/core-utils": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/core-utils/-/core-utils-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-edL4xReqbWStPhdhgSEE55AXXLtJLxMRtHEghulmZlf4UaSfS86zwSBtqDwYcUB1cd9LpcEm3GKKek/awOJB0A==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "@electron-forge/shared-types": "8.0.0-alpha.10",
+ "@electron/rebuild": "^4.0.1",
+ "@malept/cross-spawn-promise": "^2.0.0",
+ "debug": "^4.3.1",
+ "graceful-fs": "^4.2.11",
+ "semver": "^7.2.1"
+ },
"engines": {
- "node": ">=10"
+ "node": ">= 22.12.0"
+ }
+ },
+ "apps/desktop/node_modules/@electron-forge/maker-base": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/maker-base/-/maker-base-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-aZ7YlU785r/1VPy0h1HHy1VEiufqMX0fd4tzHcAWwDfZguajfhnGioPfgCaEVKBWyAgV3v7Pge2FkL7YcRsxsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@electron-forge/shared-types": "8.0.0-alpha.10",
+ "which": "^6.0.0"
},
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "engines": {
+ "node": ">= 22.12.0"
}
},
- "node_modules/@anthropic-ai/claude-code": {
- "version": "2.1.220",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-2.1.220.tgz",
- "integrity": "sha512-ogBrvwkqF9f8okmnXKxmRNHuvtFxFEffe5pWdqOV3iQDxlUOKirFqnyWC7NGXXnDA4WkkbPH8pvSbwyCR2Auyw==",
- "hasInstallScript": true,
- "license": "SEE LICENSE IN README.md",
- "bin": {
- "claude": "bin/claude.exe"
+ "apps/desktop/node_modules/@electron-forge/maker-deb": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/maker-deb/-/maker-deb-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-0uk9bCW+UsPSyIASvCRzhUJii0WRCWo2oQKGZGFelIEdfPo8ojriM2ip2zVQP21c2Q0sSiaky+Ehizsymtcd6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@electron-forge/maker-base": "8.0.0-alpha.10",
+ "@electron-forge/shared-types": "8.0.0-alpha.10"
},
"engines": {
- "node": ">=22.0.0"
+ "node": ">= 22.12.0"
},
"optionalDependencies": {
- "@anthropic-ai/claude-code-darwin-arm64": "2.1.220",
- "@anthropic-ai/claude-code-darwin-x64": "2.1.220",
- "@anthropic-ai/claude-code-linux-arm64": "2.1.220",
- "@anthropic-ai/claude-code-linux-arm64-musl": "2.1.220",
- "@anthropic-ai/claude-code-linux-x64": "2.1.220",
- "@anthropic-ai/claude-code-linux-x64-musl": "2.1.220",
- "@anthropic-ai/claude-code-win32-arm64": "2.1.220",
- "@anthropic-ai/claude-code-win32-x64": "2.1.220"
+ "electron-installer-debian": "^3.2.0"
}
},
- "node_modules/@anthropic-ai/claude-code-darwin-arm64": {
- "version": "2.1.220",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-darwin-arm64/-/claude-code-darwin-arm64-2.1.220.tgz",
- "integrity": "sha512-rmtd41Bf+n+YnhjSjtQ8WG5qy8KKogUp3YRfQrkLsTgPUD0H3j869rBInBJT3SHrKQ0hLghQLGM73CC1C+USLQ==",
- "cpu": [
- "arm64"
- ],
- "license": "SEE LICENSE IN LICENSE.md",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@anthropic-ai/claude-code-darwin-x64": {
- "version": "2.1.220",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-darwin-x64/-/claude-code-darwin-x64-2.1.220.tgz",
- "integrity": "sha512-hbuoG+YCo37VzSKzKJ47ymRmt/YjASc3dRcsZtCcftLYdopv8KL889x/IbCl3cfp/VqV2rRDZ0f3aUDpHUFweQ==",
- "cpu": [
- "x64"
- ],
- "license": "SEE LICENSE IN LICENSE.md",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@anthropic-ai/claude-code-linux-arm64": {
- "version": "2.1.220",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-linux-arm64/-/claude-code-linux-arm64-2.1.220.tgz",
- "integrity": "sha512-VHFI8mKruIntKn7eq81sbyS19/KWmQcmJQsS/C+j9M/E+w0s4UytgsL7DADPjBE/GByNiKoRtLYDMntCjRlOdA==",
- "cpu": [
- "arm64"
- ],
- "license": "SEE LICENSE IN LICENSE.md",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@anthropic-ai/claude-code-linux-arm64-musl": {
- "version": "2.1.220",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-linux-arm64-musl/-/claude-code-linux-arm64-musl-2.1.220.tgz",
- "integrity": "sha512-m37ALw8jcbSknuyG7xDQjGPY7Gth3eX8iFY1XFEWABVq1iUMVAUn96WC9eqwi8/JSqyG2t3oNRiqHdi2ZNKFGQ==",
- "cpu": [
- "arm64"
- ],
- "license": "SEE LICENSE IN LICENSE.md",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@anthropic-ai/claude-code-linux-x64": {
- "version": "2.1.220",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-linux-x64/-/claude-code-linux-x64-2.1.220.tgz",
- "integrity": "sha512-3CGFCnI0gpgsqNeJruFALBDGJaKXOuok3alQEg56ty2yOPpIrOx/r2Y0+T4uhJl7kP5Hzw4IFkxo4DZKWvzQ7Q==",
- "cpu": [
- "x64"
- ],
- "license": "SEE LICENSE IN LICENSE.md",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@anthropic-ai/claude-code-linux-x64-musl": {
- "version": "2.1.220",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-linux-x64-musl/-/claude-code-linux-x64-musl-2.1.220.tgz",
- "integrity": "sha512-+QyT1KikOdMRKReWFaBYGsroYx2vEjjx54DwhMoC24oE1DxjC+SlKjeOTRXAKiu0fr0O549Lkhg2tuT5xtQpAQ==",
- "cpu": [
- "x64"
- ],
- "license": "SEE LICENSE IN LICENSE.md",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@anthropic-ai/claude-code-win32-arm64": {
- "version": "2.1.220",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-win32-arm64/-/claude-code-win32-arm64-2.1.220.tgz",
- "integrity": "sha512-APqZwFBn38DBUwB65uUTetW7lbtUqFfAfOWKvkmOyqFDswDEsInaINuIwqMCl44WYcch10SaHhEZdXJU9MG3aQ==",
- "cpu": [
- "arm64"
- ],
- "license": "SEE LICENSE IN LICENSE.md",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@anthropic-ai/claude-code-win32-x64": {
- "version": "2.1.220",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-win32-x64/-/claude-code-win32-x64-2.1.220.tgz",
- "integrity": "sha512-UGrjH8cGhC6PzhTyZSdgf/RpKxpfk9XJZ/RT/wsG2AJg9yEJLjLg6/TrnlL8RFbEv6Zahu0Quytc02UOpA/GiA==",
- "cpu": [
- "x64"
- ],
- "license": "SEE LICENSE IN LICENSE.md",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@anthropic-ai/sdk": {
- "version": "0.71.2",
- "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.2.tgz",
- "integrity": "sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==",
+ "apps/desktop/node_modules/@electron-forge/maker-rpm": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/maker-rpm/-/maker-rpm-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-jtKz2D2WM/8l8q3difzNdrRCK8oDm1xUXfRmP9et0a31imyLRoalSR/STDjHQ4HiXfWnDZzuw0BvekzVjgGlRw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "json-schema-to-ts": "^3.1.1"
- },
- "bin": {
- "anthropic-ai-sdk": "bin/cli"
+ "@electron-forge/maker-base": "8.0.0-alpha.10",
+ "@electron-forge/shared-types": "8.0.0-alpha.10"
},
- "peerDependencies": {
- "zod": "^3.25.0 || ^4.0.0"
+ "engines": {
+ "node": ">= 22.12.0"
},
- "peerDependenciesMeta": {
- "zod": {
- "optional": true
- }
+ "optionalDependencies": {
+ "electron-installer-redhat": "^3.2.0"
}
},
- "node_modules/@asamuzakjp/css-color": {
- "version": "5.1.10",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.10.tgz",
- "integrity": "sha512-02OhhkKtgNRuicQ/nF3TRnGsxL9wp0r3Y7VlKWyOHHGmGyvXv03y+PnymU8FKFJMTjIr1Bk8U2g1HWSLrpAHww==",
+ "apps/desktop/node_modules/@electron-forge/maker-squirrel": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/maker-squirrel/-/maker-squirrel-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-AFCeuAgUWyr4G61hIXLr0pLZDNV4hvd8IgBXkfrWToMp09esE9jXS9o0SFpU40iETFCst2KxhqhraDt6URAj9Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@csstools/css-calc": "^3.1.1",
- "@csstools/css-color-parser": "^4.0.2",
- "@csstools/css-parser-algorithms": "^4.0.0",
- "@csstools/css-tokenizer": "^4.0.0"
+ "@electron-forge/core-utils": "8.0.0-alpha.10",
+ "@electron-forge/maker-base": "8.0.0-alpha.10",
+ "@electron-forge/shared-types": "8.0.0-alpha.10"
},
"engines": {
- "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ "node": ">= 22.12.0"
+ },
+ "optionalDependencies": {
+ "electron-winstaller": "^5.3.0"
}
},
- "node_modules/@asamuzakjp/dom-selector": {
- "version": "7.0.9",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.0.9.tgz",
- "integrity": "sha512-r3ElRr7y8ucyN2KdICwGsmj19RoN13CLCa/pvGydghWK6ZzeKQ+TcDjVdtEZz2ElpndM5jXw//B9CEee0mWnVg==",
+ "apps/desktop/node_modules/@electron-forge/maker-zip": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/maker-zip/-/maker-zip-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-I3N9FI8xJW7f+Ld05f2hSSuukfI2Oh9vKN7HWSPmM8+7PqN4Dwigp7DRv/s3HPFwrMdayDJKm/2me5rvXh32DQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@asamuzakjp/nwsapi": "^2.3.9",
- "bidi-js": "^1.0.3",
- "css-tree": "^3.2.1",
- "is-potential-custom-element-name": "^1.0.1"
+ "@electron-forge/core-utils": "8.0.0-alpha.10",
+ "@electron-forge/maker-base": "8.0.0-alpha.10",
+ "@electron-forge/shared-types": "8.0.0-alpha.10",
+ "cross-zip": "^4.0.0"
},
"engines": {
- "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ "node": ">= 22.12.0"
}
},
- "node_modules/@asamuzakjp/nwsapi": {
- "version": "2.3.9",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz",
- "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==",
+ "apps/desktop/node_modules/@electron-forge/plugin-base": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/plugin-base/-/plugin-base-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-AoL+VuuFVLgqeRzO0dLvrx4f2t1nMeHQ1YKj/EoqAQ6uU7D4HS2D4FNEXyxTQFVrNj4OqSte7U3sqGenc327XA==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "@electron-forge/shared-types": "8.0.0-alpha.10"
+ },
+ "engines": {
+ "node": ">= 22.12.0"
+ }
},
- "node_modules/@babel/code-frame": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
- "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "apps/desktop/node_modules/@electron-forge/plugin-vite": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/plugin-vite/-/plugin-vite-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-ctt+M1D1K5Or07oGWGUByLHfPJW91Qn1JKHWhJEkEZmrp6ggJrSrp7JqgBhNAqe5XtpEhhPCtDMaRfFmcSL+2g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/helper-validator-identifier": "^7.29.7",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.1.1"
+ "@electron-forge/core-utils": "8.0.0-alpha.10",
+ "@electron-forge/plugin-base": "8.0.0-alpha.10",
+ "@electron-forge/shared-types": "8.0.0-alpha.10",
+ "debug": "^4.3.1",
+ "listr2": "^7.0.2"
},
"engines": {
- "node": ">=6.9.0"
+ "node": ">= 22.12.0"
}
},
- "node_modules/@babel/compat-data": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
- "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "apps/desktop/node_modules/@electron-forge/publisher-base": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/publisher-base/-/publisher-base-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-UjGRM13jVr1oq+HLayJAUiQcfxvs8LyTQYm5sazxlfG9LO9UJAI/2jbNic/OXYehr5xGrJSCMXDTm/cCy5LfZQ==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "@electron-forge/shared-types": "8.0.0-alpha.10"
+ },
"engines": {
- "node": ">=6.9.0"
+ "node": ">= 22.12.0"
}
},
- "node_modules/@babel/core": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
- "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "apps/desktop/node_modules/@electron-forge/shared-types": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/shared-types/-/shared-types-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-JdwOXHXXjh1L1rgLcQJfyCX8cHgvognmuol/udDUIx9/JzMc+AZhNnsFN8JriRYunYaFrVLTHe0H8f8GQXO/LA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.29.7",
- "@babel/generator": "^7.29.7",
- "@babel/helper-compilation-targets": "^7.29.7",
- "@babel/helper-module-transforms": "^7.29.7",
- "@babel/helpers": "^7.29.7",
- "@babel/parser": "^7.29.7",
- "@babel/template": "^7.29.7",
- "@babel/traverse": "^7.29.7",
- "@babel/types": "^7.29.7",
- "@jridgewell/remapping": "^2.3.5",
- "convert-source-map": "^2.0.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.3",
- "semver": "^6.3.1"
+ "@electron-forge/tracer": "8.0.0-alpha.10",
+ "@electron/packager": "^20.0.1",
+ "@electron/rebuild": "^4.0.1",
+ "listr2": "^7.0.2"
},
"engines": {
- "node": ">=6.9.0"
+ "node": ">= 22.12.0"
+ }
+ },
+ "apps/desktop/node_modules/@electron-forge/tracer": {
+ "version": "8.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@electron-forge/tracer/-/tracer-8.0.0-alpha.10.tgz",
+ "integrity": "sha512-aoW9P+KoTtO0KQaISdJXi3sVB5k12P1kA6pK0NsgJTEbsB2i5O6c8zfor/U5eJUeb9GAVscAIHKShYuUycgZqg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chrome-trace-event": "^1.0.3"
},
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/babel"
+ "engines": {
+ "node": ">= 22.12.0"
}
},
- "node_modules/@babel/core/node_modules/semver": {
- "version": "6.3.1",
+ "apps/desktop/node_modules/@electron/asar": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-4.3.0.tgz",
+ "integrity": "sha512-k/FFC/NQoTykGBi/Ga4L4KorsAKDdkK0LfNVG90eUG6vPVpJaL3iR9V1ZLbzBAF3QpojK5DcaGOdQOheKZv4JQ==",
"dev": true,
- "license": "ISC",
+ "license": "MIT",
+ "dependencies": {
+ "glob": "^13.0.2",
+ "minimatch": "^10.0.1"
+ },
"bin": {
- "semver": "bin/semver.js"
+ "asar": "bin/asar.mjs"
+ },
+ "engines": {
+ "node": ">=22.12.0"
}
},
- "node_modules/@babel/generator": {
- "version": "7.29.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz",
- "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==",
+ "apps/desktop/node_modules/@electron/fuses": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-2.1.3.tgz",
+ "integrity": "sha512-LoKJUXNiJ4JM8IIrUltSHI+8pkogaGj5wmJx81jE/Wk3g2w1/kfMbTEKNoY5kitGE8hiC12h32R/1SlywFtxXg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "electron-fuses": "dist/bin.js"
+ },
+ "engines": {
+ "node": ">=22.12.0"
+ }
+ },
+ "apps/desktop/node_modules/@electron/get": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.1.0.tgz",
+ "integrity": "sha512-3kSBtG8ObcTVfXanm5vVJ6UnBLEVmVsRk1M+vGqCuMBV+XLCbJYuWQful+yIy0GQDsSlK0kHEriEHn7SPk4EnA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.29.8",
- "@babel/types": "^7.29.8",
- "@jridgewell/gen-mapping": "^0.3.12",
- "@jridgewell/trace-mapping": "^0.3.28",
- "jsesc": "^3.0.2"
+ "debug": "^4.1.1",
+ "env-paths": "^3.0.0",
+ "graceful-fs": "^4.2.11",
+ "progress": "^2.0.3",
+ "semver": "^7.6.3",
+ "sumchecker": "^3.0.1"
},
"engines": {
- "node": ">=6.9.0"
+ "node": ">=22.12.0"
+ },
+ "optionalDependencies": {
+ "undici": "^7.24.4"
}
},
- "node_modules/@babel/helper-compilation-targets": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
- "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "apps/desktop/node_modules/@electron/notarize": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-3.1.1.tgz",
+ "integrity": "sha512-uQQSlOiJnqRkTL1wlEBAxe90nVN/Fc/hEmk0bqpKk8nKjV1if/tXLHKUPePtv9Xsx90PtZU8aidx5lAiOpjkQQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/compat-data": "^7.29.7",
- "@babel/helper-validator-option": "^7.29.7",
- "browserslist": "^4.24.0",
- "lru-cache": "^5.1.1",
- "semver": "^6.3.1"
+ "debug": "^4.4.0",
+ "promise-retry": "^2.0.1"
},
"engines": {
- "node": ">=6.9.0"
+ "node": ">= 22.12.0"
}
},
- "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "apps/desktop/node_modules/@electron/osx-sign": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-2.7.0.tgz",
+ "integrity": "sha512-9DGhNqKMl6ibkhUoXbN7OHX2gZznfY10L3ZwG0u6r667Kfb6kec4JEfFTXftoqzmOfZ+OzwDbr4p/nKBMHnz0g==",
"dev": true,
- "license": "ISC",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "debug": "^4.3.4",
+ "isbinaryfile": "^4.0.8",
+ "plist": "^3.0.5",
+ "semver": "^7.7.1"
+ },
"bin": {
- "semver": "bin/semver.js"
+ "electron-osx-flat": "bin/electron-osx-flat.mjs",
+ "electron-osx-sign": "bin/electron-osx-sign.mjs"
+ },
+ "engines": {
+ "node": ">=22.12.0"
}
},
- "node_modules/@babel/helper-globals": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
- "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "apps/desktop/node_modules/@electron/packager": {
+ "version": "20.3.0",
+ "resolved": "https://registry.npmjs.org/@electron/packager/-/packager-20.3.0.tgz",
+ "integrity": "sha512-3MvgJgy6YJ5ti0oGGBKrWKdYwpTaoRrhranMDgHSQ6i5t56yZV9IRDyoXTuqBp97LiKqnZeAMe2wTcF/9+fP5g==",
"dev": true,
- "license": "MIT",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@electron-internal/extract-zip": "^1.0.1",
+ "@electron/asar": "^4.0.1",
+ "@electron/get": "^5.0.0",
+ "@electron/notarize": "^3.1.0",
+ "@electron/osx-sign": "^2.2.0",
+ "@electron/universal": "^3.0.1",
+ "@electron/windows-sign": "^2.0.2",
+ "@malept/cross-spawn-promise": "^2.0.0",
+ "debug": "^4.4.1",
+ "filenamify": "^6.0.0",
+ "galactus": "^2.0.2",
+ "graceful-fs": "^4.2.11",
+ "junk": "^4.0.1",
+ "plist": "^3.1.0",
+ "resedit": "^2.0.3",
+ "semver": "^7.7.2",
+ "yargs-parser": "^22.0.0"
+ },
+ "bin": {
+ "electron-packager": "bin/electron-packager.mjs"
+ },
"engines": {
- "node": ">=6.9.0"
+ "node": ">= 22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/electron/packager?sponsor=1"
}
},
- "node_modules/@babel/helper-module-imports": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
- "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "apps/desktop/node_modules/@electron/rebuild": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.2.0.tgz",
+ "integrity": "sha512-RKL/O+jGoXJMxrx/5771y1n0xTKmFuOYGO3gMmwypBM6rsH0kou0mswwdXA2JrhIkE4xyC7v9vGk0n6NPzgOxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/traverse": "^7.29.7",
- "@babel/types": "^7.29.7"
+ "@malept/cross-spawn-promise": "^2.0.0",
+ "debug": "^4.1.1",
+ "node-abi": "^4.2.0",
+ "node-api-version": "^0.2.1",
+ "node-gyp": "^12.2.0",
+ "read-binary-file-arch": "^1.0.6"
+ },
+ "bin": {
+ "electron-rebuild": "lib/cli.js"
},
"engines": {
- "node": ">=6.9.0"
+ "node": ">=22.12.0"
}
},
- "node_modules/@babel/helper-module-transforms": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
- "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "apps/desktop/node_modules/@electron/universal": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-3.0.6.tgz",
+ "integrity": "sha512-MonS1kfkZdSEkLZI0pdR/TCx8ecxwRSFm7sORfwIkDI9UaIbHnk4Mgeqq+Ob9qDQRV8LZ9+hHCmimpA9BRcNxw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/helper-module-imports": "^7.29.7",
- "@babel/helper-validator-identifier": "^7.29.7",
- "@babel/traverse": "^7.29.7"
+ "@electron/asar": "^4.0.0",
+ "debug": "^4.3.1",
+ "plist": "^3.1.0"
},
"engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
+ "node": ">=22.12.0"
}
},
- "node_modules/@babel/helper-plugin-utils": {
- "version": "7.27.1",
+ "apps/desktop/node_modules/@electron/windows-sign": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-2.0.6.tgz",
+ "integrity": "sha512-ESWgNkFsXFH06I5EB2uHv3hmZA3yF4j9GTB77W74x3b5KZNItxggNzuADw41HUy6mhnC2K+E2mT0Xgc4YKu3IQ==",
"dev": true,
- "license": "MIT",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "debug": "^4.3.4",
+ "graceful-fs": "^4.2.11",
+ "postject": "^1.0.0-alpha.6"
+ },
+ "bin": {
+ "electron-windows-sign": "bin/electron-windows-sign.mjs"
+ },
"engines": {
- "node": ">=6.9.0"
+ "node": ">=22.12.0"
}
},
- "node_modules/@babel/helper-string-parser": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
- "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "apps/desktop/node_modules/commander": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=6.9.0"
+ "node": ">=16"
}
},
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
- "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "apps/desktop/node_modules/env-paths": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
+ "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=6.9.0"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@babel/helper-validator-option": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
- "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "apps/desktop/node_modules/filename-reserved-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz",
+ "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=6.9.0"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@babel/helpers": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
- "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "apps/desktop/node_modules/filenamify": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-6.0.0.tgz",
+ "integrity": "sha512-vqIlNogKeyD3yzrm0yhRMQg8hOVwYcYRfjEoODd49iCprMn4HL85gK3HcykQE53EPIpX3HcAbGA5ELQv216dAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/template": "^7.29.7",
- "@babel/types": "^7.29.7"
+ "filename-reserved-regex": "^3.0.0"
},
"engines": {
- "node": ">=6.9.0"
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@babel/parser": {
- "version": "7.29.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
- "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
+ "apps/desktop/node_modules/flora-colossus": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/flora-colossus/-/flora-colossus-3.0.2.tgz",
+ "integrity": "sha512-Jk78K/Tzt6saxQPGChlJw69xuFGpWyTSAS8EdU0h/FyXwD2K46yNOXmo6nRHcZ9ooekyBAzMkwmiGNt7wOC5zg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.29.8"
- },
- "bin": {
- "parser": "bin/babel-parser.js"
+ "debug": "^4.4.1"
},
"engines": {
- "node": ">=6.0.0"
+ "node": ">=22.12.0"
}
},
- "node_modules/@babel/plugin-transform-react-jsx-self": {
- "version": "7.27.1",
+ "apps/desktop/node_modules/galactus": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/galactus/-/galactus-2.0.2.tgz",
+ "integrity": "sha512-HmKyTFGomdAchz4umx8MwBnrnfFmdpwiTyGA4ZOF7rya2Lmgbc9qate4yweInL+0gUBVImhaz12SBGpW3SY4Yg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
+ "debug": "^4.4.1",
+ "flora-colossus": "^3.0.2"
},
"engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
+ "node": ">=22.12.0"
}
},
- "node_modules/@babel/plugin-transform-react-jsx-source": {
- "version": "7.27.1",
+ "apps/desktop/node_modules/glob": {
+ "version": "13.0.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
+ "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
"dev": true,
- "license": "MIT",
+ "license": "BlueOak-1.0.0",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
+ "minimatch": "^10.2.2",
+ "minipass": "^7.1.3",
+ "path-scurry": "^2.0.2"
},
"engines": {
- "node": ">=6.9.0"
+ "node": "18 || 20 || >=22"
},
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/@babel/runtime": {
- "version": "7.28.4",
+ "apps/desktop/node_modules/isbinaryfile": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz",
+ "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==",
+ "dev": true,
"license": "MIT",
"engines": {
- "node": ">=6.9.0"
+ "node": ">= 8.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/gjtorikian/"
}
},
- "node_modules/@babel/template": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
- "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "apps/desktop/node_modules/isexe": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
+ "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.29.7",
- "@babel/parser": "^7.29.7",
- "@babel/types": "^7.29.7"
- },
+ "license": "BlueOak-1.0.0",
"engines": {
- "node": ">=6.9.0"
+ "node": ">=20"
}
},
- "node_modules/@babel/traverse": {
- "version": "7.29.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
- "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
+ "apps/desktop/node_modules/junk": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.1.tgz",
+ "integrity": "sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.29.7",
- "@babel/generator": "^7.29.8",
- "@babel/helper-globals": "^7.29.7",
- "@babel/parser": "^7.29.8",
- "@babel/template": "^7.29.7",
- "@babel/types": "^7.29.8",
- "debug": "^4.3.1"
- },
"engines": {
- "node": ">=6.9.0"
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@babel/types": {
- "version": "7.29.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
- "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
+ "apps/desktop/node_modules/node-abi": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.35.0.tgz",
+ "integrity": "sha512-ymk4aIzxdPopw2giv8Fs1Ec6vybGkjmyxUwVqhkI4MCy2tVfXdkOGGWieWVjL0THgH+7a8lRdevyupoYj3Js/Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/helper-string-parser": "^7.29.7",
- "@babel/helper-validator-identifier": "^7.29.7"
+ "semver": "^7.6.3"
},
"engines": {
- "node": ">=6.9.0"
+ "node": ">=22.12.0"
}
},
- "node_modules/@bramus/specificity": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz",
- "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==",
+ "apps/desktop/node_modules/which": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
+ "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^4.0.0"
+ },
+ "bin": {
+ "node-which": "bin/which.js"
+ },
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "apps/desktop/node_modules/yargs-parser": {
+ "version": "22.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
+ "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=23"
+ }
+ },
+ "node_modules/@adobe/css-tools": {
+ "version": "4.4.4",
+ "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz",
+ "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@alcalzone/ansi-tokenize": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.3.0.tgz",
+ "integrity": "sha512-p+CMKJ93HFmLkjXKlXiVGlMQEuRb6H0MokBSwUsX+S6BRX8eV5naFZpQJFfJHjRZY0Hmnqy1/r6UWl3x+19zYA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.2.1",
+ "is-fullwidth-code-point": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@alcalzone/ansi-tokenize/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@anthropic-ai/claude-code": {
+ "version": "2.1.220",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-2.1.220.tgz",
+ "integrity": "sha512-ogBrvwkqF9f8okmnXKxmRNHuvtFxFEffe5pWdqOV3iQDxlUOKirFqnyWC7NGXXnDA4WkkbPH8pvSbwyCR2Auyw==",
+ "hasInstallScript": true,
+ "license": "SEE LICENSE IN README.md",
+ "bin": {
+ "claude": "bin/claude.exe"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ },
+ "optionalDependencies": {
+ "@anthropic-ai/claude-code-darwin-arm64": "2.1.220",
+ "@anthropic-ai/claude-code-darwin-x64": "2.1.220",
+ "@anthropic-ai/claude-code-linux-arm64": "2.1.220",
+ "@anthropic-ai/claude-code-linux-arm64-musl": "2.1.220",
+ "@anthropic-ai/claude-code-linux-x64": "2.1.220",
+ "@anthropic-ai/claude-code-linux-x64-musl": "2.1.220",
+ "@anthropic-ai/claude-code-win32-arm64": "2.1.220",
+ "@anthropic-ai/claude-code-win32-x64": "2.1.220"
+ }
+ },
+ "node_modules/@anthropic-ai/claude-code-darwin-arm64": {
+ "version": "2.1.220",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-darwin-arm64/-/claude-code-darwin-arm64-2.1.220.tgz",
+ "integrity": "sha512-rmtd41Bf+n+YnhjSjtQ8WG5qy8KKogUp3YRfQrkLsTgPUD0H3j869rBInBJT3SHrKQ0hLghQLGM73CC1C+USLQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "SEE LICENSE IN LICENSE.md",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@anthropic-ai/claude-code-darwin-x64": {
+ "version": "2.1.220",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-darwin-x64/-/claude-code-darwin-x64-2.1.220.tgz",
+ "integrity": "sha512-hbuoG+YCo37VzSKzKJ47ymRmt/YjASc3dRcsZtCcftLYdopv8KL889x/IbCl3cfp/VqV2rRDZ0f3aUDpHUFweQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "SEE LICENSE IN LICENSE.md",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@anthropic-ai/claude-code-linux-arm64": {
+ "version": "2.1.220",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-linux-arm64/-/claude-code-linux-arm64-2.1.220.tgz",
+ "integrity": "sha512-VHFI8mKruIntKn7eq81sbyS19/KWmQcmJQsS/C+j9M/E+w0s4UytgsL7DADPjBE/GByNiKoRtLYDMntCjRlOdA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "SEE LICENSE IN LICENSE.md",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@anthropic-ai/claude-code-linux-arm64-musl": {
+ "version": "2.1.220",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-linux-arm64-musl/-/claude-code-linux-arm64-musl-2.1.220.tgz",
+ "integrity": "sha512-m37ALw8jcbSknuyG7xDQjGPY7Gth3eX8iFY1XFEWABVq1iUMVAUn96WC9eqwi8/JSqyG2t3oNRiqHdi2ZNKFGQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "SEE LICENSE IN LICENSE.md",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@anthropic-ai/claude-code-linux-x64": {
+ "version": "2.1.220",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-linux-x64/-/claude-code-linux-x64-2.1.220.tgz",
+ "integrity": "sha512-3CGFCnI0gpgsqNeJruFALBDGJaKXOuok3alQEg56ty2yOPpIrOx/r2Y0+T4uhJl7kP5Hzw4IFkxo4DZKWvzQ7Q==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "SEE LICENSE IN LICENSE.md",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@anthropic-ai/claude-code-linux-x64-musl": {
+ "version": "2.1.220",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-linux-x64-musl/-/claude-code-linux-x64-musl-2.1.220.tgz",
+ "integrity": "sha512-+QyT1KikOdMRKReWFaBYGsroYx2vEjjx54DwhMoC24oE1DxjC+SlKjeOTRXAKiu0fr0O549Lkhg2tuT5xtQpAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "SEE LICENSE IN LICENSE.md",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@anthropic-ai/claude-code-win32-arm64": {
+ "version": "2.1.220",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-win32-arm64/-/claude-code-win32-arm64-2.1.220.tgz",
+ "integrity": "sha512-APqZwFBn38DBUwB65uUTetW7lbtUqFfAfOWKvkmOyqFDswDEsInaINuIwqMCl44WYcch10SaHhEZdXJU9MG3aQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "SEE LICENSE IN LICENSE.md",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@anthropic-ai/claude-code-win32-x64": {
+ "version": "2.1.220",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code-win32-x64/-/claude-code-win32-x64-2.1.220.tgz",
+ "integrity": "sha512-UGrjH8cGhC6PzhTyZSdgf/RpKxpfk9XJZ/RT/wsG2AJg9yEJLjLg6/TrnlL8RFbEv6Zahu0Quytc02UOpA/GiA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "SEE LICENSE IN LICENSE.md",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@anthropic-ai/sdk": {
+ "version": "0.71.2",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.2.tgz",
+ "integrity": "sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==",
+ "license": "MIT",
+ "dependencies": {
+ "json-schema-to-ts": "^3.1.1"
+ },
+ "bin": {
+ "anthropic-ai-sdk": "bin/cli"
+ },
+ "peerDependencies": {
+ "zod": "^3.25.0 || ^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@asamuzakjp/css-color": {
+ "version": "5.1.10",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.10.tgz",
+ "integrity": "sha512-02OhhkKtgNRuicQ/nF3TRnGsxL9wp0r3Y7VlKWyOHHGmGyvXv03y+PnymU8FKFJMTjIr1Bk8U2g1HWSLrpAHww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@csstools/css-calc": "^3.1.1",
+ "@csstools/css-color-parser": "^4.0.2",
+ "@csstools/css-parser-algorithms": "^4.0.0",
+ "@csstools/css-tokenizer": "^4.0.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@asamuzakjp/dom-selector": {
+ "version": "7.0.9",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.0.9.tgz",
+ "integrity": "sha512-r3ElRr7y8ucyN2KdICwGsmj19RoN13CLCa/pvGydghWK6ZzeKQ+TcDjVdtEZz2ElpndM5jXw//B9CEee0mWnVg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@asamuzakjp/nwsapi": "^2.3.9",
+ "bidi-js": "^1.0.3",
+ "css-tree": "^3.2.1",
+ "is-potential-custom-element-name": "^1.0.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@asamuzakjp/nwsapi": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz",
+ "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helpers": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/semver": {
+ "version": "6.3.1",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz",
+ "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.8",
+ "@babel/types": "^7.29.8",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.27.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
+ "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.8"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.27.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.27.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.28.4",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
+ "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.8",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.8",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.8",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
+ "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@bramus/specificity": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz",
+ "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -816,6 +1424,101 @@
"react": ">=16.8.0"
}
},
+ "node_modules/@electron-internal/extract-zip": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@electron-internal/extract-zip/-/extract-zip-1.0.5.tgz",
+ "integrity": "sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=22.12.0"
+ }
+ },
+ "node_modules/@electron/asar": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz",
+ "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "commander": "^5.0.0",
+ "glob": "^7.1.6",
+ "minimatch": "^3.0.4"
+ },
+ "bin": {
+ "asar": "bin/asar.js"
+ },
+ "engines": {
+ "node": ">=10.12.0"
+ }
+ },
+ "node_modules/@electron/asar/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/@electron/asar/node_modules/brace-expansion": {
+ "version": "1.1.18",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
+ "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@electron/asar/node_modules/commander": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
+ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@electron/asar/node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@electron/windows-sign": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz",
+ "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "optional": true,
+ "dependencies": {
+ "cross-dirname": "^0.1.0",
+ "debug": "^4.3.4",
+ "fs-extra": "^11.1.1",
+ "minimist": "^1.2.8",
+ "postject": "^1.0.0-alpha.6"
+ },
+ "bin": {
+ "electron-windows-sign": "bin/electron-windows-sign.js"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
"node_modules/@emnapi/runtime": {
"version": "1.11.3",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz",
@@ -1684,6 +2387,19 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
+ "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"dev": true,
@@ -1709,6 +2425,29 @@
"version": "1.1.1",
"license": "MIT"
},
+ "node_modules/@malept/cross-spawn-promise": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz",
+ "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/malept"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund"
+ }
+ ],
+ "license": "Apache-2.0",
+ "dependencies": {
+ "cross-spawn": "^7.0.1"
+ },
+ "engines": {
+ "node": ">= 12.13.0"
+ }
+ },
"node_modules/@mixmark-io/domino": {
"version": "2.2.0",
"dev": true,
@@ -2193,6 +2932,10 @@
"resolved": "packages/core",
"link": true
},
+ "node_modules/@propr/desktop": {
+ "resolved": "apps/desktop",
+ "link": true
+ },
"node_modules/@propr/local-setup": {
"resolved": "packages/local-setup",
"link": true
@@ -2896,890 +3639,1360 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@types/estree": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
- "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/estree-jsx": {
+ "version": "1.0.5",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz",
+ "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^5.0.0",
+ "@types/serve-static": "^2"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.3.tgz",
+ "integrity": "sha512-dPfW8NFiOF4wOHc7+N/QSxlY9cfSsenewGbAz8C8U/MULPd/YZ27LvJUIlzaXie7e6Ove9YunJGgC9tbHD2cKw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/express-session": {
+ "version": "1.18.2",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "*"
+ }
+ },
+ "node_modules/@types/fast-levenshtein": {
+ "version": "0.0.4",
+ "license": "MIT"
+ },
+ "node_modules/@types/fs-extra": {
+ "version": "11.0.4",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/jsonfile": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/hast": {
+ "version": "3.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
+ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/jsonfile": {
+ "version": "6.1.4",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/jsonwebtoken": {
+ "version": "9.0.10",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/ms": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/lodash": {
+ "version": "4.17.21",
+ "license": "MIT"
+ },
+ "node_modules/@types/mdast": {
+ "version": "4.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
+ "node_modules/@types/ms": {
+ "version": "2.1.0",
+ "license": "MIT"
+ },
+ "node_modules/@types/multer": {
+ "version": "2.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.20.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
+ "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/oauth": {
+ "version": "0.9.6",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/parse-path": {
+ "version": "7.0.3",
+ "license": "MIT"
+ },
+ "node_modules/@types/passport": {
+ "version": "1.0.17",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "*"
+ }
+ },
+ "node_modules/@types/passport-github2": {
+ "version": "1.2.9",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "*",
+ "@types/passport": "*",
+ "@types/passport-oauth2": "*"
+ }
+ },
+ "node_modules/@types/passport-oauth2": {
+ "version": "1.8.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "*",
+ "@types/oauth": "*",
+ "@types/passport": "*"
+ }
+ },
+ "node_modules/@types/prismjs": {
+ "version": "1.26.5",
+ "license": "MIT"
+ },
+ "node_modules/@types/qs": {
+ "version": "6.15.1",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz",
+ "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.17",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
+ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@types/react-syntax-highlighter": {
+ "version": "15.5.13",
+ "license": "MIT",
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@types/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/turndown": {
+ "version": "5.0.6",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/unist": {
+ "version": "3.0.3",
"license": "MIT"
},
- "node_modules/@types/estree-jsx": {
- "version": "1.0.5",
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.6",
+ "license": "MIT"
+ },
+ "node_modules/@types/uuid": {
+ "version": "10.0.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/web-push": {
+ "version": "3.6.4",
+ "resolved": "https://registry.npmjs.org/@types/web-push/-/web-push-3.6.4.tgz",
+ "integrity": "sha512-GnJmSr40H3RAnj0s34FNTcJi1hmWFV5KXugE0mYWnYhgTAHLJ/dJKAwDmvPJYMke0RplY2XE9LnM4hqSqKIjhQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@types/estree": "*"
+ "@types/node": "*"
}
},
- "node_modules/@types/express": {
- "version": "5.0.6",
- "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz",
- "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==",
+ "node_modules/@types/ws": {
+ "version": "8.18.1",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
+ "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
"license": "MIT",
"dependencies": {
- "@types/body-parser": "*",
- "@types/express-serve-static-core": "^5.0.0",
- "@types/serve-static": "^2"
+ "@types/node": "*"
}
},
- "node_modules/@types/express-serve-static-core": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.3.tgz",
- "integrity": "sha512-dPfW8NFiOF4wOHc7+N/QSxlY9cfSsenewGbAz8C8U/MULPd/YZ27LvJUIlzaXie7e6Ove9YunJGgC9tbHD2cKw==",
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz",
+ "integrity": "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@types/node": "*",
- "@types/qs": "*",
- "@types/range-parser": "*",
- "@types/send": "*"
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.66.0",
+ "@typescript-eslint/type-utils": "8.66.0",
+ "@typescript-eslint/utils": "8.66.0",
+ "@typescript-eslint/visitor-keys": "8.66.0",
+ "ignore": "^7.0.5",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.66.0",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
}
},
- "node_modules/@types/express-session": {
- "version": "1.18.2",
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.66.0.tgz",
+ "integrity": "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/express": "*"
+ "@typescript-eslint/scope-manager": "8.66.0",
+ "@typescript-eslint/types": "8.66.0",
+ "@typescript-eslint/typescript-estree": "8.66.0",
+ "@typescript-eslint/visitor-keys": "8.66.0",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
}
},
- "node_modules/@types/fast-levenshtein": {
- "version": "0.0.4",
- "license": "MIT"
- },
- "node_modules/@types/fs-extra": {
- "version": "11.0.4",
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.66.0.tgz",
+ "integrity": "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/jsonfile": "*",
- "@types/node": "*"
+ "@typescript-eslint/tsconfig-utils": "^8.66.0",
+ "@typescript-eslint/types": "^8.66.0",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
}
},
- "node_modules/@types/hast": {
- "version": "3.0.4",
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.66.0.tgz",
+ "integrity": "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@types/unist": "*"
+ "@typescript-eslint/types": "8.66.0",
+ "@typescript-eslint/visitor-keys": "8.66.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
- "node_modules/@types/http-errors": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
- "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
- "license": "MIT"
- },
- "node_modules/@types/json-schema": {
- "version": "7.0.15",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
- "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/jsonfile": {
- "version": "6.1.4",
+ "node_modules/@typescript-eslint/tsconfig-utils": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.66.0.tgz",
+ "integrity": "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "@types/node": "*"
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
}
},
- "node_modules/@types/jsonwebtoken": {
- "version": "9.0.10",
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.66.0.tgz",
+ "integrity": "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/ms": "*",
- "@types/node": "*"
+ "@typescript-eslint/types": "8.66.0",
+ "@typescript-eslint/typescript-estree": "8.66.0",
+ "@typescript-eslint/utils": "8.66.0",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
}
},
- "node_modules/@types/lodash": {
- "version": "4.17.21",
- "license": "MIT"
- },
- "node_modules/@types/mdast": {
- "version": "4.0.4",
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.66.0.tgz",
+ "integrity": "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==",
+ "dev": true,
"license": "MIT",
- "dependencies": {
- "@types/unist": "*"
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
- "node_modules/@types/ms": {
- "version": "2.1.0",
- "license": "MIT"
- },
- "node_modules/@types/multer": {
- "version": "2.0.0",
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.66.0.tgz",
+ "integrity": "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@types/express": "*"
+ "@typescript-eslint/project-service": "8.66.0",
+ "@typescript-eslint/tsconfig-utils": "8.66.0",
+ "@typescript-eslint/types": "8.66.0",
+ "@typescript-eslint/visitor-keys": "8.66.0",
+ "debug": "^4.4.3",
+ "minimatch": "^10.2.2",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
}
},
- "node_modules/@types/node": {
- "version": "22.20.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
- "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.66.0.tgz",
+ "integrity": "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~6.21.0"
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.66.0",
+ "@typescript-eslint/types": "8.66.0",
+ "@typescript-eslint/typescript-estree": "8.66.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
}
},
- "node_modules/@types/oauth": {
- "version": "0.9.6",
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.66.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.66.0.tgz",
+ "integrity": "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/node": "*"
+ "@typescript-eslint/types": "8.66.0",
+ "eslint-visitor-keys": "^5.0.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
- "node_modules/@types/parse-path": {
- "version": "7.0.3",
- "license": "MIT"
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.3.0",
+ "license": "ISC"
},
- "node_modules/@types/passport": {
- "version": "1.0.17",
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.7.0",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/express": "*"
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
- "node_modules/@types/passport-github2": {
- "version": "1.2.9",
+ "node_modules/@vitest/expect": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz",
+ "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/express": "*",
- "@types/passport": "*",
- "@types/passport-oauth2": "*"
+ "@standard-schema/spec": "^1.1.0",
+ "@types/chai": "^5.2.2",
+ "@vitest/spy": "4.1.4",
+ "@vitest/utils": "4.1.4",
+ "chai": "^6.2.2",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
}
},
- "node_modules/@types/passport-oauth2": {
- "version": "1.8.0",
+ "node_modules/@vitest/mocker": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz",
+ "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/express": "*",
- "@types/oauth": "*",
- "@types/passport": "*"
+ "@vitest/spy": "4.1.4",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.21"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
}
},
- "node_modules/@types/prismjs": {
- "version": "1.26.5",
- "license": "MIT"
- },
- "node_modules/@types/qs": {
- "version": "6.15.1",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz",
- "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==",
- "license": "MIT"
- },
- "node_modules/@types/range-parser": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
- "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
- "license": "MIT"
- },
- "node_modules/@types/react": {
- "version": "19.2.17",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
- "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
+ "node_modules/@vitest/pretty-format": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz",
+ "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "csstype": "^3.2.2"
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
}
},
- "node_modules/@types/react-dom": {
- "version": "19.2.3",
+ "node_modules/@vitest/runner": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz",
+ "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==",
"dev": true,
"license": "MIT",
- "peerDependencies": {
- "@types/react": "^19.2.0"
+ "dependencies": {
+ "@vitest/utils": "4.1.4",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
}
},
- "node_modules/@types/react-syntax-highlighter": {
- "version": "15.5.13",
+ "node_modules/@vitest/snapshot": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz",
+ "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@types/react": "*"
+ "@vitest/pretty-format": "4.1.4",
+ "@vitest/utils": "4.1.4",
+ "magic-string": "^0.30.21",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
}
},
- "node_modules/@types/send": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
- "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==",
+ "node_modules/@vitest/spy": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz",
+ "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==",
+ "dev": true,
"license": "MIT",
- "dependencies": {
- "@types/node": "*"
+ "funding": {
+ "url": "https://opencollective.com/vitest"
}
},
- "node_modules/@types/serve-static": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz",
- "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==",
+ "node_modules/@vitest/utils": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz",
+ "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@types/http-errors": "*",
- "@types/node": "*"
+ "@vitest/pretty-format": "4.1.4",
+ "convert-source-map": "^2.0.0",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
}
},
- "node_modules/@types/turndown": {
- "version": "5.0.6",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/unist": {
- "version": "3.0.3",
- "license": "MIT"
- },
- "node_modules/@types/use-sync-external-store": {
- "version": "0.0.6",
- "license": "MIT"
- },
- "node_modules/@types/uuid": {
- "version": "10.0.0",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/web-push": {
- "version": "3.6.4",
- "resolved": "https://registry.npmjs.org/@types/web-push/-/web-push-3.6.4.tgz",
- "integrity": "sha512-GnJmSr40H3RAnj0s34FNTcJi1hmWFV5KXugE0mYWnYhgTAHLJ/dJKAwDmvPJYMke0RplY2XE9LnM4hqSqKIjhQ==",
+ "node_modules/@xmldom/xmldom": {
+ "version": "0.9.12",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.12.tgz",
+ "integrity": "sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "@types/node": "*"
+ "engines": {
+ "node": ">=14.6"
}
},
- "node_modules/@types/ws": {
- "version": "8.18.1",
- "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
- "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
+ "node_modules/accepts": {
+ "version": "1.3.8",
"license": "MIT",
"dependencies": {
- "@types/node": "*"
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
}
},
- "node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz",
- "integrity": "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==",
+ "node_modules/acorn": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz",
+ "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "@eslint-community/regexpp": "^4.12.2",
- "@typescript-eslint/scope-manager": "8.66.0",
- "@typescript-eslint/type-utils": "8.66.0",
- "@typescript-eslint/utils": "8.66.0",
- "@typescript-eslint/visitor-keys": "8.66.0",
- "ignore": "^7.0.5",
- "natural-compare": "^1.4.0",
- "ts-api-utils": "^2.5.0"
+ "bin": {
+ "acorn": "bin/acorn"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "@typescript-eslint/parser": "^8.66.0",
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.1.0"
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
- "node_modules/@typescript-eslint/parser": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.66.0.tgz",
- "integrity": "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==",
- "dev": true,
+ "node_modules/agent-base": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
"license": "MIT",
- "dependencies": {
- "@typescript-eslint/scope-manager": "8.66.0",
- "@typescript-eslint/types": "8.66.0",
- "@typescript-eslint/typescript-estree": "8.66.0",
- "@typescript-eslint/visitor-keys": "8.66.0",
- "debug": "^4.4.3"
- },
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.1.0"
+ "node": ">= 14"
}
},
- "node_modules/@typescript-eslint/project-service": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.66.0.tgz",
- "integrity": "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==",
+ "node_modules/ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.66.0",
- "@typescript-eslint/types": "^8.66.0",
- "debug": "^4.4.3"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.1.0"
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.66.0.tgz",
- "integrity": "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g==",
- "dev": true,
+ "node_modules/ajv-formats": {
+ "version": "3.0.1",
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.66.0",
- "@typescript-eslint/visitor-keys": "8.66.0"
+ "ajv": "^8.0.0"
},
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "peerDependencies": {
+ "ajv": "^8.0.0"
},
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
}
},
- "node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.66.0.tgz",
- "integrity": "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==",
- "dev": true,
+ "node_modules/ajv-formats/node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.1.0"
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/@typescript-eslint/type-utils": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.66.0.tgz",
- "integrity": "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==",
- "dev": true,
+ "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "license": "MIT"
+ },
+ "node_modules/ansi-escapes": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz",
+ "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==",
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.66.0",
- "@typescript-eslint/typescript-estree": "8.66.0",
- "@typescript-eslint/utils": "8.66.0",
- "debug": "^4.4.3",
- "ts-api-utils": "^2.5.0"
+ "environment": "^1.0.0"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">=18"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.1.0"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@typescript-eslint/types": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.66.0.tgz",
- "integrity": "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==",
- "dev": true,
+ "node_modules/ansi-regex": {
+ "version": "6.2.2",
"license": "MIT",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">=12"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.66.0.tgz",
- "integrity": "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==",
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/project-service": "8.66.0",
- "@typescript-eslint/tsconfig-utils": "8.66.0",
- "@typescript-eslint/types": "8.66.0",
- "@typescript-eslint/visitor-keys": "8.66.0",
- "debug": "^4.4.3",
- "minimatch": "^10.2.2",
- "semver": "^7.7.3",
- "tinyglobby": "^0.2.15",
- "ts-api-utils": "^2.5.0"
+ "color-convert": "^2.0.1"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">=8"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.1.0"
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/@typescript-eslint/utils": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.66.0.tgz",
- "integrity": "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==",
+ "node_modules/any-promise": {
+ "version": "1.3.0",
"dev": true,
- "license": "MIT",
+ "license": "MIT"
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "license": "ISC",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.9.1",
- "@typescript-eslint/scope-manager": "8.66.0",
- "@typescript-eslint/types": "8.66.0",
- "@typescript-eslint/typescript-estree": "8.66.0"
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">= 8"
+ }
+ },
+ "node_modules/anymatch/node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.1.0"
+ "url": "https://github.com/sponsors/jonschlinkert"
}
},
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.66.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.66.0.tgz",
- "integrity": "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==",
+ "node_modules/append-field": {
+ "version": "1.0.0",
+ "license": "MIT"
+ },
+ "node_modules/arg": {
+ "version": "5.0.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "dequal": "^2.0.3"
+ }
+ },
+ "node_modules/asn1.js": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+ "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.66.0",
- "eslint-visitor-keys": "^5.0.0"
- },
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+ "dev": true,
+ "license": "MIT",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "node": ">=12"
+ }
+ },
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "engines": {
+ "node": ">= 4.0.0"
}
},
- "node_modules/@ungap/structured-clone": {
- "version": "1.3.0",
- "license": "ISC"
+ "node_modules/atomic-sleep": {
+ "version": "1.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
},
- "node_modules/@vitejs/plugin-react": {
- "version": "4.7.0",
+ "node_modules/author-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/author-regex/-/author-regex-1.0.0.tgz",
+ "integrity": "sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "@babel/core": "^7.28.0",
- "@babel/plugin-transform-react-jsx-self": "^7.27.1",
- "@babel/plugin-transform-react-jsx-source": "^7.27.1",
- "@rolldown/pluginutils": "1.0.0-beta.27",
- "@types/babel__core": "^7.20.5",
- "react-refresh": "^0.17.0"
- },
+ "optional": true,
"engines": {
- "node": "^14.18.0 || >=16.0.0"
- },
- "peerDependencies": {
- "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ "node": ">=0.8"
}
},
- "node_modules/@vitest/expect": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz",
- "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==",
- "dev": true,
+ "node_modules/auto-bind": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz",
+ "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==",
"license": "MIT",
- "dependencies": {
- "@standard-schema/spec": "^1.1.0",
- "@types/chai": "^5.2.2",
- "@vitest/spy": "4.1.4",
- "@vitest/utils": "4.1.4",
- "chai": "^6.2.2",
- "tinyrainbow": "^3.1.0"
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
- "url": "https://opencollective.com/vitest"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@vitest/mocker": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz",
- "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==",
+ "node_modules/autoprefixer": {
+ "version": "10.4.23",
"dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
"license": "MIT",
"dependencies": {
- "@vitest/spy": "4.1.4",
- "estree-walker": "^3.0.3",
- "magic-string": "^0.30.21"
+ "browserslist": "^4.28.1",
+ "caniuse-lite": "^1.0.30001760",
+ "fraction.js": "^5.3.4",
+ "picocolors": "^1.1.1",
+ "postcss-value-parser": "^4.2.0"
},
- "funding": {
- "url": "https://opencollective.com/vitest"
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
},
- "peerDependencies": {
- "msw": "^2.4.9",
- "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ "engines": {
+ "node": "^10 || ^12 || >=14"
},
- "peerDependenciesMeta": {
- "msw": {
- "optional": true
- },
- "vite": {
- "optional": true
- }
+ "peerDependencies": {
+ "postcss": "^8.1.0"
}
},
- "node_modules/@vitest/pretty-format": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz",
- "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==",
- "dev": true,
+ "node_modules/bail": {
+ "version": "2.0.2",
"license": "MIT",
- "dependencies": {
- "tinyrainbow": "^3.1.0"
- },
"funding": {
- "url": "https://opencollective.com/vitest"
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/@vitest/runner": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz",
- "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==",
- "dev": true,
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"license": "MIT",
- "dependencies": {
- "@vitest/utils": "4.1.4",
- "pathe": "^2.0.3"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
+ "engines": {
+ "node": "18 || 20 || >=22"
}
},
- "node_modules/@vitest/snapshot": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz",
- "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==",
- "dev": true,
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/base64id": {
+ "version": "2.0.0",
"license": "MIT",
- "dependencies": {
- "@vitest/pretty-format": "4.1.4",
- "@vitest/utils": "4.1.4",
- "magic-string": "^0.30.21",
- "pathe": "^2.0.3"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
+ "engines": {
+ "node": "^4.5.0 || >= 5.9"
}
},
- "node_modules/@vitest/spy": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz",
- "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==",
- "dev": true,
+ "node_modules/base64url": {
+ "version": "3.0.1",
"license": "MIT",
- "funding": {
- "url": "https://opencollective.com/vitest"
+ "engines": {
+ "node": ">=6.0.0"
}
},
- "node_modules/@vitest/utils": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz",
- "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==",
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.9.7",
"dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.js"
+ }
+ },
+ "node_modules/before-after-hook": {
+ "version": "4.0.0",
+ "license": "Apache-2.0"
+ },
+ "node_modules/better-sqlite3": {
+ "version": "11.10.0",
+ "hasInstallScript": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "4.1.4",
- "convert-source-map": "^2.0.0",
- "tinyrainbow": "^3.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
+ "bindings": "^1.5.0",
+ "prebuild-install": "^7.1.1"
}
},
- "node_modules/accepts": {
- "version": "1.3.8",
+ "node_modules/bidi-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
+ "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "mime-types": "~2.1.34",
- "negotiator": "0.6.3"
- },
- "engines": {
- "node": ">= 0.6"
+ "require-from-string": "^2.0.2"
}
},
- "node_modules/acorn": {
- "version": "8.18.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz",
- "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==",
- "dev": true,
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
"license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
"engines": {
- "node": ">=0.4.0"
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
+ "node_modules/bindings": {
+ "version": "1.5.0",
"license": "MIT",
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ "dependencies": {
+ "file-uri-to-path": "1.0.0"
}
},
- "node_modules/agent-base": {
- "version": "7.1.4",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
- "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+ "node_modules/bl": {
+ "version": "4.1.0",
"license": "MIT",
- "engines": {
- "node": ">= 14"
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
}
},
- "node_modules/ajv": {
- "version": "6.15.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
- "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
- "dev": true,
+ "node_modules/bn.js": {
+ "version": "4.12.5",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz",
+ "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==",
+ "license": "MIT"
+ },
+ "node_modules/body-parser": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz",
+ "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==",
"license": "MIT",
"dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
+ "bytes": "^3.1.2",
+ "content-type": "^2.0.0",
+ "debug": "^4.4.3",
+ "http-errors": "^2.0.1",
+ "iconv-lite": "^0.7.2",
+ "on-finished": "^2.4.1",
+ "qs": "^6.15.2",
+ "raw-body": "^3.0.2",
+ "type-is": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18"
},
"funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
- "node_modules/ajv-formats": {
- "version": "3.0.1",
+ "node_modules/body-parser/node_modules/content-type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
+ "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
"license": "MIT",
- "dependencies": {
- "ajv": "^8.0.0"
- },
- "peerDependencies": {
- "ajv": "^8.0.0"
+ "engines": {
+ "node": ">=18"
},
- "peerDependenciesMeta": {
- "ajv": {
- "optional": true
- }
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
- "node_modules/ajv-formats/node_modules/ajv": {
- "version": "8.20.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
- "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "node_modules/body-parser/node_modules/media-typer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz",
+ "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==",
"license": "MIT",
- "dependencies": {
- "fast-deep-equal": "^3.1.3",
- "fast-uri": "^3.0.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2"
+ "engines": {
+ "node": ">= 0.8"
},
"funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
- "node_modules/ajv-formats/node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "license": "MIT"
+ "node_modules/body-parser/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
},
- "node_modules/ansi-escapes": {
- "version": "7.3.0",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz",
- "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==",
+ "node_modules/body-parser/node_modules/mime-types": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
+ "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
"license": "MIT",
"dependencies": {
- "environment": "^1.0.0"
+ "mime-db": "^1.54.0"
},
"engines": {
"node": ">=18"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
- "node_modules/ansi-regex": {
- "version": "6.2.2",
+ "node_modules/body-parser/node_modules/type-is": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz",
+ "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==",
"license": "MIT",
+ "dependencies": {
+ "content-type": "^2.0.0",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
"engines": {
- "node": ">=12"
+ "node": ">= 18"
},
"funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "node_modules/boolbase": {
+ "version": "1.0.0",
"dev": true,
+ "license": "ISC"
+ },
+ "node_modules/boundary": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz",
+ "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/brace-expansion": {
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
+ "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
"license": "MIT",
"dependencies": {
- "color-convert": "^2.0.1"
+ "balanced-match": "^4.0.2"
},
"engines": {
- "node": ">=8"
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
},
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ "engines": {
+ "node": ">=8"
}
},
- "node_modules/any-promise": {
- "version": "1.3.0",
+ "node_modules/browserslist": {
+ "version": "4.28.1",
"dev": true,
- "license": "MIT"
- },
- "node_modules/anymatch": {
- "version": "3.1.3",
- "license": "ISC",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
"dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
+ "baseline-browser-mapping": "^2.9.0",
+ "caniuse-lite": "^1.0.30001759",
+ "electron-to-chromium": "^1.5.263",
+ "node-releases": "^2.0.27",
+ "update-browserslist-db": "^1.2.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
},
"engines": {
- "node": ">= 8"
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
- "node_modules/anymatch/node_modules/picomatch": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
- "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
"license": "MIT",
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
}
},
- "node_modules/append-field": {
- "version": "1.0.0",
- "license": "MIT"
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "license": "BSD-3-Clause"
},
- "node_modules/arg": {
- "version": "5.0.2",
- "dev": true,
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
"license": "MIT"
},
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true,
- "license": "Python-2.0"
+ "node_modules/bullmq": {
+ "version": "5.81.3",
+ "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.81.3.tgz",
+ "integrity": "sha512-Q7uEH2G92rVjX3Yl2qw3+6VEO15uxehC6DfeTHQBQTehddcRDSDuquD9zuvDjxiCffXsPUaBwrRlvlbVcgKs7g==",
+ "license": "MIT",
+ "dependencies": {
+ "cron-parser": "4.9.0",
+ "ioredis": "5.11.1",
+ "msgpackr": "2.0.5",
+ "node-abort-controller": "3.1.1",
+ "semver": "7.8.5",
+ "tslib": "2.8.1"
+ },
+ "engines": {
+ "node": ">=12.22.0"
+ },
+ "peerDependencies": {
+ "redis": ">=5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "redis": {
+ "optional": true
+ }
+ }
},
- "node_modules/aria-query": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
- "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
- "dev": true,
- "license": "Apache-2.0",
+ "node_modules/busboy": {
+ "version": "1.6.0",
"dependencies": {
- "dequal": "^2.0.3"
+ "streamsearch": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.16.0"
}
},
- "node_modules/asn1.js": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
- "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
"license": "MIT",
"dependencies": {
- "bn.js": "^4.0.0",
- "inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0",
- "safer-buffer": "^2.1.0"
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
}
},
- "node_modules/assertion-error": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
- "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
- "dev": true,
+ "node_modules/call-bound": {
+ "version": "1.0.4",
"license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
"engines": {
- "node": ">=12"
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/atomic-sleep": {
- "version": "1.0.0",
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
"license": "MIT",
"engines": {
- "node": ">=8.0.0"
+ "node": ">=6"
}
},
- "node_modules/auto-bind": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz",
- "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==",
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "dev": true,
"license": "MIT",
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">= 6"
}
},
- "node_modules/autoprefixer": {
- "version": "10.4.23",
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001760",
"dev": true,
"funding": [
{
"type": "opencollective",
- "url": "https://opencollective.com/postcss/"
+ "url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/ccount": {
+ "version": "2.0.1",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/chai": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
+ "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "browserslist": "^4.28.1",
- "caniuse-lite": "^1.0.30001760",
- "fraction.js": "^5.3.4",
- "picocolors": "^1.1.1",
- "postcss-value-parser": "^4.2.0"
- },
- "bin": {
- "autoprefixer": "bin/autoprefixer"
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
},
"engines": {
- "node": "^10 || ^12 || >=14"
+ "node": ">=10"
},
- "peerDependencies": {
- "postcss": "^8.1.0"
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
}
},
- "node_modules/bail": {
+ "node_modules/character-entities": {
"version": "2.0.2",
"license": "MIT",
"funding": {
@@ -3787,1196 +5000,1354 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/balanced-match": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
- "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "node_modules/character-entities-html4": {
+ "version": "2.1.0",
"license": "MIT",
- "engines": {
- "node": "18 || 20 || >=22"
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/base64-js": {
- "version": "1.5.1",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
- "node_modules/base64id": {
- "version": "2.0.0",
+ "node_modules/character-entities-legacy": {
+ "version": "3.0.0",
"license": "MIT",
- "engines": {
- "node": "^4.5.0 || >= 5.9"
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/base64url": {
- "version": "3.0.1",
+ "node_modules/character-reference-invalid": {
+ "version": "2.0.1",
"license": "MIT",
- "engines": {
- "node": ">=6.0.0"
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/baseline-browser-mapping": {
- "version": "2.9.7",
+ "node_modules/cheerio": {
+ "version": "1.1.2",
"dev": true,
- "license": "Apache-2.0",
- "bin": {
- "baseline-browser-mapping": "dist/cli.js"
- }
- },
- "node_modules/before-after-hook": {
- "version": "4.0.0",
- "license": "Apache-2.0"
- },
- "node_modules/better-sqlite3": {
- "version": "11.10.0",
- "hasInstallScript": true,
"license": "MIT",
"dependencies": {
- "bindings": "^1.5.0",
- "prebuild-install": "^7.1.1"
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.2.2",
+ "encoding-sniffer": "^0.2.1",
+ "htmlparser2": "^10.0.0",
+ "parse5": "^7.3.0",
+ "parse5-htmlparser2-tree-adapter": "^7.1.0",
+ "parse5-parser-stream": "^7.1.2",
+ "undici": "^7.12.0",
+ "whatwg-mimetype": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=20.18.1"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
}
},
- "node_modules/bidi-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
- "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
+ "node_modules/cheerio-select": {
+ "version": "2.1.0",
"dev": true,
- "license": "MIT",
+ "license": "BSD-2-Clause",
"dependencies": {
- "require-from-string": "^2.0.2"
+ "boolbase": "^1.0.0",
+ "css-select": "^5.1.0",
+ "css-what": "^6.1.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
}
},
- "node_modules/binary-extensions": {
- "version": "2.3.0",
+ "node_modules/chokidar": {
+ "version": "3.6.0",
"license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
"engines": {
- "node": ">=8"
+ "node": ">= 8.10.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
}
},
- "node_modules/bindings": {
- "version": "1.5.0",
- "license": "MIT",
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "license": "ISC",
"dependencies": {
- "file-uri-to-path": "1.0.0"
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
}
},
- "node_modules/bl": {
- "version": "4.1.0",
- "license": "MIT",
- "dependencies": {
- "buffer": "^5.5.0",
- "inherits": "^2.0.4",
- "readable-stream": "^3.4.0"
+ "node_modules/chownr": {
+ "version": "1.1.4",
+ "license": "ISC"
+ },
+ "node_modules/chrome-trace-event": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
+ "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0"
}
},
- "node_modules/bn.js": {
- "version": "4.12.5",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz",
- "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==",
- "license": "MIT"
- },
- "node_modules/body-parser": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz",
- "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==",
+ "node_modules/cli-boxes": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-4.0.1.tgz",
+ "integrity": "sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw==",
"license": "MIT",
- "dependencies": {
- "bytes": "^3.1.2",
- "content-type": "^2.0.0",
- "debug": "^4.4.3",
- "http-errors": "^2.0.1",
- "iconv-lite": "^0.7.2",
- "on-finished": "^2.4.1",
- "qs": "^6.15.2",
- "raw-body": "^3.0.2",
- "type-is": "^2.1.0"
- },
"engines": {
- "node": ">=18"
+ "node": ">=18.20 <19 || >=20.10"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/body-parser/node_modules/content-type": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
- "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
+ "node_modules/cli-cursor": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
+ "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
"license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^4.0.0"
+ },
"engines": {
- "node": ">=18"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/body-parser/node_modules/media-typer": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz",
- "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==",
+ "node_modules/cli-truncate": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-6.0.0.tgz",
+ "integrity": "sha512-3+YKIUFsohD9MIoOFPFBldjAlnfCmCDcqe6aYGFqlDTRKg80p4wg35L+j83QQ63iOlKRccEkbn8IuM++HsgEjA==",
"license": "MIT",
+ "dependencies": {
+ "slice-ansi": "^9.0.0",
+ "string-width": "^8.2.0"
+ },
"engines": {
- "node": ">= 0.8"
+ "node": ">=22"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/body-parser/node_modules/mime-db": {
- "version": "1.54.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
- "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "node_modules/cli-truncate/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"license": "MIT",
"engines": {
- "node": ">= 0.6"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/body-parser/node_modules/mime-types": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
- "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+ "node_modules/cli-truncate/node_modules/slice-ansi": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-9.0.0.tgz",
+ "integrity": "sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==",
"license": "MIT",
"dependencies": {
- "mime-db": "^1.54.0"
+ "ansi-styles": "^6.2.3",
+ "is-fullwidth-code-point": "^5.1.0"
},
"engines": {
- "node": ">=18"
+ "node": ">=22"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
- "node_modules/body-parser/node_modules/type-is": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz",
- "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==",
+ "node_modules/cli-truncate/node_modules/string-width": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz",
+ "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==",
"license": "MIT",
"dependencies": {
- "content-type": "^2.0.0",
- "media-typer": "^1.1.0",
- "mime-types": "^3.0.0"
+ "get-east-asian-width": "^1.5.0",
+ "strip-ansi": "^7.1.2"
},
"engines": {
- "node": ">= 18"
+ "node": ">=20"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/boolbase": {
- "version": "1.0.0",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/boundary": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz",
- "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==",
- "license": "BSD-2-Clause"
- },
- "node_modules/brace-expansion": {
- "version": "5.0.9",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
- "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
+ "node_modules/clsx": {
+ "version": "2.1.1",
"license": "MIT",
- "dependencies": {
- "balanced-match": "^4.0.2"
- },
"engines": {
- "node": "20 || >=22"
+ "node": ">=6"
}
},
- "node_modules/braces": {
- "version": "3.0.3",
+ "node_modules/cluster-key-slot": {
+ "version": "1.1.2",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/code-excerpt": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz",
+ "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==",
"license": "MIT",
"dependencies": {
- "fill-range": "^7.1.1"
+ "convert-to-spaces": "^2.0.1"
},
"engines": {
- "node": ">=8"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
- "node_modules/browserslist": {
- "version": "4.28.1",
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
"license": "MIT",
"dependencies": {
- "baseline-browser-mapping": "^2.9.0",
- "caniuse-lite": "^1.0.30001759",
- "electron-to-chromium": "^1.5.263",
- "node-releases": "^2.0.27",
- "update-browserslist-db": "^1.2.0"
- },
- "bin": {
- "browserslist": "cli.js"
+ "color-name": "~1.1.4"
},
"engines": {
- "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ "node": ">=7.0.0"
}
},
- "node_modules/buffer": {
- "version": "5.7.1",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/colorette": {
+ "version": "2.0.20",
+ "license": "MIT"
+ },
+ "node_modules/comma-separated-tokens": {
+ "version": "2.0.3",
"license": "MIT",
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/buffer-equal-constant-time": {
- "version": "1.0.1",
- "license": "BSD-3-Clause"
+ "node_modules/commander": {
+ "version": "10.0.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
},
- "node_modules/buffer-from": {
- "version": "1.1.2",
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
"license": "MIT"
},
- "node_modules/bullmq": {
- "version": "5.81.3",
- "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.81.3.tgz",
- "integrity": "sha512-Q7uEH2G92rVjX3Yl2qw3+6VEO15uxehC6DfeTHQBQTehddcRDSDuquD9zuvDjxiCffXsPUaBwrRlvlbVcgKs7g==",
+ "node_modules/concat-stream": {
+ "version": "2.0.0",
+ "engines": [
+ "node >= 6.0"
+ ],
"license": "MIT",
"dependencies": {
- "cron-parser": "4.9.0",
- "ioredis": "5.11.1",
- "msgpackr": "2.0.5",
- "node-abort-controller": "3.1.1",
- "semver": "7.8.5",
- "tslib": "2.8.1"
- },
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.0.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "node_modules/connect-redis": {
+ "version": "9.0.0",
+ "license": "MIT",
"engines": {
- "node": ">=12.22.0"
+ "node": ">=18"
},
"peerDependencies": {
- "redis": ">=5.0.0"
- },
- "peerDependenciesMeta": {
- "redis": {
- "optional": true
- }
+ "express-session": ">=1",
+ "redis": ">=5"
}
},
- "node_modules/busboy": {
- "version": "1.6.0",
- "dependencies": {
- "streamsearch": "^1.1.0"
+ "node_modules/content-disposition": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz",
+ "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
},
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "license": "MIT",
"engines": {
- "node": ">=10.16.0"
+ "node": ">= 0.6"
}
},
- "node_modules/bytes": {
- "version": "3.1.2",
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/convert-to-spaces": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz",
+ "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==",
"license": "MIT",
"engines": {
- "node": ">= 0.8"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
- "node_modules/call-bind-apply-helpers": {
- "version": "1.0.2",
+ "node_modules/cookie": {
+ "version": "0.7.2",
"license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2"
- },
"engines": {
- "node": ">= 0.4"
+ "node": ">= 0.6"
}
},
- "node_modules/call-bound": {
- "version": "1.0.4",
+ "node_modules/cookie-signature": {
+ "version": "1.0.7",
+ "license": "MIT"
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
"license": "MIT",
"dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "get-intrinsic": "^1.3.0"
+ "object-assign": "^4",
+ "vary": "^1"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">= 0.10"
}
},
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
+ "node_modules/cron-parser": {
+ "version": "4.9.0",
"license": "MIT",
+ "dependencies": {
+ "luxon": "^3.2.1"
+ },
"engines": {
- "node": ">=6"
+ "node": ">=12.0.0"
}
},
- "node_modules/camelcase-css": {
- "version": "2.0.1",
+ "node_modules/cross-dirname": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz",
+ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
"dev": true,
"license": "MIT",
+ "optional": true
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
"engines": {
- "node": ">= 6"
+ "node": ">= 8"
}
},
- "node_modules/caniuse-lite": {
- "version": "1.0.30001760",
+ "node_modules/cross-zip": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/cross-zip/-/cross-zip-4.0.1.tgz",
+ "integrity": "sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==",
"dev": true,
"funding": [
{
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
},
{
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
},
{
- "type": "github",
- "url": "https://github.com/sponsors/ai"
+ "type": "consulting",
+ "url": "https://feross.org/support"
}
],
- "license": "CC-BY-4.0"
- },
- "node_modules/ccount": {
- "version": "2.0.1",
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/chai": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
- "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
- "dev": true,
"license": "MIT",
"engines": {
- "node": ">=18"
+ "node": ">=12.10"
}
},
- "node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "node_modules/css-select": {
+ "version": "5.2.2",
"dev": true,
- "license": "MIT",
+ "license": "BSD-2-Clause",
"dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
},
"funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/character-entities": {
- "version": "2.0.2",
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/character-entities-html4": {
- "version": "2.1.0",
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/character-entities-legacy": {
- "version": "3.0.0",
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/character-reference-invalid": {
- "version": "2.0.1",
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
+ "url": "https://github.com/sponsors/fb55"
}
},
- "node_modules/cheerio": {
- "version": "1.1.2",
+ "node_modules/css-tree": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz",
+ "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "cheerio-select": "^2.1.0",
- "dom-serializer": "^2.0.0",
- "domhandler": "^5.0.3",
- "domutils": "^3.2.2",
- "encoding-sniffer": "^0.2.1",
- "htmlparser2": "^10.0.0",
- "parse5": "^7.3.0",
- "parse5-htmlparser2-tree-adapter": "^7.1.0",
- "parse5-parser-stream": "^7.1.2",
- "undici": "^7.12.0",
- "whatwg-mimetype": "^4.0.0"
+ "mdn-data": "2.27.1",
+ "source-map-js": "^1.2.1"
},
"engines": {
- "node": ">=20.18.1"
- },
- "funding": {
- "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
}
},
- "node_modules/cheerio-select": {
- "version": "2.1.0",
+ "node_modules/css-what": {
+ "version": "6.2.2",
"dev": true,
"license": "BSD-2-Clause",
- "dependencies": {
- "boolbase": "^1.0.0",
- "css-select": "^5.1.0",
- "css-what": "^6.1.0",
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.3",
- "domutils": "^3.0.1"
+ "engines": {
+ "node": ">= 6"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
- "node_modules/chokidar": {
- "version": "3.6.0",
+ "node_modules/css.escape": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
+ "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "dev": true,
"license": "MIT",
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
+ "bin": {
+ "cssesc": "bin/cssesc"
},
"engines": {
- "node": ">= 8.10.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
+ "node": ">=4"
}
},
- "node_modules/chokidar/node_modules/glob-parent": {
- "version": "5.1.2",
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "license": "MIT"
+ },
+ "node_modules/d3-array": {
+ "version": "3.2.4",
"license": "ISC",
"dependencies": {
- "is-glob": "^4.0.1"
+ "internmap": "1 - 2"
},
"engines": {
- "node": ">= 6"
+ "node": ">=12"
}
},
- "node_modules/chownr": {
- "version": "1.1.4",
- "license": "ISC"
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
},
- "node_modules/cli-boxes": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-4.0.1.tgz",
- "integrity": "sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw==",
- "license": "MIT",
+ "node_modules/d3-ease": {
+ "version": "3.0.1",
+ "license": "BSD-3-Clause",
"engines": {
- "node": ">=18.20 <19 || >=20.10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">=12"
}
},
- "node_modules/cli-truncate": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-6.0.0.tgz",
- "integrity": "sha512-3+YKIUFsohD9MIoOFPFBldjAlnfCmCDcqe6aYGFqlDTRKg80p4wg35L+j83QQ63iOlKRccEkbn8IuM++HsgEjA==",
- "license": "MIT",
+ "node_modules/d3-format": {
+ "version": "3.1.0",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "license": "ISC",
"dependencies": {
- "slice-ansi": "^9.0.0",
- "string-width": "^8.2.0"
+ "d3-color": "1 - 3"
},
"engines": {
- "node": ">=22"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">=12"
}
},
- "node_modules/cli-truncate/node_modules/ansi-styles": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
- "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
- "license": "MIT",
+ "node_modules/d3-path": {
+ "version": "3.1.0",
+ "license": "ISC",
"engines": {
"node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/cli-truncate/node_modules/slice-ansi": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-9.0.0.tgz",
- "integrity": "sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==",
- "license": "MIT",
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "license": "ISC",
"dependencies": {
- "ansi-styles": "^6.2.3",
- "is-fullwidth-code-point": "^5.1.0"
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
},
"engines": {
- "node": ">=22"
- },
- "funding": {
- "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ "node": ">=12"
}
},
- "node_modules/cli-truncate/node_modules/string-width": {
- "version": "8.2.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz",
- "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==",
- "license": "MIT",
+ "node_modules/d3-shape": {
+ "version": "3.2.0",
+ "license": "ISC",
"dependencies": {
- "get-east-asian-width": "^1.5.0",
- "strip-ansi": "^7.1.2"
+ "d3-path": "^3.1.0"
},
"engines": {
- "node": ">=20"
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2 - 3"
},
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "engines": {
+ "node": ">=12"
}
},
- "node_modules/clsx": {
- "version": "2.1.1",
- "license": "MIT",
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "license": "ISC",
+ "dependencies": {
+ "d3-time": "1 - 3"
+ },
"engines": {
- "node": ">=6"
+ "node": ">=12"
}
},
- "node_modules/cluster-key-slot": {
- "version": "1.1.2",
- "license": "Apache-2.0",
+ "node_modules/d3-timer": {
+ "version": "3.0.1",
+ "license": "ISC",
"engines": {
- "node": ">=0.10.0"
+ "node": ">=12"
}
},
- "node_modules/code-excerpt": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz",
- "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==",
+ "node_modules/data-uri-to-buffer": {
+ "version": "4.0.1",
"license": "MIT",
- "dependencies": {
- "convert-to-spaces": "^2.0.1"
- },
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">= 12"
}
},
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "node_modules/data-urls": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz",
+ "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "color-name": "~1.1.4"
+ "whatwg-mimetype": "^5.0.0",
+ "whatwg-url": "^16.0.0"
},
"engines": {
- "node": ">=7.0.0"
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
}
},
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "node_modules/data-urls/node_modules/whatwg-mimetype": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz",
+ "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==",
"dev": true,
- "license": "MIT"
- },
- "node_modules/colorette": {
- "version": "2.0.20",
- "license": "MIT"
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
},
- "node_modules/comma-separated-tokens": {
- "version": "2.0.3",
+ "node_modules/dateformat": {
+ "version": "4.6.3",
"license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
+ "engines": {
+ "node": "*"
}
},
- "node_modules/commander": {
- "version": "10.0.1",
+ "node_modules/debug": {
+ "version": "4.4.3",
"license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
"engines": {
- "node": ">=14"
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
}
},
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "node_modules/decimal.js": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
+ "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
"dev": true,
"license": "MIT"
},
- "node_modules/concat-stream": {
- "version": "2.0.0",
- "engines": [
- "node >= 6.0"
- ],
- "license": "MIT",
- "dependencies": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^3.0.2",
- "typedarray": "^0.0.6"
- }
+ "node_modules/decimal.js-light": {
+ "version": "2.5.1",
+ "license": "MIT"
},
- "node_modules/connect-redis": {
- "version": "9.0.0",
+ "node_modules/decode-named-character-reference": {
+ "version": "1.2.0",
"license": "MIT",
- "engines": {
- "node": ">=18"
+ "dependencies": {
+ "character-entities": "^2.0.0"
},
- "peerDependencies": {
- "express-session": ">=1",
- "redis": ">=5"
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/content-disposition": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz",
- "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==",
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
"license": "MIT",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
"engines": {
- "node": ">=18"
+ "node": ">=10"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/content-type": {
- "version": "1.0.5",
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
"license": "MIT",
"engines": {
- "node": ">= 0.6"
+ "node": ">=4.0.0"
}
},
- "node_modules/convert-source-map": {
- "version": "2.0.0",
+ "node_modules/deep-is": {
+ "version": "0.1.4",
"dev": true,
"license": "MIT"
},
- "node_modules/convert-to-spaces": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz",
- "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==",
- "license": "MIT",
+ "node_modules/denque": {
+ "version": "2.1.0",
+ "license": "Apache-2.0",
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=0.10"
}
},
- "node_modules/cookie": {
- "version": "0.7.2",
+ "node_modules/depd": {
+ "version": "2.0.0",
"license": "MIT",
"engines": {
- "node": ">= 0.6"
+ "node": ">= 0.8"
}
},
- "node_modules/cookie-signature": {
- "version": "1.0.7",
- "license": "MIT"
- },
- "node_modules/cors": {
- "version": "2.8.5",
+ "node_modules/dequal": {
+ "version": "2.0.3",
"license": "MIT",
- "dependencies": {
- "object-assign": "^4",
- "vary": "^1"
- },
"engines": {
- "node": ">= 0.10"
+ "node": ">=6"
}
},
- "node_modules/cron-parser": {
- "version": "4.9.0",
- "license": "MIT",
- "dependencies": {
- "luxon": "^3.2.1"
- },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "license": "Apache-2.0",
"engines": {
- "node": ">=12.0.0"
+ "node": ">=8"
}
},
- "node_modules/cross-spawn": {
- "version": "7.0.6",
+ "node_modules/devlop": {
+ "version": "1.1.0",
"license": "MIT",
"dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
+ "dequal": "^2.0.0"
},
- "engines": {
- "node": ">= 8"
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/css-select": {
- "version": "5.2.2",
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
"dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "boolbase": "^1.0.0",
- "css-what": "^6.1.0",
- "domhandler": "^5.0.2",
- "domutils": "^3.0.1",
- "nth-check": "^2.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/fb55"
- }
+ "license": "Apache-2.0"
},
- "node_modules/css-tree": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz",
- "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/dom-accessibility-api": {
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
+ "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "mdn-data": "2.27.1",
- "source-map-js": "^1.2.1"
- },
- "engines": {
- "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
- }
+ "peer": true
},
- "node_modules/css-what": {
- "version": "6.2.2",
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
"dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">= 6"
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
},
"funding": {
- "url": "https://github.com/sponsors/fb55"
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
- "node_modules/css.escape": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
- "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
"dev": true,
- "license": "MIT"
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
},
- "node_modules/cssesc": {
- "version": "3.0.0",
+ "node_modules/domhandler": {
+ "version": "5.0.3",
"dev": true,
- "license": "MIT",
- "bin": {
- "cssesc": "bin/cssesc"
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
},
"engines": {
- "node": ">=4"
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
- "node_modules/csstype": {
- "version": "3.2.3",
- "license": "MIT"
- },
- "node_modules/d3-array": {
- "version": "3.2.4",
- "license": "ISC",
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "internmap": "1 - 2"
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
},
- "engines": {
- "node": ">=12"
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
}
},
- "node_modules/d3-color": {
- "version": "3.1.0",
- "license": "ISC",
+ "node_modules/dotenv": {
+ "version": "16.5.0",
+ "license": "BSD-2-Clause",
"engines": {
"node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
}
},
- "node_modules/d3-ease": {
- "version": "3.0.1",
- "license": "BSD-3-Clause",
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
"engines": {
- "node": ">=12"
+ "node": ">= 0.4"
}
},
- "node_modules/d3-format": {
- "version": "3.1.0",
- "license": "ISC",
- "engines": {
- "node": ">=12"
- }
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "dev": true,
+ "license": "MIT"
},
- "node_modules/d3-interpolate": {
- "version": "3.0.1",
- "license": "ISC",
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "license": "Apache-2.0",
"dependencies": {
- "d3-color": "1 - 3"
- },
- "engines": {
- "node": ">=12"
+ "safe-buffer": "^5.0.1"
}
},
- "node_modules/d3-path": {
- "version": "3.1.0",
- "license": "ISC",
- "engines": {
- "node": ">=12"
- }
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "license": "MIT"
},
- "node_modules/d3-scale": {
- "version": "4.0.2",
- "license": "ISC",
+ "node_modules/electron": {
+ "version": "44.0.0",
+ "resolved": "https://registry.npmjs.org/electron/-/electron-44.0.0.tgz",
+ "integrity": "sha512-FkTqPrFPZYljdPI5b7KORGsJTd6FgUQDefl5MrU3Xz9R87pAj9JLreIjDqcRN8hJIkFHIou0o8kKzvcpT9qiRQ==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "d3-array": "2.10.0 - 3",
- "d3-format": "1 - 3",
- "d3-interpolate": "1.2.0 - 3",
- "d3-time": "2.1.1 - 3",
- "d3-time-format": "2 - 4"
+ "@electron-internal/extract-zip": "^1.0.1",
+ "@electron/get": "^5.0.0",
+ "@types/node": "^24.9.0"
+ },
+ "bin": {
+ "electron": "cli.js",
+ "install-electron": "install.js"
},
"engines": {
- "node": ">=12"
+ "node": ">= 22.12.0"
}
},
- "node_modules/d3-shape": {
- "version": "3.2.0",
- "license": "ISC",
+ "node_modules/electron-installer-common": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/electron-installer-common/-/electron-installer-common-0.10.4.tgz",
+ "integrity": "sha512-8gMNPXfAqUE5CfXg8RL0vXpLE9HAaPkgLXVoHE3BMUzogMWenf4LmwQ27BdCUrEhkjrKl+igs2IHJibclR3z3Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
"dependencies": {
- "d3-path": "^3.1.0"
+ "@electron/asar": "^3.2.5",
+ "@malept/cross-spawn-promise": "^1.0.0",
+ "debug": "^4.1.1",
+ "fs-extra": "^9.0.0",
+ "glob": "^7.1.4",
+ "lodash": "^4.17.15",
+ "parse-author": "^2.0.0",
+ "semver": "^7.1.1",
+ "tmp-promise": "^3.0.2"
},
"engines": {
- "node": ">=12"
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/electron-userland/electron-installer-common?sponsor=1"
+ },
+ "optionalDependencies": {
+ "@types/fs-extra": "^9.0.1"
}
},
- "node_modules/d3-time": {
- "version": "3.1.0",
- "license": "ISC",
+ "node_modules/electron-installer-common/node_modules/@malept/cross-spawn-promise": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
+ "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/malept"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund"
+ }
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
"dependencies": {
- "d3-array": "2 - 3"
+ "cross-spawn": "^7.0.1"
},
"engines": {
- "node": ">=12"
+ "node": ">= 10"
}
},
- "node_modules/d3-time-format": {
- "version": "4.1.0",
- "license": "ISC",
+ "node_modules/electron-installer-common/node_modules/@types/fs-extra": {
+ "version": "9.0.13",
+ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
+ "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
"dependencies": {
- "d3-time": "1 - 3"
- },
- "engines": {
- "node": ">=12"
+ "@types/node": "*"
}
},
- "node_modules/d3-timer": {
- "version": "3.0.1",
- "license": "ISC",
+ "node_modules/electron-installer-common/node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
"engines": {
- "node": ">=12"
+ "node": ">=10"
}
},
- "node_modules/data-uri-to-buffer": {
- "version": "4.0.1",
+ "node_modules/electron-installer-debian": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/electron-installer-debian/-/electron-installer-debian-3.2.0.tgz",
+ "integrity": "sha512-58ZrlJ1HQY80VucsEIG9tQ//HrTlG6sfofA3nRGr6TmkX661uJyu4cMPPh6kXW+aHdq/7+q25KyQhDrXvRL7jw==",
+ "dev": true,
"license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin",
+ "linux"
+ ],
+ "dependencies": {
+ "@malept/cross-spawn-promise": "^1.0.0",
+ "debug": "^4.1.1",
+ "electron-installer-common": "^0.10.2",
+ "fs-extra": "^9.0.0",
+ "get-folder-size": "^2.0.1",
+ "lodash": "^4.17.4",
+ "word-wrap": "^1.2.3",
+ "yargs": "^16.0.2"
+ },
+ "bin": {
+ "electron-installer-debian": "src/cli.js"
+ },
"engines": {
- "node": ">= 12"
+ "node": ">= 10.0.0"
}
},
- "node_modules/data-urls": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz",
- "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==",
+ "node_modules/electron-installer-debian/node_modules/@malept/cross-spawn-promise": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
+ "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==",
"dev": true,
- "license": "MIT",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/malept"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund"
+ }
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
"dependencies": {
- "whatwg-mimetype": "^5.0.0",
- "whatwg-url": "^16.0.0"
+ "cross-spawn": "^7.0.1"
},
"engines": {
- "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ "node": ">= 10"
}
},
- "node_modules/data-urls/node_modules/whatwg-mimetype": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz",
- "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==",
+ "node_modules/electron-installer-debian/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT",
+ "optional": true,
"engines": {
- "node": ">=20"
+ "node": ">=8"
}
},
- "node_modules/dateformat": {
- "version": "4.6.3",
- "license": "MIT",
- "engines": {
- "node": "*"
+ "node_modules/electron-installer-debian/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
}
},
- "node_modules/debug": {
- "version": "4.4.3",
+ "node_modules/electron-installer-debian/node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
"license": "MIT",
+ "optional": true,
"dependencies": {
- "ms": "^2.1.3"
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
},
"engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
+ "node": ">=10"
}
},
- "node_modules/decimal.js": {
- "version": "10.6.0",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
- "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
+ "node_modules/electron-installer-debian/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
- "license": "MIT"
- },
- "node_modules/decimal.js-light": {
- "version": "2.5.1",
- "license": "MIT"
- },
- "node_modules/decode-named-character-reference": {
- "version": "1.2.0",
"license": "MIT",
+ "optional": true,
"dependencies": {
- "character-entities": "^2.0.0"
+ "ansi-regex": "^5.0.1"
},
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
+ "engines": {
+ "node": ">=8"
}
},
- "node_modules/decompress-response": {
- "version": "6.0.0",
+ "node_modules/electron-installer-debian/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
"license": "MIT",
+ "optional": true,
"dependencies": {
- "mimic-response": "^3.1.0"
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/deep-extend": {
- "version": "0.6.0",
+ "node_modules/electron-installer-debian/node_modules/yargs": {
+ "version": "16.2.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz",
+ "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==",
+ "dev": true,
"license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
"engines": {
- "node": ">=4.0.0"
+ "node": ">=10"
}
},
- "node_modules/deep-is": {
- "version": "0.1.4",
+ "node_modules/electron-installer-debian/node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
- "license": "MIT"
- },
- "node_modules/denque": {
- "version": "2.1.0",
- "license": "Apache-2.0",
+ "license": "ISC",
+ "optional": true,
"engines": {
- "node": ">=0.10"
+ "node": ">=10"
}
},
- "node_modules/depd": {
- "version": "2.0.0",
+ "node_modules/electron-installer-redhat": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/electron-installer-redhat/-/electron-installer-redhat-3.4.0.tgz",
+ "integrity": "sha512-gEISr3U32Sgtj+fjxUAlSDo3wyGGq6OBx7rF5UdpIgbnpUvMN4W5uYb0ThpnAZ42VEJh/3aODQXHbFS4f5J3Iw==",
+ "dev": true,
"license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin",
+ "linux"
+ ],
+ "dependencies": {
+ "@malept/cross-spawn-promise": "^1.0.0",
+ "debug": "^4.1.1",
+ "electron-installer-common": "^0.10.2",
+ "fs-extra": "^9.0.0",
+ "lodash": "^4.17.15",
+ "word-wrap": "^1.2.3",
+ "yargs": "^16.0.2"
+ },
+ "bin": {
+ "electron-installer-redhat": "src/cli.js"
+ },
"engines": {
- "node": ">= 0.8"
+ "node": ">= 10.0.0"
}
},
- "node_modules/dequal": {
- "version": "2.0.3",
- "license": "MIT",
+ "node_modules/electron-installer-redhat/node_modules/@malept/cross-spawn-promise": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
+ "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/malept"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund"
+ }
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.1"
+ },
"engines": {
- "node": ">=6"
+ "node": ">= 10"
}
},
- "node_modules/detect-libc": {
- "version": "2.1.2",
- "license": "Apache-2.0",
+ "node_modules/electron-installer-redhat/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
"engines": {
"node": ">=8"
}
},
- "node_modules/devlop": {
- "version": "1.1.0",
- "license": "MIT",
+ "node_modules/electron-installer-redhat/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
"dependencies": {
- "dequal": "^2.0.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
}
},
- "node_modules/didyoumean": {
- "version": "1.2.2",
+ "node_modules/electron-installer-redhat/node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dev": true,
- "license": "Apache-2.0"
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
},
- "node_modules/dlv": {
- "version": "1.1.3",
+ "node_modules/electron-installer-redhat/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
},
- "node_modules/dom-accessibility-api": {
- "version": "0.5.16",
- "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
- "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
+ "node_modules/electron-installer-redhat/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"license": "MIT",
- "peer": true
+ "optional": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
},
- "node_modules/dom-serializer": {
- "version": "2.0.0",
+ "node_modules/electron-installer-redhat/node_modules/yargs": {
+ "version": "16.2.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz",
+ "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==",
"dev": true,
"license": "MIT",
+ "optional": true,
"dependencies": {
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.2",
- "entities": "^4.2.0"
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
},
- "funding": {
- "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ "engines": {
+ "node": ">=10"
}
},
- "node_modules/domelementtype": {
- "version": "2.3.0",
+ "node_modules/electron-installer-redhat/node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/fb55"
- }
- ],
- "license": "BSD-2-Clause"
+ "license": "ISC",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ }
},
- "node_modules/domhandler": {
- "version": "5.0.3",
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.267",
"dev": true,
- "license": "BSD-2-Clause",
+ "license": "ISC"
+ },
+ "node_modules/electron-winstaller": {
+ "version": "5.4.4",
+ "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.4.tgz",
+ "integrity": "sha512-j9ETcBGJaXxAY/b6UBpR7LZfjdU4BAO+yvr4ifqHEdyuc3UNCy91PDGkWKY5UQ4coHNYfnwFggrqD6QPeFGAlg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
"dependencies": {
- "domelementtype": "^2.3.0"
+ "@electron/asar": "^3.2.1",
+ "debug": "^4.1.1",
+ "fs-extra": "^7.0.1",
+ "lodash": "^4.17.21",
+ "semver": "^7.6.3",
+ "temp": "^0.9.0"
},
"engines": {
- "node": ">= 4"
+ "node": ">=8.0.0"
},
- "funding": {
- "url": "https://github.com/fb55/domhandler?sponsor=1"
+ "optionalDependencies": {
+ "@electron/windows-sign": "^1.1.2"
}
},
- "node_modules/domutils": {
- "version": "3.2.2",
+ "node_modules/electron-winstaller/node_modules/fs-extra": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
"dev": true,
- "license": "BSD-2-Clause",
+ "license": "MIT",
+ "optional": true,
"dependencies": {
- "dom-serializer": "^2.0.0",
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.3"
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
},
- "funding": {
- "url": "https://github.com/fb55/domutils?sponsor=1"
+ "engines": {
+ "node": ">=6 <7 || >=8"
}
},
- "node_modules/dotenv": {
- "version": "16.5.0",
- "license": "BSD-2-Clause",
+ "node_modules/electron-winstaller/node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/electron-winstaller/node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
"engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://dotenvx.com"
+ "node": ">= 4.0.0"
}
},
- "node_modules/dunder-proto": {
- "version": "1.0.1",
+ "node_modules/electron/node_modules/@electron/get": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.1.0.tgz",
+ "integrity": "sha512-3kSBtG8ObcTVfXanm5vVJ6UnBLEVmVsRk1M+vGqCuMBV+XLCbJYuWQful+yIy0GQDsSlK0kHEriEHn7SPk4EnA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
+ "debug": "^4.1.1",
+ "env-paths": "^3.0.0",
+ "graceful-fs": "^4.2.11",
+ "progress": "^2.0.3",
+ "semver": "^7.6.3",
+ "sumchecker": "^3.0.1"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=22.12.0"
+ },
+ "optionalDependencies": {
+ "undici": "^7.24.4"
}
},
- "node_modules/ecdsa-sig-formatter": {
- "version": "1.0.11",
- "license": "Apache-2.0",
+ "node_modules/electron/node_modules/@types/node": {
+ "version": "24.13.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
+ "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "safe-buffer": "^5.0.1"
+ "undici-types": "~7.18.0"
}
},
- "node_modules/ee-first": {
- "version": "1.1.1",
+ "node_modules/electron/node_modules/env-paths": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
+ "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/electron/node_modules/undici-types": {
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
+ "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
+ "dev": true,
"license": "MIT"
},
- "node_modules/electron-to-chromium": {
- "version": "1.5.267",
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
- "license": "ISC"
+ "license": "MIT",
+ "optional": true
},
"node_modules/encodeurl": {
"version": "2.0.0",
@@ -5067,6 +6438,16 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/environment": {
"version": "1.1.0",
"license": "MIT",
@@ -5077,6 +6458,13 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/err-code": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+ "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/es-define-property": {
"version": "1.0.1",
"license": "MIT",
@@ -5092,9 +6480,9 @@
}
},
"node_modules/es-module-lexer": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
- "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz",
+ "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==",
"dev": true,
"license": "MIT"
},
@@ -5937,6 +7325,13 @@
"node": ">=12.0.0"
}
},
+ "node_modules/exponential-backoff": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz",
+ "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"node_modules/express": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
@@ -6472,6 +7867,14 @@
"node": ">=14.14"
}
},
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -6493,6 +7896,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/gar": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/gar/-/gar-1.0.4.tgz",
+ "integrity": "sha512-w4n9cPWyP7aHxKxYHFQMegj7WIAsL/YX/C4Bs5Rr8s1H9M1rNtRWRsw+ovYMkXDQ5S4ZbYHsHAPmevPjPgw44w==",
+ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"dev": true,
@@ -6501,6 +7913,17 @@
"node": ">=6.9.0"
}
},
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
"node_modules/get-east-asian-width": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
@@ -6513,6 +7936,21 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/get-folder-size": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/get-folder-size/-/get-folder-size-2.0.1.tgz",
+ "integrity": "sha512-+CEb+GDCM7tkOS2wdMKTn9vU7DgnKUTuDlehkNJKNSovdCOVxs14OfKCk4cvSaR3za4gj+OBdl9opPN9xrJ0zA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "gar": "^1.0.4",
+ "tiny-each-async": "2.0.3"
+ },
+ "bin": {
+ "get-folder-size": "bin/get-folder-size"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"license": "MIT",
@@ -6601,6 +8039,29 @@
"version": "0.0.0",
"license": "MIT"
},
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/glob-parent": {
"version": "6.0.2",
"dev": true,
@@ -6612,6 +8073,40 @@
"node": ">=10.13.0"
}
},
+ "node_modules/glob/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "1.1.18",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
+ "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/globals": {
"version": "16.5.0",
"dev": true,
@@ -7010,6 +8505,19 @@
"node": ">=8"
}
},
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
"node_modules/inherits": {
"version": "2.0.4",
"license": "ISC"
@@ -7091,21 +8599,6 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
- "node_modules/ink/node_modules/cli-cursor": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
- "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
- "license": "MIT",
- "dependencies": {
- "restore-cursor": "^4.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/ink/node_modules/indent-string": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz",
@@ -7118,37 +8611,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/ink/node_modules/onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "license": "MIT",
- "dependencies": {
- "mimic-fn": "^2.1.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/ink/node_modules/restore-cursor": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
- "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
- "license": "MIT",
- "dependencies": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/ink/node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -8059,50 +9521,141 @@
],
"peer": true,
"engines": {
- "node": ">= 12.0.0"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz",
+ "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "3.1.3",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/listr2": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz",
+ "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cli-truncate": "^3.1.0",
+ "colorette": "^2.0.20",
+ "eventemitter3": "^5.0.1",
+ "log-update": "^5.0.1",
+ "rfdc": "^1.3.0",
+ "wrap-ansi": "^8.1.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/listr2/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/lightningcss-win32-x64-msvc": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz",
- "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==",
- "cpu": [
- "x64"
- ],
+ "node_modules/listr2/node_modules/cli-truncate": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz",
+ "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==",
"dev": true,
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "win32"
- ],
- "peer": true,
+ "license": "MIT",
+ "dependencies": {
+ "slice-ansi": "^5.0.0",
+ "string-width": "^5.0.0"
+ },
"engines": {
- "node": ">= 12.0.0"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/lilconfig": {
- "version": "3.1.3",
+ "node_modules/listr2/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/listr2/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
"engines": {
- "node": ">=14"
+ "node": ">=12"
},
"funding": {
- "url": "https://github.com/sponsors/antonk52"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/lines-and-columns": {
- "version": "1.2.4",
+ "node_modules/listr2/node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
},
"node_modules/locate-path": {
"version": "6.0.0",
@@ -8159,6 +9712,111 @@
"version": "4.1.1",
"license": "MIT"
},
+ "node_modules/log-update": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz",
+ "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-escapes": "^5.0.0",
+ "cli-cursor": "^4.0.0",
+ "slice-ansi": "^5.0.0",
+ "strip-ansi": "^7.0.1",
+ "wrap-ansi": "^8.0.1"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/ansi-escapes": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz",
+ "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/log-update/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/log-update/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/type-fest": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
+ "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
"node_modules/longest-streak": {
"version": "3.1.0",
"license": "MIT",
@@ -9298,6 +10956,16 @@
"version": "3.1.1",
"license": "MIT"
},
+ "node_modules/node-api-version": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz",
+ "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.3.5"
+ }
+ },
"node_modules/node-domexception": {
"version": "1.0.0",
"funding": [
@@ -9331,6 +10999,31 @@
"url": "https://opencollective.com/node-fetch"
}
},
+ "node_modules/node-gyp": {
+ "version": "12.4.0",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.4.0.tgz",
+ "integrity": "sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "env-paths": "^2.2.0",
+ "exponential-backoff": "^3.1.1",
+ "graceful-fs": "^4.2.6",
+ "nopt": "^9.0.0",
+ "proc-log": "^6.0.0",
+ "semver": "^7.3.5",
+ "tar": "^7.5.4",
+ "tinyglobby": "^0.2.12",
+ "undici": "^6.25.0",
+ "which": "^6.0.0"
+ },
+ "bin": {
+ "node-gyp": "bin/node-gyp.js"
+ },
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
"node_modules/node-gyp-build-optional-packages": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
@@ -9346,6 +11039,78 @@
"node-gyp-build-optional-packages-test": "build-test.js"
}
},
+ "node_modules/node-gyp/node_modules/abbrev": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz",
+ "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/isexe": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
+ "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/node-gyp/node_modules/nopt": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz",
+ "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^4.0.0"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/proc-log": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+ "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/undici": {
+ "version": "6.28.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
+ "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.17"
+ }
+ },
+ "node_modules/node-gyp/node_modules/which": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
+ "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^4.0.0"
+ },
+ "bin": {
+ "node-which": "bin/which.js"
+ },
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
"node_modules/node-releases": {
"version": "2.0.27",
"dev": true,
@@ -9464,6 +11229,21 @@
"wrappy": "1"
}
},
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"dev": true,
@@ -9521,6 +11301,20 @@
"node": ">=6"
}
},
+ "node_modules/parse-author": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/parse-author/-/parse-author-2.0.0.tgz",
+ "integrity": "sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "author-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/parse-entities": {
"version": "4.0.2",
"license": "MIT",
@@ -9703,6 +11497,17 @@
"node": ">=14.0.0"
}
},
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/path-key": {
"version": "3.1.1",
"license": "MIT",
@@ -9714,6 +11519,33 @@
"version": "1.0.7",
"license": "MIT"
},
+ "node_modules/path-scurry": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
+ "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^11.0.0",
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "11.5.2",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz",
+ "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/path-to-regexp": {
"version": "8.4.2",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
@@ -9734,6 +11566,21 @@
"node_modules/pause": {
"version": "0.0.1"
},
+ "node_modules/pe-library": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-1.0.1.tgz",
+ "integrity": "sha512-nh39Mo1eGWmZS7y+mK/dQIqg7S1lp38DpRxkyoHf0ZcUs/HDc+yyTjuOtTvSMZHmfSLuSQaX945u05Y2Q6UWZg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14",
+ "npm": ">=7"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/jet2jet"
+ }
+ },
"node_modules/pg-connection-string": {
"version": "2.6.2",
"license": "MIT"
@@ -9884,7 +11731,22 @@
"darwin"
],
"engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/plist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz",
+ "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@xmldom/xmldom": "^0.9.10",
+ "base64-js": "^1.5.1",
+ "xmlbuilder": "^15.1.1"
+ },
+ "engines": {
+ "node": ">=10.4.0"
}
},
"node_modules/postcss": {
@@ -10038,6 +11900,32 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/postject": {
+ "version": "1.0.0-alpha.6",
+ "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz",
+ "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^9.4.0"
+ },
+ "bin": {
+ "postject": "dist/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/postject/node_modules/commander": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
+ "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || >=14"
+ }
+ },
"node_modules/prebuild-install": {
"version": "7.1.3",
"license": "MIT",
@@ -10153,6 +12041,30 @@
],
"license": "MIT"
},
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/promise-retry": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+ "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "err-code": "^2.0.2",
+ "retry": "^0.12.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/property-information": {
"version": "7.1.0",
"license": "MIT",
@@ -10474,6 +12386,19 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
+ "node_modules/read-binary-file-arch": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz",
+ "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "bin": {
+ "read-binary-file-arch": "cli.js"
+ }
+ },
"node_modules/read-cache": {
"version": "1.0.0",
"dev": true,
@@ -10883,6 +12808,17 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/require-from-string": {
"version": "2.0.2",
"license": "MIT",
@@ -10890,6 +12826,24 @@
"node": ">=0.10.0"
}
},
+ "node_modules/resedit": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/resedit/-/resedit-2.0.3.tgz",
+ "integrity": "sha512-oTeemxwoMuxxTYxXUwjkrOPfngTQehlv0/HoYFNkB4uzsP1Un1A9nI8JQKGOFkxpqkC7qkMs0lUsGrvUlbLNUA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pe-library": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=14",
+ "npm": ">=7"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/jet2jet"
+ }
+ },
"node_modules/reselect": {
"version": "5.1.1",
"license": "MIT"
@@ -10927,6 +12881,38 @@
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
+ "node_modules/restore-cursor": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
+ "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/restore-cursor/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "license": "ISC"
+ },
+ "node_modules/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/reusify": {
"version": "1.1.0",
"license": "MIT",
@@ -10935,6 +12921,13 @@
"node": ">=0.10.0"
}
},
+ "node_modules/rfdc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/rollup": {
"version": "4.62.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz",
@@ -11383,6 +13376,49 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/slice-ansi": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
+ "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.0.0",
+ "is-fullwidth-code-point": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
+ "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/socket.io": {
"version": "4.8.3",
"license": "MIT",
@@ -11457,6 +13493,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
"node_modules/space-separated-tokens": {
"version": "2.0.2",
"license": "MIT",
@@ -11531,6 +13580,58 @@
"safe-buffer": "~5.2.0"
}
},
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/stringify-entities": {
"version": "4.0.4",
"license": "MIT",
@@ -11641,6 +13742,19 @@
"node": ">= 6"
}
},
+ "node_modules/sumchecker": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
+ "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "debug": "^4.1.0"
+ },
+ "engines": {
+ "node": ">= 8.0"
+ }
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -11783,6 +13897,50 @@
"node": ">=8.0.0"
}
},
+ "node_modules/temp": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz",
+ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "mkdirp": "^0.5.1",
+ "rimraf": "~2.6.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/temp/node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/temp/node_modules/rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
"node_modules/terminal-size": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/terminal-size/-/terminal-size-4.0.1.tgz",
@@ -11795,6 +13953,36 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/terser": {
+ "version": "5.51.2",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz",
+ "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.15.0",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/terser/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true
+ },
"node_modules/thenify": {
"version": "3.3.1",
"dev": true,
@@ -11828,6 +14016,14 @@
"node": ">=8"
}
},
+ "node_modules/tiny-each-async": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-each-async/-/tiny-each-async-2.0.3.tgz",
+ "integrity": "sha512-5ROII7nElnAirvFn8g7H7MtpfV1daMcyfTGQwsn/x2VtyV+VPiO5CjReCJtWLvoKTDEDmZocf3cNPraiMnBXLA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/tiny-invariant": {
"version": "1.3.3",
"license": "MIT"
@@ -11914,6 +14110,28 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/tmp-promise": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz",
+ "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tmp": "^0.2.0"
+ }
+ },
+ "node_modules/tmp-promise/node_modules/tmp": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz",
+ "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"license": "MIT",
@@ -12866,6 +15084,16 @@
"node": ">=16.0.0"
}
},
+ "node_modules/xmlbuilder": {
+ "version": "15.1.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
+ "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
"node_modules/xmlchars": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
@@ -12879,6 +15107,17 @@
"node": ">=0.4.0"
}
},
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/yallist": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
diff --git a/package.json b/package.json
index 63a290e96..668efd4f2 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,8 @@
"propr-ui"
],
"overrides": {
+ "@electron/packager": "20.3.0",
+ "@electron/rebuild": "4.2.0",
"react": "19.2.7"
},
"scripts": {
@@ -68,6 +70,17 @@
"cli:pack": "node packages/cli/scripts/build-publish.mjs",
"cli:publish": "node packages/cli/scripts/build-publish.mjs --publish",
"deploy:hosted-ui": "npm run build -w propr-ui && npx wrangler deploy --config wrangler.hosted-ui.toml",
+ "desktop": "npm run dev -w @propr/desktop",
+ "desktop:dev": "npm run dev -w @propr/desktop",
+ "desktop:prepare": "npm run build -w @propr/shared && npm run build -w @propr/client",
+ "desktop:typecheck": "npm run typecheck -w @propr/desktop && npm run typecheck -w propr-ui",
+ "desktop:test": "npm run test -w @propr/desktop",
+ "desktop:package": "npm run package -w @propr/desktop",
+ "desktop:smoke": "npm run smoke:package -w @propr/desktop",
+ "desktop:make": "npm run make -w @propr/desktop",
+ "audit:runtime": "npm audit --package-lock-only --omit=dev --audit-level=low",
+ "desktop:audit:packaging": "npm audit --package-lock-only --workspace=@propr/desktop --include=dev --audit-level=high",
+ "desktop:audit": "npm run audit:runtime && npm run desktop:audit:packaging",
"start:prod": "docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/.env:/app/.env:ro -v $PWD/data:/app/data -v $PWD/logs:/app/logs -v $PWD/repos:/app/repos propr/launcher:latest"
},
"keywords": [],
diff --git a/packages/api/corsValidation.ts b/packages/api/corsValidation.ts
index c18a5d18e..5a35823a1 100644
--- a/packages/api/corsValidation.ts
+++ b/packages/api/corsValidation.ts
@@ -3,10 +3,11 @@
// The hosted UI origin (FRONTEND_URL, e.g. https://app.propr.dev) is always
// allowed. When COOKIE_DOMAIN is set, the base domain and any of its subdomains
// are also allowed so PR preview environments that share sessions via
-// cross-subdomain cookies can talk to the API. localhost/127.0.0.1 are allowed
-// for local development.
+// cross-subdomain cookies can talk to the API. localhost/127.0.0.1/[::1] are
+// allowed for local development.
import type { ErrorRequestHandler } from 'express';
+import { DESKTOP_RENDERER_ORIGIN } from '@propr/shared';
export type CorsOriginCallback = (err: Error | null, allow?: boolean) => void;
export type CorsOriginValidator = (origin: string | undefined, callback: CorsOriginCallback) => void;
@@ -45,6 +46,13 @@ export function createCorsOriginValidator(frontendUrl: string, cookieDomain: str
callback(null, true);
return;
}
+ // Electron registers this as a standard, secure scheme, which gives the
+ // packaged renderer a stable serialized origin. Match that origin exactly;
+ // never accept the generic `null` value used by arbitrary opaque origins.
+ if (origin === DESKTOP_RENDERER_ORIGIN) {
+ callback(null, true);
+ return;
+ }
try {
const url = new URL(origin);
// Allow the base domain and any subdomain. The previous inline validator
@@ -60,11 +68,11 @@ export function createCorsOriginValidator(frontendUrl: string, cookieDomain: str
} else if (url.origin === frontendOrigin) {
callback(null, true);
} else if (
- (url.hostname === 'localhost' || url.hostname === '127.0.0.1') &&
+ (url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]') &&
(url.protocol === 'http:' || url.protocol === 'https:')
) {
- // Allow localhost for development, but only over http/https so an unusual
- // scheme (e.g. file:, chrome-extension:) on localhost is not trusted.
+ // Allow loopback hosts for development, but only over http/https so an
+ // unusual scheme (e.g. file:, chrome-extension:) is not trusted.
callback(null, true);
} else {
callback(new CorsOriginError());
diff --git a/packages/api/test/corsValidation.test.ts b/packages/api/test/corsValidation.test.ts
index f0b24c9e4..2e960b693 100644
--- a/packages/api/test/corsValidation.test.ts
+++ b/packages/api/test/corsValidation.test.ts
@@ -1,9 +1,12 @@
import assert from 'node:assert/strict';
import { once } from 'node:events';
+import { createServer } from 'node:http';
import type { AddressInfo } from 'node:net';
import { test } from 'node:test';
+import { DESKTOP_RENDERER_ORIGIN } from '@propr/shared';
import cors from 'cors';
import express from 'express';
+import { Server as SocketIOServer } from 'socket.io';
import { corsRejectionHandler, createCorsOriginValidator } from '../corsValidation.js';
// Helper that runs the validator synchronously and reports whether the origin
@@ -39,21 +42,34 @@ test('CORS allows requests with no origin', () => {
assert.equal(isAllowed(validate, undefined), true);
});
-test('CORS allows localhost for development', () => {
+test('CORS allows only the exact packaged desktop renderer custom origin', () => {
+ const validate = createCorsOriginValidator('https://app.propr.dev', undefined);
+
+ assert.equal(isAllowed(validate, DESKTOP_RENDERER_ORIGIN), true);
+ assert.equal(isAllowed(validate, `${DESKTOP_RENDERER_ORIGIN}.evil.example`), false);
+ assert.equal(isAllowed(validate, 'propr-app://other-renderer'), false);
+ assert.equal(isAllowed(validate, 'null'), false);
+});
+
+test('CORS allows HTTP(S) loopback origins for development', () => {
const validate = createCorsOriginValidator('https://app.propr.dev', undefined);
assert.equal(isAllowed(validate, 'http://localhost:5173'), true);
assert.equal(isAllowed(validate, 'http://127.0.0.1:5173'), true);
+ assert.equal(isAllowed(validate, 'http://[::1]:5173'), true);
assert.equal(isAllowed(validate, 'https://localhost:5173'), true);
+ assert.equal(isAllowed(validate, 'https://[::1]:5173'), true);
});
-test('CORS rejects non-http(s) localhost schemes', () => {
- // Only http/https localhost origins are trusted; an unusual scheme that still
- // parses with a localhost hostname must not be allowed.
+test('CORS rejects unsafe schemes and non-loopback hosts', () => {
+ // Only http/https loopback origins are trusted; an unusual scheme that still
+ // parses with a loopback hostname must not be allowed.
const validate = createCorsOriginValidator('https://app.propr.dev', undefined);
assert.equal(isAllowed(validate, 'chrome-extension://localhost'), false);
assert.equal(isAllowed(validate, 'file://localhost'), false);
+ assert.equal(isAllowed(validate, 'file://[::1]/tmp/propr'), false);
+ assert.equal(isAllowed(validate, 'http://[2001:db8::1]:5173'), false);
});
test('CORS allows COOKIE_DOMAIN subdomains for preview environments', () => {
@@ -132,6 +148,7 @@ for (const runtimeMode of ['development', 'production'] as const) {
'https://app.propr.dev',
'https://pr-17.preview.example.com',
'http://localhost:5173',
+ 'http://[::1]:5173',
]) {
const response = await fetch(`${baseUrl}/api/protected`, { headers: { Origin: origin } });
assert.equal(response.status, 401, `expected ${origin} to reach authentication`);
@@ -142,9 +159,10 @@ for (const runtimeMode of ['development', 'production'] as const) {
assert.equal(noOrigin.status, 401);
const compatibility = await fetch(`${baseUrl}/api/compatibility`, {
- headers: { Origin: 'https://app.propr.dev' },
+ headers: { Origin: DESKTOP_RENDERER_ORIGIN },
});
assert.equal(compatibility.status, 200);
+ assert.equal(compatibility.headers.get('access-control-allow-origin'), DESKTOP_RENDERER_ORIGIN);
const allowedPreflight = await fetch(`${baseUrl}/api/protected`, {
method: 'OPTIONS',
@@ -158,3 +176,28 @@ for (const runtimeMode of ['development', 'production'] as const) {
});
});
}
+
+test('Socket.IO applies the shared CORS validator to the packaged desktop renderer', async () => {
+ const server = createServer();
+ const io = new SocketIOServer(server, {
+ cors: {
+ origin: createCorsOriginValidator('https://app.propr.dev', undefined),
+ credentials: true,
+ },
+ });
+ server.listen(0, '127.0.0.1');
+ await once(server, 'listening');
+ const { port } = server.address() as AddressInfo;
+
+ try {
+ const response = await fetch(`http://127.0.0.1:${port}/socket.io/?EIO=4&transport=polling`, {
+ headers: { Origin: DESKTOP_RENDERER_ORIGIN },
+ });
+
+ assert.equal(response.status, 200);
+ assert.equal(response.headers.get('access-control-allow-origin'), DESKTOP_RENDERER_ORIGIN);
+ assert.equal(response.headers.get('access-control-allow-credentials'), 'true');
+ } finally {
+ await new Promise(resolve => io.close(() => resolve()));
+ }
+});
diff --git a/packages/api/test/webPushDispatcher.test.ts b/packages/api/test/webPushDispatcher.test.ts
index a58b18551..ed3e38401 100644
--- a/packages/api/test/webPushDispatcher.test.ts
+++ b/packages/api/test/webPushDispatcher.test.ts
@@ -13,6 +13,11 @@ import { NotificationService } from '../../core/src/services/notificationService
import { WebPushDispatcher } from '../services/webPushDispatcher.js';
const success: SendResult = { statusCode: 201, body: '', headers: {} };
+const HISTORICAL_FIXTURE_TIME = Date.parse('2020-01-01T00:00:00.000Z');
+
+function historicalFixtureTime(): Date {
+ return new Date(HISTORICAL_FIXTURE_TIME);
+}
function createDatabase(): Knex {
return knex({
@@ -61,7 +66,7 @@ beforeEach(async () => {
await addAdvertisedActions(database);
notifications = new NotificationService({
database,
- now: () => new Date(Date.now() - 5_000),
+ now: historicalFixtureTime,
});
});
@@ -399,7 +404,7 @@ describe('Web Push dispatcher', { concurrency: false }, () => {
assert.ok(address !== null && typeof address !== 'string');
const localNotifications = new NotificationService({
database,
- now: () => new Date(Date.now() - 5_000),
+ now: historicalFixtureTime,
allowInsecureLocalhost: true,
});
await queuedEvent({
@@ -438,7 +443,7 @@ describe('Web Push dispatcher', { concurrency: false }, () => {
process.env.API_PUBLIC_URL = 'http://localhost:4000';
const localNotifications = new NotificationService({
database,
- now: () => new Date(Date.now() - 5_000),
+ now: historicalFixtureTime,
allowInsecureLocalhost: true,
});
await queuedEvent({
@@ -489,7 +494,7 @@ describe('Web Push dispatcher', { concurrency: false }, () => {
await createNotificationSchema(database);
await addPreferenceApis(database);
await addAdvertisedActions(database);
- notifications = new NotificationService({ database, now: () => new Date(Date.now() - 5_000) });
+ notifications = new NotificationService({ database, now: historicalFixtureTime });
await queuedEvent();
const exhausted = dispatcher({
sendNotification: async () => Promise.reject({ statusCode: 503, body: 'SECRET' }),
diff --git a/packages/client/test/client.test.ts b/packages/client/test/client.test.ts
index a3af466bb..dae6a6b7a 100644
--- a/packages/client/test/client.test.ts
+++ b/packages/client/test/client.test.ts
@@ -13,6 +13,7 @@ describe('Propr API base URLs and instance profiles', () => {
assert.equal(normalizeApiBaseUrl(), '');
assert.equal(normalizeApiBaseUrl(' http://localhost:4000/// '), 'http://localhost:4000');
assert.equal(normalizeApiBaseUrl('http://127.0.0.1:3000'), 'http://127.0.0.1:3000');
+ assert.equal(normalizeApiBaseUrl('http://[::1]:3000'), 'http://[::1]:3000');
assert.equal(normalizeApiBaseUrl('https://propr.example.com/'), 'https://propr.example.com');
const profile = normalizeInstanceProfile({
diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts
index ecbb3b448..561ea2645 100644
--- a/packages/shared/src/index.ts
+++ b/packages/shared/src/index.ts
@@ -92,6 +92,7 @@ export {
DEFAULT_PROPR_ROUTING_URL,
DEFAULT_PROPR_GH_RELAY_URL,
DEFAULT_PROPR_UI_ORIGIN,
+ DESKTOP_RENDERER_ORIGIN,
PROPR_UI_PROXY_SUFFIX,
PROPR_UI_PROXY_LABEL_PREFIX,
DEFAULT_CLOUDFLARED_IMAGE,
diff --git a/packages/shared/src/proprServiceUrls.ts b/packages/shared/src/proprServiceUrls.ts
index 447573de9..b06cec385 100644
--- a/packages/shared/src/proprServiceUrls.ts
+++ b/packages/shared/src/proprServiceUrls.ts
@@ -35,6 +35,12 @@ export const DEFAULT_PROPR_GH_RELAY_URL = 'https://webhook.propr.dev/v1';
*/
export const DEFAULT_PROPR_UI_ORIGIN = 'https://app.propr.dev';
+/**
+ * Exact browser origin used by the packaged Electron renderer. The API uses
+ * this value as a narrow CORS exception for desktop REST and Socket.IO calls.
+ */
+export const DESKTOP_RENDERER_ORIGIN = 'propr-app://renderer';
+
/**
* DNS suffix and label prefix for per-instance UI/API tunnel hostnames. Each
* local stack with an instance id is reachable at
diff --git a/propr-ui/src/App.tsx b/propr-ui/src/App.tsx
index 96a4a3180..dd427691d 100644
--- a/propr-ui/src/App.tsx
+++ b/propr-ui/src/App.tsx
@@ -1,5 +1,5 @@
import React, { lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react'
-import { BrowserRouter as Router, Routes, Route, Link, useLocation, useNavigate } from 'react-router-dom'
+import { BrowserRouter, HashRouter, Routes, Route, Link, useLocation, useNavigate } from 'react-router-dom'
import Layout from './components/Layout'
import { ToastProvider } from './components/ui/Toast'
import { SocketProvider } from './contexts/SocketProvider'
@@ -21,8 +21,11 @@ import RouteChunkErrorBoundary from './components/RouteChunkErrorBoundary'
import { ConnectAccountProvider } from './contexts/ConnectAccountContext'
import { BrowserPushProvider } from './hooks/useBrowserPush'
import { NotificationCenterProvider } from './contexts/NotificationCenterContext'
+import { currentUiPathname, isDesktopRuntime, publicAssetUrl } from './config/runtimeMode'
import { DesktopPresentationBoundary } from './desktop/DesktopPresentationBoundary'
+const Router = isDesktopRuntime() ? HashRouter : BrowserRouter;
+
const AiAgentsPage = lazy(() => import('./pages/AiAgentsPage'))
const AccessManagementPage = lazy(() => import('./pages/AccessManagementPage'))
const Dashboard = lazy(() => import('./components/Dashboard'))
@@ -38,9 +41,7 @@ const SettingsPage = lazy(() => import('./pages/SettingsPage'))
const SummaryBrowserPage = lazy(() => import('./pages/SummaryBrowserPage'))
const TasksPage = lazy(() => import('./pages/TasksPage'))
-type CompatibilityState =
- | { status: 'checking' }
- | { status: 'ready' }
+type CompatibilityState = { status: 'checking' } | { status: 'ready' }
| { status: 'blocked'; title: string; message: string };
const AUTHORIZATION_REFRESH_INTERVAL_MS = 60_000;
@@ -94,7 +95,7 @@ const HostedConnectionBlocked: React.FC<{ title: string; message: string }> = ({
const HostedOAuthCompletion: React.FC = () => (
-
+
GitHub sign-in complete
You can close this window and return to ProPR.
@@ -143,7 +144,7 @@ export const NotFoundRouteContent: React.FC<{ hostname?: string }> = ({ hostname
const AppContent: React.FC = () => {
const { isDemoMode, isLoading: isDemoModeLoading } = useDemoMode();
// Auth check state - start loading unless already on login page
- const [isLoading, setIsLoading] = useState(window.location.pathname !== '/login');
+ const [isLoading, setIsLoading] = useState(currentUiPathname() !== '/login');
const [currentUser, setCurrentUser] = useState
(null);
const refreshPromiseRef = useRef | null>(null);
@@ -164,7 +165,7 @@ const AppContent: React.FC = () => {
const checkSession = async () => {
// Don't check if we are already on login page
- if (window.location.pathname === '/login') {
+ if (currentUiPathname() === '/login') {
setIsLoading(false);
return;
}
@@ -197,7 +198,7 @@ const AppContent: React.FC = () => {
}, [refreshCurrentUser]);
useEffect(() => {
- if (isDemoMode || window.location.pathname === '/login') return;
+ if (isDemoMode || currentUiPathname() === '/login') return;
const refreshAuthorization = () => {
if (document.visibilityState === 'hidden') return;
void refreshCurrentUser().catch(error => {
diff --git a/propr-ui/src/api/apiClient.ts b/propr-ui/src/api/apiClient.ts
index 23b9619aa..32cf33f2f 100644
--- a/propr-ui/src/api/apiClient.ts
+++ b/propr-ui/src/api/apiClient.ts
@@ -1,6 +1,7 @@
import { DEMO_MODE_READ_ONLY_CODE } from '@propr/shared';
import { ProprClient } from '@propr/client';
import { getApiBaseUrl, pathWithActiveHostedTunnelFlow } from '../config/runtimeConfig';
+import { currentUiPathname, navigateToUiPath } from '../config/runtimeMode';
const createProprClient = (baseUrl: string): ProprClient => new ProprClient({
baseUrl,
@@ -115,10 +116,10 @@ const throwUnauthorizedResponse = (data: ApiErrorBody | null): never => {
if (data?.code === TOKEN_REFRESHED_CODE) {
throw new TokenRefreshRetryRequiredError(getApiErrorMessage(data));
}
- if (window.location.pathname === '/login') throw new Error('Authentication required');
+ if (currentUiPathname() === '/login') throw new Error('Authentication required');
// Preserve only the validated active flow so login/OAuth cannot be driven by
// arbitrary raw URL input or copied sessionStorage.
- window.location.href = pathWithActiveHostedTunnelFlow('/login');
+ navigateToUiPath(pathWithActiveHostedTunnelFlow('/login'));
throw new Error('Authentication required');
};
diff --git a/propr-ui/src/api/proprApi.logout.test.ts b/propr-ui/src/api/proprApi.logout.test.ts
index 40a9ddff9..cd249051e 100644
--- a/propr-ui/src/api/proprApi.logout.test.ts
+++ b/propr-ui/src/api/proprApi.logout.test.ts
@@ -28,6 +28,10 @@ interface TestWindow {
search: string;
};
name: string;
+ proprDesktop?: {
+ auth: { logout: ReturnType };
+ external: { open: ReturnType };
+ };
sessionStorage: MemoryStorage;
}
@@ -175,4 +179,28 @@ describe('logout', () => {
expect(fetchSpy).not.toHaveBeenCalled();
expect(testWindow.location.href).toBe('http://localhost:4000/api/auth/logout');
});
+
+ it('logs out the active Electron session and uses hash-aware login navigation', async () => {
+ const testWindow = stubTestWindow({
+ apiBaseUrl: 'http://localhost:4000',
+ hostname: 'renderer',
+ href: 'propr-app://renderer/renderer.html#/tasks',
+ pathname: '/renderer.html',
+ });
+ testWindow.location.hash = '#/tasks';
+ const sessionLogout = vi.fn().mockResolvedValue(undefined);
+ const openExternal = vi.fn();
+ testWindow.proprDesktop = {
+ auth: { logout: sessionLogout },
+ external: { open: openExternal },
+ };
+ const { logout } = await importProprApi();
+
+ await Promise.resolve(logout());
+
+ expect(sessionLogout).toHaveBeenCalledWith('http://localhost:4000');
+ expect(openExternal).not.toHaveBeenCalled();
+ expect(testWindow.location.href).toBe('propr-app://renderer/renderer.html#/tasks');
+ expect(testWindow.location.hash).toBe('/login?logged_out=true');
+ });
});
diff --git a/propr-ui/src/api/proprApi.ts b/propr-ui/src/api/proprApi.ts
index 5927f1688..d58d5ae1b 100644
--- a/propr-ui/src/api/proprApi.ts
+++ b/propr-ui/src/api/proprApi.ts
@@ -274,6 +274,11 @@ const hostedLogout = async (): Promise => {
};
export const logout = (): void | Promise => {
+ if (typeof window !== 'undefined' && window.proprDesktop) {
+ return window.proprDesktop.auth.logout(API_BASE_URL).then(() => {
+ window.location.hash = '/login?logged_out=true';
+ });
+ }
if (typeof window !== 'undefined' && isHostedUiOrigin(window.location.hostname) && isProprProxyUrl(API_BASE_URL)) {
hostedLogoutInFlight ??= hostedLogout();
return hostedLogoutInFlight;
diff --git a/propr-ui/src/components/Layout.tsx b/propr-ui/src/components/Layout.tsx
index ce4736071..388da96be 100644
--- a/propr-ui/src/components/Layout.tsx
+++ b/propr-ui/src/components/Layout.tsx
@@ -14,6 +14,7 @@ import { QueueStatsUpdatePayload, IndexingUpdatePayload, DraftUpdatePayload } fr
import { useCurrentUser, userHasPermission } from '../contexts/AuthContext';
import { ConnectCapacityBanner } from './ConnectPlusBanner';
import { useNotificationCenter } from '../contexts/NotificationCenterContext';
+import { publicAssetUrl } from '../config/runtimeMode';
import { DesktopTitleBar } from '../desktop/DesktopTitleBar';
import { useDesktop } from '../desktop/DesktopContext';
@@ -187,7 +188,7 @@ const Layout: React.FC = ({ children }) => {
`}>
-

+