Skip to content

fix(wasm): load native assets from a real directory in compiled binaries - #449

Merged
jan-kubica merged 3 commits into
mainfrom
fix/compiled-binary-asset-loading
Aug 10, 2026
Merged

fix(wasm): load native assets from a real directory in compiled binaries#449
jan-kubica merged 3 commits into
mainfrom
fix/compiled-binary-asset-loading

Conversation

@jan-kubica

@jan-kubica jan-kubica commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Inside a compiled single binary (bun build --compile), import.meta.url points into the binary's embedded filesystem and dynamic import() resolves against it exclusively. The binding's asset URLs (glue module, wasm, prepared packages) derive from import.meta.url, so they can never reach assets installed on disk — getBinding() fails in compiled binaries even when dist/native/ is copied next to the binary. Filesystem APIs do fall back to disk; ESM import() does not, which is why only the glue import breaks.

Changes

  • STLL_ANONYMIZE_ASSET_DIR overrides the native-asset base directory (absolute POSIX path or file: URL). Deployments that compile a consumer to a single binary copy dist/native/ to a real directory and point the variable at it. Browsers never define process, so the override is inert there; the default resolution path is byte-for-byte unchanged.
  • smoke-wasm-compiled.mjs (wired into CI next to the runtime-matrix smoke) compiles a minimal consumer of the built wasm/dist/wasm.mjs and asserts both directions: without the override the engine load must fail — if it ever starts succeeding, the embedded-filesystem constraint changed and the guard demands re-evaluation — and with the override a default redaction resolves entities end to end, covering glue, wasm module, and the prepared pipeline package.

Validation

Local run of the new smoke: the compiled consumer fails without the override and redacts with it ({"event":"smoke-wasm-compiled","ok":true,"entities":2}). Package typecheck passes.

Summary by CodeRabbit

  • New Features

    • Added support for loading anonymisation assets from a directory configured through STLL_ANONYMIZE_ASSET_DIR.
    • Improved compatibility with compiled single-binary environments while retaining the existing default asset-loading behaviour.
  • Bug Fixes

    • Resolved WebAssembly asset-loading issues when native files are not located beside the module.
  • Tests

    • Added automated coverage for compiled-binary WebAssembly loading and end-to-end redaction.

Inside a compiled single binary (bun build --compile), import.meta.url
points into the binary's embedded filesystem; dynamic import() resolves
against it exclusively, so the binding's relative asset URLs can never
reach assets installed on disk and getBinding() fails even when
dist/native/ is present next to the binary.

STLL_ANONYMIZE_ASSET_DIR now overrides the asset base (absolute POSIX path
or file: URL). Browsers never define process, so the override is inert
there; the default path is unchanged.

smoke-wasm-compiled.mjs guards both directions: a compiled consumer must
fail without the override (proving the guard exercises the embedded
filesystem class) and must redact end to end with it — glue, wasm, and
prepared package all resolve through the override.
@github-actions

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jan-kubica, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 39 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2bc2c838-85c8-4110-9046-b839b0406826

📥 Commits

Reviewing files that changed from the base of the PR and between 3ce95a8 and 285e6cb.

📒 Files selected for processing (3)
  • packages/anonymize/scripts/smoke-wasm-compiled.mjs
  • packages/anonymize/src/vite.ts
  • packages/anonymize/src/wasm.ts
📝 Walkthrough

Walkthrough

The WebAssembly loader now supports STLL_ANONYMIZE_ASSET_DIR for native assets in compiled single-binary environments. A Bun-based smoke test verifies failure without the override and successful redaction with copied assets. CI and release metadata include the new behaviour.

Changes

Compiled WebAssembly asset loading

