mirror of
https://github.com/unraid/api.git
synced 2026-01-04 07:29:48 -06:00
- **New Features** - Created a dynamic plugin system for the API to enable community augmentation of GraphQL, CLI, and Cron functionalities capabilities. - Included an example plugin under `packages/unraid-api-plugin-health` that adds a new graphql query for API health checks. - Added `rc.unraid-api` commands for backing up, restoring, and installing production dependencies, streamlining maintenance and deployment. - Improved dependency vendoring by bundling a versioned pnpm store (instead of `node_modules`). Versioning will allow users to add plugins to a specific api release without requiring an internet connection on subsequent reboots. - **Chores** - Upgraded build workflows and versioning processes to ensure more reliable artifact handling and production packaging.
117 lines
3.6 KiB
TypeScript
117 lines
3.6 KiB
TypeScript
import { join } from "path";
|
|
import { $, cd } from "zx";
|
|
import { existsSync } from "node:fs";
|
|
import { readdir } from "node:fs/promises";
|
|
import { getTxzName, pluginName, startingDir } from "./utils/consts";
|
|
import { setupTxzEnv, TxzEnv } from "./cli/setup-txz-environment";
|
|
import { cleanupTxzFiles } from "./utils/cleanup";
|
|
import { apiDir } from "./utils/paths";
|
|
|
|
// Recursively search for manifest files
|
|
const findManifestFiles = async (dir: string): Promise<string[]> => {
|
|
try {
|
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
const files: string[] = [];
|
|
|
|
for (const entry of entries) {
|
|
const fullPath = join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
try {
|
|
files.push(...(await findManifestFiles(fullPath)));
|
|
} catch (error) {
|
|
// Log and continue if a subdirectory can't be read
|
|
console.warn(`Warning: Could not read directory ${fullPath}: ${error.message}`);
|
|
}
|
|
} else if (
|
|
entry.isFile() &&
|
|
(entry.name === "manifest.json" || entry.name === "ui.manifest.json")
|
|
) {
|
|
files.push(entry.name);
|
|
}
|
|
}
|
|
|
|
return files;
|
|
} catch (error) {
|
|
if (error.code === 'ENOENT') {
|
|
console.warn(`Directory does not exist: ${dir}`);
|
|
return [];
|
|
}
|
|
throw error; // Re-throw other errors
|
|
}
|
|
};
|
|
|
|
const validateSourceDir = async (validatedEnv: TxzEnv) => {
|
|
if (!validatedEnv.ci) {
|
|
console.log("Validating TXZ source directory");
|
|
}
|
|
const sourceDir = join(startingDir, "source");
|
|
if (!existsSync(sourceDir)) {
|
|
throw new Error(`Source directory ${sourceDir} does not exist`);
|
|
}
|
|
// Validate existence of webcomponent files:
|
|
// source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components
|
|
const webcomponentDir = join(
|
|
sourceDir,
|
|
"dynamix.unraid.net",
|
|
"usr",
|
|
"local",
|
|
"emhttp",
|
|
"plugins",
|
|
"dynamix.my.servers",
|
|
"unraid-components"
|
|
);
|
|
if (!existsSync(webcomponentDir)) {
|
|
throw new Error(`Webcomponent directory ${webcomponentDir} does not exist`);
|
|
}
|
|
|
|
const manifestFiles = await findManifestFiles(webcomponentDir);
|
|
const hasManifest = manifestFiles.includes("manifest.json");
|
|
const hasUiManifest = manifestFiles.includes("ui.manifest.json");
|
|
|
|
if (!hasManifest || !hasUiManifest) {
|
|
console.log("Existing Manifest Files:", manifestFiles);
|
|
throw new Error(
|
|
`Webcomponents must contain both "ui.manifest.json" and "manifest.json" - be sure to have run pnpm build:wc in unraid-ui`
|
|
);
|
|
}
|
|
|
|
if (!existsSync(apiDir)) {
|
|
throw new Error(`API directory ${apiDir} does not exist`);
|
|
}
|
|
const packageJson = join(apiDir, "package.json");
|
|
if (!existsSync(packageJson)) {
|
|
throw new Error(`API package.json file ${packageJson} does not exist`);
|
|
}
|
|
// Now CHMOD the api/dist directory files to allow execution
|
|
await $`chmod +x ${apiDir}/dist/*.js`;
|
|
};
|
|
|
|
const buildTxz = async (validatedEnv: TxzEnv) => {
|
|
await validateSourceDir(validatedEnv);
|
|
const txzPath = join(validatedEnv.txzOutputDir, getTxzName());
|
|
|
|
// Create package - must be run from within the pre-pack directory
|
|
// Use cd option to run command from prePackDir
|
|
await cd(join(startingDir, "source", pluginName));
|
|
$.verbose = true;
|
|
|
|
await $`${join(startingDir, "scripts/makepkg")} --chown y --compress -${
|
|
validatedEnv.compress
|
|
} --linkadd y ${txzPath}`;
|
|
$.verbose = false;
|
|
await cd(startingDir);
|
|
};
|
|
|
|
const main = async () => {
|
|
try {
|
|
const validatedEnv = await setupTxzEnv(process.argv);
|
|
await cleanupTxzFiles();
|
|
await buildTxz(validatedEnv);
|
|
} catch (error) {
|
|
console.error(error);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
await main();
|