mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 04:15:48 -06:00
fix(worker): keep source bundles npm-installable (#122430)
This commit is contained in:
committed by
GitHub
parent
f6459a3255
commit
e30df72045
@@ -101,11 +101,13 @@
|
||||
"@anthropic-ai/sdk": "0.115.0",
|
||||
"@google/genai": "2.13.0",
|
||||
"@mistralai/mistralai": "2.5.0",
|
||||
"@openclaw/normalization-core": "workspace:*",
|
||||
"openai": "6.49.0",
|
||||
"partial-json": "0.1.7",
|
||||
"typebox": "1.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openclaw/normalization-core": "workspace:*"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@ async function productionImportsPackage(packageName: string): Promise<boolean> {
|
||||
}
|
||||
|
||||
describe("@openclaw/ai source dependency contract", () => {
|
||||
it("declares normalization-core while production source imports it", async () => {
|
||||
it("declares bundled normalization-core imports as a workspace dev dependency", async () => {
|
||||
const manifest = JSON.parse(
|
||||
await fs.readFile(path.join(PACKAGE_ROOT, "package.json"), "utf8"),
|
||||
) as {
|
||||
@@ -53,6 +53,7 @@ describe("@openclaw/ai source dependency contract", () => {
|
||||
};
|
||||
|
||||
expect(await productionImportsPackage("@openclaw/normalization-core")).toBe(true);
|
||||
expect(manifest.dependencies?.["@openclaw/normalization-core"]).toBe("workspace:*");
|
||||
expect(manifest.dependencies?.["@openclaw/normalization-core"]).toBeUndefined();
|
||||
expect(manifest.devDependencies?.["@openclaw/normalization-core"]).toBe("workspace:*");
|
||||
});
|
||||
});
|
||||
|
||||
Generated
+4
-3
@@ -2167,9 +2167,6 @@ importers:
|
||||
'@mistralai/mistralai':
|
||||
specifier: 2.5.0
|
||||
version: 2.5.0(@opentelemetry/api@1.9.1)
|
||||
'@openclaw/normalization-core':
|
||||
specifier: workspace:*
|
||||
version: link:../normalization-core
|
||||
openai:
|
||||
specifier: 6.49.0
|
||||
version: 6.49.0(@aws-sdk/credential-provider-node@3.972.72)(@smithy/hash-node@4.4.14)(@smithy/signature-v4@5.6.10)(ws@8.21.1)(zod@4.4.3)
|
||||
@@ -2179,6 +2176,10 @@ importers:
|
||||
typebox:
|
||||
specifier: 1.3.6
|
||||
version: 1.3.6
|
||||
devDependencies:
|
||||
'@openclaw/normalization-core':
|
||||
specifier: workspace:*
|
||||
version: link:../normalization-core
|
||||
|
||||
packages/gateway-client:
|
||||
dependencies:
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import * as tar from "tar";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { runCommandWithTimeout } from "../../process/exec.js";
|
||||
import { withTestDir } from "../../test-helpers/temp-dir.js";
|
||||
import {
|
||||
createWorkerBundleProducer,
|
||||
@@ -246,6 +247,76 @@ describe("worker bundle producer", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("installs a source bundle when the AI workspace import is bundled", async () => {
|
||||
await withTestDir({ prefix: "openclaw-worker-bundle-npm-install-" }, async (root) => {
|
||||
const repoRoot = path.resolve(import.meta.dirname, "../../..");
|
||||
const aiManifest = JSON.parse(
|
||||
await fs.readFile(path.join(repoRoot, "packages/ai/package.json"), "utf8"),
|
||||
) as {
|
||||
dependencies?: Record<string, string>;
|
||||
devDependencies?: Record<string, string>;
|
||||
};
|
||||
const dependencyFields = (["dependencies", "devDependencies"] as const).filter(
|
||||
(field) => aiManifest[field]?.["@openclaw/normalization-core"] !== undefined,
|
||||
);
|
||||
if (dependencyFields.length !== 1) {
|
||||
throw new Error(
|
||||
"@openclaw/ai must classify normalization-core in exactly one dependency field",
|
||||
);
|
||||
}
|
||||
const dependencyField = dependencyFields[0]!;
|
||||
const normalizationCoreSpec = aiManifest[dependencyField]?.["@openclaw/normalization-core"];
|
||||
if (!normalizationCoreSpec?.startsWith("workspace:")) {
|
||||
throw new Error("@openclaw/ai must use a workspace normalization-core dependency");
|
||||
}
|
||||
const packageRoot = path.join(root, "package");
|
||||
await writeFixture(packageRoot, [["dist/entry.js", 'import "@openclaw/ai";\nexport {};\n']]);
|
||||
await fs.writeFile(
|
||||
path.join(packageRoot, "package.json"),
|
||||
`${JSON.stringify({
|
||||
name: "openclaw",
|
||||
version: "1.2.3",
|
||||
type: "module",
|
||||
files: ["dist/"],
|
||||
dependencies: { "@openclaw/ai": "workspace:*" },
|
||||
})}\n`,
|
||||
"utf8",
|
||||
);
|
||||
const vendorSource = path.join(packageRoot, "node_modules/@openclaw/ai");
|
||||
await fs.mkdir(path.join(vendorSource, "dist"), { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(vendorSource, "package.json"),
|
||||
`${JSON.stringify({
|
||||
name: "@openclaw/ai",
|
||||
version: "1.2.3",
|
||||
type: "module",
|
||||
main: "./dist/index.js",
|
||||
[dependencyField]: { "@openclaw/normalization-core": normalizationCoreSpec },
|
||||
})}\n`,
|
||||
"utf8",
|
||||
);
|
||||
await fs.writeFile(path.join(vendorSource, "dist/index.js"), "export {};\n", "utf8");
|
||||
|
||||
const bundle = await createWorkerBundleProducer({
|
||||
packageRoot,
|
||||
cacheDir: path.join(root, "cache"),
|
||||
}).prepare();
|
||||
const extractRoot = path.join(root, "extract");
|
||||
await fs.mkdir(extractRoot);
|
||||
await tar.extract({ file: bundle.tarballPath, cwd: extractRoot });
|
||||
|
||||
const install = await runCommandWithTimeout(
|
||||
["npm", "install", "--ignore-scripts", "--omit=dev", "--no-audit", "--no-fund"],
|
||||
{
|
||||
cwd: extractRoot,
|
||||
env: { NPM_CONFIG_CACHE: path.join(root, "npm-cache") },
|
||||
timeoutMs: 30_000,
|
||||
},
|
||||
);
|
||||
expect(install.code, install.stderr).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it("fails closed when a dist-referenced workspace package is not installed", async () => {
|
||||
await withTestDir({ prefix: "openclaw-worker-bundle-vendor-missing-" }, async (root) => {
|
||||
const packageRoot = path.join(root, "package");
|
||||
|
||||
Reference in New Issue
Block a user