Files
SubMiner/package.json
T
sudacode 78eca52b7e test: add headless end-to-end harness (#286)
* test: add headless end-to-end harness and CI job

Boot the built app against a real mpv, a synthetic clip, a fixture Yomitan
dictionary, and a fake AnkiConnect inside a private Xvfb display, then assert
on the overlay DOM and the AnkiConnect requests. Adds the test:e2e lane, an
e2e session CLI for exploratory checks, and a three-platform CI job.

* ci: set e2e temp dir from a step

* test: make e2e session startup robust on slow machines

Bun caps node:test hooks at 5s, so boot the session inside the first test.
Keep pausing until the app's resume retries stop, read cue tokens in one
round trip, and resolve Electron through its package entry so CI downloads
the binary.

* test: harden e2e harness for CI runners

Fail fast when mpv cannot be spawned, read every Yomitan popup frame instead
of trusting target order, and put the chocolatey mpv directory on PATH.

* test: add e2e failure diagnostics and mark Windows job experimental

Report what the overlay showed when a cue never renders, dispose the session
when the overlay cannot be opened, skip popup frames that vanish mid-poll,
and turn off AniSkip lookups in the harness config.

* test: read the lookup popup entry from textContent

* test: capture renderer console and main-side subtitle state in e2e failures

* test: expose the Electron main-process inspector to the e2e harness

Adds session.mainProcess() and 'e2e eval main', and reports main's window
list alongside the overlay state when a cue never renders.

* test: tap subtitle sends and receipts in e2e failure diagnostics

* test: probe alternate main-to-renderer paths in e2e failure diagnostics

* test: select the visible overlay layer, not the primed modal window

Windows and macOS pre-create a hidden modal window that loads the same
renderer document, and the harness could attach to it instead of the
visible overlay. Drops the delivery taps that found this.

* ci: run the Windows e2e job as a normal matrix entry

* test: address review on e2e harness

Slice the app log at a byte offset before decoding, create the session state
file owner-only since it carries the inspector URL, and keep the cue failure
when inspector diagnostics are unavailable.

* test: create the e2e session state file exclusively
2026-10-05 22:00:58 -07:00

280 lines
13 KiB
JSON

{
"name": "subminer",
"productName": "SubMiner",
"desktopName": "SubMiner.desktop",
"version": "0.20.1",
"description": "All-in-one sentence mining overlay with AnkiConnect and dictionary integration",
"packageManager": "bun@1.3.5",
"main": "dist/main-entry.js",
"scripts": {
"typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
"typecheck:watch": "tsc --watch --preserveWatchOutput -p tsconfig.typecheck.json",
"get-frequency": "bun run scripts/get_frequency.ts --pretty --color-top-x 10000 --yomitan-user-data ~/.config/SubMiner --colorized-line",
"get-frequency:electron": "bun run build:yomitan && bun build scripts/get_frequency.ts --format=cjs --target=node --outfile dist/scripts/get_frequency.js --external electron && env -u ELECTRON_RUN_AS_NODE electron dist/scripts/get_frequency.js --pretty --color-top-x 10000 --yomitan-user-data ~/.config/SubMiner --colorized-line",
"test-yomitan-parser": "bun run scripts/test-yomitan-parser.ts",
"test-yomitan-parser:electron": "bun run build:yomitan && bun build scripts/test-yomitan-parser.ts --format=cjs --target=node --outfile dist/scripts/test-yomitan-parser.js --external electron && env -u ELECTRON_RUN_AS_NODE electron dist/scripts/test-yomitan-parser.js",
"verify-known-word-highlights:electron": "bun run build:yomitan && bun build scripts/verify-known-word-highlights.ts --format=cjs --target=node --outfile dist/scripts/verify-known-word-highlights.js --packages=external && env -u ELECTRON_RUN_AS_NODE electron dist/scripts/verify-known-word-highlights.js",
"record-tokenizer-fixture:electron": "bun run build:yomitan && bun build scripts/record-tokenizer-fixture.ts --format=cjs --target=node --outfile dist/scripts/record-tokenizer-fixture.js --external electron && env -u ELECTRON_RUN_AS_NODE electron dist/scripts/record-tokenizer-fixture.js",
"compare-yomitan-api:electron": "bun run build:yomitan && bun build scripts/compare-yomitan-api.ts --format=cjs --target=node --outfile dist/scripts/compare-yomitan-api.js --external electron && env -u ELECTRON_RUN_AS_NODE electron dist/scripts/compare-yomitan-api.js",
"build:yomitan": "bun scripts/build-yomitan.mjs",
"build:assets": "bun scripts/prepare-build-assets.mjs",
"build:launcher": "bun run scripts/build-launcher.ts",
"build:stats": "cd stats && bun run build",
"dev:stats": "cd stats && bun run dev",
"build": "bun run build:yomitan && bun run build:stats && tsc -p tsconfig.json && bun run build:renderer && bun run build:settings && bun run build:syncui && bun run build:launcher && bun run build:assets",
"build:renderer": "esbuild src/renderer/renderer.ts --bundle --platform=browser --format=esm --target=es2022 --outfile=dist/renderer/renderer.js --sourcemap",
"build:settings": "esbuild src/settings/settings.ts --bundle --platform=browser --format=esm --target=es2022 --outfile=dist/settings/settings.js --sourcemap",
"build:syncui": "esbuild src/syncui/syncui.ts --bundle --platform=browser --format=esm --target=es2022 --outfile=dist/syncui/syncui.js --sourcemap && esbuild src/preload-syncui.ts --bundle --platform=node --format=cjs --target=node20 --external:electron --outfile=dist/preload-syncui.js --sourcemap",
"changelog:build": "bun run scripts/build-changelog.ts build-release",
"changelog:check": "bun run scripts/build-changelog.ts check",
"changelog:docs": "bun run scripts/build-changelog.ts docs",
"changelog:lint": "bun run scripts/build-changelog.ts lint",
"changelog:pr-check": "bun run scripts/build-changelog.ts pr-check",
"changelog:release-notes": "bun run scripts/build-changelog.ts release-notes",
"changelog:prerelease-notes": "bun run scripts/build-changelog.ts prerelease-notes",
"changelog:check-prerelease-notes": "bun run scripts/build-changelog.ts check-prerelease-notes",
"format": "prettier --write .",
"format:check": "prettier --check .",
"format:src": "bash scripts/prettier-scope.sh --write",
"format:check:src": "bash scripts/prettier-scope.sh --check",
"format:stats": "bun x prettier --write stats/index.html stats/package.json stats/src stats/tsconfig.json stats/vite.config.ts",
"format:check:stats": "bun x prettier --check stats/index.html stats/package.json stats/src stats/tsconfig.json stats/vite.config.ts",
"typecheck:stats": "cd stats && bun x tsc --noEmit -p tsconfig.json",
"lint:stats": "bun run format:check:stats",
"lint:stats:typecheck": "bun run typecheck:stats",
"lint": "bun run lint:stats",
"docs:dev": "bun run --cwd docs-site docs:dev",
"docs:build": "bun run --cwd docs-site docs:build",
"docs:build:versioned": "bun run scripts/build-versioned-docs.ts",
"docs:preview": "bun run --cwd docs-site docs:preview",
"docs:test": "bun run --cwd docs-site test",
"test:docs:kb": "bun test scripts/docs-knowledge-base.test.ts",
"test:plugin:src": "lua scripts/test-plugin-lua-compat.lua && lua scripts/test-plugin-start-gate.lua && lua scripts/test-plugin-process-start-retries.lua && lua scripts/test-plugin-restart-feedback.lua && lua scripts/test-plugin-session-bindings.lua && lua scripts/test-plugin-binary-windows.lua",
"test:launcher:smoke:src": "bun test launcher/smoke.e2e.test.ts",
"test:smoke:dist": "env ELECTRON_RUN_AS_NODE=1 electron scripts/compiled-runtime-smoke.mjs",
"test:subtitle:src": "bun test src/core/services/subsync.test.ts src/subsync/utils.test.ts",
"test:immersion:sqlite:src": "bun test src/core/services/immersion-tracker-service.test.ts src/core/services/immersion-tracker/storage-session.test.ts",
"test:immersion:sqlite:dist": "bun test dist/core/services/immersion-tracker-service.test.js dist/core/services/immersion-tracker/storage-session.test.js",
"test:immersion:sqlite": "bun run tsc && bun run test:immersion:sqlite:dist",
"test:src": "bun run build:yomitan && bun scripts/run-test-lane.mjs bun-src-full",
"test:coverage:src": "bun run build:yomitan && bun run scripts/run-coverage-lane.ts bun-src-full --coverage-dir coverage/test-src",
"test:coverage:subtitle:src": "bun test --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir coverage/test-subtitle src/core/services/subsync.test.ts src/subsync/utils.test.ts",
"test:launcher:unit:src": "bun scripts/run-test-lane.mjs bun-launcher-unit",
"test:scripts": "bun scripts/run-test-lane.mjs scripts",
"test:stats": "bun scripts/run-test-lane.mjs stats",
"test:e2e": "bun scripts/run-test-lane.mjs e2e --jobs 1",
"e2e": "bun e2e/cli.ts",
"test:env": "bun run test:launcher:smoke:src && bun run test:plugin:src && bun run test:immersion:sqlite:src",
"test:runtime:compat": "bun run test:smoke:dist",
"test": "bun run test:fast",
"test:config": "bun scripts/run-test-lane.mjs config",
"test:launcher": "bun scripts/run-test-lane.mjs launcher && bun run test:plugin:src",
"test:subtitle": "bun run test:subtitle:src",
"test:fast": "bun run test:src && bun run test:launcher:unit:src && bun run test:scripts",
"generate:config-example": "bun run src/generate-config-example.ts",
"verify:config-example": "bun run src/verify-config-example.ts",
"start": "bun run build && electron . --start",
"dev": "bun run build && electron . --start --dev",
"stop": "electron . --stop",
"toggle": "electron . --toggle",
"build:appimage": "bun run build && electron-builder --linux AppImage --publish never",
"build:mac": "bun run build && electron-builder --mac dmg zip --publish never",
"build:mac:unsigned": "bun run build && env -u APPLE_ID -u APPLE_APP_SPECIFIC_PASSWORD -u APPLE_TEAM_ID -u CSC_LINK -u CSC_KEY_PASSWORD CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --mac dmg zip --publish never",
"build:mac:zip": "bun run build && electron-builder --mac zip --publish never",
"build:win": "bun run build && electron-builder --win nsis zip --publish never",
"build:win:unsigned": "bun run build && node scripts/build-win-unsigned.mjs",
"test:package": "bun scripts/run-package-smoke.mjs"
},
"overrides": {
"@xmldom/xmldom": "0.8.15",
"app-builder-lib": "26.16.1",
"brace-expansion": "5.0.11",
"electron-builder-squirrel-windows": "26.16.1",
"fast-uri": "3.1.7",
"form-data": "4.0.6",
"ip-address": "10.2.0",
"js-yaml": "4.3.2",
"lodash": "4.18.0",
"minimatch": "10.2.5",
"picomatch": "4.0.4",
"tar": "7.5.21",
"tmp": "0.2.7",
"undici": "7.29.1"
},
"keywords": [
"anki",
"ankiconnect",
"sentence-mining",
"japanese",
"subtitles",
"overlay",
"mpv",
"yomitan"
],
"author": "",
"license": "GPL-3.0-or-later",
"dependencies": {
"@fontsource-variable/geist": "^5.2.8",
"@fontsource-variable/geist-mono": "^5.2.7",
"@xhayper/discord-rpc": "^1.3.4",
"axios": "^1.20.0",
"commander": "^14.0.3",
"electron-updater": "^6.8.9",
"hono": "^4.12.28",
"jsonc-parser": "^3.3.1",
"koffi": "^2.15.6",
"libsql": "^0.5.22",
"ws": "^8.21.0"
},
"devDependencies": {
"@electron/asar": "3.4.1",
"@types/node": "^24.10.0",
"@types/ws": "^8.18.1",
"electron": "43.7.7",
"electron-builder": "26.16.1",
"esbuild": "^0.25.12",
"eslint": "^10.8.0",
"prettier": "^3.8.1",
"typescript": "^5.9.3",
"undici": "7.29.1"
},
"build": {
"appId": "com.sudacode.SubMiner",
"productName": "SubMiner",
"executableName": "SubMiner",
"artifactName": "SubMiner-${version}.${ext}",
"afterPack": "scripts/electron-builder-after-pack.cjs",
"icon": "assets/SubMiner-square.png",
"directories": {
"output": "release"
},
"publish": [
{
"provider": "github",
"owner": "ksyasuda",
"repo": "SubMiner"
}
],
"electronUpdaterCompatibility": ">=2.16",
"linux": {
"target": [
"AppImage"
],
"category": "AudioVideo",
"executableArgs": [
"--background"
],
"files": [
"package.json",
"!node_modules/koffi{,/**/*}"
]
},
"mac": {
"artifactName": "SubMiner-${version}-mac.${ext}",
"target": [
"dmg",
"zip"
],
"category": "public.app-category.video",
"icon": "assets/SubMiner-square.png",
"hardenedRuntime": true,
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist",
"extraResources": [
{
"from": "dist/scripts/get-mpv-window-macos",
"to": "scripts/get-mpv-window-macos"
}
],
"files": [
"package.json",
"!node_modules/koffi{,/**/*}"
]
},
"dmg": {
"artifactName": "SubMiner-${version}.${ext}"
},
"win": {
"artifactName": "SubMiner-${version}-win.${ext}",
"target": [
"nsis",
"zip"
],
"icon": "assets/SubMiner.ico",
"files": [
"package.json",
"!node_modules/koffi/build/koffi/!(win32_${arch}){,/**/*}"
]
},
"nsis": {
"artifactName": "SubMiner-${version}.${ext}",
"oneClick": false,
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"include": "build/installer.nsh"
},
"files": [
"dist/**/*",
"stats/dist/**/*",
"vendor/texthooker-ui/docs/**/*",
"config.example.jsonc",
"LICENSE",
"!**/*.map",
"!**/*.{ts,tsx,mts,cts}",
"!**/*.{test,spec}.*",
"!**/{test,tests,__tests__,fixture,fixtures,__fixtures__}{,/**/*}",
"!dist/launcher{,/**/*}",
"!dist/scripts{,/**/*}",
"!dist/{renderer,settings,syncui}/fonts{,/**/*}",
"!node_modules/koffi/{src,vendor,doc}{,/**/*}",
"!node_modules/@libsql/linux-x64-musl{,/**/*}"
],
"extraResources": [
{
"from": "build/yomitan",
"to": "yomitan"
},
{
"from": "vendor/yomitan-jlpt-vocab",
"to": "yomitan-jlpt-vocab"
},
{
"from": "assets",
"to": "assets",
"filter": [
"SubMiner*.png",
"SubMiner.ico",
"themes/**/*",
"thumbnailers/**/*"
]
},
{
"from": "plugin/subminer",
"to": "plugin/subminer"
},
{
"from": "plugin/subminer.conf",
"to": "plugin/subminer.conf"
},
{
"from": "dist/launcher",
"to": "launcher",
"filter": [
"subminer",
"subminer.cmd",
"subminer.js",
"prepare.cjs",
"version"
]
},
{
"from": "CHANGELOG.md",
"to": "CHANGELOG.md"
}
]
},
"patchedDependencies": {
"@discordjs/rest@2.6.1": "patches/@discordjs%2Frest@2.6.1.patch"
}
}