openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
277 lines (276 loc) • 14.6 kB
JavaScript
import { v as sortUniqueStrings } from "./string-normalization-CECOqf64.mjs";
import { w as root } from "./fs-safe-BUXBSN-4.mjs";
import { r as isMissingPathError } from "./errno-FR4CRyya.mjs";
import { t as escapeRegExp } from "./regexp-BZyMFTlj.mjs";
import { o as readJsonIfExists } from "./json-files-C5mNTScg.mjs";
import { c as sha256File } from "./directory-durability-CqSvP1tc.mjs";
import { t as _usingCtx } from "./usingCtx-DwOBYOJf.mjs";
import path from "node:path";
import fs from "node:fs/promises";
import pLimit from "p-limit";
/**
* Dist paths that contain local build metadata and should not be packaged as source.
* @internal Shared repository-script contract.
*/
const LOCAL_BUILD_METADATA_DIST_PATHS = Object.freeze([`dist/.buildstamp`, `dist/.runtime-postbuildstamp`]);
const LOCAL_BUILD_METADATA_DIST_PATH_SET = new Set(LOCAL_BUILD_METADATA_DIST_PATHS);
/** Return whether a dist-relative path is local build metadata. */
function isLocalBuildMetadataDistPath(relativePath) {
return LOCAL_BUILD_METADATA_DIST_PATH_SET.has(relativePath);
}
//#endregion
//#region scripts/lib/package-dist-inventory-contract.mts
const PACKAGE_DIST_INVENTORY_RELATIVE_PATH = "dist/postinstall-inventory.json";
const PACKAGE_DIST_CONTENT_INVENTORY_RELATIVE_PATH = "dist/postinstall-content-inventory.json";
function createPackageDistContentInventoryEntry(relativePath, hash, mode) {
return {
path: relativePath.replace(/\\/g, "/"),
sha256: hash.digest,
mode: mode & 511,
size: hash.bytes
};
}
function parsePackageDistContentInventory(value) {
if (!Array.isArray(value)) throw new Error("Invalid package dist content inventory");
const seen = /* @__PURE__ */ new Set();
return value.map((entry) => {
if (!entry || typeof entry !== "object") throw new Error("Invalid package dist content inventory entry");
const item = entry;
if (typeof item.path !== "string" || !item.path.startsWith("dist/") || item.path.includes("\\") || item.path.includes("\0") || item.path.split("/").some((part) => !part || part === "." || part === "..") || item.path === "dist/postinstall-inventory.json" || item.path === "dist/postinstall-content-inventory.json" || typeof item.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(item.sha256) || !Number.isSafeInteger(item.size) || item.size < 0 || !Number.isInteger(item.mode) || item.mode < 0 || item.mode > 511 || seen.has(item.path)) throw new Error("Invalid package dist content inventory entry");
seen.add(item.path);
return {
path: item.path,
sha256: item.sha256,
size: item.size,
mode: item.mode
};
}).toSorted((a, b) => a.path.localeCompare(b.path));
}
function comparePackageDistContentInventory(expected, actual) {
const format = (entry) => `${entry.path}:${entry.sha256}:${entry.size}:${process.platform === "win32" ? "" : Boolean(entry.mode & 73)}`;
return JSON.stringify(expected.map(format).toSorted()) === JSON.stringify(actual.map(format).toSorted()) ? [] : [`Invalid package dist content inventory at ${PACKAGE_DIST_CONTENT_INVENTORY_RELATIVE_PATH}: expected packaged file hashes and executable bits to match current dist files.`];
}
//#endregion
//#region src/infra/package-dist-inventory.ts
const PACKAGE_DIST_INVENTORY_SCAN_CONCURRENCY = 32;
const LEGACY_QA_CHANNEL_DIR = ["qa", "channel"].join("-");
const LEGACY_QA_LAB_DIR = ["qa", "lab"].join("-");
const OMITTED_QA_EXTENSION_PREFIXES = [`dist/extensions/${LEGACY_QA_CHANNEL_DIR}/`, `dist/extensions/${LEGACY_QA_LAB_DIR}/`];
const OMITTED_PRIVATE_QA_PLUGIN_SDK_PREFIXES = [`dist/plugin-sdk/extensions/${LEGACY_QA_CHANNEL_DIR}/`, `dist/plugin-sdk/extensions/${LEGACY_QA_LAB_DIR}/`];
const OMITTED_PRIVATE_QA_PLUGIN_SDK_FILES = /* @__PURE__ */ new Set([
`dist/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}.d.ts`,
`dist/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}.js`,
`dist/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}-protocol.d.ts`,
`dist/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}-protocol.js`,
`dist/plugin-sdk/${LEGACY_QA_LAB_DIR}.d.ts`,
`dist/plugin-sdk/${LEGACY_QA_LAB_DIR}.js`,
"dist/plugin-sdk/qa-runtime.d.ts",
"dist/plugin-sdk/qa-runtime.js"
]);
const OMITTED_DEEP_PLUGIN_SDK_DECLARATION_PREFIX = "dist/plugin-sdk/src/";
const OMITTED_PRIVATE_QA_DIST_PREFIXES = ["dist/qa-runtime-"];
const OMITTED_PLUGIN_SDK_TEST_FILES = new Set([
"agent-runtime-test-contracts",
"channel-contract-testing",
"channel-target-testing",
"channel-test-helpers",
"compiled-subprocess-testing",
"plugin-test-api",
"plugin-test-contracts",
"plugin-test-runtime",
"provider-http-test-mocks",
"provider-test-contracts",
"test-env",
"test-fixtures",
"test-live",
"test-live-auth",
"test-media-generation",
"test-media-understanding",
"test-node-mocks"
].flatMap((name) => [`dist/plugin-sdk/${name}.d.ts`, `dist/plugin-sdk/${name}.js`]));
const OMITTED_DIST_SUBTREE_PATTERNS = [
/^dist\/extensions\/node_modules(?:\/|$)/u,
/^dist\/extensions\/[^/]+\/node_modules(?:\/|$)/u,
/^dist\/plugin-sdk\/src(?:\/|$)/u,
new RegExp(`^dist/plugin-sdk/extensions/${LEGACY_QA_CHANNEL_DIR}(?:/|$)`, "u"),
new RegExp(`^dist/plugin-sdk/extensions/${LEGACY_QA_LAB_DIR}(?:/|$)`, "u")
];
function normalizeRelativePath(value) {
return value.replace(/\\/g, "/");
}
function isLegacyPluginDependencyDirPath(relativePath) {
const parts = normalizeRelativePath(relativePath).split("/");
if (parts[0]?.toLowerCase() !== "dist" || parts[1]?.toLowerCase() !== "extensions") return false;
return parts[2]?.toLowerCase() === "node_modules" || parts[3]?.toLowerCase() === "node_modules";
}
function compilePackageFilesExclusionPattern(pattern) {
let source = "^";
for (let index = 0; index < pattern.length; index += 1) {
const char = pattern[index];
if (char === "*") {
if (pattern[index + 1] === "*") {
if (pattern[index + 2] === "/") {
source += "(?:[^/]+/)*";
index += 2;
} else {
source += ".*";
index += 1;
}
} else source += "[^/]*";
continue;
}
source += escapeRegExp(char ?? "");
}
source += "$";
return new RegExp(source, "u");
}
function collectPackageDistExclusionRules(rootPackageJson) {
if (!rootPackageJson || typeof rootPackageJson !== "object") return {
files: /* @__PURE__ */ new Set(),
prefixes: [],
patterns: []
};
const files = rootPackageJson.files;
if (!Array.isArray(files)) return {
files: /* @__PURE__ */ new Set(),
prefixes: [],
patterns: []
};
const excludedFiles = /* @__PURE__ */ new Set();
const excludedPrefixes = /* @__PURE__ */ new Set();
const excludedPatterns = [];
for (const entry of files) {
if (typeof entry !== "string") continue;
const normalized = normalizeRelativePath(entry);
const match = /^!dist\/extensions\/([^/]+)\/\*\*$/u.exec(normalized);
if (match?.[1]) {
excludedFiles.add(`dist/extensions/${match[1]}`);
excludedPrefixes.add(`dist/extensions/${match[1]}/`);
}
if (!normalized.startsWith("!dist/")) continue;
const excludedPath = normalized.slice(1);
if (excludedPath.endsWith("/**") && !excludedPath.slice(0, -3).includes("*")) excludedPrefixes.add(excludedPath.slice(0, -2));
else if (excludedPath.includes("*")) excludedPatterns.push(compilePackageFilesExclusionPattern(excludedPath));
else excludedFiles.add(excludedPath);
}
return {
files: excludedFiles,
prefixes: [...excludedPrefixes].toSorted((left, right) => left.localeCompare(right)),
patterns: excludedPatterns
};
}
function isPackageFilesExcludedDistPath(relativePath, exclusions) {
return exclusions.files.has(relativePath) || exclusions.prefixes.some((prefix) => relativePath.startsWith(prefix)) || exclusions.patterns.some((pattern) => pattern.test(relativePath));
}
function isPackagedDistPath(relativePath, rules) {
if (!relativePath.startsWith("dist/")) return false;
if (rules.includePackageExcludedFiles) return relativePath !== "dist/postinstall-inventory.json" && !isLegacyPluginDependencyDirPath(relativePath);
return !(isPackageFilesExcludedDistPath(relativePath, rules) || isLegacyPluginDependencyDirPath(relativePath) || relativePath === "dist/postinstall-inventory.json" || isLocalBuildMetadataDistPath(relativePath) || relativePath.endsWith(".map") || relativePath === "dist/plugin-sdk/.tsbuildinfo" || OMITTED_PLUGIN_SDK_TEST_FILES.has(relativePath) || relativePath.startsWith(OMITTED_DEEP_PLUGIN_SDK_DECLARATION_PREFIX) || OMITTED_PRIVATE_QA_PLUGIN_SDK_PREFIXES.some((prefix) => relativePath.startsWith(prefix)) || OMITTED_PRIVATE_QA_PLUGIN_SDK_FILES.has(relativePath) || OMITTED_PRIVATE_QA_DIST_PREFIXES.some((prefix) => relativePath.startsWith(prefix)) || OMITTED_QA_EXTENSION_PREFIXES.some((prefix) => relativePath.startsWith(prefix)));
}
function isOmittedDistSubtree(relativePath, rules) {
if (rules.includePackageExcludedFiles) return isLegacyPluginDependencyDirPath(relativePath);
return isPackageFilesExcludedDistPath(relativePath, rules) || isPackageFilesExcludedDistPath(`${relativePath}/`, rules) || isLegacyPluginDependencyDirPath(relativePath) || OMITTED_PLUGIN_SDK_TEST_FILES.has(relativePath) || OMITTED_DIST_SUBTREE_PATTERNS.some((pattern) => pattern.test(relativePath));
}
async function collectRelativeFiles(rootDir, baseDir, rules, fsLimit, onDirectory) {
const rootRelativePath = normalizeRelativePath(path.relative(baseDir, rootDir));
if (rootRelativePath && isOmittedDistSubtree(rootRelativePath, rules)) return [];
try {
const rootStats = await fsLimit(() => fs.lstat(rootDir));
if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) throw new Error(`Unsafe package dist path: ${normalizeRelativePath(path.relative(baseDir, rootDir))}`);
await onDirectory?.(rootDir);
const entries = await fsLimit(() => fs.readdir(rootDir, { withFileTypes: true }));
return (await Promise.all(entries.map(async (entry) => {
const entryPath = path.join(rootDir, entry.name);
const relativePath = normalizeRelativePath(path.relative(baseDir, entryPath));
if (entry.isSymbolicLink()) throw new Error(`Unsafe package dist path: ${relativePath}`);
if (entry.isDirectory()) return await collectRelativeFiles(entryPath, baseDir, rules, fsLimit, onDirectory);
if (entry.isFile()) return isPackagedDistPath(relativePath, rules) ? [relativePath] : [];
if (rules.includePackageExcludedFiles) throw new Error(`Unsupported local package entry: ${relativePath}`);
return [];
}))).flat().toSorted((left, right) => left.localeCompare(right));
} catch (error) {
if (error.code === "ENOENT") return [];
throw error;
}
}
/** Collects package dist files that should be present after install/update publication. */
async function collectPackageDistInventory(packageRoot, options = {}) {
const rules = options.includePackageExcludedFiles ? {
...collectPackageDistExclusionRules({}),
includePackageExcludedFiles: true
} : options.packageManifest === void 0 ? collectPackageDistExclusionRules(await readJsonIfExists(path.join(packageRoot, "package.json"))) : collectPackageDistExclusionRules(options.packageManifest);
const fsLimit = pLimit(PACKAGE_DIST_INVENTORY_SCAN_CONCURRENCY);
return await collectRelativeFiles(path.join(packageRoot, "dist"), packageRoot, rules, fsLimit, options.onDirectory);
}
/** Reads an existing package dist inventory, returning null when the inventory is absent. */
async function readPackageDistInventoryIfPresent(packageRoot) {
const parsed = await readPackageDistJsonIfExists(packageRoot, PACKAGE_DIST_INVENTORY_RELATIVE_PATH);
if (parsed === void 0) return null;
if (!Array.isArray(parsed) || parsed.some((entry) => typeof entry !== "string")) throw new Error(`Invalid package dist inventory at ${PACKAGE_DIST_INVENTORY_RELATIVE_PATH}`);
return sortUniqueStrings(parsed.map(normalizeRelativePath));
}
async function openPackageDistFsRootIfPresent(packageRoot) {
const packageFs = await root(packageRoot, {
hardlinks: "allow",
symlinks: "reject"
});
let distStats;
try {
distStats = await fs.lstat(path.join(packageFs.rootReal, "dist"));
} catch (error) {
if (isMissingPathError(error)) return null;
throw error;
}
if (!distStats.isDirectory() || distStats.isSymbolicLink()) throw new Error("Unsafe package dist path: dist");
return packageFs;
}
async function readPackageDistJsonIfExists(packageRoot, relativePath) {
const packageFs = await openPackageDistFsRootIfPresent(packageRoot);
if (!packageFs) return;
try {
return await packageFs.readJson(relativePath, {
hardlinks: "allow",
maxBytes: 16777216,
symlinks: "reject"
});
} catch (error) {
if (isMissingPathError(error)) return;
throw error;
}
}
async function collectPackageDistContentInventory(packageRoot, inventory) {
const files = (inventory ?? await collectPackageDistInventory(packageRoot)).filter((file) => file !== PACKAGE_DIST_CONTENT_INVENTORY_RELATIVE_PATH);
const packageFs = await openPackageDistFsRootIfPresent(packageRoot);
if (!packageFs) {
if (files.length === 0) return [];
throw new Error("Unsafe package dist path: dist");
}
const fsLimit = pLimit(PACKAGE_DIST_INVENTORY_SCAN_CONCURRENCY);
return (await Promise.all(files.map((relativePath) => fsLimit(async () => {
try {
var _usingCtx$1 = _usingCtx();
const opened = _usingCtx$1.a(await packageFs.open(relativePath, {
hardlinks: "allow",
symlinks: "reject"
}));
return createPackageDistContentInventoryEntry(relativePath, await sha256File(opened.handle), opened.stat.mode);
} catch (_) {
_usingCtx$1.e = _;
} finally {
await _usingCtx$1.d();
}
})))).toSorted((left, right) => left.path.localeCompare(right.path));
}
async function readPackageDistContentInventoryIfPresent(packageRoot) {
const parsed = await readPackageDistJsonIfExists(packageRoot, PACKAGE_DIST_CONTENT_INVENTORY_RELATIVE_PATH);
if (parsed !== void 0) return parsePackageDistContentInventory(parsed);
if ((await readPackageDistInventoryIfPresent(packageRoot))?.includes("dist/postinstall-content-inventory.json")) throw new Error(`missing package dist content inventory ${PACKAGE_DIST_CONTENT_INVENTORY_RELATIVE_PATH}`);
return null;
}
async function collectPackageDistContentInventoryErrors(packageRoot) {
const expected = await readPackageDistContentInventoryIfPresent(packageRoot);
if (expected === null) return [];
return comparePackageDistContentInventory(expected, await collectPackageDistContentInventory(packageRoot));
}
//#endregion
export { readPackageDistInventoryIfPresent as a, comparePackageDistContentInventory as c, readPackageDistContentInventoryIfPresent as i, collectPackageDistContentInventoryErrors as n, PACKAGE_DIST_CONTENT_INVENTORY_RELATIVE_PATH as o, collectPackageDistInventory as r, PACKAGE_DIST_INVENTORY_RELATIVE_PATH as s, collectPackageDistContentInventory as t };