Skip to content

fix(desktop): bundle DuckDB native binding into x64 macOS build#4694

Merged
saddlepaddle merged 2 commits into
mainfrom
cyan-lavender
May 19, 2026
Merged

fix(desktop): bundle DuckDB native binding into x64 macOS build#4694
saddlepaddle merged 2 commits into
mainfrom
cyan-lavender

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented May 18, 2026

Problem

The Intel (x64) macOS build crashes immediately on launch:

Error: Cannot find module '@duckdb/node-bindings-darwin-x64/duckdb.node'

Any Intel Mac user is fully blocked — the app cannot start. Reproduced across 1.9.5 and 1.9.6; a clean reinstall does not help.

Root cause

mastracode is externalized from the desktop main bundle, so at runtime Node resolves @mastra/duckdb@duckdb/node-api@duckdb/node-bindings → the platform binding from node_modules. The desktop native-module pipeline (runtime-dependencies.ts + copy-native-modules.ts) never accounted for DuckDB at all.

@duckdb/node-bindings-darwin-x64 is a cpu: "x64" / os: "darwin"-gated optional dependency. Both macOS build legs run on an arm64 runner, so Bun only ever installs the arm64 binding — the x64 leg packages no x64 binding. arm64 was unaffected only because the runner arch happened to match.

packages/cli/scripts/build-dist.ts and packages/host-service/build.ts already externalize the full @duckdb/node-bindings-* set, confirming the desktop config was the outlier.

Fix

  • runtime-dependencies.ts — externalize @mastra/duckdb and materialize + copy @mastra/duckdb / @duckdb/node-api / @duckdb/node-bindings, with asarUnpack for the native @duckdb files (duckdb.node + libduckdb.dylib).
  • copy-native-modules.ts — add copyDuckdbPlatformPackages, modeled on copyAstGrepPlatformPackages / copyLibsqlDependencies: resolve the @duckdb/node-bindings optionalDependencies, and fetch the TARGET_ARCH platform package from npm at the pinned 1.5.2-r.1 version when it is missing from the Bun store (cross-arch build scenario).
  • validate-native-runtime.ts — add validateDuckdbPrepared, a build-time guard that the target-arch binding is present before packaging, matching the existing libsql / ast-grep / parcel-watcher guards.

Linux audit

Per the ticket gotcha — the Linux job runs on ubuntu-latest (x64 host) with TARGET_ARCH=x64. Host arch matches target, so Bun installs @duckdb/node-bindings-linux-x64 and copyDuckdbPlatformPackages finds it in the Bun store. No gap, no workflow change needed.

Verification

  • bun run scripts/copy-native-modules.ts (host arm64) materializes the three DuckDB modules and copies the arm64 binding from the Bun store.
  • TARGET_ARCH=x64 bun run scripts/copy-native-modules.ts fetches @duckdb/node-bindings-darwin-x64@1.5.2-r.1 (duckdb.node + libduckdb.dylib) from npm — the previously-missing piece.
  • bun run lint and bun run typecheck pass.
  • Remaining: build the x64 DMG in CI and launch it on an Intel Mac (or arch -x86_64).

Fixes #4666


Open in Stage

Summary by cubic

Fixes the Intel (x64) macOS desktop crash by bundling the DuckDB native binding into the x64 build and validating it at build time and in CI. Ensures cross-arch builds fetch the correct @duckdb/node-bindings-* package so the app launches on x64. Fixes #4666.

  • Bug Fixes
    • Externalized @mastra/duckdb and materialized/copied @mastra/duckdb, @duckdb/node-api, and @duckdb/node-bindings; unpack native @duckdb files from ASAR.
    • Added copy step to resolve platform-gated @duckdb/node-bindings-<platform>-<arch>; fetches the target-arch package from npm when Bun doesn’t install it.
    • Added validations: build-time guard for the target binding and a CI check that fails if @duckdb/node-bindings-darwin-<arch>/duckdb.node is missing from the packaged app.

Written for commit c545de6. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • Chores
    • Added DuckDB runtime dependency configuration for the desktop application.
    • Implemented handling to materialize/copy platform-specific DuckDB native modules into the app package.
    • Added build-time validation and CI verification to ensure the correct DuckDB native bindings are present for each target platform.

Review Change Stack

