mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 17:53:39 +00:00
* fix(nodes): bootstrap source builds with private QA tooling Keep private QA chunks out of node bootstrap archives only when their current bytes match the shared ownership record and no retained runtime requires them. Preserve root URL and bound createRequire imports, verify copied bytes, and keep package inventory and updater selection unchanged. Move the existing ownership reader, import parser and private plugin set to runtime-safe owners with all tooling callers migrated. Cover archive creation, root scripts, dependency scopes and package verification; retain the existing source-build bootstrap contract. * test(build): stage shared sources for declaration fixtures Copy the relocated build configuration owners into the synthetic project and resolve record-coerce through its existing local source. Keep the package forwarder relative so cache relocation stays stable and generator imports do not depend on the compiler configuration under test. Preserve the original declaration assertions, including invalid-config failures and cleanup ownership checks. * fix(build): keep ownership metadata readable by cold tooling Import the existing normalization source directly so native run-node, updater, and packaging entrypoints do not need workspace package resolution before their bootstrap logic can run. Copy the shared policy source into the two remaining concrete packaging fixtures and remove the declaration fixture package forwarder made obsolete by the native-readable owner. Preserve existing assertions and timeouts.
59 lines
2.4 KiB
TypeScript
59 lines
2.4 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import path from "node:path";
|
|
import type { TsdownPlugin } from "tsdown";
|
|
import {
|
|
RUNTIME_DEPENDENCY_OWNERSHIP_ASSET_NAME,
|
|
type RuntimeDependencyOwnership,
|
|
} from "../../src/infra/runtime-dependency-ownership.ts";
|
|
|
|
export function createRuntimeDependencyOwnershipBuildPlugin(rootDir = process.cwd()): TsdownPlugin {
|
|
return {
|
|
name: "openclaw:runtime-dependency-ownership",
|
|
generateBundle: {
|
|
order: "post",
|
|
handler(_options, bundle) {
|
|
const chunks = Object.values(bundle).filter((output) => output.type === "chunk");
|
|
const ownersByChunk = new Map<string, Set<string>>();
|
|
for (const entry of chunks.filter((chunk) => chunk.isEntry)) {
|
|
const source = entry.facadeModuleId?.split("?", 1)[0];
|
|
const relative = source ? path.relative(rootDir, source).split(path.sep).join("/") : "";
|
|
// An empty owner represents a root entry and prevents plugin authorization.
|
|
const owner = /^extensions\/([a-z0-9][a-z0-9-]*)\//u.exec(relative)?.[1] ?? "";
|
|
const pending = [entry.fileName];
|
|
const visited = new Set<string>();
|
|
while (pending.length > 0) {
|
|
const fileName = pending.pop()!;
|
|
if (visited.has(fileName)) {
|
|
continue;
|
|
}
|
|
visited.add(fileName);
|
|
const chunk = bundle[fileName];
|
|
if (chunk?.type !== "chunk") {
|
|
continue;
|
|
}
|
|
const owners = ownersByChunk.get(fileName) ?? new Set<string>();
|
|
owners.add(owner);
|
|
ownersByChunk.set(fileName, owners);
|
|
pending.push(...chunk.imports, ...chunk.dynamicImports);
|
|
}
|
|
}
|
|
const ownership: RuntimeDependencyOwnership = { chunks: {} };
|
|
for (const chunk of chunks.toSorted((a, b) => a.fileName.localeCompare(b.fileName))) {
|
|
const owners = ownersByChunk.get(chunk.fileName);
|
|
if (!owners?.size || owners.has("") || chunk.fileName.startsWith("extensions/")) {
|
|
continue;
|
|
}
|
|
ownership.chunks[chunk.fileName] = {
|
|
sha256: createHash("sha256").update(chunk.code).digest("hex"),
|
|
extensions: [...owners].toSorted(),
|
|
};
|
|
}
|
|
this.emitFile({
|
|
type: "asset",
|
|
fileName: RUNTIME_DEPENDENCY_OWNERSHIP_ASSET_NAME,
|
|
source: `${JSON.stringify(ownership)}\n`,
|
|
});
|
|
},
|
|
},
|
|
};
|
|
}
|