From be45ab54137ed2093250b827284d996487cf2ac1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 9 Nov 2026 08:29:39 +0000 Subject: [PATCH] Fix declined paste killing the Windows host and publish updates from OpenPood. A switch break was exiting the PowerShell loop, and a 300ms foreground race dropped the target before the host was ready. New builds also request gotzastory/OpenPood and pick up the Electron and fast-uri fixes. Co-authored-by: Thana --- README.md | 4 +- architecture/current-architecture.md | 2 +- architecture/reliability-testing.md | 2 +- architecture/system-design.md | 4 +- electron/main.test.ts | 22 +++++++- electron/main.ts | 31 ++++++++---- electron/pasteText.test.ts | 7 +-- electron/pasteText.ts | 5 +- electron/updater.test.ts | 11 +++- electron/updater.ts | 11 +++- electron/winHost.test.ts | 23 +++++++++ electron/winHost.ts | 15 +++--- package-lock.json | 76 ++++------------------------ package.json | 9 ++-- src/lib/runtimeConfig.ts | 1 - 15 files changed, 123 insertions(+), 100 deletions(-) create mode 100644 electron/winHost.test.ts diff --git a/README.md b/README.md index 53ad6ab..915eed1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ สร้างด้วย Electron + React + TypeScript + Vite + Tailwind CSS v4 + DaisyUI -**[ดาวน์โหลดตัวติดตั้งล่าสุด](https://github.com/gotzastory/OpenPud/releases/latest)** · [Releases ทั้งหมด](https://github.com/gotzastory/OpenPud/releases) +**[ดาวน์โหลดตัวติดตั้งล่าสุด](https://github.com/gotzastory/OpenPood/releases/latest)** · [Releases ทั้งหมด](https://github.com/gotzastory/OpenPood/releases) --- @@ -27,7 +27,7 @@ ## ดาวน์โหลด / ติดตั้ง -ดาวน์โหลดตัวติดตั้งจาก [GitHub Releases](https://github.com/gotzastory/OpenPud/releases/latest) — **ไม่ต้องมี Node.js** +ดาวน์โหลดตัวติดตั้งจาก [GitHub Releases](https://github.com/gotzastory/OpenPood/releases/latest) — **ไม่ต้องมี Node.js** 1. เปิดหน้า Releases แล้วดาวน์โหลด `OpenPood-Setup-x.x.x.exe` 2. ดับเบิลคลิกเพื่อติดตั้ง (NSIS, ไม่ต้องสิทธิ์ admin) diff --git a/architecture/current-architecture.md b/architecture/current-architecture.md index 19a02ab..b28163b 100644 --- a/architecture/current-architecture.md +++ b/architecture/current-architecture.md @@ -61,7 +61,7 @@ flowchart LR - Keep renderer access behind the preload bridge: `contextIsolation: true`, `nodeIntegration: false`. - API keys are redacted from returned settings; `safeStorage` encrypts them when available. Current code falls back to plaintext if encryption is unavailable. -- A known changed HWND skips paste; paste failure leaves text on the clipboard. Missing captured target or failed foreground lookup still permits a paste attempt in current code. +- A known changed HWND skips paste; paste failure leaves text on the clipboard. A missing or failed foreground lookup does not paste and does not replace the clipboard. - There is no application backend or server database. Audio/text leaves the device when sent to the configured AI provider. - Microphone, hotkeys, focus, clipboard/paste, tray and updates require manual Windows verification. diff --git a/architecture/reliability-testing.md b/architecture/reliability-testing.md index c22fe92..9cf6da2 100644 --- a/architecture/reliability-testing.md +++ b/architecture/reliability-testing.md @@ -38,7 +38,7 @@ npm.cmd run dev - Clipboard restore grace period เป็นค่า configurable; ทดสอบ Word/browser/chat และแอปที่ตอบสนองช้า. - Cancellation หลังส่ง keystrokeแล้วไม่สามารถดึงข้อความกลับจากแอปปลายทาง. - History failure เก็บ entry ใน RAM; entry ที่ยังไม่ persist จะหายเมื่อปิดแอป. -- Clipboard handling อ้างอิง [Electron 43.2.0 API](https://github.com/electron/electron/blob/v43.2.0/docs/api/clipboard.md); file/custom formats ที่คืนไม่ได้จะไม่ถูกเขียนทับ. +- Clipboard handling อ้างอิง [Electron 43.8.7 API](https://github.com/electron/electron/blob/v43.8.7/docs/api/clipboard.md); file/custom formats ที่คืนไม่ได้จะไม่ถูกเขียนทับ. ## Performance diagnostics diff --git a/architecture/system-design.md b/architecture/system-design.md index 57fd930..3e06f62 100644 --- a/architecture/system-design.md +++ b/architecture/system-design.md @@ -63,7 +63,7 @@ Global hotkey ``` - Escape is registered globally during microphone setup, recording, and processing. Processing cancellation aborts provider work and prevents late delivery; already-injected keystrokes cannot be retracted. -- Hotkey starts are serialized before microphone acquisition. The foreground target is captured once on the start press; a stop press never changes it. Slow or failed foreground capture becomes an unknown target. +- Hotkey starts are serialized before microphone acquisition. The foreground target is captured once on the start press; a stop press never changes it. Capture waits for the PowerShell host and retries once after a failed start. Only a lookup that still fails becomes an unknown target, and an unknown target does not replace the clipboard. - Recorder permission/stop operations have deadlines, late permission grants are released after cancellation, and errors/device disconnection stop tracks and close the audio context. - If a saved microphone disappears, recording retries with the OS default device. - Missing/unknown HWNDs never trigger automatic paste. The native host verifies the captured HWND and transcript clipboard sequence immediately before input injection; changed foreground falls back to clipboard delivery. @@ -118,7 +118,7 @@ Global hotkey ## Desktop updates -- `electron/updater.ts` owns `electron-updater` in main. Installed Windows builds check the public GitHub Releases feed configured by `build.publish` after startup and every six hours; development builds disable updates. +- `electron/updater.ts` owns `electron-updater` in main. Installed Windows builds check the public GitHub Releases feed for `gotzastory/OpenPood` (`build.publish`, also set with `setFeedURL`) after startup and every six hours; development builds disable updates. Builds already installed from v1.0.3 still have `gotzastory/OpenPud` in `app-update.yml` and follow GitHub's rename redirect. - Updates never download or install without an explicit dashboard action. Closing the dashboard or quitting via tray does not install a downloaded update. - Settings displays current/new versions, plain-text release notes, download progress, retry, and Restart & Update. A native notification opens Settings when a new version is found. - Update IPC is dashboard-only. Main rejects installation while a hotkey start is pending, the widget is recording/processing, or transcription/paste is active. Hotkeys are suspended during installation and restored if installation fails. diff --git a/electron/main.test.ts b/electron/main.test.ts index 3389648..62b2bd1 100644 --- a/electron/main.test.ts +++ b/electron/main.test.ts @@ -56,7 +56,7 @@ vi.mock('electron', async () => { screen: { getCursorScreenPoint: () => ({ x: 0, y: 0 }), getDisplayNearestPoint: () => ({ workArea: { x: 0, y: 0, width: 1920, height: 1080 } }), on: vi.fn() }, }; }); -vi.mock('electron-updater', () => ({ default: { autoUpdater: { on: vi.fn() } } })); +vi.mock('electron-updater', () => ({ default: { autoUpdater: { on: vi.fn(), setFeedURL: vi.fn() } } })); vi.mock('./config', () => { const settings = { apiKey: 'test-key', model: 'test-model', hotkey: 'Control+Space', translateHotkey: 'Control+Alt+T', launchAtStartup: false, onboardingCompleted: true, stripFillersEnabled: false, aiPolishEnabled: false, apiBaseUrl: 'https://provider.test' }; @@ -130,12 +130,30 @@ describe('main dictation integration', () => { state('idle'); expect(mocks.shortcuts.has('Escape')).toBe(false); }); - it('passes unknown foreground through the clipboard fallback', async () => { + it('passes unknown foreground through without a paste target', async () => { mocks.foreground.mockRejectedValue(new Error('host unavailable')); startHotkey(); state('processing'); await run(); + expect(mocks.foreground).toHaveBeenCalledTimes(2); expect(mocks.paste).toHaveBeenCalledWith('transcript', null, expect.any(AbortSignal)); }); + it('waits for a slow foreground host instead of dropping the HWND', async () => { + mocks.foreground.mockImplementation(() => new Promise((resolve) => { + setTimeout(() => resolve({ hwnd: '456', processName: 'notepad' }), 350); + })); + startHotkey(); state('processing'); + await run(); + expect(mocks.paste).toHaveBeenCalledWith('transcript', { hwnd: '456', processName: 'notepad' }, expect.any(AbortSignal)); + }); + it('retries after a cold host fails and uses the HWND from the restarted lookup', async () => { + mocks.foreground + .mockRejectedValueOnce(new Error('win host did not become ready')) + .mockResolvedValueOnce({ hwnd: '789', processName: 'chrome' }); + startHotkey(); state('processing'); + await run(); + expect(mocks.foreground).toHaveBeenCalledTimes(2); + expect(mocks.paste).toHaveBeenCalledWith('transcript', { hwnd: '789', processName: 'chrome' }, expect.any(AbortSignal)); + }); it('cancels an active request and prevents late history/paste', async () => { mocks.transcribe.mockImplementation((_audio, _mime, _settings, _bias, signal: AbortSignal) => new Promise((_resolve, reject) => { signal.addEventListener('abort', () => reject(new Error('aborted')), { once: true }); diff --git a/electron/main.ts b/electron/main.ts index 9fbfc49..524a710 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -124,14 +124,24 @@ function recoverWidget(win: BrowserWindow): void { }, RUNTIME.widgetRecoveryDelayMs); } +const FOREGROUND_LOOKUP_ATTEMPTS = 2; + +function knownForeground(window: ForegroundWindow): boolean { + return /^[1-9]\d*$/.test(window.hwnd); +} + +// Wait for the PowerShell host to compile and answer. A cold or crashed host +// is restarted by the next lookup; do not give up on a short timer. async function captureForeground(): Promise { - let timer: ReturnType | undefined; - try { - return await Promise.race([ - getForegroundWindow().catch(() => null), - new Promise((resolve) => { timer = setTimeout(() => resolve(null), RUNTIME.foregroundCaptureTimeoutMs); }), - ]); - } finally { clearTimeout(timer); } + for (let attempt = 0; attempt < FOREGROUND_LOOKUP_ATTEMPTS; attempt++) { + try { + const window = await getForegroundWindow(); + if (knownForeground(window)) return window; + } catch (err) { + console.warn('[winHost] foreground lookup failed:', err instanceof Error ? err.message : 'unknown'); + } + } + return null; } type RendererCapability = 'main' | 'widget' | 'either'; @@ -153,7 +163,8 @@ function requireRenderer(event: { sender: WebContents }, capability: RendererCap } // Capture once at the start press. Stopping in another window must never retarget -// the dictation. Slow/unavailable lookups deliberately fall back to clipboard. +// the dictation. A lookup that still fails after a host restart leaves the target +// unknown; paste then keeps the previous clipboard and History holds the text. let foregroundAtHotkey: Promise = Promise.resolve(null); // Bottom-center of whichever monitor the cursor is on, not just the primary. @@ -526,7 +537,9 @@ app.whenReady().then(() => { sendToWindow(mainWindow, 'history:updated'); assertCurrent(); const delivery = await measureStage('paste', () => pasteAtCursor(text, target, controller.signal)); - if (delivery.reason === 'focus-changed') { + if (delivery.reason === 'target-unknown') { + notify('ยืนยันหน้าต่างปลายทางไม่ได้', 'ไม่พบหน้าต่างปลายทาง กรุณาคัดลอกข้อความจาก History'); + } else if (delivery.reason === 'focus-changed') { notify('ยืนยันหน้าต่างปลายทางไม่ได้', 'ข้อความอยู่ใน clipboard แล้ว กด Ctrl+V เพื่อวางเอง'); } else if (delivery.reason === 'clipboard-preserved') { notify('เก็บ clipboard เดิมไว้แล้ว', 'clipboard มีไฟล์ รูปแบบพิเศษ หรือถูกเปลี่ยน กรุณาคัดลอกข้อความจาก History'); diff --git a/electron/pasteText.test.ts b/electron/pasteText.test.ts index 5d4f2c7..6c623f0 100644 --- a/electron/pasteText.test.ts +++ b/electron/pasteText.test.ts @@ -34,10 +34,11 @@ afterEach(() => vi.restoreAllMocks()); const target = { hwnd: '123', processName: 'test' }; describe('safe paste delivery', () => { - it.each([null, { hwnd: '0', processName: '' }])('does not inject keys when the captured target is unknown', async (missing) => { - expect(await pasteAtCursor('transcript', missing)).toEqual({ pasted: false, reason: 'focus-changed' }); + it.each([null, { hwnd: '0', processName: '' }])('does not replace the clipboard when the captured target is unknown', async (missing) => { + expect(await pasteAtCursor('transcript', missing)).toEqual({ pasted: false, reason: 'target-unknown' }); expect(mocks.sendCtrlV).not.toHaveBeenCalled(); - expect(mocks.text).toBe('transcript'); + expect(mocks.clipboard.writeText).not.toHaveBeenCalled(); + expect(mocks.text).toBe('previous'); }); it('passes the original HWND and clipboard sequence to the native focus guard', async () => { expect(await pasteAtCursor('transcript', target)).toEqual({ pasted: true }); diff --git a/electron/pasteText.ts b/electron/pasteText.ts index 0763812..524ebe8 100644 --- a/electron/pasteText.ts +++ b/electron/pasteText.ts @@ -4,7 +4,7 @@ import { RUNTIME } from '../src/lib/runtimeConfig'; export interface PasteResult { pasted: boolean; - reason?: 'focus-changed' | 'paste-failed' | 'clipboard-preserved'; + reason?: 'focus-changed' | 'paste-failed' | 'clipboard-preserved' | 'target-unknown'; } function delay(ms: number): Promise { @@ -37,6 +37,8 @@ function snapshotClipboard(hasNativeFormats: boolean): Data { export async function pasteAtCursor(text: string, target: ForegroundWindow | null, signal?: AbortSignal): Promise { signal?.throwIfAborted(); + // A missing HWND must not touch the clipboard. The transcript stays in History. + if (!target || !/^[1-9]\d*$/.test(target.hwnd)) return { pasted: false, reason: 'target-unknown' }; let previous: Data; try { const before = await getClipboardState(signal); @@ -64,7 +66,6 @@ export async function pasteAtCursor(text: string, target: ForegroundWindow | nul // Check content too: another application could change clipboard while the // host request is in flight. Recheck sequence in native code at injection. if (clipboard.readText() !== text || written.hasFiles || written.hasUnsupported) return { pasted: false, reason: 'clipboard-preserved' }; - if (!target || !/^[1-9]\d*$/.test(target.hwnd)) return { pasted: false, reason: 'focus-changed' }; await delay(RUNTIME.clipboardSettleMs); signal?.throwIfAborted(); const result = await sendCtrlV(target.hwnd, ownedSequence, signal); diff --git a/electron/updater.test.ts b/electron/updater.test.ts index 73bc628..f2e9fdc 100644 --- a/electron/updater.test.ts +++ b/electron/updater.test.ts @@ -1,11 +1,13 @@ import { EventEmitter } from 'node:events'; +import { readFileSync } from 'node:fs'; import type { AppUpdater } from 'electron-updater'; import { describe, expect, it, vi } from 'vitest'; -import { UpdateController } from './updater'; +import { UpdateController, UPDATE_FEED } from './updater'; function fixture(enabled = true) { const events = new EventEmitter(); const client = Object.assign(events, { + setFeedURL: vi.fn(), autoDownload: true, autoInstallOnAppQuit: true, allowPrerelease: true, allowDowngrade: true, checkForUpdates: vi.fn(async () => { events.emit('update-available', { version: '1.0.2', releaseNotes: '' }); @@ -23,6 +25,13 @@ function fixture(enabled = true) { } describe('desktop updates', () => { + it('checks the OpenPood GitHub release feed', () => { + const { client } = fixture(); + expect(client.setFeedURL).toHaveBeenCalledWith(UPDATE_FEED); + expect(UPDATE_FEED.repo).toBe('OpenPood'); + const pkg = JSON.parse(readFileSync('package.json', 'utf8')) as { build: { publish: { provider: string; owner: string; repo: string } } }; + expect(pkg.build.publish).toMatchObject({ provider: UPDATE_FEED.provider, owner: UPDATE_FEED.owner, repo: UPDATE_FEED.repo }); + }); it('requires explicit download and install, and excludes prereleases/downgrades', async () => { const { client, controller } = fixture(); expect(client.autoDownload).toBe(false); diff --git a/electron/updater.ts b/electron/updater.ts index 2a4b1e5..22f6764 100644 --- a/electron/updater.ts +++ b/electron/updater.ts @@ -2,7 +2,15 @@ import type { AppUpdater, UpdateInfo } from 'electron-updater'; import type { UpdateStatus } from '../src/lib/updateTypes'; export const UPDATE_SCHEDULE = { startupDelayMs: 15_000, intervalMs: 6 * 60 * 60 * 1000 }; -type Client = Pick; +// Installed v1.0.3 builds still have gotzastory/OpenPud in app-update.yml. +// New builds ask GitHub for this repository directly. +export const UPDATE_FEED = { + provider: 'github', + owner: 'gotzastory', + repo: 'OpenPood', + releaseType: 'release', +} as const; +type Client = Pick; function notes(info: UpdateInfo): string { const value = typeof info.releaseNotes === 'string' @@ -40,6 +48,7 @@ export class UpdateController { this.prepareInstall = prepareInstall; this.restoreAfterFailure = restoreAfterFailure; this.status = { phase: enabled ? 'idle' : 'disabled', currentVersion, busy: false }; + client.setFeedURL(UPDATE_FEED); client.autoDownload = false; client.autoInstallOnAppQuit = false; client.allowPrerelease = false; diff --git a/electron/winHost.test.ts b/electron/winHost.test.ts new file mode 100644 index 0000000..c499c0a --- /dev/null +++ b/electron/winHost.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it } from 'vitest'; +import { HOST_SCRIPT } from './winHost'; + +function pasteBranch(script: string): string { + const start = script.indexOf("'paste'"); + const end = script.indexOf("'clipboard'"); + return script.slice(start, end); +} + +describe('PowerShell host paste replies', () => { + it('replies to a declined paste and stays in the host loop so the reply is flushed', () => { + const paste = pasteBranch(HOST_SCRIPT); + expect(paste).toContain('clipboard-changed'); + expect(paste).toContain('focus-changed'); + expect(paste).not.toMatch(/\b(break|continue|exit|return)\b/); + const declinedAt = HOST_SCRIPT.indexOf('clipboard-changed'); + const flushAt = HOST_SCRIPT.lastIndexOf('$out.Flush()'); + expect(declinedAt).toBeGreaterThan(-1); + expect(flushAt).toBeGreaterThan(declinedAt); + expect(HOST_SCRIPT.match(/\bbreak\b/g)).toEqual(['break']); + expect(HOST_SCRIPT).toContain('if ($null -eq $line) { break }'); + }); +}); diff --git a/electron/winHost.ts b/electron/winHost.ts index 2d7aa19..fa62512 100644 --- a/electron/winHost.ts +++ b/electron/winHost.ts @@ -26,7 +26,8 @@ const READY_TIMEOUT_MS = 15000; // SendInput with virtual-key codes rather than WinForms SendKeys("^v"): // SendKeys maps the letter "v" through the active keyboard layout — with Thai // Kedmanee active that is not physical V, so Ctrl+V silently does nothing. -const HOST_SCRIPT = ` +// Exported so tests can check the host loop without launching PowerShell. +export const HOST_SCRIPT = ` [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 Add-Type -TypeDefinition @" using System; @@ -130,16 +131,16 @@ while ($true) { } 'paste' { if ($commandParts.Length -ne 3 -or $commandParts[1] -notmatch '^[1-9][0-9]*$' -or $commandParts[2] -notmatch '^[0-9]+$') { throw 'invalid paste target' } + # Stay inside this switch case. A loop-control statement here would leave + # the while, skip the flush below, and end the host process. if ([OpenPoodNative]::GetClipboardSequenceNumber() -ne [uint32]$commandParts[2]) { $out.WriteLine("$id ok clipboard-changed") - break - } - if ([OpenPoodNative]::GetForegroundWindow().ToInt64() -ne [int64]$commandParts[1]) { + } elseif ([OpenPoodNative]::GetForegroundWindow().ToInt64() -ne [int64]$commandParts[1]) { $out.WriteLine("$id ok focus-changed") - break + } else { + [OpenPoodNative]::CtrlV() + $out.WriteLine("$id ok pasted") } - [OpenPoodNative]::CtrlV() - $out.WriteLine("$id ok pasted") } 'clipboard' { $sequence = [OpenPoodNative]::GetClipboardSequenceNumber() diff --git a/package-lock.json b/package-lock.json index d172ee2..480498a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@fontsource/kanit": "^5.3.0", "electron-store": "^11.0.2", - "electron-updater": "^6.8.9", + "electron-updater": "6.8.11", "react": "^19.3.0", "react-dom": "^19.3.0" }, @@ -23,7 +23,7 @@ "concurrently": "^10.0.3", "cross-env": "^10.1.0", "daisyui": "^5.7.47", - "electron": "^43.2.0", + "electron": "^43.8.7", "electron-builder": "^26.15.3", "tailwindcss": "^4.3.3", "typescript": "~6.0.2", @@ -738,9 +738,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -758,9 +755,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -778,9 +772,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -798,9 +789,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -818,9 +806,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -838,9 +823,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1119,9 +1101,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1143,9 +1122,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1167,9 +1143,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1191,9 +1164,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1366,9 +1336,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1386,9 +1353,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1406,9 +1370,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1426,9 +1387,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2936,9 +2894,9 @@ } }, "node_modules/electron": { - "version": "43.7.7", - "resolved": "https://registry.npmjs.org/electron/-/electron-43.7.7.tgz", - "integrity": "sha512-y0pg+KhWLAkW2Ts2njkFFNFl3KtB1FmbUp9Te9i+R2Og2v1fcI/I6MADJ7jvnzB5UKdt+U+0EUoCnVL79xMPMA==", + "version": "43.8.7", + "resolved": "https://registry.npmjs.org/electron/-/electron-43.8.7.tgz", + "integrity": "sha512-F3Z7xEYlS62Re9Y2WCRhB8jFIkDwpUO7wjJ85l8NpPEgQ/CEyBvwtYEsNY2lioT7VOWi2vBrnMckCvXBkq+Cnw==", "dev": true, "license": "MIT", "dependencies": { @@ -3242,9 +3200,9 @@ } }, "node_modules/electron-updater": { - "version": "6.8.9", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.9.tgz", - "integrity": "sha512-ZhVxM9iGONUpZGI1FxdMRgJjUFXi7AYGVa5PwKlO1tV1/4zDxQmfKpXOHVztKrd6L9rLcFjERvi1Mf2vxyTkig==", + "version": "6.8.11", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.11.tgz", + "integrity": "sha512-12U/mbzaIKQS3Q543aQ7DjyAZMXeVJy1Wpu0qdq5ne4RXpIQDpWYm25zRjgXngAoo6swMrm4C4owGyiIipelsg==", "license": "MIT", "dependencies": { "builder-util-runtime": "9.7.0", @@ -3525,9 +3483,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", - "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.9.tgz", + "integrity": "sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==", "funding": [ { "type": "github", @@ -4319,9 +4277,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4343,9 +4298,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4367,9 +4319,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4391,9 +4340,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ diff --git a/package.json b/package.json index 3245f1e..cb1a35e 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "concurrently": "^10.0.3", "cross-env": "^10.1.0", "daisyui": "^5.7.47", - "electron": "^43.2.0", + "electron": "^43.8.7", "electron-builder": "^26.15.3", "tailwindcss": "^4.3.3", "typescript": "~6.0.2", @@ -35,7 +35,7 @@ "dependencies": { "@fontsource/kanit": "^5.3.0", "electron-store": "^11.0.2", - "electron-updater": "^6.8.9", + "electron-updater": "6.8.11", "react": "^19.3.0", "react-dom": "^19.3.0" }, @@ -45,7 +45,7 @@ "publish": { "provider": "github", "owner": "gotzastory", - "repo": "OpenPud", + "repo": "OpenPood", "releaseType": "release" }, "directories": { @@ -63,5 +63,8 @@ "artifactName": "${productName}-Setup-${version}.${ext}", "guid": "3d3b2486-1b4f-5e19-895e-ab7f29245ba3" } + }, + "overrides": { + "fast-uri": "3.1.9" } } diff --git a/src/lib/runtimeConfig.ts b/src/lib/runtimeConfig.ts index 4a30c7f..80b2001 100644 --- a/src/lib/runtimeConfig.ts +++ b/src/lib/runtimeConfig.ts @@ -16,7 +16,6 @@ export const RUNTIME = { widgetRecoveryDelayMs: 1_000, widgetRecoveryAttempts: 3, widgetRecoveryWindowMs: 60_000, - foregroundCaptureTimeoutMs: 300, clipboardSettleMs: 40, clipboardRestoreMs: 1_000, maxClipboardBytes: 32 * 1024 * 1024,