The Intel (x64) macOS build crashed on launch with
`Cannot find module '@duckdb/node-bindings-darwin-x64/duckdb.node'`.
mastracode is externalized, so Node resolves @mastra/duckdb →
@duckdb/node-api → @duckdb/node-bindings → the platform binding from
node_modules at runtime, but the desktop native-module pipeline never
accounted for DuckDB. The binding is a cpu/os-gated optional dependency,
so Bun on the arm64 build runner only installs the arm64 one — the x64
leg packaged no x64 binding at all.

- runtime-dependencies.ts: externalize @mastra/duckdb and materialize +
  copy @mastra/duckdb / @duckdb/node-api / @duckdb/node-bindings, with
  asarUnpack for the native @duckdb files.
- copy-native-modules.ts: add copyDuckdbPlatformPackages to fetch the
  TARGET_ARCH @duckdb/node-bindings-<platform>-<arch> package from npm
  when it is missing from the Bun store (cross-arch builds).
- validate-native-runtime.ts: guard that the target-arch duckdb binding
  is present before packaging.

Fixes #4666
@capy-ai
Copy link
Copy Markdown

capy-ai Bot commented May 18, 2026

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@stage-review
Copy link
Copy Markdown

stage-review Bot commented May 18, 2026

Ready to review this PR? Stage has broken it down into 4 individual chapters for you:

Title
1 Configure DuckDB as an externalized runtime dependency
2 Implement cross-arch DuckDB platform package copying
3 Add build-time validation for DuckDB native bindings
4 Verify native bindings in CI workflow
Open in Stage

Chapters generated by Stage for commit c545de6 on May 18, 2026 10:43pm UTC.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a1cb26e7-66c6-4eb3-9dea-9c2b0f28b9e2

📥 Commits

Reviewing files that changed from the base of the PR and between 012c18e and c545de6.

📒 Files selected for processing (1)
  • .github/workflows/build-desktop.yml

📝 Walkthrough

Walkthrough

This PR adds comprehensive DuckDB native binding support to the desktop build pipeline. A configuration declares DuckDB modules for bundling, build-time logic materializes the correct platform/architecture-specific binding, and validation checks ensure the binding is present before the build succeeds.

Changes

DuckDB Native Binding Support

Layer / File(s) Summary
DuckDB Runtime Dependency Configuration
apps/desktop/runtime-dependencies.ts
@mastra/duckdb is added to externalized runtime modules with materialization paths and packaging strategy for @mastra/duckdb and @duckdb.
Platform-Specific Binding Materialization
apps/desktop/scripts/copy-native-modules.ts
copyDuckdbPlatformPackages() reads @duckdb/node-bindings optional dependencies, selects the entry matching TARGET_PLATFORM-TARGET_ARCH, and ensures the matching @duckdb/node-bindings-* package exists in node_modules by replacing symlinks or copying exact versions. prepareNativeModules() calls this as part of native module preparation.
DuckDB Binding Build-Time Validation
apps/desktop/scripts/validate-native-runtime.ts, .github/workflows/build-desktop.yml
validateDuckdbPrepared() checks that the platform/arch-specific @duckdb/node-bindings-* binding and its duckdb.node file exist and is invoked in the main validation pipeline. The macOS CI workflow now verifies the binding inside app.asar.unpacked and fails with diagnostics if missing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A tiny rabbit hopped through deps and logs,
Found DuckDB bindings hidden in fogs.
It copied, checked, and packed with care,
Ensuring duckdb.node was truly there.
Now builds sleep sound — no binding sobs. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main fix: bundling DuckDB native binding into x64 macOS build, which is the core problem and solution addressed.
Description check ✅ Passed The PR description thoroughly covers Problem, Root cause, Fix, and Verification sections; however, the Description, Related Issues, and Type of Change sections from the template are not explicitly filled in the structured format.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cyan-lavender

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Re-trigger cubic

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 18, 2026

Greptile Summary

This PR fixes an Intel (x64) macOS crash on launch caused by the DuckDB native binding (@duckdb/node-bindings-darwin-x64) never being included in the x64 DMG — both macOS build legs run on arm64 runners where Bun only installs the arm64 binding. The fix wires DuckDB into the existing three-layer native-module pipeline (externalization, copy/materialize, build-time validation) that was already established for libsql, ast-grep, and parcel-watcher.

  • runtime-dependencies.ts: adds @mastra/duckdb to the externalized runtime module list with materialize, packagedCopies, and asarUnpackGlobs entries covering the full @duckdb scope.
  • copy-native-modules.ts: adds copyDuckdbPlatformPackages, which reads optionalDependencies from @duckdb/node-bindings/package.json, materializes the target-arch binding from the Bun store, and falls back to fetching the tarball from npm for the cross-arch case.
  • validate-native-runtime.ts: adds validateDuckdbPrepared, a build-time guard confirming the target platform's duckdb.node is present before electron-builder packages the app.

