Skip to content

Releases: cablehead/http-nu

Release v0.17.2

09 Jun 05:11

Choose a tag to compare

v0.17.2

Highlights

  • Embedded cross.stream store updated to 0.13.3. A re-registered (hot-replaced) service no longer loses .append, and a module's exported function can now call the store builtins (.append, .cat, .last, ...), not just plain nushell. See the cross-stream 0.13.3 notes for detail.

  • --watch no longer reload-loops on the store directory. The --store directory is now excluded from the recursive --watch, so a handler writing frames no longer triggers an endless reload cycle.

Raw commits

  • feat: update embedded cross.stream to 0.13.3 (2026-06-09)
  • docs: note Homebrew tap-trust before install (2026-06-08)
  • fix: exclude --store dir from --watch to prevent reload loops (2026-06-07)
  • docs: note --watch is recursive; keep --store out of the watched dir (2026-06-07)
  • chore: bump to v0.17.2-dev (2026-06-07)

Release v0.17.1

07 Jun 15:57

Choose a tag to compare

v0.17.1

Highlights

  • to sse emits a comment field as an SSE comment line. A record with a comment key now renders a : text line ahead of any event / id / retry / data lines. SSE comments are ignored by the browser but keep idle connections alive through proxies, so a handler can ship {comment: "hb"} as a heartbeat without patching the DOM. Empty (Value::Nothing) comments are skipped, matching how the other fields behave.

  • value_to_json no longer panics on types without a JSON analogue. Dates, durations, filesizes, binary, closures, and similar values now fall back to their string rendering instead of hitting a todo!(). A record carrying a timestamp or duration field can be returned straight to an HTTP/JSON response without crashing the handler. The data-line JSON path (value_to_bytes) inherits the same fallback.

  • nu2048 example: the splash page credits Datastar with the animated rocket; changelog link fixed.

Raw commits

  • fix: render unsupported value_to_json types as strings instead of panicking (2026-06-07)
  • feat: emit an SSE comment line from a record's comment field (2026-06-07)
  • feat(2048): splash credits Datastar with the animated rocket (2026-06-07)
  • docs: fix nu2048 changelog link (trailing slash) (2026-06-07)
  • chore: bump to v0.17.1-dev (2026-06-07)

Release v0.17.0

07 Jun 09:23

Choose a tag to compare

v0.17.0

Highlights

  • xs store: 0.12 -> 0.13.2. A breaking change, but only to the store's internal bookkeeping. The topics your own handlers append to and read are unaffected.

    • xs now keeps its lifecycle records under a reserved xs. prefix, named consistently across actors, services, and actions as xs.<kind>.<name>.<event>. Previously each kind used its own ad-hoc topic names in the same namespace as your data.
    • An old store still opens. To bring its --services automation back up, rewrite those lifecycle topics to the new names with the new binary (.export -> rewrite -> .import); see examples/2048/migrate-topics.nu.
    • Registration topics renamed: *.register -> xs.actor.*.create, *.spawn -> xs.service.*.create, *.define -> xs.action.*.create, *.nu -> xs.module.*.
    • Exit reasons are now distinct topics (fin.ok / fin.error / fin.term) rather than a field on the frame.
    • New handler builtins: .import (restore frames) and .cas-post (write a CAS blob).
  • --services for http-nu eval. Eval mode can now start the same background services serve mode runs, so scripts can exercise actors, services, and actions without a live server.

  • Nushell engine: 0.112.1 -> 0.113.1. Handlers gain peek (sample a stream without a collect) and the idx family (in-memory file index with fuzzy lookup and content search). Minimum Rust is now 1.93.1; CI's setup-nu tracks the bundled engine.

  • Datastar SDK: 1.0.1 -> 1.0.2. The bundle http-nu serves under --datastar advances to /datastar@1.0.2.js (sourcemap comment stripped). Upstream changes:

    • datastar-patch-elements events accept a viewTransitionSelector data line naming the element to use for the view transition (defaults to document);
    • in-flight requests are cancelled by matching method + URL, regardless of which element initiated them;
    • checkboxes and radios bound with data-bind now sync on the input event for more immediate updates;
    • faster single-target element patches;
    • fixes for data-bind with a modifier on an array-valued checkbox signal, and for retrying on 5xx responses.
  • Accurate startup_ms. The startup timer now starts before handler eval, so the banner and started log event report the real cold start. build.rs also reruns on Cargo.lock changes to keep NU_VERSION / XS_VERSION in sync.

  • 2048 example, substantially rebuilt. nu2048 is now a full event-sourced, multiplayer app and a worked example of the http-nu + xs primitives. Game state is a chain of game.snapshot.<id> frames in the store, each pointing at its predecessor, so a move appends a snapshot and undo walks back up the chain. Three xs actors write and derive from that stream:

    • the snapshot actor is the single writer of the chain: per move it reads the head, computes the next state, and appends the new snapshot;
    • the leaderboard actor watches every snapshot and maintains a derived leaderboard.top view, resuming from a stored cursor rather than replaying all history;
    • the presence actor folds ephemeral per-tab pings into a _presence.summary frame, pruning stale tabs on each xs.pulse.
    • SSE handlers follow these frames with .last --follow / .cat --follow and patch the browser over Datastar, with cookie sessions, a <game-board> web component, and a /design playground.

