workspace: centralize desktop outputs and verified root dependency installs

This commit is contained in:
aphrody-dev committed 2026-10-13 21:57:39 +02:00
1 parent 1e5c6435ff
commit 32e9d4cc2c
12 files changed
+106 -15

No files matched your search

+2 -2
View File
@@ -3,13 +3,13 @@
"runtime": {
"version": "1.4.4",
"repository": "aphrody-labs/bun",
"revision": "c62d01d81506a8b78b1d39b44d17edc81b4a6355"
"revision": "cb64a09ae6dd618efc300c39b9b03ccfa861cac2"
},
"runtimeTargets": {
"windows-x64": {
"version": "1.4.4",
"repository": "aphrody-labs/bun",
"revision": "c62d01d81506a8b78b1d39b44d17edc81b4a6355"
"revision": "cb64a09ae6dd618efc300c39b9b03ccfa861cac2"
},
"linux-x64": {
"version": "1.4.4",
+7 -6
View File
@@ -1,9 +1,10 @@
import { join, resolve } from "node:path";
import { join } from "node:path";
import { loadConfig, assertRuntime, repositoryRoot } from "@aphrody/bun-workspace";
import { capabilityFor, type Catalog } from "./shared.ts";
import { nativeVideoCapabilities } from "@aphrody/bun-video-project/native";
export const desktopRoot = import.meta.dir;
export const desktopOutput = join(repositoryRoot, "build/apps/desktop");
export async function buildDesktop() {
const config = await loadConfig(repositoryRoot);
@@ -25,7 +26,7 @@ export async function buildDesktop() {
};
const web = await Bun.build({
entrypoints: [join(desktopRoot, "src/app.ts")],
outdir: join(desktopRoot, "dist/web"),
outdir: join(desktopOutput, "web"),
target: "browser",
format: "esm",
minify: true,
@@ -33,19 +34,19 @@ export async function buildDesktop() {
});
if (!web.success) throw new AggregateError(web.logs, "Bun frontend build failed");
await Promise.all([
Bun.write(join(desktopRoot, "dist/web/index.html"), Bun.file(join(desktopRoot, "src/index.html"))),
Bun.write(join(desktopRoot, "dist/web/style.css"), Bun.file(join(desktopRoot, "src/style.css"))),
Bun.write(join(desktopOutput, "web/index.html"), Bun.file(join(desktopRoot, "src/index.html"))),
Bun.write(join(desktopOutput, "web/style.css"), Bun.file(join(desktopRoot, "src/style.css"))),
]);
const server = await Bun.build({
entrypoints: [join(desktopRoot, "server.ts")],
outdir: join(desktopRoot, "dist"),
outdir: desktopOutput,
target: "bun",
format: "esm",
minify: true,
});
if (!server.success) throw new AggregateError(server.logs, "Bun backend build failed");
console.log("Aphrody: " + catalog.libraries.length + " libraries bundled.");
return resolve(desktopRoot, "dist");
return desktopOutput;
}
if (import.meta.main) await buildDesktop();
+1 -1
View File
@@ -50,7 +50,7 @@ if (command === "build") {
target: "bun",
minify: true,
compile: {
outfile: join(desktopRoot, "src-tauri/binaries", filename),
outfile: join(output, "native", filename),
autoloadDotenv: false,
autoloadBunfig: false,
autoloadPackageJson: false,
+1 -1
View File
@@ -14,7 +14,7 @@
"dependencies": {
"@aphrody/bun-video-project": "workspace:*",
"@aphrody/bun-workspace": "workspace:*",
"@aphrody/tauri": "file:../../toolchains/bun/packages/bun-tauri"
"@aphrody/tauri": "catalog:"
},
"engines": {
"bun": "1.4.4"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "aphrody-bun-desktop"
version = "0.1.0"
version = "1.4.4"
description = "Aphrody desktop library inspector"
authors = ["aphrody-dev <contact@aphrody.com>"]
edition = "2024"
+3 -3
View File
@@ -1,8 +1,8 @@
{
"productName": "Aphrody",
"version": "0.1.0",
"version": "1.4.4",
"identifier": "com.aphrody.bun",
"build": { "frontendDist": "../dist/web" },
"build": { "frontendDist": "../../../build/apps/desktop/web" },
"app": {
"windows": [
{
@@ -22,7 +22,7 @@
"bundle": {
"active": true,
"targets": "all",
"externalBin": ["binaries/aphrody-server"],
"externalBin": ["../../../build/apps/desktop/native/aphrody-server"],
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"]
}
}
+10 -1
View File
@@ -9,6 +9,7 @@
"@aphrody/bun-artifacts": "workspace:*",
"@aphrody/bun-video-project": "workspace:*",
"@aphrody/bun-workspace": "workspace:*",
"@aphrody/tauri": "catalog:",
},
"devDependencies": {
"@aphrody/bun-types": "1.4.4",
@@ -20,12 +21,15 @@
"dependencies": {
"@aphrody/bun-video-project": "workspace:*",
"@aphrody/bun-workspace": "workspace:*",
"@aphrody/tauri": "file:../../toolchains/bun/packages/bun-tauri",
"@aphrody/tauri": "catalog:",
},
},
"packages/bun-app-host": {
"name": "@aphrody/bun-app-host",
"version": "1.4.4",
"bin": {
"aphrody-server": "./src/cli.ts",
},
"dependencies": {
"@aphrody/bun-artifacts": "workspace:*",
"@aphrody/bun-video-project": "workspace:*",
@@ -81,6 +85,9 @@
},
},
},
"catalog": {
"@aphrody/tauri": "file:toolchains/bun/packages/bun-tauri",
},
"packages": {
"@aphrody/bun-app-host": ["@aphrody/bun-app-host@workspace:packages/bun-app-host"],
@@ -96,6 +103,8 @@
"@aphrody/bun-workspace": ["@aphrody/bun-workspace@workspace:packages/bun-workspace"],
"@aphrody/tauri": ["@aphrody/tauri@file:toolchains/bun/packages/bun-tauri", {}],
"@bun-os/package-converter": ["@bun-os/package-converter@workspace:packages/package-converter"],
"@types/node": ["@types/node@26.6.5", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg=="],
+1
View File
@@ -1,5 +1,6 @@
[install]
exact = true
linker = "hoisted"
[run]
shell = "bun"
+4
View File
@@ -60,11 +60,15 @@
"workspace:manifests": "bun scripts/workspace-manifests.ts"
},
"dependencies": {
"@aphrody/tauri": "catalog:",
"@aphrody/bun-workspace": "workspace:*",
"@aphrody/bun-artifacts": "workspace:*",
"@aphrody/bun-video-project": "workspace:*",
"@aphrody/bun-app-host": "workspace:*"
},
"catalog": {
"@aphrody/tauri": "file:toolchains/bun/packages/bun-tauri"
},
"devDependencies": {
"@aphrody/bun-types": "1.4.4"
},
+74
View File
@@ -0,0 +1,74 @@
#!/usr/bin/env bun
/** Retire redundant workspace installs after proving the root package owner. */
import { lstat, readdir, realpath, rm } from "node:fs/promises";
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
import { runProcess } from "../packages/bun-workspace/src/process.ts";
const root = resolve(import.meta.dir, "..");
const product = await Bun.file(join(root, "package.json")).json();
const members: string[] = product.workspaces;
for (const member of members) {
const directory = resolve(root, member, "node_modules");
const within = relative(root, directory);
if (
isAbsolute(within) ||
within.startsWith(".." + sep) ||
within === ".." ||
directory === join(root, "node_modules")
)
throw new Error("Workspace install target is outside the product root.");
const info = await lstat(directory).catch(error => {
if (error.code === "ENOENT") return undefined;
throw error;
});
if (!info || info.isSymbolicLink()) continue;
const resolvedParent = relative(root, await realpath(dirname(directory)));
if (isAbsolute(resolvedParent) || resolvedParent.startsWith(".." + sep) || resolvedParent === "..")
throw new Error("Workspace install target resolves outside the product root.");
const packageDirectories: { name: string; path: string }[] = [];
for (const entry of await readdir(directory, { withFileTypes: true })) {
if (entry.name === ".bin") continue;
if (entry.name.startsWith("@")) {
for (const scoped of await readdir(join(directory, entry.name)))
packageDirectories.push({ name: `${entry.name}/${scoped}`, path: join(directory, entry.name, scoped) });
} else packageDirectories.push({ name: entry.name, path: join(directory, entry.name) });
}
for (const installed of packageDirectories) {
const canonical = join(root, "node_modules", installed.name);
const [local, shared] = await Promise.all([
Bun.file(join(installed.path, "package.json")).json(),
Bun.file(join(canonical, "package.json")).json(),
]);
if (local.name !== shared.name || local.version !== shared.version)
throw new Error(`Root package does not replace ${installed.name}.`);
if (!(await lstat(installed.path)).isSymbolicLink()) {
for (const path of new Bun.Glob("**/*").scanSync({ cwd: installed.path, onlyFiles: true, dot: true })) {
const source = Bun.file(join(installed.path, path));
const target = Bun.file(join(canonical, path));
if (
!(await target.exists()) ||
(await source.arrayBuffer()).byteLength !== target.size ||
Bun.CryptoHasher.hash("sha256", await source.arrayBuffer(), "hex") !==
Bun.CryptoHasher.hash("sha256", await target.arrayBuffer(), "hex")
)
throw new Error(`Root package differs from workspace package ${installed.name}.`);
}
}
}
if (process.platform === "win32") {
const removed = await runProcess(
[
"powershell.exe",
"-NoProfile",
"-NonInteractive",
"-Command",
"& { param([string]$target) Remove-Item -LiteralPath $target -Recurse -ErrorAction Stop }",
directory,
],
root,
{ timeoutMs: 30_000, maxOutputBytes: 1024 * 1024 },
);
if (removed.code !== 0) throw new Error("Workspace install cleanup failed.");
} else await rm(directory, { recursive: true });
console.log(`Root node_modules now owns ${member}`);
}
+1
View File
@@ -24,5 +24,6 @@ async function run(argv: string[]): Promise<void> {
await run(["git", "submodule", "update", "--init", "--depth", "1"]);
await run([process.execPath, "install", "--frozen-lockfile"]);
await run([process.execPath, "scripts/node-modules.ts"]);
const cargo = await inspectCargoWorkspace(await loadConfig(root), { root, timeoutMs: 60_000 });
console.log(`Cargo workspace: ${cargo.packageNames.length} packages in ${cargo.workspaceRoot}`);
+1
View File
@@ -16,6 +16,7 @@ for (const entry of [{ path: "package.json", manifest: product }, ...entries]) {
for (const field of ["dependencies", "devDependencies", "optionalDependencies"]) {
for (const name of Object.keys(entry.manifest[field] ?? {})) {
if (names.has(name)) entry.manifest[field][name] = "workspace:*";
else if (Object.hasOwn(product.catalog ?? {}, name)) entry.manifest[field][name] = "catalog:";
}
}
}