Compare commits

...

3 Commits

Author SHA1 Message Date
f79e6bde3b test: mock win32 in overlay runtime init test 2026-04-10 03:12:26 -07:00
bd5275fbf8 fix: refresh lockfile for prerelease 2026-04-10 03:09:46 -07:00
3281a7b39e chore(release): prep v0.12.0-beta.2 prerelease 2026-04-10 03:03:51 -07:00
3 changed files with 74 additions and 52 deletions

View File

@@ -12,6 +12,7 @@
"commander": "^14.0.3",
"hono": "^4.12.7",
"jsonc-parser": "^3.3.1",
"koffi": "^2.15.6",
"libsql": "^0.5.22",
"ws": "^8.19.0",
},
@@ -478,6 +479,8 @@
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
"koffi": ["koffi@2.15.6", "", {}, "sha512-WQBpM5uo74UQ17UpsFN+PUOrQQg4/nYdey4SGVluQun2drYYfePziLLWdSmFb4wSdWlJC1aimXQnjhPCheRKuw=="],
"lazy-val": ["lazy-val@1.0.5", "", {}, "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q=="],
"libsql": ["libsql@0.5.28", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.5.28", "@libsql/darwin-x64": "0.5.28", "@libsql/linux-arm-gnueabihf": "0.5.28", "@libsql/linux-arm-musleabihf": "0.5.28", "@libsql/linux-arm64-gnu": "0.5.28", "@libsql/linux-arm64-musl": "0.5.28", "@libsql/linux-x64-gnu": "0.5.28", "@libsql/linux-x64-musl": "0.5.28", "@libsql/win32-x64-msvc": "0.5.28" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "arm", "x64", "arm64", ] }, "sha512-wKqx9FgtPcKHdPfR/Kfm0gejsnbuf8zV+ESPmltFvsq5uXwdeN9fsWn611DmqrdXj1e94NkARcMA2f1syiAqOg=="],

View File

@@ -2,7 +2,7 @@
"name": "subminer",
"productName": "SubMiner",
"desktopName": "SubMiner.desktop",
"version": "0.12.0-beta.1",
"version": "0.12.0-beta.2",
"description": "All-in-one sentence mining overlay with AnkiConnect and dictionary integration",
"packageManager": "bun@1.3.5",
"main": "dist/main-entry.js",

View File

@@ -2,6 +2,23 @@ import assert from 'node:assert/strict';
import test from 'node:test';
import { initializeOverlayAnkiIntegration, initializeOverlayRuntime } from './overlay-runtime-init';
function withPlatform(platform: NodeJS.Platform, run: () => void): void {
const originalPlatform = process.platform;
Object.defineProperty(process, 'platform', {
value: platform,
configurable: true,
});
try {
run();
} finally {
Object.defineProperty(process, 'platform', {
value: originalPlatform,
configurable: true,
});
}
}
test('initializeOverlayRuntime skips Anki integration when ankiConnect.enabled is false', () => {
let createdIntegrations = 0;
let startedIntegrations = 0;
@@ -548,59 +565,61 @@ test('initializeOverlayRuntime hides overlay windows when tracker loses the targ
});
test('initializeOverlayRuntime preserves visible overlay on Windows tracker loss when target is not minimized', () => {
const calls: string[] = [];
const tracker = {
onGeometryChange: null as ((...args: unknown[]) => void) | null,
onWindowFound: null as ((...args: unknown[]) => void) | null,
onWindowLost: null as (() => void) | null,
onWindowFocusChange: null as ((focused: boolean) => void) | null,
isTargetWindowMinimized: () => false,
start: () => {},
};
const overlayWindows = [
{
hide: () => calls.push('hide-visible'),
},
];
withPlatform('win32', () => {
const calls: string[] = [];
const tracker = {
onGeometryChange: null as ((...args: unknown[]) => void) | null,
onWindowFound: null as ((...args: unknown[]) => void) | null,
onWindowLost: null as (() => void) | null,
onWindowFocusChange: null as ((focused: boolean) => void) | null,
isTargetWindowMinimized: () => false,
start: () => {},
};
const overlayWindows = [
{
hide: () => calls.push('hide-visible'),
},
];
initializeOverlayRuntime({
backendOverride: null,
createMainWindow: () => {},
registerGlobalShortcuts: () => {},
updateVisibleOverlayBounds: () => {},
isVisibleOverlayVisible: () => true,
updateVisibleOverlayVisibility: () => {
calls.push('update-visible');
},
refreshCurrentSubtitle: () => {},
getOverlayWindows: () => overlayWindows as never,
syncOverlayShortcuts: () => {
calls.push('sync-shortcuts');
},
setWindowTracker: () => {},
getMpvSocketPath: () => '/tmp/mpv.sock',
createWindowTracker: () => tracker as never,
getResolvedConfig: () => ({
ankiConnect: { enabled: false } as never,
}),
getSubtitleTimingTracker: () => null,
getMpvClient: () => null,
getRuntimeOptionsManager: () => null,
setAnkiIntegration: () => {},
showDesktopNotification: () => {},
createFieldGroupingCallback: () => async () => ({
keepNoteId: 1,
deleteNoteId: 2,
deleteDuplicate: false,
cancelled: false,
}),
getKnownWordCacheStatePath: () => '/tmp/known-words-cache.json',
initializeOverlayRuntime({
backendOverride: null,
createMainWindow: () => {},
registerGlobalShortcuts: () => {},
updateVisibleOverlayBounds: () => {},
isVisibleOverlayVisible: () => true,
updateVisibleOverlayVisibility: () => {
calls.push('update-visible');
},
refreshCurrentSubtitle: () => {},
getOverlayWindows: () => overlayWindows as never,
syncOverlayShortcuts: () => {
calls.push('sync-shortcuts');
},
setWindowTracker: () => {},
getMpvSocketPath: () => '/tmp/mpv.sock',
createWindowTracker: () => tracker as never,
getResolvedConfig: () => ({
ankiConnect: { enabled: false } as never,
}),
getSubtitleTimingTracker: () => null,
getMpvClient: () => null,
getRuntimeOptionsManager: () => null,
setAnkiIntegration: () => {},
showDesktopNotification: () => {},
createFieldGroupingCallback: () => async () => ({
keepNoteId: 1,
deleteNoteId: 2,
deleteDuplicate: false,
cancelled: false,
}),
getKnownWordCacheStatePath: () => '/tmp/known-words-cache.json',
});
calls.length = 0;
tracker.onWindowLost?.();
assert.deepEqual(calls, ['sync-shortcuts']);
});
calls.length = 0;
tracker.onWindowLost?.();
assert.deepEqual(calls, ['sync-shortcuts']);
});
test('initializeOverlayRuntime restores overlay bounds and visibility when tracker finds the target window again', () => {