Layer / File(s) Summary
Configurable native asset resolution
packages/anonymize/src/wasm.ts
The loader reads STLL_ANONYMIZE_ASSET_DIR. It resolves assets from the configured absolute path or file: URL, and keeps the module-relative fallback.
Compiled binary smoke test
packages/anonymize/scripts/smoke-wasm-compiled.mjs
The smoke test builds a temporary Bun single binary, checks loading without the override, then validates redaction with copied native assets and the override.
Smoke-test and release wiring
packages/anonymize/package.json, .github/workflows/ci.yml, .changeset/compiled-binary-asset-loading.md
The package script and CI job run the smoke test. The changeset records a patch release for the asset-loading support.

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

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant SmokeTest
  participant Bun
  participant CompiledConsumer
  participant wasm_ts
  CI->>SmokeTest: run smoke:wasm-compiled
  SmokeTest->>Bun: compile temporary consumer
  SmokeTest->>CompiledConsumer: run without asset override
  CompiledConsumer->>wasm_ts: load WebAssembly entry point
  wasm_ts-->>CompiledConsumer: fail to resolve native assets
  SmokeTest->>CompiledConsumer: run with copied assets and STLL_ANONYMIZE_ASSET_DIR
  CompiledConsumer->>wasm_ts: load engine and redact entity
  wasm_ts-->>SmokeTest: return redacted output
Loading

Possibly related PRs

  • stella/anonymize#407: Its browser-WASM asset loading work is extended by configurable native asset-directory resolution for compiled binaries.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: loading native assets from a real directory for compiled binaries.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/compiled-binary-asset-loading

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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ce95a8a74

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/anonymize/src/wasm.ts Outdated

@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

🧹 Nitpick comments (1)
packages/anonymize/scripts/smoke-wasm-compiled.mjs (1)

80-95: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Exercise the file: URL override.

Line 84 tests only the absolute POSIX-path form. The loader also accepts a file: URL, but CI does not execute that branch.

Run the compiled consumer once more with STLL_ANONYMIZE_ASSET_DIR set to new URL(assetDir, "file:///").href. Require the same successful redaction result.

🤖 Prompt for 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.