Confidence Score: 4/5

Safe to merge — the change correctly wires DuckDB into an existing, well-tested native-module pipeline and is mechanically consistent with the libsql, ast-grep, and parcel-watcher implementations.

The core logic is sound and the cross-arch fetch path follows established patterns. The asarUnpack glob covers the entire @duckdb scope rather than just the native binding packages, and the validate function has no early-exit guard if DuckDB is ever made optional on a per-platform basis. Neither affects correctness for the current supported platforms.

No files require special attention. copy-native-modules.ts is the most complex change but follows the existing copyAstGrepPlatformPackages pattern closely.

Important Files Changed

Filename Overview
apps/desktop/runtime-dependencies.ts Adds @mastra/duckdb as an externalized runtime module with materialize, packagedCopies, and asarUnpackGlobs entries; the asarUnpack glob is broader than strictly necessary (covers all of @duckdb instead of only native binding packages).
apps/desktop/scripts/copy-native-modules.ts Adds copyDuckdbPlatformPackages which resolves the target-arch binding from @duckdb/node-bindings optionalDependencies, fetching from npm when absent — correctly handles the cross-arch scenario. The targetVersion from optionalDeps is passed verbatim to the npm tarball URL, which could break if a range is ever used instead of an exact version.
apps/desktop/scripts/validate-native-runtime.ts Adds validateDuckdbPrepared which checks for the target-arch duckdb.node file before packaging; lacks an early-exit guard for platforms/configs where DuckDB is not installed, unlike the existing parcel-watcher and libsql validators.

Sequence Diagram

sequenceDiagram
    participant CI as CI Runner (arm64)
    participant Copy as copy-native-modules.ts
    participant Bun as Bun Store
    participant npm as npm Registry
    participant Validate as validate-native-runtime.ts
    participant Builder as electron-builder

    CI->>Copy: "bun run copy:native-modules TARGET_ARCH=x64"
    Copy->>Copy: copyDuckdbPlatformPackages()
    Copy->>Copy: "read @duckdb/node-bindings optionalDependencies"
    Copy->>Bun: "check for @duckdb/node-bindings-darwin-x64"
    Bun-->>Copy: not found (arm64 runner x64 target)
    Copy->>npm: "fetch @duckdb/node-bindings-darwin-x64 tarball"
    npm-->>Copy: duckdb.node + libduckdb.dylib extracted
    CI->>Validate: bun run validate:native-runtime
    Validate->>Validate: validateNativeModulesPrepared()
    Validate->>Validate: validateDuckdbPrepared()
    Validate-->>CI: all checks passed
    CI->>Builder: electron-builder package
    Builder-->>CI: x64 DMG with correct native binding
Loading
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
apps/desktop/scripts/validate-native-runtime.ts:507-526
**`validateDuckdbPrepared` lacks a guard for when `@duckdb/node-bindings` is not installed**

All other similar validators (`validateParcelWatcherPrepared`, the ast-grep section of `validateNativeModulesPrepared`) return early or emit a warning when no candidates apply to the current platform. `validateDuckdbPrepared` unconditionally fails if `duckdb.node` is not present. In practice this is shielded by `validateNativeModulesPrepared` running first (since `@duckdb/node-bindings` is in `requiredMaterializedNodeModules`), but there is no analogous guard here if DuckDB is ever made optional per-platform. The failure message would then say "Missing platform-specific @duckdb/node-bindings package" rather than a clear skip.

### Issue 2 of 3
apps/desktop/scripts/copy-native-modules.ts:473-515
**`targetVersion` from `optionalDependencies` is passed verbatim to `fetchNpmPackage`**

`copyExactModuleVersion``fetchNpmPackage` constructs the tarball URL as `https://registry.npmjs.org/${pkg}/-/${bare}-${version}.tgz`. If `optionalDependencies` ever specifies a semver range instead of an exact version, the URL is malformed and the fetch silently falls through to `process.exit(1)`. The same pattern exists in `copyLibsqlDependencies`, so this is not unique to this PR, but the risk is worth noting given the cross-arch fetch path is the sole fallback for the x64 binding in CI.