Raw commits

  • fix: start the startup timer before handler eval so startup_ms reflects real cold start (2026-06-06)
  • build: rerun build.rs on Cargo.lock change so NU_VERSION/XS_VERSION track dep bumps (2026-06-06)
  • docs: add how-to for refreshing the embedded datastar SDK (2026-06-06)
  • deps: update datastar to v1.0.2, strip embedded sourcemap comment (2026-06-06)
  • refactor: register store builtins via cross-stream's add_{core,read,write}_commands (2026-06-06)
  • build: bump cross-stream to 0.13.2; strip-store imports via .import in one eval (2026-06-06)
  • feat(2048): undo tally left of score (score stays put); undo evicts a game from the leaderboard (2026-06-05)
  • feat(2048): live undo tally next to score on /play and /watch (2026-06-05)
  • feat(2048): leaderboard ranks clean runs only (undo-assisted scores excluded) (2026-06-05)
  • feat(2048): track undos count in snapshot meta; leaderboard reads it O(1) (2026-06-05)
  • perf(2048): list-games/list-players/top-players use indexed -T "prefix.*" not full .cat scans (2026-06-05)
  • perf(2048): /sse-wc reads head via --last 1 instead of replaying the chain (2026-06-05)
  • fix(2048): emit trailing newline from strip-store.nu (2026-06-04)
  • refactor(2048): xs 0.13 lifecycle topics, actor-owned snapshot rebuild (2026-06-04)
  • build: upgrade to cross-stream 0.13.0 and nushell 0.113.1 (2026-06-04)
  • fix(2048): widen /design via body max-width after column moved to body (2026-06-03)
  • fix(2048): drop preview frame on the design markdown story (2026-06-03)
  • fix(2048): render design markdown preview in so it matches /notes (2026-06-03)
  • feat(2048): add 'why is this so addictive' notes page (2026-06-03)
  • refactor(2048): render notes in semantic , drop .prose wrapper (2026-06-03)
  • docs(adr): remove 0006 (moved to xs/docs/adr/0005-lifecycle-topics.md) (2026-05-30)
  • docs(adr): reword 'load-bearing' to 'depend on' (2026-05-30)
  • docs(adr): rename parse.error to invalid, strip em-dashes, reframe trade-off as property (2026-05-30)
  • docs(adr): plainer wording, drop 'collapses' (2026-05-30)
  • docs(adr): enumerate deficiencies, add lifecycle invariants (2026-05-30)
  • docs(adr): xs.. namespacing, one-shot migration (2026-05-30)
  • docs(adr): xs lifecycle topics + compaction algorithm (2026-05-30)
  • examples/2048: add migrate-topics.nu for old->new topic shape (2026-05-28)
  • examples/2048: prefix-shape game topics; reroute no-op ack via ephemeral snapshot (2026-05-28)
  • examples/2048: add /sse-wc integration test (2026-05-28)
  • examples/2048: add snapshot-actor integration test (2026-05-28)
  • feat: add --services flag to eval subcommand (2026-05-28)
  • examples/2048: plain-language test-sse.nu names, fix leaderboard resume comment (2026-05-28)
  • examples/2048: fix leaderboard-actor crash on empty .last, guard the idiom (2026-05-27)
  • examples/2048: snapshot-actor resumes from cursor so reloads don't drop moves (2026-05-27)
  • examples/2048: dim the board while a move's response is pending (2026-05-27)
  • docs: note to keep setup-nu in sync with the bundled nu version (2026-05-26)
  • ci: run nu tests on 0.112.1 to match the bundled engine (2026-05-26)
  • examples/2048: enlarge splash PLAY NOW button and callout text (2026-05-25)
  • examples/2048: use Cirulli-continued palette in the board WC (2026-05-25)
  • examples/2048: tile-palette gallery in /design, drop colors experiment (2026-05-25)
  • examples/2048: thumb-ergonomic D-pad controls, mobile-friendly chrome (2026-05-24)
  • examples/2048: snapshot-actor clears spawned/merged on undo (no re-animation) (2026-05-20)
  • examples/2048: strip decorative parens around single-line let values (2026-05-20)
  • examples/2048: drop dead try around .last; use get?.field? | default for chained access (2026-05-20)
  • examples/2048: /sse/games --from instead of --new (race-free cursor) (2026-05-20)
  • examples/2048: /sse/games uses .cat --follow --new instead of .cat | last head probe (2026-05-20)
  • examples/2048: layout owns $presence seed; drop redundant per-route declarations (2026-05-20)
  • examples/2048: hoist /watch signals to so site-header data-text can read $presence (2026-05-20)
  • examples/2048: leaderboard-actor resumes from last_processed_id cursor (2026-05-20)
  • examples/2048: cap actor register topics with --ttl last:1 (2026-05-20)
  • examples/2048: presence-stream filters xs.threshold before .meta access (2026-05-20)
  • examples/2048: fix let board_stream = .cat --follow hang in 3 SSE handlers + test-sse.nu regression guard (2026-05-20)
  • examples/2048: site-wide presence (X here chip + per-game count, /presence/ping) (2026-05-20)
  • examples/2048: fold playedMs into board signal, owns overlay (2026-05-20)
  • examples/2048: leaderboard link in header; #1 podium row, #2-5 two-up (2026-05-20)
  • examples/2048: /leaderboard page reads leaderboard.top, dimmed-card per row (2026-05-20)
  • examples/2048: leaderboard-actor maintains leaderboard.top (last:5) (2026-05-20)
  • examples/2048: reserve over-slot so 'you win' stays in place (2026-05-19)
  • examples/2048: per-tab splash topic, no more shared bus.splash.seek (2026-05-19)
  • examples/2...
