fix(anime): rescan runtime after preference cleanup failures

- Keep extension removal reflected in the runtime when preference cleanup fails
- Clarify auto-open playback resume behavior in configuration docs
This commit is contained in:
2026-09-02 23:28:32 -07:00
parent 68dd789fbf
commit 7bc9a07a52
6 changed files with 36 additions and 7 deletions
@@ -1,6 +1,6 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtemp, readFile, writeFile } from 'node:fs/promises';
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import type { BridgePreference } from '../../anime-bridge/types';
@@ -145,6 +145,32 @@ test('colliding bridge ids keep package preferences isolated and uninstall clear
await runtime.dispose();
});
test('uninstall rescans after preference cleanup fails and propagates the failure', async () => {
const saved = textPreference('password', 'secret');
const client = {
listAnimeSources: async () => [{ id: 'shared', name: 'Source', lang: 'en' }],
getSourcePreferences: async () => [textPreference('password')],
};
const { runtime, preferencesFile } = await setupRuntime(
client,
{ 'pkg.one': 'one' },
{ 'pkg.one:shared': [saved] },
);
await runtime.getPreferences('pkg.one:shared');
const blockedTemporaryFile = `${preferencesFile}.tmp`;
await mkdir(blockedTemporaryFile);
try {
await assert.rejects(runtime.removeExtension('pkg.one'));
assert.deepEqual(runtime.getSnapshot().installed, []);
assert.deepEqual(runtime.getSnapshot().sources, []);
} finally {
await chmod(blockedTemporaryFile, 0o700);
await rm(blockedTemporaryFile, { recursive: true, force: true });
await runtime.dispose();
}
});
test('standalone and modal browser sessions keep source selection and searches isolated', async () => {
const client = {
listAnimeSources: async () => [{ id: 'shared', name: 'Source', lang: 'en' }],
+5 -2
View File
@@ -632,8 +632,11 @@ export function createAnimeBrowserRuntime(deps: AnimeBrowserRuntimeDeps) {
removeExtension(pkg: string): Promise<void> {
return withExtensionMutation(async () => {
await removeExtensionFile(deps.extensionsDir(), pkg);
await preferenceStore.clear(pkg).catch(() => undefined);
if (sidecar) await scanExtensions(sidecar);
try {
await preferenceStore.clear(pkg);
} finally {
if (sidecar) await scanExtensions(sidecar);
}
});
},