### Issue 3 of 3
apps/desktop/runtime-dependencies.ts:82-94
**`asarUnpackGlobs` is broader than necessary — unpacks the pure-JS `@duckdb/node-api` package**

The glob `"**/node_modules/@duckdb/**/*"` asar-unpacks the entire `@duckdb` scope, including `@duckdb/node-api` which is a pure-JS module that does not need filesystem access outside the asar. Existing patterns in this file are scoped to the packages that actually require native access (e.g., `@ast-grep/napi*`, `@parcel/watcher*`). A more targeted glob like `"**/node_modules/@duckdb/node-bindings*/**/*"` reduces the unpacked asar size and more precisely documents what actually needs native filesystem access.

```suggestion
	{
		specifier: "@mastra/duckdb",
		materialize: [
			"@mastra/duckdb",
			"@duckdb/node-api",
			"@duckdb/node-bindings",
		],
		packagedCopies: [
			copyWholeModule("@mastra/duckdb"),
			copyWholeModule("@duckdb"),
		],
		asarUnpackGlobs: ["**/node_modules/@duckdb/node-bindings*/**/*"],
	},
```

Reviews (1): Last reviewed commit: "fix(desktop): bundle DuckDB native bindi..." | Re-trigger Greptile

Comment on lines +507 to +526
function validateDuckdbPrepared(): void {
const nodeModulesDir = join(projectRoot, "node_modules");
const targetArch = process.env.TARGET_ARCH || process.arch;
const targetPlatform = process.env.TARGET_PLATFORM || process.platform;
const bindingPackage = `@duckdb/node-bindings-${targetPlatform}-${targetArch}`;

if (!existsSync(join(nodeModulesDir, bindingPackage, "duckdb.node"))) {
fail(
[
"Missing platform-specific @duckdb/node-bindings package.",
`Expected: ${bindingPackage}/duckdb.node`,
"Run `bun run copy:native-modules` and ensure optional dependencies are materialized.",
].join("\n"),
);
}

console.log(
`[validate:native-runtime] OK: platform duckdb binding present (${bindingPackage})`,
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 validateDuckdbPrepared lacks a guard for when @duckdb/node-bindings is not installed

All other similar validators (validateParcelWatcherPrepared, the ast-grep section of validateNativeModulesPrepared) return early or emit a warning when no candidates apply to the current platform. validateDuckdbPrepared unconditionally fails if duckdb.node is not present. In practice this is shielded by validateNativeModulesPrepared running first (since @duckdb/node-bindings is in requiredMaterializedNodeModules), but there is no analogous guard here if DuckDB is ever made optional per-platform. The failure message would then say "Missing platform-specific @duckdb/node-bindings package" rather than a clear skip.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/scripts/validate-native-runtime.ts
Line: 507-526

Comment:
**`validateDuckdbPrepared` lacks a guard for when `@duckdb/node-bindings` is not installed**

All other similar validators (`validateParcelWatcherPrepared`, the ast-grep section of `validateNativeModulesPrepared`) return early or emit a warning when no candidates apply to the current platform. `validateDuckdbPrepared` unconditionally fails if `duckdb.node` is not present. In practice this is shielded by `validateNativeModulesPrepared` running first (since `@duckdb/node-bindings` is in `requiredMaterializedNodeModules`), but there is no analogous guard here if DuckDB is ever made optional per-platform. The failure message would then say "Missing platform-specific @duckdb/node-bindings package" rather than a clear skip.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +473 to +515
function copyDuckdbPlatformPackages(nodeModulesDir: string): void {
const nodeBindingsPath = join(nodeModulesDir, "@duckdb", "node-bindings");
const nodeBindingsPkgJsonPath = join(nodeBindingsPath, "package.json");
if (!existsSync(nodeBindingsPkgJsonPath)) return;

type DuckdbBindingsPackageJson = {
optionalDependencies?: Record<string, string>;
};
const nodeBindingsPkg = JSON.parse(
readFileSync(nodeBindingsPkgJsonPath, "utf8"),
) as DuckdbBindingsPackageJson;
const optionalDeps = nodeBindingsPkg.optionalDependencies ?? {};

console.log("\nPreparing duckdb platform package...");

// The native binding is a `cpu`/`os`-gated optional dependency, so Bun only
// installs the host's. For the target arch, fetch it from npm when missing.
const targetSuffix = `${TARGET_PLATFORM}-${TARGET_ARCH}`;
const targetEntry = Object.entries(optionalDeps).find(([name]) =>
name.endsWith(targetSuffix),
);
if (!targetEntry) {
console.error(
` [ERROR] No @duckdb/node-bindings optional dependency matched ${targetSuffix}`,
);
process.exit(1);
}

const [targetName, targetVersion] = targetEntry;
const destPath = join(nodeModulesDir, targetName);
if (existsSync(destPath)) {
copyModuleIfSymlink(nodeModulesDir, targetName, true);
return;
}

copyExactModuleVersion(
nodeModulesDir,
targetName,
targetVersion,
destPath,
true,
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 targetVersion from optionalDependencies is passed verbatim to fetchNpmPackage

copyExactModuleVersionfetchNpmPackage constructs the tarball URL as https://registry.npmjs.org/${pkg}/-/${bare}-${version}.tgz. If optionalDependencies ever specifies a semver range instead of an exact version, the URL is malformed and the fetch silently falls through to process.exit(1). The same pattern exists in copyLibsqlDependencies, so this is not unique to this PR, but the risk is worth noting given the cross-arch fetch path is the sole fallback for the x64 binding in CI.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/scripts/copy-native-modules.ts
Line: 473-515

Comment:
**`targetVersion` from `optionalDependencies` is passed verbatim to `fetchNpmPackage`**

`copyExactModuleVersion``fetchNpmPackage` constructs the tarball URL as `https://registry.npmjs.org/${pkg}/-/${bare}-${version}.tgz`. If `optionalDependencies` ever specifies a semver range instead of an exact version, the URL is malformed and the fetch silently falls through to `process.exit(1)`. The same pattern exists in `copyLibsqlDependencies`, so this is not unique to this PR, but the risk is worth noting given the cross-arch fetch path is the sole fallback for the x64 binding in CI.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +82 to +94
{
specifier: "@mastra/duckdb",
materialize: [
"@mastra/duckdb",
"@duckdb/node-api",
"@duckdb/node-bindings",
],
packagedCopies: [
copyWholeModule("@mastra/duckdb"),
copyWholeModule("@duckdb"),
],
asarUnpackGlobs: ["**/node_modules/@duckdb/**/*"],
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 asarUnpackGlobs is broader than necessary — unpacks the pure-JS @duckdb/node-api package

The glob "**/node_modules/@duckdb/**/*" asar-unpacks the entire @duckdb scope, including @duckdb/node-api which is a pure-JS module that does not need filesystem access outside the asar. Existing patterns in this file are scoped to the packages that actually require native access (e.g., @ast-grep/napi*, @parcel/watcher*). A more targeted glob like "**/node_modules/@duckdb/node-bindings*/**/*" reduces the unpacked asar size and more precisely documents what actually needs native filesystem access.

Suggested change
{
specifier: "@mastra/duckdb",
materialize: [
"@mastra/duckdb",
"@duckdb/node-api",
"@duckdb/node-bindings",
],
packagedCopies: [
copyWholeModule("@mastra/duckdb"),
copyWholeModule("@duckdb"),
],
asarUnpackGlobs: ["**/node_modules/@duckdb/**/*"],
},
{
specifier: "@mastra/duckdb",
materialize: [
"@mastra/duckdb",
"@duckdb/node-api",
"@duckdb/node-bindings",
],
packagedCopies: [
copyWholeModule("@mastra/duckdb"),
copyWholeModule("@duckdb"),
],
asarUnpackGlobs: ["**/node_modules/@duckdb/node-bindings*/**/*"],
},
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/runtime-dependencies.ts
Line: 82-94

Comment:
**`asarUnpackGlobs` is broader than necessary — unpacks the pure-JS `@duckdb/node-api` package**

The glob `"**/node_modules/@duckdb/**/*"` asar-unpacks the entire `@duckdb` scope, including `@duckdb/node-api` which is a pure-JS module that does not need filesystem access outside the asar. Existing patterns in this file are scoped to the packages that actually require native access (e.g., `@ast-grep/napi*`, `@parcel/watcher*`). A more targeted glob like `"**/node_modules/@duckdb/node-bindings*/**/*"` reduces the unpacked asar size and more precisely documents what actually needs native filesystem access.

```suggestion
	{
		specifier: "@mastra/duckdb",
		materialize: [
			"@mastra/duckdb",
			"@duckdb/node-api",
			"@duckdb/node-bindings",
		],
		packagedCopies: [
			copyWholeModule("@mastra/duckdb"),
			copyWholeModule("@duckdb"),
		],
		asarUnpackGlobs: ["**/node_modules/@duckdb/node-bindings*/**/*"],
	},
```

How can I resolve this? If you propose a fix, please make it concise.

build-desktop.yml never inspected the packaged output, so a missing
native binding only surfaced when users launched the app. Add a step
that cracks open app.asar.unpacked and fails the build if the
target-arch @duckdb/node-bindings-darwin-<arch>/duckdb.node is absent.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 18, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@saddlepaddle
Copy link
Copy Markdown
Collaborator Author

Verified — full desktop build green

Triggered release-desktop on this branch: run 26064753636 — all three legs succeeded (macOS x64, macOS arm64, Linux x64).

x64 leg, the previously-broken one — fix chain confirmed on the CI runner:

  • copy-native-modules.ts@duckdb/node-bindings-darwin-x64: fetching from npm (1.5.2-r.1) → extracted
  • validate-native-runtime.tsOK: platform duckdb binding present (@duckdb/node-bindings-darwin-x64)
  • new build-desktop.yml step → OK: bundled .../Superset.app/.../node-bindings-darwin-x64/duckdb.node

Independent inspection of the downloaded x64 artifact (Superset-1.9.6-mac.zip):

  • app.asar.unpacked/node_modules/@duckdb/node-bindings-darwin-x64/duckdb.nodeMach-O 64-bit bundle x86_64 ✅ (the exact module path the crash reported missing)
  • libduckdb.dylib — universal, x86_64 slice present ✅
  • Superset.app/Contents/MacOS/Supersetx86_64

The Cannot find module '@duckdb/node-bindings-darwin-x64/duckdb.node' crash is resolved.

Follow-up (not blocking, pre-existing)

The x64 build also ships the unused @duckdb/node-bindings-darwin-arm64 (~107 MB of dead libduckdb.dylib) — electron-builder auto-collects the build host's optional dep. It's wasteful but harmless (duckdb.js dispatches on process.arch). Worth a separate PR to exclude the non-target-arch @duckdb/node-bindings-* from each leg's files.

@saddlepaddle saddlepaddle merged commit 71bd81c into main May 19, 2026
21 checks passed
sazabi Bot pushed a commit that referenced this pull request May 20, 2026
* fix(desktop): bundle DuckDB native binding into x64 macOS build

The Intel (x64) macOS build crashed on launch with
`Cannot find module '@duckdb/node-bindings-darwin-x64/duckdb.node'`.
mastracode is externalized, so Node resolves @mastra/duckdb →
@duckdb/node-api → @duckdb/node-bindings → the platform binding from
node_modules at runtime, but the desktop native-module pipeline never
accounted for DuckDB. The binding is a cpu/os-gated optional dependency,
so Bun on the arm64 build runner only installs the arm64 one — the x64
leg packaged no x64 binding at all.

- runtime-dependencies.ts: externalize @mastra/duckdb and materialize +
  copy @mastra/duckdb / @duckdb/node-api / @duckdb/node-bindings, with
  asarUnpack for the native @duckdb files.
- copy-native-modules.ts: add copyDuckdbPlatformPackages to fetch the
  TARGET_ARCH @duckdb/node-bindings-<platform>-<arch> package from npm
  when it is missing from the Bun store (cross-arch builds).
- validate-native-runtime.ts: guard that the target-arch duckdb binding
  is present before packaging.

Fixes #4666

* ci(desktop): assert DuckDB native binding is in the packaged app

build-desktop.yml never inspected the packaged output, so a missing
native binding only surfaced when users launched the app. Add a step
that cracks open app.asar.unpacked and fails the build if the
target-arch @duckdb/node-bindings-darwin-<arch>/duckdb.node is absent.
MocA-Love added a commit to MocA-Love/superset that referenced this pull request May 29, 2026
Non-applicable to current fork structure: superset-sh#3960 and superset-sh#4068 require linux-arm64/full CLI dist targets that this fork does not ship; superset-sh#4678 targets a relay deploy script intentionally absent from the fork; superset-sh#4694 requires DuckDB native packaging but the fork has no DuckDB runtime dependency; superset-sh#4822 targets removed v1 import modal paths; superset-sh#4826 assumes upstream release-cli.yml while this fork uses build-cli.yml with draft release semantics.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] x64 build crashes on launch - missing @duckdb/node-bindings-darwin-x64

2 participants