0.1.0-alpha.1

The unified page module release. A Datastar page is now one module and one router line. Alpha until the page layer has survived its proving ground (a full production-app migration); the functional core is the same battle-tested code as 0.0.x.

Added

  • Dstar.Pageuse it for one-module pages: mount/2, render/1, handle_event/3, handle_connect/2, handle_info/2, stream_key/1.
  • Dstar.Page.Plug — drives all page requests; owns the SSE receive loop with idle checks and stray-message tolerance.
  • Dstar.Component — shared UI with colocated event handlers; event/2 targets the dispatch URL with a client-side data-ds-prefix base.
  • Dstar.Routerdstar/2 (page routes) and dstar_components/2 (dispatch route) macros.
  • Dstar.Page.Helpersevent/1,2, connect/0,1, patch/3,4.
  • Dstar.Page.Assignsassign/assign_new/update working on both conns and component assigns.
  • Dstar.Testsse_events/1, patched_signals/1, assert_patched_signals/2, assert_patched_element/2.
  • Optional deps: phoenix ~> 1.7, phoenix_live_view ~> 1.0. The functional core still needs only plug + jason.

Changed

  • Docs restructured around pages; the original API is now "the functional core". Nothing breaks: all 0.0.x code works unchanged.

0.0.10 — 2026-04-24

Fixed

  • Removed Connection: keep-alive header from SSE responses. The header is forbidden in HTTP/2 (RFC 9113 §8.2.2) and caused browsers and curl to reject the entire response body over HTTP/2 connections. It was also redundant in HTTP/1.1, where keep-alive is already the default.

0.0.9 — 2026-04-16

Fixed

  • README copy fixes. The install snippet now references ~> 0.0.9 (was stuck on ~> 0.0.7 in the v0.0.8 release). Removed two stale mentions of "CSRF headers" in the URL-generation feature list and the Quick Start — verb helpers stopped injecting CSRF headers in 0.0.8 when CSRF moved to the Phoenix meta tag. Removed a stray T after the License section.

0.0.8 — 2026-04-16

Consolidates the unreleased 0.0.7 work (CSRF rewrite, expanded usage rules) with Datastar v1.0 compatibility fixes. Users on 0.0.6 upgrading to 0.0.8 should read the Changed section — CSRF handling has been rewritten.

Changed

  • CSRF is no longer transported through a Datastar signal. Verb helpers (Dstar.post/2,3, get, put, patch, delete) no longer inject an {headers: {'x-csrf-token': $_csrfToken}} options object into generated expressions. Datastar reads the token from Phoenix's standard <meta name="csrf-token"> tag and sends it as an x-csrf-token header automatically. This decouples CSRF from Datastar's signal round-tripping and shortens every generated expression.

    Migration from 0.0.6: remove any data-signals:_csrf-token / $_csrfToken signal from your root layout. Keep the standard Phoenix <meta name="csrf-token" content={get_csrf_token()}> tag in <head>. If you use Datastar-driven form POSTs that go through Plug.CSRFProtection, expose the token as a non-prefixed csrf signal and keep Dstar.Plugs.RenameCsrfParam in your pipeline — that plug's role is now scoped to bridging form posts, not SSE.

  • Datastar version references bumped from 1.0.0-RC.8 to v1.0.0 in the README, doc/readme.md, and the datastar-attributes usage rule. v1.0's other changes (new data-bind __prop/__event modifiers, data-on __document modifier, morphing improvements, retryMaxWaitMsretryMaxWait rename, Rocket JS API rewrite) are all client-side and need no Dstar changes.

