Skip to content

build(server-release): prune foreign-platform and unreachable Prisma artifacts - #231

Open
Miista wants to merge 3 commits into
happier-dev:devfrom
Miista:fix/prune-server-prisma-foreign-platform-artifacts
Open

build(server-release): prune foreign-platform and unreachable Prisma artifacts#231
Miista wants to merge 3 commits into
happier-dev:devfrom
Miista:fix/prune-server-prisma-foreign-platform-artifacts

Conversation

@Miista

@Miista Miista commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

The packaged server binary release artifact (used by the relay-server Docker image and apps/stack's self-host installers) shipped Prisma query-engine binaries for all 5 platforms even though a single release build only ever runs on one:

  • schema.prisma's binaryTargets lists linux-x64, linux-arm64, darwin-x64, darwin-arm64, windows — a build for e.g. linux-arm64 still had all 5 native .node/.dll files copied into generated/{sqlite,mysql}-client and node_modules/.prisma/client.
  • node_modules/@prisma/client/runtime bundles WASM query engines for every database Prisma supports (postgresql, mysql, sqlite, cockroachdb, sqlserver) plus .map sourcemaps for every bundled format — cockroachdb/sqlserver are never reachable (ServerDbProvider is only ever 'sqlite' | 'mysql', with postgres always generated as the default), and sourcemaps are never needed by a production binary.

The codebase already knows exactly which single engine file a build target needs (resolvePrismaEngineFileNameForTarget), but that knowledge was only used for validating the artifact post-copy, never for pruning the other 4 platform variants.

Fix

Added pruneServerPrismaArtifactsForTarget() in buildServerBinaryArtifactPayload.ts, called after sidecar staging and before the existing validation step (so validation now also proves pruning didn't break the kept engine):

  • Deletes non-target-platform .node/.dll engine files from generated/*-client and node_modules/.prisma/client.
  • Deletes cockroachdb/sqlserver WASM engines and all .map files from node_modules/@prisma/client/runtime.

Impact

Compared against the currently-published happierdev/relay-server:dev image (real OCI manifest layer sizes via docker manifest inspect, arm64, digest sha256:ece74a90..., already includes the earlier ee63f5d45 Docker-side trim) versus the same Dockerfile recipe built locally with this fix applied (real bun compile + prisma generate, no mocking, pushed to a local registry to measure genuine compressed transfer size):

Before (live relay-server:dev) After (this fix) Savings
relay-server image (compressed, what's actually pulled/pushed) 245.2 MB 205.3 MB -39.9 MB (-16.3%)
Server artifact (uncompressed, for reference) ~470 MB 392 MB ~-78 MB

This is on top of the already-merged ee63f5d45 (Docker-side pruning of the duplicate ui-web copy and mysql-client/non-matching-arch files, reflected in the 245.2 MB baseline above) — this fix additionally covers apps/stack's native self-host installers, which consume the same underlying artifact but don't go through that Docker-side pruning at all.

Verification

  • New test: buildServerBinaryArtifactPayload.prismaEnginePrune.test.ts (4 cases) — RED confirmed before implementation, GREEN after.
  • Full packages/cli-common componentArtifacts suite: all passing, no regressions.
  • Typecheck: clean (yarn tsc -p packages/cli-common).
  • Real-world boot test: built the pruned artifact locally, wrapped it in a container matching the production Dockerfile's apt packages, and confirmed:
    • sqlite provider boots and serves HTTP 200.
    • mysql provider correctly locates and loads its query engine (fails only on the fake DATABASE_URL connection, as expected — no "Could not locate the Query Engine" error).
  • Real-world compressed-size measurement: pulled the actual currently-published happierdev/relay-server:dev image and diffed its real OCI manifest layer sizes against a locally-built image with this fix applied (same Dockerfile recipe, pushed to a local registry) — not just docker images, which shows uncompressed and can double-count shared layers.

Test plan

  • Unit tests for the new pruning function (target-specific engine survival, cockroachdb/sqlserver + sourcemap removal, no-op on missing directories)
  • Full cli-common test suite green
  • Typecheck clean
  • Manual boot verification in a Linux container (sqlite + mysql provider paths)
  • Real compressed image size measured against the currently-published image
  • CI release-pipeline contract tests (will run on this PR)

Note

Prune foreign-platform and unreachable Prisma artifacts during server binary payload build

  • Adds pruneServerPrismaArtifactsForTarget in buildServerBinaryArtifactPayload.ts to remove non-target native engine binaries from node_modules/.prisma/client and each generated/*-client directory.
  • Removes cockroachdb/sqlserver WASM engines and all .map sourcemap files from node_modules/@prisma/client/runtime.
  • Pruning runs after sidecar copy and before validation in buildServerBinaryArtifactPayload; missing directories are treated as no-ops.
  • Risk: non-ENOENT filesystem errors during directory reads now propagate and fail the build instead of being silently ignored.

Macroscope summarized 2f6e872.

Summary by CodeRabbit

  • New Features
    • Server builds now include only the Prisma engine binaries required for the selected deployment target, including Linux ARM64 and Darwin ARM64.
    • Unused provider runtime files and sourcemaps are removed from generated server artifacts, helping reduce deployment payload size while retaining required files.
  • Bug Fixes
    • Improved handling of missing Prisma directories and invalid artifact paths during server build processing.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The server artifact build now prunes Prisma files that do not match the target platform. It removes unreachable provider runtimes and sourcemaps before validating required engines. Tests cover supported targets, cleanup behavior, retained files, missing directories, and filesystem errors.

Changes

Prisma artifact pruning

Layer / File(s) Summary
Pruning implementation and build integration
packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.ts
Adds target-specific Prisma engine pruning, removes unreachable provider runtimes and sourcemaps, handles missing directories, and runs cleanup before engine validation.
Pruning behavior coverage
packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.prismaEnginePrune.test.ts
Tests Linux ARM64 and Darwin ARM64 retention, provider cleanup, sourcemap removal, unrelated file retention, missing-directory handling, and filesystem error propagation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ServerArtifactBuild
  participant PrismaPruning
  participant PayloadDirectory
  participant EngineValidation
  ServerArtifactBuild->>PrismaPruning: Prune for target
  PrismaPruning->>PayloadDirectory: Inspect and remove incompatible files
  ServerArtifactBuild->>EngineValidation: Validate remaining engines
Loading

Possibly related PRs

  • happier-dev/happier#219: Both PRs prune architecture-specific Prisma artifacts. This PR changes server payload builds, while #219 changes the Dockerfile.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.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
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.
Description check ✅ Passed The description covers the required summary, rationale, implementation, testing, impact, risks, and checklist items; only the pending CI contract tests remain.
Title check ✅ Passed The title clearly and concisely identifies the main change: pruning foreign-platform and unreachable Prisma artifacts during server release builds.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.ts`:
- Line 42: Update both readdir handlers in buildServerBinaryArtifactPayload to
return an empty list only when the filesystem error code is ENOENT, and rethrow
all other errors. Add a test covering an expected directory path that is
actually a file, asserting that pruning rejects instead of silently continuing.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: adb50fb1-1174-432e-89c3-754c14d0fef7

📥 Commits

Reviewing files that changed from the base of the PR and between c65ea28 and 36fb948.

📒 Files selected for processing (2)
  • packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.prismaEnginePrune.test.ts
  • packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.ts

Comment thread packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.ts Outdated
@greptile-apps

greptile-apps Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR reduces packaged server artifacts by pruning non-target Prisma native engines, unreachable provider WASM bundles, and runtime sourcemaps before validating the retained target engine.

  • Adds target-aware pruning across generated clients and .prisma/client.
  • Removes unreachable CockroachDB/SQL Server runtime bundles and sourcemaps.
  • Adds focused cross-platform and missing-directory tests.

Confidence Score: 4/5

The PR appears safe to merge, with one non-blocking concern that unexpected filesystem errors can silently leave release artifacts unpruned.

The retained engine names align with current library-mode runtime consumers and reachable database providers, while blanket readdir error suppression can conceal incomplete pruning without breaking engine-presence validation.

Files Needing Attention: packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.ts

Important Files Changed

Filename Overview
packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.ts Adds coherent target-aware Prisma pruning, but unexpected directory-read failures are silently treated as successful no-ops.
packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.prismaEnginePrune.test.ts Covers target-specific retention, runtime pruning, and absent-directory behavior with focused filesystem fixtures.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Stage server sidecars] --> B[Prune non-target native engines]
  B --> C[Prune unreachable WASM and sourcemaps]
  C --> D[Validate target native engines]
  D --> E[Finalize release payload]
Loading

Reviews (1): Last reviewed commit: "build(server-release): prune foreign-pla..." | Re-trigger Greptile

// ever runs on the one platform it was built for. Keep only that target's engine file.
async function pruneNonTargetPrismaEngineFiles(directoryPath: string, target: BinaryTarget): Promise<void> {
const keepFileName = resolvePrismaEngineFileNameForTarget(target);
const entries = await readdir(directoryPath, { withFileTypes: true }).catch(() => []);

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 Directory errors skip pruning

If an unexpected filesystem error occurs while enumerating a staged Prisma directory, the blanket catch treats it as empty and silently skips pruning, allowing foreign engines, unreachable WASM files, or sourcemaps to remain in the release artifact while target-engine validation still passes.

Knowledge Base Used: packages/cli-common

…artifacts

The packaged server binary artifact shipped Prisma query-engine binaries
for all 5 platforms (schema.prisma's binaryTargets lists linux-x64,
linux-arm64, darwin-x64, darwin-arm64, windows) even though a release
build only ever targets one, plus WASM engines for cockroachdb/sqlserver
(never a reachable ServerDbProvider) and .map sourcemaps in
@prisma/client/runtime. On a linux-arm64 build this drops the artifact
656MB -> 392MB (-40%), verified against a real local build (real bun
compile + Prisma generate) and confirmed both sqlite and mysql providers
still resolve their query engine correctly at runtime in a container.
@Miista
Miista force-pushed the fix/prune-server-prisma-foreign-platform-artifacts branch from 36fb948 to 1b51548 Compare August 6, 2026 21:04
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Address CodeRabbit/Greptile review feedback on happier-dev#231: the pruning
helpers swallowed every readdir failure into an empty directory, not
just a missing one. A permission error or an expected directory path
that's actually a file would silently skip pruning for that directory
while validateServerPrismaEnginesForTarget still passes (it only
checks that the kept engine file exists, not that pruning ran) --
letting foreign-platform engines, unreachable WASM engines, or
sourcemaps survive into the release artifact undetected.

Only ENOENT is now treated as "nothing to prune"; every other error
propagates and fails the build.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.prismaEnginePrune.test.ts`:
- Line 146: Update the rejection assertion in the test around
readdirOrEmptyIfMissing to use toMatchObject({ code: 'ENOTDIR' }) instead of
only toThrow(). Preserve the existing scenario and verify that the propagated
filesystem error specifically has the ENOTDIR code.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0001ed1d-5858-4596-b798-10f97f4b98d4

📥 Commits

Reviewing files that changed from the base of the PR and between 1b51548 and 57dd8ff.

📒 Files selected for processing (2)
  • packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.prismaEnginePrune.test.ts
  • packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli-common/src/componentArtifacts/buildServerBinaryArtifactPayload.ts

…test

Address CodeRabbit follow-up on happier-dev#231: the new rejection test only
asserted .rejects.toThrow(), which would also pass on an unrelated
error. Assert the specific ENOTDIR code so the test can't silently
pass for the wrong reason.
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.

1 participant