doxa-maps/internal/plugin-targets.mjs
Doxa Maps 6451a2b158 bun run desktop:build <plugin> packages a desktop plugin as an app; check:targets keeps non-web plugins out of the web build
A plugin's <profile>.meta.json targets (web, mobile, desktop, widget; absent = web)
now decide where it is built. internal/plugin-targets.mjs is the one reading.
desktop:build builds a desktop plugin into .desktop/<plugin>/ with a page that
names its engine, builds its backend as a Tauri sidecar for this machine, and runs
tauri build with a --config override; tauri.conf.json and public/ are untouched.
The shell starts the bundled rudder-engine (RUDDER_AUDIO=browser, RUDDER_HOME in the
app data folder) and stops it on exit. A plugin whose targets leave out web
(Rudder: desktop + widget) is no longer built for the web tree: run-parallel,
generate-tree and check-composite-freshness skip it, and its public/ folder is
removed; the dev server still gives the Studio its corner. check:targets
(gates:pre, with a self-test of five planted violations) validates the values,
widget corners and backend folders and fails if a non-web plugin reaches the built
tree. Measured: desktop:build rudder-voice on Linux produced Rudder_0.1.0_amd64.deb
(8.8 MB) with the app and the engine side by side; the app has not been launched.
2026-09-28 06:44:14 +00:00

37 lines
1.9 KiB
JavaScript

/**
* plugin-targets.mjs — where a plugin runs, read from its own <profile>.meta.json "targets".
*
* Known values: web (a published map or tool), mobile, desktop (the Tauri app, `bun run desktop:build`),
* widget (the Plugin Studio's corner). ABSENT = web: most plugins never declare it and never need to.
* A plugin is built into the WEB tree (bun run build, the /cdn export, the Research Gallery) unless every
* profile declares targets and none of them is "web" — Rudder (["desktop","widget"]) is built only by
* desktop:build, and the dev server still discovers it from source for the Studio's corner.
* Read by run-parallel (--bundles), check-composite-freshness, check-shared-component-reached-bundles,
* desktop-build and check:targets, so there is ONE rule.
*/
import { readdirSync, readFileSync, existsSync } from 'node:fs'
import { join } from 'node:path'
export const KNOWN_TARGETS = ['web', 'mobile', 'desktop', 'widget']
/** [{ profile, targets|null, meta }] for every <profile>.meta.json in a bundle folder. */
export function profileTargets(bundleDir) {
if (!existsSync(bundleDir)) return []
return readdirSync(bundleDir).filter((f) => f.endsWith('.meta.json')).map((f) => {
let meta = {}
try { meta = JSON.parse(readFileSync(join(bundleDir, f), 'utf8')) } catch { /* unreadable meta = no declaration */ }
return { profile: f.replace(/\.meta\.json$/, ''), targets: Array.isArray(meta.targets) ? meta.targets : null, meta }
})
}
/** True unless every profile declares targets and none of them is "web". No meta at all = web. */
export function isWebBuilt(bundleDir) {
const p = profileTargets(bundleDir)
if (!p.length) return true
return p.some((x) => !x.targets || x.targets.includes('web'))
}
/** The profile a desktop app opens, or null: the first profile whose targets include "desktop". */
export function desktopProfile(bundleDir) {
return profileTargets(bundleDir).find((x) => x.targets && x.targets.includes('desktop')) || null
}