Skip to content

local-dev/dapp-builder: lessons learned from freenet-email v0.1.x publish + debug #23

@iduartgomez

Description

@iduartgomez

Captured during freenet-email v0.1.0/v0.1.1 production publish and identity-creation debugging (April 2026). Filing so local-dev and dapp-builder skills absorb the gotchas before the next dApp hits them.

1. Gateway iframe shell + same-origin WebSocket check

The gateway wraps every webapp in a sandboxed iframe at ?__sandbox=1. The parent shell (freenetBridge) intercepts window.WebSocket from inside the iframe and proxies to the real node WS via postMessage.

The bridge enforces strict origin equality:

const LOCAL_API_ORIGIN = location.origin;  // e.g. "http://127.0.0.1:7509"
if (httpProto + '//' + u.host !== LOCAL_API_ORIGIN) reject;

host includes hostname, so localhost127.0.0.1. Hardcoding ws://localhost:7509/... in the dApp breaks the moment the page is opened by IP (or vice versa).

Fix pattern — derive WS URL from window.location at runtime:

let host = window().location().host()?;  // "127.0.0.1:7509"
let scheme = if location.protocol()? == "https:" { "wss" } else { "ws" };
let url = format!(\"{scheme}://{host}/v1/contract/command?encodingProtocol=native\");

Skill should warn against hardcoded WS URLs and document the bridge's origin check.

2. wasm-bindgen onerror shim crash

Bridge proxy fires new Event('error') (no filename/message). wasm-bindgen's onerror handler calls event.filenameundefined → wbg crash:

wasm-bindgen: imported JS function that was not marked as 'catch' threw an error: expected a string argument, found undefined

Surfaces as a console error during normal operation. Smoke tests asserting consoleErrors === [] will fail. Allowlist the message until wbg upstream fixes, or use --catch on the import.

3. fdev port targeting

fdev defaults to port 7509. Targeting an isolated test node needs:

fdev --port 7510 execute put ...           # CLI flag
WS_API_PORT=7510 cargo make publish-...    # env override for cargo-make

Argument order matters: --port before execute, --code/--parameters before the contract subcommand. Skill already says this — worth a more prominent callout because the failure mode is put failed after 4 attempts which gives no hint about port.

4. Monotonic version requirement for web-container updates

On-chain web-container update check is strictly monotonic. Common broken schemes:

  • commit-hash hex truncated to u32 — not monotonic, newer commit can hash lower
  • commit count (git rev-list --count HEAD) — monotonic per branch but starts at ~22, far below versions already accepted under broken schemes

Working scheme: date -u +%s (unix timestamp at sign time). Tradeoff: contract IDs no longer reproducible from source — the committed snapshot becomes the authoritative ID.

5. Persistent vs ephemeral test nodes

--id creates ephemeral temp directories wiped on restart, destroying delegate secrets (signing keys, app data). Use --data-dir for persistent isolation. Skill already covers — keep.

6. Mobile browser WASM cache

Firefox mobile especially aggressive. After republish, clear cache or use ?_v={timestamp} cache-buster. Skill covers — keep.

7. Delegate-not-found loop (open question)

Observed during identity-management delegate calls on a fresh local node:

Delegate not found in store (expected for migration probes) delegate_key=Cu...
Module cache miss — compiling

Loops indefinitely on each call. Suggests delegate registration not persisting between calls, or migration probe path is hot. Worth investigating + documenting in skill if it's a known pattern.

8. GNU tar requirement

compress-webapp needs --sort=name --mtime=… --owner=0 --group=0 flags only GNU tar supports. macOS BSD tar silently produces non-reproducible archives. Install gnu-tar brew and detect gtar. Worth mentioning in dapp-builder when scaffolding signed-webapp pipelines.

9. Browser MCP for dApp debugging

chrome-devtools MCP + Playwright MCP both work for diagnosing UI ↔ node interaction. Particularly useful for:

  • reading actual gateway shell HTML (to find bridge origin checks)
  • capturing console errors invisible on mobile
  • watching network requests against the node WS

Could be a local-dev subsection: "Debugging dApps via browser MCP".

Suggested skill changes

  • local-dev: add "Gateway iframe + WS origin check" section with the window.location derivation pattern
  • local-dev: expand fdev port section with the WS_API_PORT env var
  • dapp-builder: add "Reproducible signed webapps" section covering monotonic version, GNU tar, committed-snapshot vs reproducible-from-source tradeoff
  • dapp-builder: add "WebSocket URL derivation" as a required pattern when the dApp loads inside the gateway iframe
  • Either: capture the wbg onerror crash as a known noise pattern + smoke-test allowlist guidance

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions