fix: read/write the library via the host ingest inbox (de-privileged runner)
CI / publish (push) Successful in 17s
CI / exporter (push) Successful in 11s
CI / build (push) Successful in 20s

The host plugin runner is de-privileged now (LocalService) and can't read the
interactive user's %APPDATA%\Playnite\ExtensionsData — so it never saw the
export. Bridge it through the host's user-writable ingest inbox:

- exporter (C#): also drop punktfunk-library.json into
  %ProgramData%\punktfunk\ingest\playnite (best-effort, only when a punktfunk
  host is present), alongside its ExtensionsData home.
- plugin (TS): locateExport() reads <config_dir>/ingest/playnite first, then
  falls back to the ExtensionsData scan (same-user/SYSTEM runner, Linux). The
  watcher also watches the inbox so a drop reconciles within seconds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 00:40:28 +02:00
parent 1eb0f650ab
commit e832201669
6 changed files with 133 additions and 31 deletions
+20
View File
@@ -44,6 +44,26 @@ describe("locateExport", () => {
expect(loc.dir).toBe(dir);
expect(loc.file).toBeNull();
});
test("reads the ingest inbox first — the de-privileged runner's source", () => {
const cfg = fs.mkdtempSync(path.join(os.tmpdir(), "pf-cfg-"));
const prev = process.env.PUNKTFUNK_CONFIG_DIR;
process.env.PUNKTFUNK_CONFIG_DIR = cfg;
try {
const inbox = path.join(cfg, "ingest", "playnite");
fs.mkdirSync(inbox, { recursive: true });
fs.writeFileSync(path.join(inbox, EXPORT_FILE), JSON.stringify(validDoc));
// Even with a Playnite ExtensionsData dir present, the ingest drop wins.
const pd = layout("with-ingest", validDoc);
const loc = locateExport(resolveConfig({ playniteDir: pd }));
expect(loc.dir).toBe(inbox);
expect(loc.file).toBe(path.join(inbox, EXPORT_FILE));
} finally {
if (prev === undefined) delete process.env.PUNKTFUNK_CONFIG_DIR;
else process.env.PUNKTFUNK_CONFIG_DIR = prev;
fs.rmSync(cfg, { recursive: true, force: true });
}
});
});
describe("readExport", () => {