refactor: rewrite on @punktfunk/plugin-kit — contract + plugin workspaces

The framework half of this plugin (engine lifecycle, config/state, host
reconcile, UI server, CLI) was ~80% identical to rom-manager's. That code is
now @punktfunk/plugin-kit; this replaces the local copy with it and adopts the
rom-manager blueprint layout.

  contract/  Effect Schemas: the cross-process export contract (the C#
             exporter's other half, with the schema-version guard as a decode
             check), the config schema (one schema, Encoded = authored file
             shape, defaults only via withDecodingDefaultKey), domain DTOs, the
             HttpApi contract, API errors.
  plugin/    src/domain = the pure core (locate/read, art, reconcile), ported
             tests green before any Effect wiring; src/services = the kit's
             ConfigService/CacheStore/SyncEngine/ProviderClient; definePluginKit
             entry, kit CLI, auth-free dev API.

Preserved, because they are what makes playnite work at all: the ingest inbox
is still read FIRST (the de-privileged LocalService runner cannot reach the
interactive user's %APPDATA%), the host/dataurl/off art modes, and the
playnite:// launch hand-back. The C# exporter is untouched.

New: per-game include/exclude overrides, and an allow-listed /api/art proxy so
the SPA can render local Playnite covers — it serves only paths the currently
ingested export references.

Dropped: the standalone password UI server (console surface + CLI only, as in
rom-manager 0.3.0) and the devEntry flag.

Trap found and fixed here: the HttpApi encoder serialises `undefined` as
`null`, so a `Schema.optional` field the server omits cannot be decoded by the
client — silently in the SSE feed, loudly in the typed client. Every optional
EngineStatus field is `Schema.NullOr` with an explicit value on the wire.
This commit is contained in:
2026-07-20 20:56:12 +02:00
parent e832201669
commit b81e03685a
59 changed files with 3408 additions and 2634 deletions
+10 -46
View File
@@ -1,55 +1,19 @@
{
"name": "@punktfunk/plugin-playnite",
"version": "0.1.1",
"private": false,
"name": "playnite-workspace",
"private": true,
"type": "module",
"description": "Punktfunk plugin: syncs your Playnite library into the host game library as a provider — every store and emulator Playnite manages, launched back through Playnite, with a console-hosted web UI. Pairs with the bundled Playnite exporter extension.",
"license": "MIT OR Apache-2.0",
"homepage": "https://git.unom.io/unom/punktfunk-plugin-playnite",
"repository": {
"type": "git",
"url": "https://git.unom.io/unom/punktfunk-plugin-playnite.git"
},
"bugs": {
"url": "https://git.unom.io/unom/punktfunk-plugin-playnite/issues"
},
"keywords": [
"punktfunk",
"workspaces": [
"contract",
"plugin",
"playnite",
"game-library",
"game-streaming"
"ui"
],
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"bin": {
"punktfunk-plugin-playnite": "./dist/cli.js"
},
"files": [
"dist"
],
"publishConfig": {
"registry": "https://git.unom.io/api/packages/unom/npm/"
},
"scripts": {
"typecheck": "tsc --noEmit",
"test": "bun test",
"build": "tsc -p tsconfig.build.json",
"build:ui": "cd ui && bun install --silent && bun run build",
"build:all": "bun run build && bun run build:ui",
"sync": "bun src/cli.ts sync",
"where": "bun src/cli.ts where",
"preview": "bun src/cli.ts preview",
"prepublishOnly": "bun run build:all"
},
"dependencies": {
"@punktfunk/host": "^0.1.1",
"effect": "^4.0.0-beta.98"
"typecheck": "cd contract && bun run typecheck && cd ../plugin && bun run typecheck && cd ../ui && bun run typecheck",
"test": "cd plugin && bun test",
"build": "cd plugin && bun run build:all",
"check": "bunx biome check ."
},
"devDependencies": {
"@biomejs/biome": "^2.5.2",
"@types/bun": "^1.3.0",
"typescript": "^5.9.3"
"@biomejs/biome": "^2.5.2"
}
}