Showing the changes to apps/cli/src (2 of 8 files). Show all
Unified · Split
| @@ -2,7 +2,7 @@ import { cp, mkdir, rm, writeFile, chmod } from "node:fs/promises"; · 1 unmodified line | |||
| 2 | import { existsSync } from "node:fs"; | 2 | import { existsSync } from "node:fs"; |
| 3 | import { createRequire } from "node:module"; | 3 | import { createRequire } from "node:module"; |
| 4 | import { resolve, join, dirname } from "node:path"; | 4 | import { resolve, join, dirname } from "node:path"; |
| 5 | import { fileURLToPath } from "node:url"; | 5 | import { fileURLToPath, pathToFileURL } from "node:url"; |
| 6 | import { parseArgs } from "node:util"; | 6 | import { parseArgs } from "node:util"; |
| 7 | import { $ } from "bun"; | 7 | import { $ } from "bun"; |
| 8 | 8 | ||
| @@ -11,6 +11,8 @@ const cliRoot = resolve(repoRoot, "apps/cli"); · 2 unmodified lines | |||
| 11 | const webRoot = resolve(repoRoot, "apps/local"); | 11 | const webRoot = resolve(repoRoot, "apps/local"); |
| 12 | const distDir = resolve(cliRoot, "dist"); | 12 | const distDir = resolve(cliRoot, "dist"); |
| 13 | const ONEPASSWORD_CORE_WASM_FILENAME = "onepassword-core_bg.wasm"; | 13 | const ONEPASSWORD_CORE_WASM_FILENAME = "onepassword-core_bg.wasm"; |
| 14 | const WORKERD_VERSION = "1.20260708.1"; | ||
| 15 | const WORKER_BUNDLER_DIRNAME = "worker-bundler"; | ||
| 14 | 16 | ||
| 15 | const resolveQuickJsWasmPath = (): string => { | 17 | const resolveQuickJsWasmPath = (): string => { |
| 16 | const req = createRequire(join(repoRoot, "packages/kernel/runtime-quickjs/package.json")); | 18 | const req = createRequire(join(repoRoot, "packages/kernel/runtime-quickjs/package.json")); |
| @@ -33,6 +35,34 @@ const resolveOnePasswordCoreWasmPath = (): string => { · 16 unmodified lines | |||
| 33 | return wasmPath; | 35 | return wasmPath; |
| 34 | }; | 36 | }; |
| 35 | 37 | ||
| 38 | const resolveWorkerBundlerDistPath = (): string => { | ||
| 39 | const req = createRequire(join(repoRoot, "packages/plugins/apps/package.json")); | ||
| 40 | const pkgJson = req.resolve("@cloudflare/worker-bundler/package.json"); | ||
| 41 | const distPath = join(dirname(pkgJson), "dist"); | ||
| 42 | if (!existsSync(join(distPath, "index.js")) || !existsSync(join(distPath, "esbuild.wasm"))) { | ||
| 43 | throw new Error(`@cloudflare/worker-bundler dist files not found at ${distPath}`); | ||
| 44 | } | ||
| 45 | return distPath; | ||
| 46 | }; | ||
| 47 | |||
| 48 | const createPackedWorkerBundlerSource = async (distPath: string): Promise<string> => { | ||
| 49 | const esbuildPath = join(repoRoot, "node_modules/.bun/node_modules/esbuild/lib/main.js"); | ||
| 50 | if (!existsSync(esbuildPath)) throw new Error(`esbuild not found at ${esbuildPath}`); | ||
| 51 | const { build } = await import(pathToFileURL(esbuildPath).href); | ||
| 52 | const result = await build({ | ||
| 53 | entryPoints: [join(distPath, "index.js")], | ||
| 54 | bundle: true, | ||
| 55 | format: "esm", | ||
| 56 | platform: "browser", | ||
| 57 | external: ["./esbuild.wasm"], | ||
| 58 | logLevel: "silent", | ||
| 59 | write: false, | ||
| 60 | }); | ||
| 61 | const source = result.outputFiles[0]?.text; | ||
| 62 | if (source === undefined) throw new Error("failed to bundle @cloudflare/worker-bundler"); | ||
| 63 | return source; | ||
| 64 | }; | ||
| 65 | |||
| 36 | // --------------------------------------------------------------------------- | 66 | // --------------------------------------------------------------------------- |
| 37 | // Metadata | 67 | // Metadata |
| 38 | // --------------------------------------------------------------------------- | 68 | // --------------------------------------------------------------------------- |
| @@ -119,6 +149,7 @@ const bunTarget = (t: Target): Bun.Build.CompileTarget => { · 80 unmodified lines | |||
| 119 | }; | 149 | }; |
| 120 | 150 | ||
| 121 | const binaryName = (t: Target) => (t.os === "win32" ? "executor.exe" : "executor"); | 151 | const binaryName = (t: Target) => (t.os === "win32" ? "executor.exe" : "executor"); |
| 152 | const workerdBinaryName = (t: Target) => (t.os === "win32" ? "workerd.exe" : "workerd"); | ||
| 122 | 153 | ||
| 123 | const isCurrentPlatform = (t: Target) => | 154 | const isCurrentPlatform = (t: Target) => |
| 124 | t.os === process.platform && t.arch === process.arch && !t.abi; | 155 | t.os === process.platform && t.arch === process.arch && !t.abi; |
| @@ -211,6 +242,41 @@ const resolveLibsqlNative = (t: Target): string | null => { · 86 unmodified lines | |||
| 211 | } | 242 | } |
| 212 | }; | 243 | }; |
| 213 | 244 | ||
| 245 | const resolveWorkerdBinary = (t: Target): string | null => { | ||
| 246 | const platformMap: Record<string, string> = { | ||
| 247 | "darwin-arm64": "@cloudflare/workerd-darwin-arm64", | ||
| 248 | "darwin-x64": "@cloudflare/workerd-darwin-64", | ||
| 249 | "linux-arm64": "@cloudflare/workerd-linux-arm64", | ||
| 250 | "linux-x64": "@cloudflare/workerd-linux-64", | ||
| 251 | "win32-x64": "@cloudflare/workerd-windows-64", | ||
| 252 | }; | ||
| 253 | const key = [t.os, t.arch, t.abi].filter(Boolean).join("-"); | ||
| 254 | const pkg = platformMap[key]; | ||
| 255 | if (!pkg) return null; | ||
| 256 | const binary = workerdBinaryName(t); | ||
| 257 | try { | ||
| 258 | const req = createRequire( | ||
| 259 | join(repoRoot, "packages/kernel/runtime-workerd-subprocess/package.json"), | ||
| 260 | ); | ||
| 261 | const pkgJson = req.resolve(`${pkg}/package.json`); | ||
| 262 | for (const candidate of [ | ||
| 263 | join(dirname(pkgJson), "bin", binary), | ||
| 264 | join(dirname(pkgJson), binary), | ||
| 265 | ]) { | ||
| 266 | if (existsSync(candidate)) return candidate; | ||
| 267 | } | ||
| 268 | } catch { | ||
| 269 | const packageRoot = join( | ||
| 270 | repoRoot, | ||
| 271 | `node_modules/.bun/${pkg.replace("/", "+")}@${WORKERD_VERSION}/node_modules/${pkg}`, | ||
| 272 | ); | ||
| 273 | for (const candidate of [join(packageRoot, "bin", binary), join(packageRoot, binary)]) { | ||
| 274 | if (existsSync(candidate)) return candidate; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | return null; | ||
| 278 | }; | ||
| 279 | |||
| 214 | // --------------------------------------------------------------------------- | 280 | // --------------------------------------------------------------------------- |
| 215 | // Build mode | 281 | // Build mode |
| 216 | // --------------------------------------------------------------------------- | 282 | // --------------------------------------------------------------------------- |
| @@ -333,6 +399,8 @@ const buildBinaries = async (targets: Target[], mode: BuildMode) => { · 116 unmodified lines | |||
| 333 | 399 | ||
| 334 | const quickJsWasmPath = resolveQuickJsWasmPath(); | 400 | const quickJsWasmPath = resolveQuickJsWasmPath(); |
| 335 | const onePasswordCoreWasmPath = resolveOnePasswordCoreWasmPath(); | 401 | const onePasswordCoreWasmPath = resolveOnePasswordCoreWasmPath(); |
| 402 | const workerBundlerDistPath = resolveWorkerBundlerDistPath(); | ||
| 403 | const packedWorkerBundlerSource = await createPackedWorkerBundlerSource(workerBundlerDistPath); | ||
| 336 | 404 | ||
| 337 | try { | 405 | try { |
| 338 | for (const target of targets) { | 406 | for (const target of targets) { |
| @@ -375,12 +443,35 @@ const buildBinaries = async (targets: Target[], mode: BuildMode) => { · 36 unmodified lines | |||
| 375 | await cp(libsqlNative, join(binDir, "libsql.node")); | 443 | await cp(libsqlNative, join(binDir, "libsql.node")); |
| 376 | } | 444 | } |
| 377 | 445 | ||
| 446 | const workerdBinary = resolveWorkerdBinary(target); | ||
| 447 | if (workerdBinary && existsSync(workerdBinary)) { | ||
| 448 | await cp(workerdBinary, join(binDir, workerdBinaryName(target))); | ||
| 449 | if (target.os !== "win32") await chmod(join(binDir, workerdBinaryName(target)), 0o755); | ||
| 450 | } | ||
| 451 | |||
| 452 | await cp(workerBundlerDistPath, join(binDir, WORKER_BUNDLER_DIRNAME, "dist"), { | ||
| 453 | recursive: true, | ||
| 454 | }); | ||
| 455 | await writeFile( | ||
| 456 | join(binDir, WORKER_BUNDLER_DIRNAME, "dist", "index.bundled.js"), | ||
| 457 | packedWorkerBundlerSource, | ||
| 458 | ); | ||
| 459 | |||
| 378 | // Smoke test on current platform | 460 | // Smoke test on current platform |
| 379 | if (isCurrentPlatform(target)) { | 461 | if (isCurrentPlatform(target)) { |
| 380 | const bin = join(binDir, binaryName(target)); | 462 | const bin = join(binDir, binaryName(target)); |
| 381 | console.log(` Smoke test: ${bin} --version`); | 463 | console.log(` Smoke test: ${bin} --version`); |
| 382 | const version = await $`${bin} --version`.text(); | 464 | const version = await $`${bin} --version`.text(); |
| 383 | console.log(` OK: ${version.trim()}`); | 465 | console.log(` OK: ${version.trim()}`); |
| 466 | console.log(` Smoke test: packed apps source sync and invoke`); | ||
| 467 | const smoke = Bun.spawn( | ||
| 468 | ["bun", "run", join(cliRoot, "scripts/smoke-packed-apps.ts"), bin], | ||
| 469 | { | ||
| 470 | cwd: repoRoot, | ||
| 471 | stdio: ["ignore", "inherit", "inherit"], | ||
| 472 | }, | ||
| 473 | ); | ||
| 474 | if ((await smoke.exited) !== 0) throw new Error("packed apps smoke failed"); | ||
| 384 | } | 475 | } |
| 385 | 476 | ||
| 386 | // Variant package.json. All variants publish to the SAME npm package | 477 | // Variant package.json. All variants publish to the SAME npm package |
| @@ -1,11 +1,10 @@ | |||
| 1 | // --------------------------------------------------------------------------- | 1 | // --------------------------------------------------------------------------- |
| 2 | // Native-binding bootstrap for the `bun build --compile` binary. | 2 | // Native-binding bootstrap for the `bun build --compile` binary. |
| 3 | // | 3 | // |
| 4 | // `bun --compile` bundles JS into bunfs but does NOT include `.node` native | 4 | // `bun --compile` bundles JS into bunfs but does NOT include native binaries, |
| 5 | // addons, so a dynamic `require('@libsql/<platform>')` / keyring walk inside | 5 | // wasm sidecars, or runtime-read package files. build.ts copies those artifacts |
| 6 | // the binary fails. build.ts copies each platform's `.node` next to the | 6 | // next to the executable; here we publish their on-disk paths via env vars the |
| 7 | // executable (`libsql.node`, `keyring.node`); here we publish their on-disk | 7 | // loaders read. |
| 8 | // paths via env vars the loaders read. | ||
| 9 | // | 8 | // |
| 10 | // This MUST be the FIRST import in main.ts. ES modules evaluate every import | 9 | // This MUST be the FIRST import in main.ts. ES modules evaluate every import |
| 11 | // before the importer's own body, and libSQL resolves its native addon EAGERLY | 10 | // before the importer's own body, and libSQL resolves its native addon EAGERLY |
| @@ -43,3 +42,18 @@ if ( · 31 unmodified lines | |||
| 43 | ) { | 42 | ) { |
| 44 | process.env.EXECUTOR_KEYRING_NATIVE_PATH = keyringNodeOnDisk; | 43 | process.env.EXECUTOR_KEYRING_NATIVE_PATH = keyringNodeOnDisk; |
| 45 | } | 44 | } |
| 45 | |||
| 46 | const workerdOnDisk = join(execDir, process.platform === "win32" ? "workerd.exe" : "workerd"); | ||
| 47 | if (typeof Bun !== "undefined" && !process.env.EXECUTOR_WORKERD_BIN && existsSync(workerdOnDisk)) { | ||
| 48 | process.env.EXECUTOR_WORKERD_BIN = workerdOnDisk; | ||
| 49 | } | ||
| 50 | |||
| 51 | const workerBundlerOnDisk = join(execDir, "worker-bundler"); | ||
| 52 | if ( | ||
| 53 | typeof Bun !== "undefined" && | ||
| 54 | !process.env.EXECUTOR_WORKER_BUNDLER_DIR && | ||
| 55 | existsSync(join(workerBundlerOnDisk, "dist", "index.js")) && | ||
| 56 | existsSync(join(workerBundlerOnDisk, "dist", "esbuild.wasm")) | ||
| 57 | ) { | ||
| 58 | process.env.EXECUTOR_WORKER_BUNDLER_DIR = workerBundlerOnDisk; | ||
| 59 | } | ||