Read more

Release v0.16.0

06 May 18:08

Choose a tag to compare

v0.16.0

Highlights

  • .bus pub / .bus sub: ephemeral local pub/sub. A new in-process bus for UI events that don't belong in the durable event log. .bus pub <topic> publishes a value; .bus sub [pattern] yields {topic, value} records and supports glob patterns like tab-abc.*. Always available; no flag required. Slow subscribers are disconnected on overflow so the SSE stream ends and the client reconnects fresh. Sits alongside the cross.stream --store for a clean ephemeral / persistent split.

  • .run for evaluating user-submitted nushell scripts. Parses, compiles, and evaluates a script string against a clone of the engine state. Parse, compile, and runtime errors surface as distinct types with source-excerpt diagnostics. Each call's defs and lets stay scoped to the call. Useful for in-browser REPLs and similar; expose only on localhost or in trusted environments since the script has full process access.

  • --datastar flag for http-nu eval. Sets $HTTP_NU.datastar so eval-mode scripts can branch on the same flag the serve mode uses.

  • Datastar bumped to v1.0.1 (from RC.8); the bundled JS and CDN reference advance together. The startup banner only reports the datastar version when --datastar is set.

  • SSE cancel surfaces a stream error so clients reliably auto-retry instead of seeing a clean EOF.

  • 2048 example demonstrates the .bus round-trip end-to-end with view-transition tile slides, plus a tests-browser/ infrastructure mirroring stacks.nu for chromium-driven end-to-end tests.

  • README: documents the href helper for mount-aware URL construction, splits the Local Bus and Embedded cross.stream sections so each describes itself before comparing.

Raw commits

  • docs: document .run command; drop two filler phrases (2026-05-06)
  • feat: 2048 advertises og:image and twitter card; harden browser test (2026-05-06)
  • feat: add 2048 example demonstrating .bus pub/sub with view transitions (2026-05-06)
  • style: format .nu files with topiary (2026-05-05)
  • feat: add .bus pub / .bus sub for ephemeral local pub/sub (2026-05-05)
  • feat: render .run parse/compile errors with source excerpts (2026-05-04)
  • feat: add .run command for sandboxed nushell pipeline evaluation (2026-05-04)
  • feat: add --datastar flag to http-nu eval (2026-04-28)
  • deps: update datastar to v1.0.1 (2026-04-27)
  • fix: SSE cancel surfaces stream error so clients auto-retry (2026-04-27)
  • fix: only show datastar version in startup banner when --datastar is set (2026-04-27)
  • chore: bump to v0.15.1-dev (2026-04-13)

Release v0.15.0

13 Apr 18:27

Choose a tag to compare

v0.15.0

