Initial import: open-design source for helix-mind.ai distribution
Some checks failed
ci / Validate workspace (push) Successful in 12m32s
landing-page-ci / Validate landing page (push) Successful in 9m41s
landing-page-deploy / Deploy landing page (push) Failing after 5m23s
github-metrics / Generate repository metrics SVG (push) Failing after 2m6s
refresh-contributors-wall / Refresh contributors wall cache bust (push) Failing after 12s
Some checks failed
ci / Validate workspace (push) Successful in 12m32s
landing-page-ci / Validate landing page (push) Successful in 9m41s
landing-page-deploy / Deploy landing page (push) Failing after 5m23s
github-metrics / Generate repository metrics SVG (push) Failing after 2m6s
refresh-contributors-wall / Refresh contributors wall cache bust (push) Failing after 12s
This repository contains the open-design daemon CLI source code, built and packaged at https://helix-mind.ai/cli/open-design/latest.tgz for use by the HelixMind /design slash command. Licenses: Apache-2.0 (root) + MIT (skills/*)
This commit is contained in:
514
tools/pack/resources/mac/web-standalone-after-pack.cjs
Normal file
514
tools/pack/resources/mac/web-standalone-after-pack.cjs
Normal file
@@ -0,0 +1,514 @@
|
||||
const { access, cp, lstat, mkdir, readFile, readdir, rm, stat, symlink, writeFile } = require("node:fs/promises");
|
||||
const { createRequire } = require("node:module");
|
||||
const path = require("node:path");
|
||||
|
||||
const CONFIG_ENV = "OD_TOOLS_PACK_WEB_STANDALONE_HOOK_CONFIG";
|
||||
const STANDALONE_RESOURCE_NAME = "open-design-web-standalone";
|
||||
const REQUIRED_MODULES = ["next/package.json", "react/package.json", "react-dom/package.json", "styled-jsx/package.json"];
|
||||
|
||||
function isRecord(value) {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function requireString(record, key) {
|
||||
const value = record[key];
|
||||
if (typeof value !== "string" || value.length === 0) {
|
||||
throw new Error(`[tools-pack web-standalone] config.${key} must be a non-empty string`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function requireBoolean(record, key) {
|
||||
const value = record[key];
|
||||
if (typeof value !== "boolean") {
|
||||
throw new Error(`[tools-pack web-standalone] config.${key} must be a boolean`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function requireAbsolutePath(record, key) {
|
||||
const value = requireString(record, key);
|
||||
if (!path.isAbsolute(value)) {
|
||||
throw new Error(`[tools-pack web-standalone] config.${key} must be absolute: ${value}`);
|
||||
}
|
||||
return path.resolve(value);
|
||||
}
|
||||
|
||||
function isWithin(parent, child) {
|
||||
const relative = path.relative(parent, child);
|
||||
return relative.length === 0 || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
||||
}
|
||||
|
||||
async function pathExists(filePath) {
|
||||
try {
|
||||
await access(filePath);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function pathLstatExists(filePath) {
|
||||
try {
|
||||
await lstat(filePath);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function readHookConfig() {
|
||||
const configPath = process.env[CONFIG_ENV];
|
||||
if (configPath == null || configPath.length === 0) {
|
||||
throw new Error(`[tools-pack web-standalone] missing ${CONFIG_ENV}`);
|
||||
}
|
||||
if (!path.isAbsolute(configPath)) {
|
||||
throw new Error(`[tools-pack web-standalone] ${CONFIG_ENV} must be absolute: ${configPath}`);
|
||||
}
|
||||
|
||||
const raw = JSON.parse(await readFile(configPath, "utf8"));
|
||||
if (!isRecord(raw) || raw.version !== 1) {
|
||||
throw new Error("[tools-pack web-standalone] hook config must be an object with version=1");
|
||||
}
|
||||
|
||||
const workspaceRoot = requireAbsolutePath(raw, "workspaceRoot");
|
||||
const standaloneSourceRoot = requireAbsolutePath(raw, "standaloneSourceRoot");
|
||||
const webStaticSourceRoot = requireAbsolutePath(raw, "webStaticSourceRoot");
|
||||
const webPublicSourceRoot = requireAbsolutePath(raw, "webPublicSourceRoot");
|
||||
const auditReportPath = requireAbsolutePath(raw, "auditReportPath");
|
||||
const resourceName = requireString(raw, "resourceName");
|
||||
if (resourceName !== STANDALONE_RESOURCE_NAME) {
|
||||
throw new Error(`[tools-pack web-standalone] unsupported resourceName: ${resourceName}`);
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries({ standaloneSourceRoot, webStaticSourceRoot, webPublicSourceRoot })) {
|
||||
if (!isWithin(workspaceRoot, value)) {
|
||||
throw new Error(`[tools-pack web-standalone] config.${key} must stay under workspaceRoot: ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
auditReportPath,
|
||||
pruneCopiedSharp: requireBoolean(raw, "pruneCopiedSharp"),
|
||||
pruneRootNext: requireBoolean(raw, "pruneRootNext"),
|
||||
pruneRootSharp: requireBoolean(raw, "pruneRootSharp"),
|
||||
resourceName,
|
||||
standaloneSourceRoot,
|
||||
webPublicSourceRoot,
|
||||
webStaticSourceRoot,
|
||||
workspaceRoot,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveAppPath(context) {
|
||||
if (context == null || typeof context.appOutDir !== "string" || context.appOutDir.length === 0) {
|
||||
throw new Error("[tools-pack web-standalone] electron-builder context.appOutDir is missing");
|
||||
}
|
||||
const productFilename = context.packager?.appInfo?.productFilename;
|
||||
if (typeof productFilename !== "string" || productFilename.length === 0) {
|
||||
throw new Error("[tools-pack web-standalone] electron-builder productFilename is missing");
|
||||
}
|
||||
return path.join(context.appOutDir, `${productFilename}.app`);
|
||||
}
|
||||
|
||||
async function sizePathBytes(filePath) {
|
||||
let metadata;
|
||||
try {
|
||||
metadata = await lstat(filePath);
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!metadata.isDirectory()) return metadata.size;
|
||||
|
||||
const entries = await readdir(filePath, { withFileTypes: true }).catch(() => []);
|
||||
let total = 0;
|
||||
for (const entry of entries) {
|
||||
total += await sizePathBytes(path.join(filePath, entry.name));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
async function copyRequired(sourcePath, destinationPath) {
|
||||
if (!(await pathExists(sourcePath))) {
|
||||
throw new Error(`[tools-pack web-standalone] required source missing: ${sourcePath}`);
|
||||
}
|
||||
await rm(destinationPath, { force: true, recursive: true });
|
||||
await mkdir(path.dirname(destinationPath), { recursive: true });
|
||||
await cp(sourcePath, destinationPath, {
|
||||
dereference: false,
|
||||
recursive: true,
|
||||
verbatimSymlinks: true,
|
||||
});
|
||||
}
|
||||
|
||||
async function copyOptional(sourcePath, destinationPath) {
|
||||
if (!(await pathExists(sourcePath))) return false;
|
||||
await copyRequired(sourcePath, destinationPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function linkRelative(sourcePath, destinationPath) {
|
||||
if (!(await pathExists(sourcePath))) return false;
|
||||
if (await pathLstatExists(destinationPath)) return false;
|
||||
await mkdir(path.dirname(destinationPath), { recursive: true });
|
||||
const relativeTarget = path.relative(path.dirname(destinationPath), sourcePath);
|
||||
await symlink(relativeTarget.length === 0 ? "." : relativeTarget, destinationPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function linkPnpmPublicHoist(destinationRoot) {
|
||||
const nodeModulesRoot = path.join(destinationRoot, "node_modules");
|
||||
const hoistRoot = path.join(nodeModulesRoot, ".pnpm", "node_modules");
|
||||
const entries = await readdir(hoistRoot, { withFileTypes: true }).catch(() => []);
|
||||
const linked = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
const sourcePath = path.join(hoistRoot, entry.name);
|
||||
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
||||
const scopedEntries = await readdir(sourcePath).catch(() => []);
|
||||
for (const scopedEntry of scopedEntries) {
|
||||
const scopedSource = path.join(sourcePath, scopedEntry);
|
||||
const scopedDestination = path.join(nodeModulesRoot, entry.name, scopedEntry);
|
||||
if (await linkRelative(scopedSource, scopedDestination)) linked.push(scopedDestination);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const destinationPath = path.join(nodeModulesRoot, entry.name);
|
||||
if (await linkRelative(sourcePath, destinationPath)) linked.push(destinationPath);
|
||||
}
|
||||
|
||||
return linked;
|
||||
}
|
||||
|
||||
async function resolveStandaloneSourceWebRoot(standaloneSourceRoot) {
|
||||
const candidates = [
|
||||
path.join(standaloneSourceRoot, "apps", "web"),
|
||||
standaloneSourceRoot,
|
||||
];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (await pathExists(path.join(candidate, "server.js"))) return candidate;
|
||||
}
|
||||
|
||||
throw new Error(`[tools-pack web-standalone] standalone server.js not found under ${standaloneSourceRoot}`);
|
||||
}
|
||||
|
||||
async function installStandaloneResource(config, appPath) {
|
||||
const sourceWebRoot = await resolveStandaloneSourceWebRoot(config.standaloneSourceRoot);
|
||||
const destinationRoot = path.join(appPath, "Contents", "Resources", config.resourceName);
|
||||
const destinationWebRoot = path.join(destinationRoot, "apps", "web");
|
||||
|
||||
await rm(destinationRoot, { force: true, recursive: true });
|
||||
await mkdir(destinationWebRoot, { recursive: true });
|
||||
|
||||
await copyRequired(path.join(config.standaloneSourceRoot, "node_modules"), path.join(destinationRoot, "node_modules"));
|
||||
await copyRequired(path.join(sourceWebRoot, "server.js"), path.join(destinationWebRoot, "server.js"));
|
||||
await copyOptional(path.join(sourceWebRoot, "package.json"), path.join(destinationWebRoot, "package.json"));
|
||||
const copiedNestedNodeModules = await copyOptional(path.join(sourceWebRoot, "node_modules"), path.join(destinationWebRoot, "node_modules"));
|
||||
const linkedHoistEntries = await linkPnpmPublicHoist(destinationRoot);
|
||||
await copyRequired(path.join(sourceWebRoot, ".next"), path.join(destinationWebRoot, ".next"));
|
||||
const copiedStatic = await copyOptional(config.webStaticSourceRoot, path.join(destinationWebRoot, ".next", "static"));
|
||||
const copiedPublic = await copyOptional(config.webPublicSourceRoot, path.join(destinationWebRoot, "public"));
|
||||
|
||||
return {
|
||||
copiedNestedNodeModules,
|
||||
copiedPublic,
|
||||
copiedStatic,
|
||||
destinationRoot,
|
||||
destinationWebRoot,
|
||||
linkedHoistEntries,
|
||||
sourceWebRoot,
|
||||
};
|
||||
}
|
||||
|
||||
async function removePathAndRecord(targetPath, reason, removedPaths) {
|
||||
const existed = await pathExists(targetPath);
|
||||
const bytes = await sizePathBytes(targetPath);
|
||||
await rm(targetPath, { force: true, recursive: true });
|
||||
if (existed || bytes > 0) {
|
||||
removedPaths.push({ bytes, path: targetPath, reason });
|
||||
}
|
||||
}
|
||||
|
||||
function isPrunablePnpmSharpEntry(name) {
|
||||
return name.startsWith("sharp@") || name.startsWith("@img+colour@") || name.startsWith("@img+sharp-");
|
||||
}
|
||||
|
||||
function isPrunableImgEntry(name) {
|
||||
return name === "colour" || name.startsWith("sharp-");
|
||||
}
|
||||
|
||||
async function pruneImgScope(scopePath, reason, removedPaths) {
|
||||
const entries = await readdir(scopePath).catch(() => []);
|
||||
for (const entry of entries) {
|
||||
if (isPrunableImgEntry(entry)) {
|
||||
await removePathAndRecord(path.join(scopePath, entry), reason, removedPaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function pruneCopiedSharp(destinationRoot) {
|
||||
const nodeModulesRoot = path.join(destinationRoot, "node_modules");
|
||||
const pnpmRoot = path.join(nodeModulesRoot, ".pnpm");
|
||||
const removedPaths = [];
|
||||
|
||||
await removePathAndRecord(path.join(nodeModulesRoot, "sharp"), "copied top-level sharp symlink", removedPaths);
|
||||
await pruneImgScope(path.join(nodeModulesRoot, "@img"), "copied top-level @img sharp symlink", removedPaths);
|
||||
await removePathAndRecord(path.join(pnpmRoot, "node_modules", "sharp"), "copied pnpm sharp symlink", removedPaths);
|
||||
await pruneImgScope(path.join(pnpmRoot, "node_modules", "@img"), "copied pnpm @img sharp symlink", removedPaths);
|
||||
|
||||
const pnpmEntries = await readdir(pnpmRoot).catch(() => []);
|
||||
for (const entry of pnpmEntries) {
|
||||
if (isPrunablePnpmSharpEntry(entry)) {
|
||||
await removePathAndRecord(path.join(pnpmRoot, entry), "copied pnpm sharp package", removedPaths);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.startsWith("next@")) {
|
||||
await removePathAndRecord(path.join(pnpmRoot, entry, "node_modules", "sharp"), "copied next sharp symlink", removedPaths);
|
||||
}
|
||||
}
|
||||
|
||||
return removedPaths;
|
||||
}
|
||||
|
||||
async function pruneBrokenSymlinks(root, current = root, removedPaths = [], reason = "broken symlink") {
|
||||
let metadata;
|
||||
try {
|
||||
metadata = await lstat(current);
|
||||
} catch {
|
||||
return removedPaths;
|
||||
}
|
||||
|
||||
if (metadata.isSymbolicLink()) {
|
||||
try {
|
||||
await stat(current);
|
||||
} catch {
|
||||
await removePathAndRecord(current, reason, removedPaths);
|
||||
}
|
||||
return removedPaths;
|
||||
}
|
||||
|
||||
if (!metadata.isDirectory()) return removedPaths;
|
||||
|
||||
const entries = await readdir(current, { withFileTypes: true }).catch(() => []);
|
||||
for (const entry of entries) {
|
||||
await pruneBrokenSymlinks(root, path.join(current, entry.name), removedPaths, reason);
|
||||
}
|
||||
return removedPaths;
|
||||
}
|
||||
|
||||
function isForbiddenCopiedEntry(relativePath) {
|
||||
const normalized = relativePath.split(path.sep).join("/");
|
||||
const withRootSlash = `/${normalized}`;
|
||||
return (
|
||||
withRootSlash.includes("/node_modules/.pnpm/sharp@") ||
|
||||
withRootSlash.includes("/node_modules/.pnpm/@img+colour@") ||
|
||||
withRootSlash.includes("/node_modules/.pnpm/@img+sharp-") ||
|
||||
withRootSlash.includes("/node_modules/sharp") ||
|
||||
withRootSlash.includes("/node_modules/@img/colour") ||
|
||||
withRootSlash.includes("/node_modules/@img/sharp-") ||
|
||||
withRootSlash.includes("sharp-libvips") ||
|
||||
withRootSlash.includes("swc-darwin")
|
||||
);
|
||||
}
|
||||
|
||||
async function collectClosureStats(root, current = root, stats = { brokenSymlinks: [], forbiddenEntries: [], symlinks: 0 }) {
|
||||
let metadata;
|
||||
try {
|
||||
metadata = await lstat(current);
|
||||
} catch {
|
||||
return stats;
|
||||
}
|
||||
|
||||
const relativePath = path.relative(root, current);
|
||||
if (relativePath.length > 0 && isForbiddenCopiedEntry(relativePath)) {
|
||||
stats.forbiddenEntries.push(relativePath.split(path.sep).join("/"));
|
||||
}
|
||||
|
||||
if (metadata.isSymbolicLink()) {
|
||||
stats.symlinks += 1;
|
||||
try {
|
||||
await stat(current);
|
||||
} catch {
|
||||
stats.brokenSymlinks.push(relativePath.split(path.sep).join("/"));
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
if (!metadata.isDirectory()) return stats;
|
||||
|
||||
const entries = await readdir(current, { withFileTypes: true }).catch(() => []);
|
||||
for (const entry of entries) {
|
||||
await collectClosureStats(root, path.join(current, entry.name), stats);
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
function assertResolvedInside(root, moduleName, resolvedPath) {
|
||||
if (!isWithin(root, resolvedPath)) {
|
||||
throw new Error(`[tools-pack web-standalone] ${moduleName} resolved outside copied standalone: ${resolvedPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function auditCopiedStandalone(config, installResult) {
|
||||
const serverPath = path.join(installResult.destinationWebRoot, "server.js");
|
||||
const staticRoot = path.join(installResult.destinationWebRoot, ".next", "static");
|
||||
const publicRoot = path.join(installResult.destinationWebRoot, "public");
|
||||
const nodeModulesRoot = path.join(installResult.destinationRoot, "node_modules");
|
||||
const requiredPaths = [serverPath, staticRoot, nodeModulesRoot];
|
||||
if (await pathExists(config.webPublicSourceRoot)) requiredPaths.push(publicRoot);
|
||||
|
||||
for (const requiredPath of requiredPaths) {
|
||||
if (!(await pathExists(requiredPath))) {
|
||||
throw new Error(`[tools-pack web-standalone] copied standalone audit missing: ${requiredPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
const localRequire = createRequire(serverPath);
|
||||
const resolvedModules = {};
|
||||
for (const moduleName of REQUIRED_MODULES) {
|
||||
const resolvedPath = localRequire.resolve(moduleName);
|
||||
assertResolvedInside(installResult.destinationRoot, moduleName, resolvedPath);
|
||||
resolvedModules[moduleName] = resolvedPath;
|
||||
}
|
||||
|
||||
const closureStats = await collectClosureStats(installResult.destinationRoot);
|
||||
if (closureStats.brokenSymlinks.length > 0) {
|
||||
throw new Error(`[tools-pack web-standalone] copied standalone has broken symlinks: ${closureStats.brokenSymlinks.join(", ")}`);
|
||||
}
|
||||
if (closureStats.forbiddenEntries.length > 0) {
|
||||
throw new Error(`[tools-pack web-standalone] copied standalone has forbidden entries: ${closureStats.forbiddenEntries.join(", ")}`);
|
||||
}
|
||||
|
||||
return {
|
||||
brokenSymlinks: closureStats.brokenSymlinks,
|
||||
bytes: await sizePathBytes(installResult.destinationRoot),
|
||||
destinationRoot: installResult.destinationRoot,
|
||||
destinationWebRoot: installResult.destinationWebRoot,
|
||||
forbiddenEntries: closureStats.forbiddenEntries,
|
||||
nodeModulesBytes: await sizePathBytes(nodeModulesRoot),
|
||||
resolvedModules,
|
||||
serverPath,
|
||||
symlinks: closureStats.symlinks,
|
||||
};
|
||||
}
|
||||
|
||||
async function pruneRootNext(appPath) {
|
||||
const appNodeModulesRoot = path.join(appPath, "Contents", "Resources", "app", "node_modules");
|
||||
const removedPaths = [];
|
||||
|
||||
const nextScopeRoot = path.join(appNodeModulesRoot, "@next");
|
||||
const nextScopeEntries = await readdir(nextScopeRoot).catch(() => []);
|
||||
for (const entry of nextScopeEntries) {
|
||||
if (entry.startsWith("swc-darwin-")) {
|
||||
await removePathAndRecord(path.join(nextScopeRoot, entry), "root next darwin swc package", removedPaths);
|
||||
}
|
||||
}
|
||||
|
||||
await removePathAndRecord(
|
||||
path.join(appNodeModulesRoot, "@open-design", "web", ".next", "standalone"),
|
||||
"root @open-design/web standalone output",
|
||||
removedPaths,
|
||||
);
|
||||
|
||||
return removedPaths;
|
||||
}
|
||||
|
||||
async function pruneRootSharp(appPath) {
|
||||
const appNodeModulesRoot = path.join(appPath, "Contents", "Resources", "app", "node_modules");
|
||||
const pnpmRoot = path.join(appNodeModulesRoot, ".pnpm");
|
||||
const removedPaths = [];
|
||||
|
||||
await removePathAndRecord(path.join(appNodeModulesRoot, "sharp"), "root sharp package", removedPaths);
|
||||
await pruneImgScope(path.join(appNodeModulesRoot, "@img"), "root @img sharp package", removedPaths);
|
||||
await removePathAndRecord(path.join(pnpmRoot, "node_modules", "sharp"), "root pnpm sharp symlink", removedPaths);
|
||||
await pruneImgScope(path.join(pnpmRoot, "node_modules", "@img"), "root pnpm @img sharp symlink", removedPaths);
|
||||
|
||||
const pnpmEntries = await readdir(pnpmRoot).catch(() => []);
|
||||
for (const entry of pnpmEntries) {
|
||||
if (isPrunablePnpmSharpEntry(entry)) {
|
||||
await removePathAndRecord(path.join(pnpmRoot, entry), "root pnpm sharp package", removedPaths);
|
||||
}
|
||||
}
|
||||
|
||||
return removedPaths;
|
||||
}
|
||||
|
||||
async function auditNoBrokenSymlinks(root, label) {
|
||||
const stats = await collectClosureStats(root);
|
||||
if (stats.brokenSymlinks.length > 0) {
|
||||
throw new Error(`[tools-pack web-standalone] ${label} has broken symlinks: ${stats.brokenSymlinks.join(", ")}`);
|
||||
}
|
||||
return {
|
||||
brokenSymlinks: stats.brokenSymlinks,
|
||||
symlinks: stats.symlinks,
|
||||
};
|
||||
}
|
||||
|
||||
async function runWebStandaloneAfterPack(context) {
|
||||
if (context?.electronPlatformName != null && context.electronPlatformName !== "darwin") return;
|
||||
|
||||
const config = await readHookConfig();
|
||||
const appPath = resolveAppPath(context);
|
||||
if (!(await pathExists(appPath))) {
|
||||
throw new Error(`[tools-pack web-standalone] app bundle not found: ${appPath}`);
|
||||
}
|
||||
|
||||
const installResult = await installStandaloneResource(config, appPath);
|
||||
const copiedPrune = config.pruneCopiedSharp ? await pruneCopiedSharp(installResult.destinationRoot) : [];
|
||||
const brokenSymlinkPrune = await pruneBrokenSymlinks(
|
||||
installResult.destinationRoot,
|
||||
installResult.destinationRoot,
|
||||
[],
|
||||
"copied broken symlink",
|
||||
);
|
||||
const copiedAudit = await auditCopiedStandalone(config, installResult);
|
||||
const rootPrune = config.pruneRootNext ? await pruneRootNext(appPath) : [];
|
||||
const rootSharpPrune = config.pruneRootSharp ? await pruneRootSharp(appPath) : [];
|
||||
const rootBrokenSymlinkPrune = await pruneBrokenSymlinks(
|
||||
path.join(appPath, "Contents", "Resources", "app", "node_modules"),
|
||||
path.join(appPath, "Contents", "Resources", "app", "node_modules"),
|
||||
[],
|
||||
"root broken symlink",
|
||||
);
|
||||
const rootSymlinkAudit = await auditNoBrokenSymlinks(
|
||||
path.join(appPath, "Contents", "Resources", "app", "node_modules"),
|
||||
"root app node_modules",
|
||||
);
|
||||
const report = {
|
||||
appPath,
|
||||
brokenSymlinkPrune,
|
||||
copiedAudit,
|
||||
copiedPrune,
|
||||
generatedAt: new Date().toISOString(),
|
||||
rootBrokenSymlinkPrune,
|
||||
rootPrune,
|
||||
rootSharpPrune,
|
||||
rootSymlinkAudit,
|
||||
sourceWebRoot: installResult.sourceWebRoot,
|
||||
version: 1,
|
||||
};
|
||||
|
||||
await mkdir(path.dirname(config.auditReportPath), { recursive: true });
|
||||
await writeFile(config.auditReportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
||||
}
|
||||
|
||||
module.exports = async function webStandaloneAfterPack(context) {
|
||||
try {
|
||||
await runWebStandaloneAfterPack(context);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"[tools-pack web-standalone] after-pack hook failed:",
|
||||
error instanceof Error ? error.message : error,
|
||||
);
|
||||
console.error("[tools-pack web-standalone] electron-builder context:", {
|
||||
appOutDir: context?.appOutDir,
|
||||
electronPlatformName: context?.electronPlatformName,
|
||||
productFilename: context?.packager?.appInfo?.productFilename,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user