Skip to content

feat: expand plugin surface to mirror buckaroo server (load_expr, diagnostics, backend)#3

Open
paddymul wants to merge 2 commits into
mainfrom
feat/load-backend-xorq
Open

feat: expand plugin surface to mirror buckaroo server (load_expr, diagnostics, backend)#3
paddymul wants to merge 2 commits into
mainfrom
feat/load-backend-xorq

Conversation

@paddymul

Copy link
Copy Markdown
Contributor

Summary

Closes the gap between the plugin's IPC surface and the buckaroo server's HTTP surface. Two new commands, two new optional fields on the existing load command, matching JS adapter helpers.

  • buckaroo_load_path gains mode and backend optional args, forwarded into the POST body. Pre-existing single-arg callers unaffected.
  • New buckaroo_load_expr command — POSTs /load_expr with {build_dir, session?, project_root?, prompt?, component_config?} and opens the internal WS. Counterpart to buckaroo_load_path for the xorq-build-dir-driven path.
  • New buckaroo_diagnostics command — thin GET passthrough for /diagnostics.
  • JS adapter:
    • loadPath(path, opts?)opts: { mode?, backend?, session? }.
    • loadExpr(build_dir, opts?) — new helper paired with buckaroo_load_expr.

Why

buckaroo.server already supports a richer surface than the plugin exposes:

Endpoint Plugin before Plugin after
/health buckaroo_health (WS state) unchanged
/diagnostics buckaroo_diagnostics
/load buckaroo_load_path + mode + backend
/load_expr buckaroo_load_expr

mode / backend forwarding pairs with the matching feat(server): /load gains backend=xorq buckaroo PR: hosts that already materialised a parquet on disk can opt into XorqInfiniteBuckaroo's push-down query execution by passing { mode: "buckaroo", backend: "xorq" } instead of eager-pandas-loading the file.

Test plan

  • cargo build clean.
  • Existing loadPath(path) single-arg callers still work.
  • Manual: loadPath(path, { mode: "buckaroo", backend: "xorq" }) against a sidecar with the matching server change produces a XorqInfiniteBuckaroo session.
  • Playwright tests on the example app still pass (test job currently runs only against /load defaults — extending coverage is a follow-up).

Compatibility

  • All new fields on LoadPathArgs are Option<String> with #[serde(default)] — old JSON payloads deserialize unchanged.
  • loadPath's second arg is optional — old single-arg call sites compile and run identically.

🤖 Generated with Claude Code

paddymul added 2 commits May 22, 2026 17:06
…gnostics, backend)

Brings the buckaroo-tauri plugin closer to parity with `buckaroo.server`'s
HTTP surface. Adds the two endpoint passthroughs that were missing
(`load_expr`, `diagnostics`) and threads two new optional fields
(`mode`, `backend`) through the existing `buckaroo_load_path` so hosts
can route a parquet via the xorq push-down backend without separately
extracting a build_dir.

## Rust (crates/buckaroo-tauri/src)

- `LoadPathArgs` gains `mode: Option<String>` and `backend: Option<String>`.
  Forwarded into the POST body verbatim when present; otherwise the
  Layer-3 contract (server defaults) holds. Pre-existing callers that
  pass only `path` (+ optional `session`) are unaffected.
- New `LoadExprArgs` + `buckaroo_load_expr` command. POSTs `/load_expr`
  with `{build_dir, session?, project_root?, prompt?, component_config?}`
  and opens the internal WS to the returned session — same shape as
  `buckaroo_load_path` but for the xorq-build-dir-driven path.
- New `buckaroo_diagnostics` command. Thin GET passthrough for the
  server's `/diagnostics` endpoint; returns the JSON blob verbatim so
  host UIs can surface server version, uptime, installed extras, etc.
- Both new commands registered in `init()`.

## JS adapter (packages/buckaroo-tauri-adapter)

- `loadPath` gains an `opts?: { mode?, backend?, session? }` argument
  that's forwarded to the Rust command. Existing single-arg callers
  (`loadPath(path)`) keep working.
- New `loadExpr(build_dir, opts?)` helper paired with `buckaroo_load_expr`.
- Both exported from `index.ts`.

## Why

`buckaroo.server` already supports a richer surface than the plugin
exposes:

| Endpoint     | Plugin command before        | Plugin command after  |
|--------------|------------------------------|-----------------------|
| `/health`    | `buckaroo_health` (WS state) | unchanged             |
| `/diagnostics` | —                          | `buckaroo_diagnostics`|
| `/load`      | `buckaroo_load_path`         | + `mode` + `backend`  |
| `/load_expr` | —                            | `buckaroo_load_expr`  |

`mode` / `backend` forwarding on `/load` pairs with the
[`feat(server): /load gains backend=xorq` change in buckaroo](buckaroo-data/buckaroo#840):
hosts that already materialised a parquet on disk can opt into
XorqInfiniteBuckaroo's push-down query execution by passing
`{ mode: "buckaroo", backend: "xorq" }`, avoiding the eager-pandas
load that was the only path before.

## Test plan

- [x] `cargo build` clean on the Rust crate.
- [x] Manual: existing single-arg `loadPath(path)` still works.
- [ ] Manual: `loadPath(path, { mode: "buckaroo", backend: "xorq" })`
      against a sidecar that has the matching server change produces a
      XorqInfiniteBuckaroo session (verified end-to-end via the
      xorq-desktop integration that motivated this PR).
- [ ] Playwright tests on the example app still pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
… race

Adds `listenForInitialState()` — a variant of `waitForInitialState()`
that awaits the underlying `listen()` subscription before returning, so
the caller can fire a load call immediately afterwards without losing
the resulting `initial_state` push to a registration race.

Pattern:

    const received = await listenForInitialState();
    await loadPath(path, { mode: "buckaroo", backend: "xorq" });
    const initial = await received;

`waitForInitialState()` is left in place for hosts that pre-attach the
listener and only call `loadPath` later (the race doesn't bite there).
A docstring warning calls out the failure mode so new callers know
to reach for the race-safe variant when the two operations are
back-to-back.

## Background

`waitForInitialState()` returns a Promise immediately but the
`listen("buckaroo:msg", ...)` call inside is async — Tauri's event
channel needs an IPC round-trip to register the subscription. If the
caller fires `loadPath` next, the load_path IPC and the listen IPC
race; if load_path wins, the server's initial_state push arrives
before the listener attaches and Tauri drops it (no pre-subscription
buffering). The Promise then hangs forever waiting for a message
that already fled.

Confirmed in xorq-desktop integration: clicking a fast-path entry
like `batting` (parquet path returned in ~1 ms) reliably stalled on
"loading into sidecar + awaiting initial_state…" until the inline
fix landed. With `listenForInitialState()` the same flow lands the
view in milliseconds.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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