Skip to content

Commit 5901467

Browse files
committed
Fix executor beta packaging for 1Password wasm
1 parent 9aa445b commit 5901467

6 files changed

Lines changed: 97 additions & 2 deletions

File tree

.changeset/fuzzy-camels-cheer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"executor": patch
3+
---
4+
5+
Fix the packaged beta so the bundled 1Password SDK can load its wasm asset after install.

.changeset/pre.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
},
5252
"changesets": [
5353
"funny-forks-listen",
54+
"fuzzy-camels-cheer",
5455
"tame-trains-confess"
5556
]
5657
}

apps/executor/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# executor
22

3+
## 1.3.0-beta.2
4+
5+
### Patch Changes
6+
7+
- Fix the packaged beta so the bundled 1Password SDK can load its wasm asset after install.
8+
39
## 1.3.0-beta.1
410

511
### Patch Changes

apps/executor/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "executor",
3-
"version": "1.3.0-beta.1",
3+
"version": "1.3.0-beta.2",
44
"description": "Local AI executor with a CLI, local API server, and web UI.",
55
"keywords": [
66
"executor",

apps/executor/src/distribution/artifact.ts

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { spawn } from "node:child_process";
2-
import { existsSync } from "node:fs";
2+
import { existsSync, readFileSync } from "node:fs";
33
import { chmod, cp, mkdir, rename, rm, writeFile } from "node:fs/promises";
44
import { createRequire } from "node:module";
55
import { dirname, join, resolve } from "node:path";
@@ -23,6 +23,12 @@ export type DistributionPackageArtifact = {
2323
resourcesDir: string;
2424
};
2525

26+
type BundledDependency = {
27+
name: string;
28+
version: string;
29+
packageDir: string;
30+
};
31+
2632
type CommandInput = {
2733
command: string;
2834
args: ReadonlyArray<string>;
@@ -90,6 +96,56 @@ const resolveQuickJsWasmPath = (): string => {
9096
return wasmPath;
9197
};
9298

99+
const resolveInstalledPackage = (input: {
100+
packageName: string;
101+
fromPackageJsonPath: string;
102+
}): BundledDependency => {
103+
const requireFromPackage = createRequire(input.fromPackageJsonPath);
104+
const packageEntrypointPath = requireFromPackage.resolve(input.packageName);
105+
let packageDir = dirname(packageEntrypointPath);
106+
let packageJsonPath = join(packageDir, "package.json");
107+
108+
while (!existsSync(packageJsonPath)) {
109+
const parentDir = dirname(packageDir);
110+
if (parentDir === packageDir) {
111+
throw new Error(`Unable to locate package.json for ${input.packageName} from ${packageEntrypointPath}`);
112+
}
113+
packageDir = parentDir;
114+
packageJsonPath = join(packageDir, "package.json");
115+
}
116+
117+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as {
118+
name?: string;
119+
version?: string;
120+
};
121+
122+
if (!packageJson.name || !packageJson.version) {
123+
throw new Error(`Invalid package metadata at ${packageJsonPath}`);
124+
}
125+
126+
return {
127+
name: packageJson.name,
128+
version: packageJson.version,
129+
packageDir,
130+
};
131+
};
132+
133+
const resolveBundledDependencies = (): ReadonlyArray<BundledDependency> => {
134+
const onePasswordSdk = resolveInstalledPackage({
135+
packageName: "@1password/sdk",
136+
fromPackageJsonPath: join(repoRoot, "plugins/onepassword/sdk/package.json"),
137+
});
138+
const onePasswordSdkCore = resolveInstalledPackage({
139+
packageName: "@1password/sdk-core",
140+
fromPackageJsonPath: join(onePasswordSdk.packageDir, "package.json"),
141+
});
142+
143+
return [
144+
onePasswordSdk,
145+
onePasswordSdkCore,
146+
];
147+
};
148+
93149

94150
const createPackageJson = (input: {
95151
packageName: string;
@@ -105,6 +161,8 @@ const createPackageJson = (input: {
105161
url?: string;
106162
};
107163
license?: string;
164+
dependencies?: Readonly<Record<string, string>>;
165+
bundleDependencies?: ReadonlyArray<string>;
108166
}) => {
109167
const packageJson = {
110168
name: input.packageName,
@@ -122,13 +180,16 @@ const createPackageJson = (input: {
122180
},
123181
files: [
124182
"bin",
183+
"node_modules",
125184
"resources",
126185
"README.md",
127186
"package.json",
128187
],
129188
engines: {
130189
node: ">=20",
131190
},
191+
dependencies: input.dependencies,
192+
bundleDependencies: input.bundleDependencies,
132193
};
133194

134195
return JSON.stringify(packageJson, null, 2) + "\n";
@@ -195,6 +256,7 @@ const buildCliBundle = async (input: {
195256
"node",
196257
"--outdir",
197258
input.binDir,
259+
"--external=@1password/sdk",
198260
],
199261
cwd: repoRoot,
200262
});
@@ -217,14 +279,17 @@ export const buildDistributionPackage = async (
217279
const webDir = join(resourcesDir, "web");
218280
const bundlePath = join(binDir, "executor.mjs");
219281
const launcherPath = join(binDir, "executor.js");
282+
const nodeModulesDir = join(packageDir, "node_modules");
220283
const quickJsWasmPath = resolveQuickJsWasmPath();
284+
const bundledDependencies = resolveBundledDependencies();
221285

222286
const webDistDir = join(repoRoot, "apps/web/dist");
223287
const readmePath = join(repoRoot, "README.md");
224288
const packageName = options.packageName ?? defaults.name;
225289
const packageVersion = options.packageVersion ?? defaults.version;
226290
await rm(packageDir, { recursive: true, force: true });
227291
await mkdir(binDir, { recursive: true });
292+
await mkdir(nodeModulesDir, { recursive: true });
228293
await mkdir(resourcesDir, { recursive: true });
229294

230295
if ((options.buildWeb ?? true) || !existsSync(webDistDir)) {
@@ -245,6 +310,11 @@ export const buildDistributionPackage = async (
245310
});
246311

247312
await cp(webDistDir, webDir, { recursive: true });
313+
for (const dependency of bundledDependencies) {
314+
const destinationDir = join(nodeModulesDir, ...dependency.name.split("/"));
315+
await mkdir(dirname(destinationDir), { recursive: true });
316+
await cp(dependency.packageDir, destinationDir, { recursive: true });
317+
}
248318
await cp(quickJsWasmPath, join(binDir, "emscripten-module.wasm"));
249319
await cp(
250320
join(repoRoot, "packages/kernel/runtime-deno-subprocess/src/deno-subprocess-worker.mjs"),
@@ -271,6 +341,10 @@ export const buildDistributionPackage = async (
271341
bugs: defaults.bugs,
272342
repository: defaults.repository,
273343
license: defaults.license,
344+
dependencies: Object.fromEntries(
345+
bundledDependencies.map((dependency) => [dependency.name, dependency.version]),
346+
),
347+
bundleDependencies: bundledDependencies.map((dependency) => dependency.name),
274348
}));
275349
await cp(readmePath, join(packageDir, "README.md"));
276350
await writeFile(launcherPath, createLauncherSource());

apps/executor/src/distribution/distribution.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { existsSync, readFileSync } from "node:fs";
2+
import { join } from "node:path";
3+
14
import { describe, expect, it } from "@effect/vitest";
25
import * as Effect from "effect/Effect";
36

@@ -17,6 +20,12 @@ describe("distribution flow", () => {
1720
) =>
1821
Effect.gen(function* () {
1922
const harness = yield* DistributionHarness;
23+
const bundleSource = readFileSync(join(harness.packageDir, "bin/executor.mjs"), "utf8");
24+
25+
expect(bundleSource).not.toContain("core_bg.wasm");
26+
expect(
27+
existsSync(join(harness.packageDir, "node_modules/@1password/sdk-core/nodejs/core_bg.wasm")),
28+
).toBe(true);
2029

2130
yield* harness.writeProjectConfig(`{
2231
"runtime": "ses",

0 commit comments

Comments
 (0)