diff --git a/packages/cli/.18cb51bffb6ffabb-00000000.bun-build b/packages/cli/.18cb51bffb6ffabb-00000000.bun-build new file mode 100755 index 00000000..e2313ffe Binary files /dev/null and b/packages/cli/.18cb51bffb6ffabb-00000000.bun-build differ diff --git a/packages/cli/backend-runtime/import-map.json b/packages/cli/backend-runtime/import-map.json index 65760336..b91dab08 100644 --- a/packages/cli/backend-runtime/import-map.json +++ b/packages/cli/backend-runtime/import-map.json @@ -1,5 +1,6 @@ { "imports": { - "base44:runtime": "./base44-runtime.ts" + "base44:runtime": "./base44-runtime.ts", + "npm:@base44/sdk": "./vendor/base44-sdk.js" } } diff --git a/packages/cli/infra/build-binaries.ts b/packages/cli/infra/build-binaries.ts index 6d575d6a..bc1fce13 100644 --- a/packages/cli/infra/build-binaries.ts +++ b/packages/cli/infra/build-binaries.ts @@ -56,6 +56,9 @@ for (const required of [ "dist/assets/backend-runtime/main.ts", "dist/assets/backend-runtime/import-map.json", "dist/assets/backend-runtime/base44-runtime.ts", + // The import map points at this bundle, so a binary built without it would + // only fail once a user actually runs `base44 exec`. + "dist/assets/backend-runtime/vendor/base44-sdk.js", ]) { if (!existsSync(join(ROOT, required))) { console.error( diff --git a/packages/cli/infra/build.ts b/packages/cli/infra/build.ts index d28f8542..287ea1d8 100644 --- a/packages/cli/infra/build.ts +++ b/packages/cli/infra/build.ts @@ -40,6 +40,19 @@ const copyBackendRuntime = () => { return outDir; }; +// The Deno wrappers import `npm:@base44/sdk`, which the import map redirects to +// this bundle. Fetching it from a registry at run time fails wherever the +// registry is proxied behind a TLS-intercepting gateway, so it ships with the +// CLI and the SDK version is pinned to the release. +const bundleVendoredSdk = () => + runBuild({ + entrypoints: ["./infra/vendor/base44-sdk.ts"], + outdir: "./dist/assets/backend-runtime/vendor", + // Third-party code the user never debugs through us; the map would add + // ~1MB to the published package for nothing. + sourcemap: "none", + }); + // Runtime dependencies of the local workerd function runtime. They cannot be // bundled (workerd and esbuild ship native binaries; @deno/loader ships WASM), // so they are real npm `dependencies` resolved from node_modules at runtime — @@ -55,6 +68,7 @@ const runAllBuilds = async () => { external: RUNTIME_EXTERNALS, }); const backendRuntimePath = copyBackendRuntime(); + await bundleVendoredSdk(); return { cli, backendRuntimePath, diff --git a/packages/cli/infra/vendor/base44-sdk.ts b/packages/cli/infra/vendor/base44-sdk.ts new file mode 100644 index 00000000..fb54ecbe --- /dev/null +++ b/packages/cli/infra/vendor/base44-sdk.ts @@ -0,0 +1,4 @@ +// Bundle entry for the vendored SDK shipped to the Deno runtimes. The exec +// wrapper imports `npm:@base44/sdk`, which the runtime import map redirects +// here so Deno never fetches it from a registry at run time. +export * from "@base44/sdk"; diff --git a/packages/cli/src/core/assets.ts b/packages/cli/src/core/assets.ts index 63205d3e..a2def196 100644 --- a/packages/cli/src/core/assets.ts +++ b/packages/cli/src/core/assets.ts @@ -17,6 +17,10 @@ function getBackendRuntimeDir(): string { return join(ASSETS_DIR, "backend-runtime"); } +export function getImportMapPath(): string { + return join(getBackendRuntimeDir(), "import-map.json"); +} + export function getDenoWrapperPath(): string { return join(getBackendRuntimeDir(), "main.ts"); } diff --git a/packages/cli/src/core/exec/run-script.ts b/packages/cli/src/core/exec/run-script.ts index 82473b8b..ad6a815a 100644 --- a/packages/cli/src/core/exec/run-script.ts +++ b/packages/cli/src/core/exec/run-script.ts @@ -1,7 +1,7 @@ import { spawn } from "node:child_process"; import { copyFileSync, writeFileSync } from "node:fs"; import { file } from "tmp-promise"; -import { getExecWrapperPath } from "@/core/assets.js"; +import { getExecWrapperPath, getImportMapPath } from "@/core/assets.js"; import { getAppUserToken, getSiteUrl } from "@/core/project/api.js"; import { verifyDenoInstalled } from "@/core/utils/index.js"; @@ -50,11 +50,23 @@ export async function runScript( cleanupFns.push(tempWrapper.cleanup); copyFileSync(getExecWrapperPath(), tempWrapper.path); + // Redirects the wrapper's `npm:@base44/sdk` import to the SDK bundled with + // this release. Its entries resolve relative to the map itself, so it stays + // correct even though the wrapper runs from a temp directory. + const importMapPath = getImportMapPath(); + try { const exitCode = await new Promise((resolvePromise) => { const child = spawn( "deno", - ["run", "--allow-all", "--node-modules-dir=auto", tempWrapper.path], + [ + "run", + "--allow-all", + "--node-modules-dir=auto", + "--import-map", + importMapPath, + tempWrapper.path, + ], { env: { ...process.env,