Skip to content

Adopt the glaze native transport on macOS; dual-transport bridge - #1

Merged
turinglambdaai merged 3 commits into
mainfrom
native-transport
Oct 14, 2026
Merged

turinglambdaai merged 3 commits into
mainfrom
native-transport

Conversation

@turinglambdaai

Copy link
Copy Markdown
Owner

What

run-app starts with #:transport 'native on macOS (HACKDIGEST_TRANSPORT overrides; other platforms keep the HTTP adapter until verified). The page loads from glaze://, every call rides the GLZ1 message handler — no TCP port, no token. Depends on glaze#63 (GLZ1 streaming + FFI-stack discipline) landing first.

Bridge

bridge.ts keeps one interface over both transports:

  • apiPost/hasBackend detect window.__glz1 and route through GLZ1 invoke; without it, the relative-fetch path runs unchanged (vite dev, plain-browser, HTTP adapter).
  • streamChat/streamLines keep the backend's wire protocol (first line OK / ERR <status> <message>, then raw text / ndjson lines) on both transports — the native channel delivers the handler's bytes verbatim as chunk frames, so one parser serves both. Parser errors cannot throw out of onDelta (the native bootstrap swallows callback exceptions by design), so LineStreamParser records them and the caller raises after the stream settles.
  • AbortSignal cancels through invokeStream's signal support (immediate reject + server-side cancel op closing the stream pipe).

Verified on the machine

The app opens from glaze://, renders the full UI with real data through the native channel, and survives the React startup burst of invokes with a clean log (this exact burst found two glaze bugs — see glaze#63).

Tests

12 new bridge cases over both transports: invoke value/error pass-through, per-chunk onDelta, ERR-line handling, ndjson lines split across fetch chunks, missing-status-line error. 26 in the suite, plus tsc --noEmit and vite build clean.

run-app now starts with #:transport 'native on macOS (HACKDIGEST_TRANSPORT
overrides; other platforms keep the HTTP adapter until their native runs
are verified end to end). The page loads from glaze:// and every call
rides the GLZ1 message handler — no TCP port, no token, no loopback API.

bridge.ts speaks both transports behind the same interface:

- apiPost/hasBackend detect window.__glz1 and route through GLZ1 invoke;
  without it the old relative-fetch path runs unchanged (vite dev,
  plain-browser).
- streamChat/streamLines keep the backend's line protocol (first line OK
  or ERR <status> <message>, then raw text / ndjson lines) on both
  transports — the native channel delivers the handler's bytes verbatim
  as chunk frames, so one parser serves both. Parser errors cannot throw
  out of onDelta (the native bootstrap swallows callback exceptions), so
  LineStreamParser records them and the caller raises after settle.
- AbortSignal cancels through glaze.invokeStream's signal support, which
  rejects immediately and closes the stream server side via the cancel op.

Also verified on the machine: the app opens from glaze://, loads real
data through the native channel, and survives the React startup burst of
invokes with a clean log.

Tests: 12 new bridge cases cover both transports — invoke value/error
pass-through, per-chunk onDelta, ERR-line handling, ndjson lines split
across chunks, and the missing-status-line error.
The native adoption needs GLZ1 streaming, and the typed-descriptor
re-exports landed on glaze main after v0.14.0. Revert to a version pin
once glaze#63 merges and releases.
@turinglambdaai
turinglambdaai merged commit 59a7fa3 into main Oct 14, 2026
2 checks passed
@turinglambdaai
turinglambdaai deleted the native-transport branch October 14, 2026 08:10
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