Fixed

  • Dstar.Signals.read/1 now reads signals from query params for DELETE requests. Datastar v1.0 stopped sending a body on DELETE requests (#1144), so signals from Dstar.delete/2,3 actions arrived empty under the previous code path. read/1 now treats GET and DELETE the same — both read from the datastar query param.

Added

  • New usage-rules reference files ship with the package: error-handling.md, heex-rendering.md, loading-states.md, and a full datastar-attributes.md cheat sheet. Consumers of the usage_rules package will pick these up automatically.

  • HTTP/2 SSE connection limit docs added to the README, covering why the browser 6-connection-per-origin cap on HTTP/1.1 matters for long-lived Datastar streams and how HTTP/2 multiplexing removes it.

0.0.6 — 2026-03-21

Added

  • Dstar.Utility.StreamRegistry — Opt-in per-tab SSE stream deduplication. Tracks one stream process per user+tab using Elixir's Registry. When a new stream opens from the same tab, the previous process is killed instantly — no waiting for keepalive timeouts or PubSub broadcasts. Fixes zombie processes that hold subscriptions, run wasted DB queries, and exhaust the browser's 6-connection-per-origin limit on HTTP/1.1. Add it to your supervision tree, set a tabId signal in your root layout, and replace Dstar.start/1 with Dstar.start_stream/2. Falls back to Dstar.start/1 when no tabId is present. See the README's "Stream Deduplication" section for full setup.

  • Dstar.start_stream/2 — Convenience delegate to Dstar.Utility.StreamRegistry.start_stream/2.

0.0.5 — 2026-03-18

Added

  • Dstar.SSE.check_connection/1 — Checks if an SSE connection is still open by sending an SSE comment line. Returns {:ok, conn} if the connection is active, {:error, conn} if closed or not yet started. Useful for detecting disconnections in streaming loops. Also available via Dstar.check_connection/1.

  • Dstar.Signals.remove_signals/3 — Removes signals from the client by setting them to nil. Accepts a single dot-notated path string (e.g. "user.profile.theme") or a list of paths (e.g. ["user.name", "user.email"]). Paths with shared prefixes are deep-merged correctly: ["user.a", "user.b"] becomes %{"user" => %{"a" => nil, "b" => nil}}. Validates paths and raises on empty strings, leading/trailing/consecutive dots. Also available via Dstar.remove_signals/3 and Dstar.Signals.format_remove/2 for string formatting.

  • :namespace option for Dstar.Elements.patch/3 and Dstar.Elements.format_patch/2 — Specify element namespace: :html (default), :svg, or :mathml. When set to :svg or :mathml, emits a namespace data line in the SSE event. Default :html omits the line (backward compatible).

Changed

0.0.4 — 2026-03-15

Added

  • HTTP verb helpersDstar.post/2,3, Dstar.get/2,3, Dstar.put/2,3, Dstar.patch/2,3, Dstar.delete/2,3 generate @verb(...) expressions for Datastar attributes. Same API across all verbs.

Deprecated

  • Dstar.event/2,3 — use Dstar.post/2,3 (or the appropriate verb) instead. Still works, will be removed in a future version.

0.0.3 — 2026-03-15

Added

  • UsageRules integration — ships usage-rules.md, streaming sub-rule, and a pre-built use-dstar skill with API patterns reference. Consumers using the usage_rules package can pull these in automatically.

Changed

  • README rewrite — new Quick Start walks through routes → controller → event handler → template, showing patch_signals, patch_elements, execute_script, and console_log in one cohesive counter example. Dispatch is now the primary routing pattern; plain controller routes shown as an alternative in "Without Dispatch" section.

0.0.2 — 2026-03-15

Added

  • Migration guide from PhoenixDatastar to Dstar (docs/migrating-from-phoenix-datastar.md)

0.0.1 — 2025-03-12

Initial release after the grug-brain simplification. The library was gutted from 1,742 lines / 15 files down to ~735 lines / 6 files. Everything that reimplemented LiveView was deleted.

What's in the box

  • Dstar.SSE — Open SSE connections (start/1), send events (send_event/4, send_event!/4), format events as strings (format_event/2).

  • Dstar.Signals — Read Datastar signals from requests (read/1). Patch signals on the client via SSE (patch/3). Format signal patches as strings (format_patch/2).

  • Dstar.Elements — Patch DOM elements via SSE (patch/3) with selector, mode, and view transition support. Remove elements (remove/3). Format patches as strings (format_patch/2).

  • Dstar.Actions — Generate @post(...) expressions for Datastar attributes (event/1,2). Encode/decode Elixir module names to/from URL-safe strings (encode_module/1, decode_module/1).

  • Dstar.Plugs.Dispatch — Optional dynamic dispatch plug. Routes POST /ds/:module/:event to handler modules from an allowlist.

  • Dstar — Thin convenience module that delegates to the above.

What was removed

The following modules were deleted because they reimplemented LiveView's process-per-session model, which contradicts Datastar's client-holds-state architecture:

  • Dstar.Server — GenServer per session (284 lines)
  • Dstar.Socket — LiveView-style socket struct with event queues (315 lines)
  • Dstar.Plugs.Page — Custom HTML page renderer (147 lines)
  • Dstar.Plugs.Stream — Token-verified SSE streaming endpoint (80 lines)
  • Dstar.Scripts — Script execution via DOM patching (106 lines)
  • Dstar.Registry — Process registry for GenServers (28 lines)
  • Dstar.Token — Plug.Crypto token signing (48 lines)
  • Dstar.Application — OTP application that started the registry (15 lines)
  • Dstar.Helpers.JS — JS string escaping helper (13 lines)
  • Dstar behaviour and __using__ macro — mount/handle_event/render callback system (rewritten to thin delegation module)

Design

  • No processes. No supervision tree. No OTP application callback.
  • No behaviours. No macros. No use Dstar.
  • Two dependencies: plug and jason.
  • Designed to sit on top of deadview Phoenix. Use your controllers, templates, and layouts. The library just formats and sends SSE events.