refactor(core): normalize core service naming

Standardize core service module and export names to reduce naming ambiguity and make imports predictable across runtime, tests, scripts, and docs.
This commit is contained in:
2026-02-17 01:18:10 -08:00
parent 02034e6dc7
commit a359e91b14
80 changed files with 793 additions and 771 deletions

View File

@@ -0,0 +1,105 @@
import test from "node:test";
import assert from "node:assert/strict";
import { AppReadyRuntimeDeps, runAppReadyRuntime } from "./startup";
function makeDeps(overrides: Partial<AppReadyRuntimeDeps> = {}) {
const calls: string[] = [];
const deps: AppReadyRuntimeDeps = {
loadSubtitlePosition: () => calls.push("loadSubtitlePosition"),
resolveKeybindings: () => calls.push("resolveKeybindings"),
createMpvClient: () => calls.push("createMpvClient"),
reloadConfig: () => calls.push("reloadConfig"),
getResolvedConfig: () => ({ websocket: { enabled: "auto" }, secondarySub: {} }),
getConfigWarnings: () => [],
logConfigWarning: () => calls.push("logConfigWarning"),
setLogLevel: (level, source) => calls.push(`setLogLevel:${level}:${source}`),
initRuntimeOptionsManager: () => calls.push("initRuntimeOptionsManager"),
setSecondarySubMode: (mode) => calls.push(`setSecondarySubMode:${mode}`),
defaultSecondarySubMode: "hover",
defaultWebsocketPort: 9001,
hasMpvWebsocketPlugin: () => true,
startSubtitleWebsocket: (port) => calls.push(`startSubtitleWebsocket:${port}`),
log: (message) => calls.push(`log:${message}`),
createMecabTokenizerAndCheck: async () => {
calls.push("createMecabTokenizerAndCheck");
},
createSubtitleTimingTracker: () => calls.push("createSubtitleTimingTracker"),
createImmersionTracker: () => calls.push("createImmersionTracker"),
loadYomitanExtension: async () => {
calls.push("loadYomitanExtension");
},
texthookerOnlyMode: false,
shouldAutoInitializeOverlayRuntimeFromConfig: () => true,
initializeOverlayRuntime: () => calls.push("initializeOverlayRuntime"),
handleInitialArgs: () => calls.push("handleInitialArgs"),
...overrides,
};
return { deps, calls };
}
test("runAppReadyRuntime starts websocket in auto mode when plugin missing", async () => {
const { deps, calls } = makeDeps({
hasMpvWebsocketPlugin: () => false,
});
await runAppReadyRuntime(deps);
assert.ok(calls.includes("startSubtitleWebsocket:9001"));
assert.ok(calls.includes("initializeOverlayRuntime"));
assert.ok(calls.includes("createImmersionTracker"));
assert.ok(
calls.includes("log:Runtime ready: invoking createImmersionTracker."),
);
});
test("runAppReadyRuntimeService logs when createImmersionTracker dependency is missing", async () => {
const { deps, calls } = makeDeps({
createImmersionTracker: undefined,
});
await runAppReadyRuntimeService(deps);
assert.ok(
calls.includes(
"log:Runtime ready: createImmersionTracker dependency is missing.",
),
);
});
test("runAppReadyRuntimeService logs and continues when createImmersionTracker throws", async () => {
const { deps, calls } = makeDeps({
createImmersionTracker: () => {
calls.push("createImmersionTracker");
throw new Error("immersion init failed");
},
});
await runAppReadyRuntimeService(deps);
assert.ok(calls.includes("createImmersionTracker"));
assert.ok(
calls.includes(
"log:Runtime ready: createImmersionTracker failed: immersion init failed",
),
);
assert.ok(calls.includes("initializeOverlayRuntime"));
assert.ok(calls.includes("handleInitialArgs"));
});
test("runAppReadyRuntime logs defer message when overlay not auto-started", async () => {
const { deps, calls } = makeDeps({
shouldAutoInitializeOverlayRuntimeFromConfig: () => false,
});
await runAppReadyRuntime(deps);
assert.ok(
calls.includes(
"log:Overlay runtime deferred: waiting for explicit overlay command.",
),
);
});
test("runAppReadyRuntime applies config logging level during app-ready", async () => {
const { deps, calls } = makeDeps({
getResolvedConfig: () => ({
websocket: { enabled: "auto" },
secondarySub: {},
logging: { level: "warn" },
}),
});
await runAppReadyRuntime(deps);
assert.ok(calls.includes("setLogLevel:warn:config"));
});