Files
T
enricobuehler aee3c194af
CI / publish (push) Has been cancelled
CI / build (push) Has been cancelled
fix(dist): ship a self-contained bundle so it installs from the registry
The unscoped package lives on the Gitea npm registry but its deps span two
registries (`@punktfunk/host` on Gitea, `effect`/`undici` on npmjs). Installing
by name with `--registry <gitea>` sets the default registry for the whole tree,
so `effect` 404s (Gitea doesn't proxy npm), and an unscoped name can't be
scope-mapped. Fix: bundle the backend into ONE self-contained `dist/index.js`
(+ `dist/cli.js`) via `bun build --target=bun` with `@punktfunk/host` + `effect`
inlined — mirroring the scripting runner. The published package now has zero
runtime dependencies and installs with a single `--registry` flag.

- build → `bun build src/{index,cli}.ts --target=bun --outdir dist --external undici`
- @punktfunk/host + effect → devDependencies (bundled, not resolved at install)
- resolveUiDir(): walk to the SPA dir so staticDir works in the bundled
  (dist/index.js) and unbundled (dist/server/index.js) layouts
- version 0.1.0 → 0.1.1

Verified: the bundle loads + scans/detects/previews with NO node_modules present.
2026-07-18 11:18:38 +02:00

56 lines
2.4 KiB
TypeScript

// Where the plugin's own files live. The host config dir resolution mirrors the SDK's `configDir`
// (`@punktfunk/host` does not re-export it) so we always land in the same place the host and runner
// use; the plugin owns a `rom-manager/` subtree under it (design §9), created 0700.
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
/** The host's config dir — the same resolution the host and SDK use. */
export const hostConfigDir = (): string => {
const explicit = process.env.PUNKTFUNK_CONFIG_DIR;
if (explicit) return explicit;
if (process.platform === "win32") {
const base = process.env.ProgramData ?? process.env.APPDATA ?? ".";
return path.join(base, "punktfunk");
}
const base =
process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config");
return path.join(base, "punktfunk");
};
/** This plugin's private directory: `<config_dir>/rom-manager`. */
export const pluginDir = (): string =>
path.join(hostConfigDir(), "rom-manager");
/** `<config_dir>/rom-manager/config.json` — operator-editable, atomic-written. */
export const configPath = (): string => path.join(pluginDir(), "config.json");
/** `<config_dir>/rom-manager/cache.json` — disposable derived state (art verdicts, detection, fingerprint). */
export const cachePath = (): string => path.join(pluginDir(), "cache.json");
/**
* Locate the built SPA directory (`dist/ui`) at runtime. The package ships as ONE self-contained bundle
* (`dist/index.js`) so it installs from the Gitea registry with no external deps — which means
* `import.meta.url` can be `dist/index.js` (bundled) or `dist/server/index.js` (unbundled dev). We walk
* up from the calling module looking for a `ui/index.html`, so both layouts resolve. `fromUrl` is the
* caller's `import.meta.url`.
*/
export const resolveUiDir = (fromUrl: string): string => {
let dir = path.dirname(fileURLToPath(fromUrl));
for (let i = 0; i < 6; i++) {
for (const cand of [path.join(dir, "ui"), path.join(dir, "dist", "ui")]) {
try {
if (fs.existsSync(path.join(cand, "index.html"))) return cand;
} catch {
// keep walking
}
}
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
// Fallback to the bundled layout (dist/index.js → dist/ui) even if unbuilt.
return path.join(path.dirname(fileURLToPath(fromUrl)), "ui");
};