In `@packages/anonymize/scripts/smoke-wasm-compiled.mjs` around lines 80 - 95,
Extend the smoke test after the existing withOverride validation to run the
compiled consumer again with STLL_ANONYMIZE_ASSET_DIR set to the file URL
derived from assetDir via new URL(assetDir, "file:///").href. Validate that this
invocation exits successfully and produces the same JSON redaction result,
reusing the existing output parsing and failure checks where appropriate.
🤖 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/anonymize/src/wasm.ts`:
- Around line 193-196: Update the override handling in the asset-directory URL
logic to reject relative filesystem paths and non-local file URLs, then convert
valid filesystem paths with pathToFileURL so characters such as # and ? remain
encoded as path data. Preserve the existing trailing-slash URL behavior and
ASSET_DIR_ENV override handling.

---

Nitpick comments:
In `@packages/anonymize/scripts/smoke-wasm-compiled.mjs`:
- Around line 80-95: Extend the smoke test after the existing withOverride
validation to run the compiled consumer again with STLL_ANONYMIZE_ASSET_DIR set
to the file URL derived from assetDir via new URL(assetDir, "file:///").href.
Validate that this invocation exits successfully and produces the same JSON
redaction result, reusing the existing output parsing and failure checks where
appropriate.
🪄 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: 3f816279-64eb-41f8-beab-977f0e2f12df

📥 Commits

Reviewing files that changed from the base of the PR and between 57fd873 and 3ce95a8.

📒 Files selected for processing (5)
  • .changeset/compiled-binary-asset-loading.md
  • .github/workflows/ci.yml
  • packages/anonymize/package.json
  • packages/anonymize/scripts/smoke-wasm-compiled.mjs
  • packages/anonymize/src/wasm.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,md,json,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Do not publish private user, customer, infrastructure, incident, pricing, roadmap, competitive, or internal security context in repository artifacts, comments, PRs, or generated instructions.

Files:

  • packages/anonymize/package.json
  • packages/anonymize/src/wasm.ts
**/*.{ts,tsx,js,jsx,rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Treat legal data, personal data, repository secrets, and raw anonymization inputs as sensitive; never log or publish them unless intentionally public and minimal.

Files:

  • packages/anonymize/src/wasm.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Prefer explicit discriminator values throughout the stack; model mutually exclusive states with discriminated unions rather than boolean flags and optional payloads.
Use as const objects or union types instead of TypeScript enums.
Avoid unnecessary casts and annotations; preserve compiler inference, avoid explicit generic arguments to inference-driven hooks, and fix type mismatches at their source.
Use as const satisfies T for large object-literal unions instead of a widening : T annotation.
Use .at(0) when an element may be absent; use [0] only after existence is established or with a documented // SAFETY: invariant.
Prefer arrow functions, parameter destructuring when the intermediate value is not reused, and discriminated-union checks over in checks when a discriminator exists.
Use options/args/params objects for three or more function arguments or interchangeable same-type arguments; reserve Props for React component props.
Reuse library utility types, keep helper-local types near their helpers, and hoist noisy return types into nearby aliases.
Do not assign directly to document.cookie.
Avoid spread syntax in loop accumulators; use .push() instead.
Never import test-only types into production code; use structural constraints when production code must accept test instances.
Keep language-dependent vocabulary and ambiguity rules in per-language reproducible data; never fix one language by unioning another language's words, and provide coverage matrices or explicit scope rationale for cross-language concepts.

Files:

  • packages/anonymize/src/wasm.ts
**/*.{ts,tsx,rs}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,rs}: Fail fast: validate at boundaries, return or throw early, minimize brace nesting, and use named constants for domain values instead of string literals.
Do not introduce unnecessary module-level side effects; split reusable utilities from side-effecting singletons and defer dependent initialization through lazy getters.
Prefer vertical end-to-end feature slices, preserve standard formats and self-hosting, batch operations, minimize round trips, and lazy-load aggressively.
Prepared-package schema versions describe payload schema only; represent compression and digest choices with explicit tagged fields, and prefer clean fail-closed breaks for unreleased formats.

Files:

  • packages/anonymize/src/wasm.ts
**/*.{rs,ts,py}

📄 CodeRabbit inference engine (AGENTS.md)

Keep binding layers thin; business logic belongs in the Rust core, while TypeScript, Python, WASM, and NAPI layers translate types and call shared logic.

Files:

  • packages/anonymize/src/wasm.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use oxlint with the ultracite preset and oxfmt; suppress a rule only with // eslint-disable-next-line rule-name.

Files:

  • packages/anonymize/src/wasm.ts
**/*.{rs,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Runtime parity must compare complete structural configuration, reject unknown DTO members except open language-keyed maps, assign every capability to a parity profile, and run each profile through all applicable runtimes.

Files:

  • packages/anonymize/src/wasm.ts
🔇 Additional comments (5)
packages/anonymize/src/wasm.ts (1)

128-128: LGTM!

Also applies to: 164-167

packages/anonymize/scripts/smoke-wasm-compiled.mjs (1)

1-78: LGTM!

Also applies to: 97-101

packages/anonymize/package.json (1)

95-95: LGTM!

.github/workflows/ci.yml (1)

381-382: LGTM!

.changeset/compiled-binary-asset-loading.md (1)

1-5: LGTM!

Comment thread packages/anonymize/src/wasm.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f82a999d40

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/anonymize/src/wasm.ts Outdated
- The override rejects relative paths, keeps file: URLs as-is, and encodes
  path segments (pathToFileURL semantics without importing node:url, since
  this module also ships to browsers), so #, ?, and % stay path data.
- The default asset base stays one verbatim expression and the Vite plugin
  anchors on its exact emitted text, re-pointing it at the emitted anchor
  asset; new URL(fileName, <anchor URL>) keeps the last-segment replacement
  behavior.
@jan-kubica
jan-kubica merged commit 2b804b3 into main Aug 10, 2026
17 checks passed
@jan-kubica
jan-kubica deleted the fix/compiled-binary-asset-loading branch August 10, 2026 22:16
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 10, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant