fix(library): isolate per-type sync failures, suppress dry-run notices

syncAll() ran each enabled type's sync in sequence with no per-type
error handling, so one type throwing (e.g. its vault folder missing)
aborted the whole run and skipped libraryLastSync -- every other
enabled type silently never synced. Each type's runSync is now wrapped
individually: failures are logged (and surfaced via Notice unless
quiet) and the loop continues; libraryLastSync still updates after the
loop regardless.

Also: dry-run sync previews now route spec-level flip notifications
(the "chapter/issue out" Notices) through the log instead of a real
Notice, since a dry run never actually writes the change it's
describing.
This commit is contained in:
afiqzudinhadi 2026-08-03 22:09:04 +08:00
parent ea5ddd9454
commit 548e4c8ce0
2 changed files with 170 additions and 7 deletions

View file

@ -91,17 +91,25 @@ export class LibraryController {
};
}
private makeSpecDeps(): SpecDeps {
/** dryRun=true routes flip notifications to the log instead of a real Notice -- a dry-run
* preview shouldn't pop user-facing notices for changes that were never actually written. */
private makeSpecDeps(dryRun = false): SpecDeps {
return {
http: this.makeHttp(),
httpText: this.makeHttpText(),
getKey: name => this.getKey(name),
log: msg => console.log(`[media-db-library] ${msg}`),
notify: msg => this.notify(msg),
notify: msg => {
if (dryRun) {
console.log(`[media-db-library] [dry] ${msg}`);
} else {
this.notify(msg);
}
},
};
}
private makeDeps(spec: MediaTypeSpec): LibraryEngineDeps {
private makeDeps(spec: MediaTypeSpec, dryRun = false): LibraryEngineDeps {
const { app } = this.plugin;
const folderPath = this.folderFor(spec);
const folder = app.vault.getAbstractFileByPath(folderPath);
@ -122,7 +130,7 @@ export class LibraryController {
},
sleep: ms => new Promise(r => setTimeout(r, ms)),
log: msg => console.log(`[media-db-library] ${msg}`),
specDeps: this.makeSpecDeps(),
specDeps: this.makeSpecDeps(dryRun),
};
}
@ -140,7 +148,7 @@ export class LibraryController {
private async runSync(spec: MediaTypeSpec, full: boolean, dryRun: boolean, quiet: boolean): Promise<LibraryReport> {
this.warnMissingKey(spec, quiet);
const deps = this.makeDeps(spec);
const deps = this.makeDeps(spec, dryRun);
const report = await libraryFolderSync(spec, deps, { full, dryRun });
const mode = dryRun ? 'DRY-RUN ' : '';
if (shouldNotifySync(quiet, report.written, report.errors.length)) {
@ -172,7 +180,7 @@ export class LibraryController {
}
this.syncing = true;
try {
const deps = this.makeDeps(spec);
const deps = this.makeDeps(spec, dryRun);
const report = await libraryFolderResolve(spec, deps, { dryRun });
const mode = dryRun ? 'DRY-RUN ' : '';
this.notify(
@ -194,7 +202,15 @@ export class LibraryController {
try {
for (const spec of this.specs) {
if (!this.enabledFor(spec)) continue;
await this.runSync(spec, full, false, quiet);
try {
await this.runSync(spec, full, false, quiet);
} catch (e) {
// one type's failure (e.g. its vault folder is missing) must not abort the
// rest of the run -- log + surface it, then keep going with the other types
const msg = `Library sync failed for ${spec.typeName}: ${e instanceof Error ? e.message : String(e)}`;
console.log(`[media-db-library] ${msg}`);
if (!quiet) this.notify(msg);
}
}
if (!full) {
this.plugin.settings.libraryLastSync = Date.now();