Highlights

  • Updated to Nushell 0.112.1 and cross.stream 0.12.0. Nushell removed the --merge flag from metadata set. If you were using metadata set --merge {...}, switch to the closure form: metadata set { merge {'http.response': {status: 404}} }. The { merge {...} } form that was already used in examples and docs continues to work unchanged.

  • Security hardening for HTML output. Minijinja templates now autoescape by default. The .md command escapes code fence language attributes. HTML DSL attribute values are properly escaped. The escape-html utility consistently escapes all five HTML-significant characters (& < > " ') everywhere.

  • SSRF fix in reverse proxy. The strip_prefix logic now rejects URLs with authority components (e.g. //evil.com) that could confuse downstream routing.

Raw commits

  • deps: update nushell to 0.112.1 and cross-stream to 0.12.0 (2026-04-13)
  • refactor: unify escape-html to escape all 5 chars everywhere (2026-04-13)
  • fix: consolidate HTML escaping, add attribute escaping to HTML DSL (2026-04-13)
  • fix: escape code fence language in .md to prevent XSS (2026-04-08)
  • fix: enable HTML autoescape in minijinja templates to prevent XSS (2026-04-08)
  • fix: prevent SSRF via URL authority confusion in reverse proxy strip_prefix (2026-04-08)
  • feat: add cargo-docs example (2026-04-07)
  • docs: update v0.14.0 release notes (2026-04-04)
  • fix: rename const to avoid collision when sourced from www/serve.nu (2026-04-04)
  • fix: use path self for cwd-independent path resolution in templates example (2026-04-03)
  • docs: rewrite v0.14.0 release notes (2026-04-04)
  • chore: bump to v0.14.1-dev (2026-04-03)

Release v0.14.0

03 Apr 22:12

Choose a tag to compare

New release, http-nu :: v0.14.0

https://github.com/cablehead/http-nu/releases/tag/v0.14.0

Highlights

  • .md supports GFM: Tables, strikethrough, - [x] checklists, footnotes, and definition lists now render correctly.
  • eval --store <path>: eval now accepts a --store flag to use .cat, .append, .cas against a store directory directly.
  • ICONIFY: Use any of 200k+ icons from Iconify: ICONIFY "lucide:copy", ICONIFY "mdi:home".
  • Clean SSE shutdown: SSE connections now close immediately on Ctrl+C instead of hanging for 10 seconds.
  • Datastar SDK update: from datastar-signals now handles DELETE like GET — signals come from query params, matching the updated ADR. Also adds SCRIPT-DATASTAR to emit the client script tag (served from the binary, no CDN needed).
  • New examples: A blog example showing routing, layouts, and HTML composition, plus a reworked stor example that demonstrates in-memory SQLite by logging its own page views.
  • href: Mount-aware link helper. $req | href "/about" returns /blog/about when mounted at /blog.

Release v0.13.0

02 Mar 20:06

Choose a tag to compare

v0.13.0

Highlights

Updated to Nushell 0.111, cross.stream 0.11, and Datastar v1.0.0-RC.8.

The $HTTP_NU const is now available in handler scripts, providing access to runtime context (version, dev mode, store path, etc.) without environment variables. An examples hub at examples/ showcases available demos with live links.

SSE streams with brotli compression now correctly abort on hot reload, fixing a race where compressed SSE connections could hang during --watch reloads.

The curl hint URL now respects X-Forwarded-Proto when running behind a reverse proxy.

Changelog

  • chore: bump Datastar to v1.0.0-RC.8 (2026-03-02)
  • feat: add getting started tutorial and unified copy buttons for www site (2026-03-02)
  • fix: compose SSE reload-abort with brotli compression (2026-02-26)
  • fix: use X-Forwarded-Proto for curl hint URL behind reverse proxy (2026-02-26)
  • feat: add curl hint for streaming /time endpoint in basic example (2026-02-26)
  • docs: link to live examples from README and examples/README (2026-02-26)
  • feat: $HTTP_NU const + examples hub (#42) (2026-02-26)
  • examples: add live mermaid editor with Datastar + web component (2026-02-23)

Release v0.12.0

19 Feb 05:04

Choose a tag to compare

v0.12.0

Highlights

Templates can now load from the store. .mj --topic "page.html" renders a template stored in an xs topic, and {% extends %} / {% include %} references resolve as topic names from the same store. Previously you could load template content via --inline, but if that template referenced other templates they'd resolve from the filesystem -- there was no way for stream-sourced templates to reference each other.

.mj and .mj compile now take exactly one of three mutually exclusive modes:

  • File -- {% extends %} / {% include %} resolve from the template's directory on disk
  • Inline (--inline) -- self-contained, no resolution
  • Topic (--topic, requires --store) -- resolves template names as store topics

examples/templates/ demonstrates all three modes with visually distinct template variants so you can tell which source served the page.

Scripts can use path self for relative paths. Handler scripts no longer need to hardcode paths relative to the working directory:

const script_dir = path self | path dirname
let slides = open ($script_dir | path join data.json)
let page = .mj compile ($script_dir | path join page.html)

http-nu eval works the same way, so you can unit test handler endpoints from anywhere:

# test.nu
use std/assert

const script_dir = path self | path dirname
let handler = source ($script_dir | path join serve.nu)
let response = do $handler {method: GET, path: "/", headers: {}}
assert ($response | str contains "<h1>State in the Right Place</h1>")
http-nu eval test.nu

The Nushell standard library (std/assert, std/log, etc.) is now available in scripts and eval.

Breaking changes

  • feat!: inline mode no longer attaches a filesystem loader -- {% include "local.html" %} in an --inline template previously resolved from the working directory; use file mode instead

Changelog

  • feat!: .mj --topic for store-backed templates (#40) (2026-02-18)
  • feat: support path self in file-based scripts (2026-02-18)
  • feat: load nushell stdlib into engine (2026-02-19)
  • examples: add unit test for tao handler (2026-02-19)
  • examples: use path self for relative paths in tao (2026-02-18)
  • examples: The Tao of Datastar (#39) (2026-02-18)
  • docs: document unit testing endpoints with eval (2026-02-19)

Release v0.11.0

16 Feb 16:15

Choose a tag to compare

v0.11.0

Highlights

The server can now run entirely from the stream. --topic loads the handler closure from an xs topic instead of a file, and with -w it hot-reloads whenever the topic is updated:

http-nu :3001 --store ./store --topic serve -w

If the topic doesn't exist yet, a placeholder page serves a 503 with instructions on how to get started. Append a closure and the server picks it up:

'{|req| "hello, world"}' | .append serve

Topic-sourced handlers get access to VFS modules stored on the stream -- any *.nu topic appended to the store is available via standard use imports, same as with actors and services in xs.

Cookies have first-class support. use http-nu/http gives you cookie parse, cookie set, and cookie delete with secure defaults (HttpOnly, SameSite=Lax, Secure). Multiple cookies accumulate naturally through the pipeline:

use http-nu/http *

{|req|
  let cookies = $req | cookie parse
  "logged in"
  | cookie set "session" "abc123" --max-age 86400
  | cookie set "theme" "dark"
}

The --dev flag tells the cookie module to omit the Secure attribute, so cookies work over plain HTTP during local development.

Datastar's JS bundle is now embedded in the binary. --datastar serves it at a versioned path with immutable cache headers -- no CDN dependency, zero runtime compression (brotli is pre-built at compile time):

use http-nu/datastar *
SCRIPT {type: "module" src: $DATASTAR_JS_PATH}

--expose opens the xs API on an additional address, useful for separating the public-facing HTTP server from the stream management interface. Accepts TCP addresses or iroh:// for peer-to-peer QUIC.

Breaking changes

  • feat!: update cross-stream to 0.10.0 -- aligns with the xs processor rename (handlers/generators/commands are now actors/services/actions) and the 2-parameter actor closure shape

Changelog

  • feat: add --topic flag to load handler from xs store
  • feat: add cookie module (cookie parse, cookie set, cookie delete) with secure defaults
  • feat: add --dev flag for development mode
  • feat: embed Datastar JS bundle, serve via --datastar
  • feat: add --expose flag to expose xs API on additional address
  • feat: display startup options and dependency versions in preamble
  • feat: VFS modules from the stream available to topic-sourced handlers
  • feat: add cross.stream-powered branding
  • refactor: bundle handler params into AppConfig struct
  • refactor: align with xs processor rename (actor/service/action)
  • fix: update actor closure signature to match xs 2-param requirement
  • fix: add duration literal support to nushell syntax grammar

Release v0.10.2

29 Jan 05:05

Choose a tag to compare

v0.10.2

Highlights

  • Empty response bodies now default to 204 No Content
  • Datastar SDK naming aligned with spec (breaking for datastar users)
  • Shutdown message now gets a timestamp like other log lines
  • File watcher uses trailing-edge debounce for more reliable reloads
  • Bumped cross-stream to 0.9.3

Raw commits

  • chore: bump cross-stream to 0.9.3 (2026-01-29)
  • feat: timestamp the shutdown message separately from the closing tag (2026-01-29)
  • feat: default to 204 No Content for empty response body (2026-01-27)
  • refactor(datastar)!: align SDK naming with spec (2026-01-26)
  • fix: use trailing-edge debounce for file watcher (2026-01-23)
  • docs: update release.md for versioned artifact naming (2026-01-22)