Packages

octane

0.14.3 · 21 Oct 2026MIT19k / weekRepositorynpmAtom feed

105 stable releases, newest first, by release line. Notes are quoted as the maintainers published them.

  1. 1.x
  2. 1.0.3

    3 Jun 2015

    Reading the note…

  3. 1.0.2

    3 Jun 2015

    Reading the note…

  4. 1.0.1

    1 Jun 2015

    Reading the note…

  5. 1.0.0

    1 Jun 2015

    Reading the note…

  6. 0.14.x · latest line
  7. 0.14.3

    21 Oct 2026
    • 6e1ba80: Preserve suspended server-rendered content when a guarded native query remains unchanged during an unrelated parent update.

  8. 0.14.2

    21 Oct 2026
    • 87bf841: Reduce context dependency allocation for consumers reading one or two contexts while preserving memoized provider updates.

    • 9eede44: Resolve useFormStatus through portal source frontiers on the first render.

    • 1b42344: Preserve server-rendered input state when a pending query remains current across an unrelated hydration update.

  9. 0.14.1

    21 Oct 2026
    • 8766299: Preserve server-rendered DOM when hydrating component props containing conditional render blocks.

    • 3b1610d: Restore hydration handoff for complete fixed DOM binding views with pure setup locals.

    • b6f8ff4: Allow early DOM bindings for a complete fixed native view to hand ownership to hydration without requiring a structural binding program.

  10. 0.14.0

    20 Oct 2026
    • 175b85d: Render computes, commit writes, for compiled template bindings. An update now
      records changed text, attribute, class, style, event-handler and
      controlled-form values, and a commit function the compiler generates per
      template writes them at commit, before refs and effects. A transition or
      other render that is dropped never touches the DOM, and an event during a held
      transition calls the committed handler.

      As in React, an update coerces attribute and style values while it commits, so
      an error from a value's toString reaches the nearest error boundary as a
      commit-phase error instead of a render error. Mounts still write as they render.

    • 175b85d: A dormant <Hydrate> island whose captures or provided context values changed
      before it activated now hydrates first, as React hydrates a dehydrated boundary
      before the update that reached it, instead of rendering on the client. The
      newer values then apply as an update in a render of their own. This changes
      what an island observes when a parent update reaches it before activation:

      An update that reaches an island while its hydration attempt waits on data
      still leaves the server HTML in place until the attempt retries, an intentional
      difference from React that docs/differences-from-react.md records.

    • 175b85d: A descriptor list item (an array of createElement or .tsx children) now
      serializes without a comment range of its own whenever it renders exactly one
      host element and no component or portal inside it, as a compiled @for row with one
      element does. A host whose children are other elements or arrays no longer
      gets a range. Hydration decides the same from the item's value, so an item
      that arrives in a range it does not need, as from an older server, is a
      structural mismatch: the nearest Suspense or <Hydrate> boundary, or the root,
      renders on the client and reports one recoverable error.

  11. 0.13.x
  12. 0.13.8

    15 Oct 2026
    • 19033e4: A server render that reads a pending or failed query through snapshot() no
      longer throws "A completed native server read has no serializable ready value"
      once the server has loaded a module that reads signals. The snapshot renders
      the state as it is and adds nothing to the hydration snapshot, rather than an
      invented ready value: the client resolves that state itself, or takes the
      result a stream delivers, as it does when no module reads signals. A completed
      get() of a value that is not ready still throws.

    • a9dfdf7: Remove a Provider's previous children when they become null or undefined, for both a .tsx <Context value> and CompiledContext. They used to stay mounted, with their effects and state, until the Provider rendered children again.

    • c6cb71a: renderToString(<App />) and the other server entry points render a component
      element as its component's root, so hydrateRoot with either entry form adopts
      it.

  13. 0.13.7

    15 Oct 2026
    • 781fd29: Support the website document shell, links, route-bound hooks, and head assets through the compiled Router entry. Add matching compiled Start client/server entries and a compiled build-plugin option that coordinates route generation and lazy imports while preserving ordinary Router/Start behavior.

      Make editor/type tooling recognize dynamic style content props as ordinary host elements, matching runtime compilation and preserving scoped CSS blocks.

    • ea438fb: Avoid rerendering memoized context consumers when only a sibling provider changes. Retain updates for real nearest-provider value changes and conservative invalidation for hosted, replayed, and externally invalidated contexts.

    • 2623e7a: Preserve table sections, rows, and cells when mounting multi-root template children through a component.

  14. 0.13.6

    14 Oct 2026
    • 55376d8: Support checked compiled-only dynamic component and context boundaries on the client and server. Streamed document signal bootstrap validates already-parsed signal manifests directly.

      Add an opt-in @octanejs/tanstack-router/compiled entry for compiled route trees, pending and error handling, lazy imports, and matching router hooks. The existing descriptor-capable router entry remains compatible.

    • d8e2d9f: Add modulePackage(code, id) to the bundler compiler. It returns the package that owns a module and whether transform compiles the module or slots its hooks. octane analyze --strong-dependencies uses it.

    • 1f4ccb8: Strong mode now rejects element descriptor APIs with OCTANE_STRONG_ELEMENT_API: importing or reaching createElement, cloneElement, isValidElement, Children, or descriptorChildren from octane, or jsx, jsxs, jsxDEV, or Fragment from an Octane JSX runtime entry. Descriptors render through the generic descriptor renderer instead of compiled templates. Write template JSX, pass the component itself (icon={Plus}), or pass a () => @{ … } render function. Type-only imports stay valid.

      Strong .tsrx modules also reject a single-item @for, such as @for (const item of [value]; key item), with OCTANE_STRONG_SINGLE_ITEM_FOR. A const holding a one-item literal that nothing but @for headers reads is rejected too. To remount a subtree when a value changes, wrap it in <Fragment key={value}>…</Fragment> or key its only element or component. To render one value, render it directly.

  15. 0.13.5

    14 Oct 2026
    • 7d003a4: Retain eligible Strong object and array values created in setup when they are passed to props inside another component's children. Unrelated updates no longer restart subscriptions to those values. Inline child expressions still evaluate only when the child renders.

  16. 0.13.4

    14 Oct 2026
    • 87f9fec: Keep eligible Strong ref arrays stable within entered conditional and keyed render scopes, so unrelated updates do not restart ref observers. Changed refs and removed branches still clean up normally.

  17. 0.13.3

    13 Oct 2026
    • 1c7f7cb: Ship less signal code to the browser. Client bundles that read signals no longer
      carry the server's seed serialization, which only the server's native read
      collector installs: about 2.1 kB raw and 0.5 kB gzip. Behavior is unchanged.

    • e75d7a8: Hydrating applications without a <Hydrate> island no longer ship the island-only parts of hydration: resuming an activation that suspended, settling the island's trailing server content, and keeping the server nodes an island attempt changed. About 0.4 kB of minified runtime leaves bundles that call hydrateRoot without islands. Behavior is unchanged.

    • cfdb2ca: Compiled component bodies in modules that import octane/signals no longer wrap every render in a native-read bracket. The renderer already collects each body's reads, including reads made through helper calls, so the bracket only rejoined that collection. Signal-enabled modules compile smaller and hydrate slightly faster; their behavior is unchanged.

  18. 0.13.2

    13 Oct 2026
    • dcb376a: Fix a Suspense boundary that could stay on its fallback forever when a component reads a fresh promise on every render, such as use(props.source.promise) through a getter. When the compiler batches such a call, the resumed render now keeps the promise the first render suspended on, as an unbatched use() call already did, instead of suspending again on each new promise.

    • ffd1f91: Fix production memo regions and cached @for lists leaving a context consumer stale when it renders through a tag bound in the component body, such as const C = props.comp; <C /> or { comp: C }, or when a component returns an element it received, such as if (props.on) return props.content. That component now records its context reads, and a cached list refreshes rows that render such a tag or a value hole like {item.content}.

    • 1d43f07: Fix a production memo region skipping a context update below a pure callee that renders a prop value as a child, such as {props.content} holding an element whose component reads context. The region now refreshes that consumer when the context changes.

  19. 0.13.1

    11 Oct 2026
    • 7d6f6c0: Let applications that deliver streamed signal frames directly omit unused receiver-attachment code from their bundles.

    • efe12e3: Vendor the Alien Signals dependency graph and move internal signal feature helpers out of classes so unused feature code can be removed from application bundles.

    • 4bc1eaa: Stop server-rendered <ViewTransition> from wrapping .tsx element children in an extra hydration range, which made every such boundary mismatch on hydration and regenerate on the client.

  20. 0.13.0

    11 Oct 2026
    • 974a3a6: Complete the profiling counter core with bounded accepted-commit history, delayed effect attribution, per-component counters, and counters for lists, effects, refs, boundaries, Activity, scheduler work, and discarded renders. Profiling-disabled builds erase the probes; counter snapshots now use schema 2.

    • b27d8db: Add opt-in TypeScript output for the web (DOM client and SSR) and the experimental Valdi compiler target, preserving authored declarations, component API types, declaration comments, and source maps for downstream typed build pipelines.

    • bdc21d8: Add opt-in TypeScript build handoff for web and Valdi. Preserve typed compiler output and maps for automatic custom-hook modules, and let Vite's native TypeScript transform compose maps through client and SSR builds. Document and verify real Valdi Workspace emission with separately composed authored source maps.

  21. 0.12.x
  22. 0.12.1

    9 Oct 2026
    • 114e3b8: Fix compile() output for .ts, .mts, and .cts modules, including Valdi
      custom hooks. The native parser returned these files without their type
      information, so import type, inline type specifiers, export type { … }, and
      export type * were emitted as value imports and exports that fail to link.
      Parameter properties also lost their this.x = x assignment, and declare
      fields became real fields. These modules are now parsed with TypeScript's own
      grammar, which keeps all of that, and <T>value type assertions still parse.

      Type erasure also covers two cases that broke .tsx and .tsrx output: type
      arguments on a superclass (extends Base<T>), and re-exports of a name that is
      only a type (import type { T } then export { T }). Both previously left
      invalid JavaScript.

    • 7af43dc: Ship less runtime to Vite applications that do not use optional capabilities
      such as ViewTransition, Activity, form actions, or native signal reads. Vite's
      default production minifier can now drop the code behind each capability an
      application never installs. The js-framework rows app ships 2.6 kB less gzip,
      and TodoMVC 3.0 kB less. Behavior is unchanged.

    • 4f82777: Fix a keyed list row that kept showing its old props after a suspended root
      update resolved. The production build's output cache for the row recorded the
      update's props while the update was held, and the rollback restored the screen
      but not the cache, so the retry skipped the row.

  23. 0.12.0

    9 Oct 2026
    • 7d5a0df: Complete the writer compiler's optional host-text mode and add an opt-in host-ref capability.
      Existing adapters keep ABI 1; opted-in modules guard ABI 2 before creating prototypes.

    • 28552d9: Keep signals writable after an empty list fills with 16 or more rows.

      With native signal reads enabled, a production build mounts host-only rows into
      an existing empty @for list without the ordinary row renderer once there are
      at least 16 rows. Each row that read signals natively left its read frame open,
      so the signal write guard stayed active after the render returned and the next
      unrelated write threw SignalWriteError (#152). Each row now opens and closes
      that frame as the ordinary renderer does, including when a row throws or
      suspends, and rows holding a signal handle keep updating.

    • f934732: hostComponent now creates its element in the namespace of the node it is inserted into, as descriptor and dynamic host tags already do. A motion.circle inside an <svg>, or a motion.svg in HTML, now renders as an SVG element instead of an unknown HTML element.

  24. 0.11.x
  25. 0.11.0

    8 Oct 2026
    • 37a1c14: Ship less signal engine code to applications that use signal$, derived$,
      query$ or useSignal$ without calling createScope. Owner scopes the runtime
      creates for those declarations get the public Scope methods (serialize,
      inspect, derived$, get, set, isPending, batch and action) only once
      the program can hold one: createScope, currentSignalOwner and
      installSignalOwnerEnvironment from octane/signals install them first. Only a
      debug scope records a trace.

      SignalOwnerEnvironment now carries owners as SignalOwnerIdentity values. A
      host carrier, including one installed through octane/server, can store and
      return the owners it receives but can no longer narrow them to Scope and call
      its methods. Carriers that store owners as SignalOwner compile unchanged.

      Signal applications are 0.49 to 0.65 kB smaller gzipped. Applications without
      signals are unchanged.

    • 0ce371a: Count engine work in profile builds.

      Profile builds now keep session totals of the work around component renders:
      render attempts and their outcomes, bailouts, Blocks created and torn down,
      @if/@switch arms kept or replaced, Suspense fallbacks and error catches,
      render-queue passes, root commits, and work discarded by rollbacks. Read them
      with profiler.counters(), or take profiler.snapshot() before and after an
      interaction and pass both to profiler.diff(). Snapshots carry a schema
      version, build, renderer set, and recording generation; diff() rejects pairs
      it cannot compare. A counter the installed renderer does not record is absent
      rather than zero.

      Builds without profile contain none of this code once optimized; unminified
      development output keeps the disabled branches as dead code.

    • 8444db8: Support recursive 'use dom bindings' views. A view can now render itself, or another view in the same module that renders it back, including beneath a keyed @for, so a tree's depth comes from its data:

      export function Tree({ node }: { node: Branch }) @{
          'use dom bindings';
          <section>
              <span>{node.label as string}</span>
              @for (const child of node.children; key child.key) {
                  <Tree node={child} />
              }
          </section>
      }

      Server rendering and the extracted binding artifact both compile, where they previously failed with "recursive binding child programs are not supported". The artifact still loads only the binding runtime, not the renderer. Each level the data reaches is its own instance with its own text, keyed items, native handlers, mount-only effects and @try arms. Removing a branch retires the instances beneath it. Recursive calls use the generic program rather than specializing fixed primitive props, so depth={depth + 1} does not unroll at compile time.

      Recursion that could never end is a compile error. A view that renders itself on every path, for example with a recursive call outside any @if, @for or @try, fails with an error that names the cycle, such as binding view Tree renders itself on every path (Tree → Tree).

      A local child view used at several call sites with different prop names now shares one compiled descriptor, unless it spreads a rest parameter.

  26. 0.10.x
  27. 0.10.2

    7 Oct 2026
    • 62e6448: Fix Strong mode rejecting effect setup that reads or writes a ref's current
      or calls a state getter. Neither is an effect dependency: a ref holds a value
      the effect uses without re-running, and a getter reads the latest state without
      subscribing. Strong mode reported both as OCTANE_STRONG_EFFECT_HIDDEN_DEPENDENCY,
      so previous-value refs, ref counters, a Map of callback-ref elements, a
      useLazyRef store, and getCount() failed to compile in useEffect,
      useLayoutEffect, and useInsertionEffect setup. They now compile as they do
      in React. The diagnostic still reports a reassigned module variable read in
      effect setup, and render-time ref reads and writes and state getter calls stay
      errors.

  28. 0.10.0

    6 Oct 2026
    • removed

      32e4f3f: Remove the server range that hydration left behind when a stale node, such as one a browser extension inserted, stood before a component's range in an element. The client rebuilt the component but kept the server's copy too, so the component's content appeared twice.

    • 91079dd: Handle hydration mismatches the way React 19 does.

      Apps that only call createRoot no longer ship any hydration code. In production, setHTML's <script> normalization is no longer needed and is gone (#1785).

    • e233e4a: Stop shipping the signal binding runtime in apps that never pass signal
      handles through ordinary props.

      Since async signals landed, the compiler bound every opaque text, attribute,
      control, and textarea hole, such as {row.label as string}, as a potential
      signal handle in every module. Every app therefore carried the binding runtime
      and stamped signal identities on every component. Now such a hole binds a
      handle only in a module with an import from octane/signals; a type-only
      import type { SignalHandle } from 'octane/signals' is enough and does not
      enable native reads. Modules using DOM bindings keep binding handles, and
      $-named expressions such as {props.label$} still bind everywhere.

      This removes 1.7 to 3.3 kB gzip of runtime from the benchmark applications
      (rows 38,991 → 37,307 bytes, TodoMVC 44,217 → 41,076, chat 43,638 → 40,347).

      An untyped component that renders handles from a lazily loaded signals engine
      can either type its props or set the new opaqueSignalHandles compiler option
      (also accepted by octane() and @octanejs/vite-plugin) to keep the previous
      behavior. In development, a handle that reaches a plain text hole logs an
      error naming these fixes instead of silently rendering [object Object].

      Hydration through the ordinary writers now matches the signal-aware path it
      replaces for these holes: a sibling or whole-output {expr} hole whose first
      client value is undefined discards the server content it cannot adopt, and an
      attribute whose first client value is undefined removes the server attribute.

  29. 0.9.x
  30. 0.9.1

    4 Oct 2026
    • ff77a8a: Preserve early form submissions when an already-aborted behavior registration is followed by a live replacement.

    • f852068: collectDiagnostics no longer prepares and analyzes a module a second time when Strong accepts it. It continues compiling from the tree that Strong analysis already checked, so octane analyze costs about the same as compile() on Strong modules instead of up to 1.26 times as much. It reports the same diagnostics and errors as before.

    • 77504c1: Cancel a component's superseded query$ request when only a pending @try arm reads it.

      A query$ declared in a component and read with .get() inside that component's
      @try/@pending boundary kept its previous request live after the component
      committed a new selection. The arm's suspended attempt discarded the new
      declaration, so the old request's AbortSignal stayed un-aborted until the
      component unmounted. The component's commit now selects the new request and
      aborts or closes the obsolete one, for promise and stream queries alike. An
      asynchronous derived$ read the same way now adopts the committed computation
      for its next dependency-driven restart instead of keeping the previous render's
      closure.

  31. 0.9.0

    4 Oct 2026
    • c1a8faf: Load the idle(), visible() and media() triggers for independent Hydrate widgets only when a page has a widget that uses one. The independent island bootstrap used to import all three, so every islands page shipped them, even one whose widgets used only load() and interaction(). The signal-chat islands-only route now loads 612 fewer bytes of gzipped JavaScript. A widget with one of these triggers loads the strategies the first time the bootstrap registers it, then installs its trigger. A custom host can pass strategies: independentHydrationStrategies, from the new octane/hydration/independent-strategies entry, to bootstrapIndependentHydration or registerIndependentHydrationIsland to install triggers during registration instead.

    • 00f8304: Add useLayoutSnapshot to derive a renderable value from a committed DOM measurement, with an SSR initial value and configurable equality. LayoutSnapshotOptionsWithInitial types a reusable options object whose initial value keeps the snapshot defined, and Strong mode reports an async or generator measurement as OCTANE_STRONG_LAYOUT_SNAPSHOT_ASYNC.

    • dfff293: Add useLazyRef(factory), which initializes a mutable ref from a factory when its hook cell is created and keeps that ref on later renders. useRef(callback) still stores the callback without calling it. Strong mode checks the factory with the same rules as a lazy useState initializer: it may read a clock, randomness, or browser state, but may not schedule work. Strong mode now also checks hook initializers, reducers, and updaters passed through a literal array spread, such as useState(...[() => value]). On universal renderers, a ref escaped from an abandoned render now keeps the last value written to it, as a plain object would. It no longer reverts to its initial value, and it no longer reads or writes a different ref committed later in the same hook slot.

  32. 0.8.x
  33. 0.8.0

    3 Oct 2026
    • removed

      fbf6e40: Remove the server content left after a component's content during hydration. When the server rendered more in a component's range than the client renders there, the client adopted the matching prefix and kept the rest on screen without a report. This happened for a component whose identity differs on the client, for a hookless component in a renderable hole, and for a component that returns less on the client, including one rendered as a list item. Hydration now discards the stale remainder and reports it once through onRecoverableError, plus a located development warning. The nodes the client adopted keep their identity. To find where a multi-root template's roots end without parsing it in production, the compiler now passes the template's root count to template().

    • removed

      bc30a18: Remove the server markup left after a component's last call when that call adopted its server node in place. When the server rendered another component's markup in a component's range, and the client's content there is a sequence of calls without server ranges of their own, each call adopts its server node in place. Whatever the server rendered after the last call's nodes stayed on screen, and hydration reported nothing. Hydration now removes it and reports the mismatch once through onRecoverableError, while the nodes the calls adopted keep their identity. This covers single roots and fragments, in lite and full component slots, in development and production builds.

    • 53db436: 'use dom bindings' views can now drive whole islands without the renderer:

  34. 0.7.x
  35. 0.7.1

    30 Sep 2026
    • 9c324f6: A @{ … } component passed to Object.assign, as in
      return Object.assign(Button, { Item }) inside a factory function, compiles
      again. Since 0.7.0 the compiler treated every function passed to a call as one
      that code would call, and rewrote it to return JSX. Inside a module-level
      function, that rewrite rejected a directive such as @if in the component as
      being in a module-level callback. Object.assign only stores or returns the
      function, so the component keeps its template body, with its props, control
      flow, and captured variables, on the client and the server. The same holds for
      Object.defineProperty, Object.defineProperties, Object.freeze,
      Object.seal, Object.preventExtensions, and Object.setPrototypeOf. A
      directive in a function passed to a call that may call it, such as xs.map(Row),
      is still reported.

    • 73138de: Cancel injection producers when initial document seed validation fails during
      prerender() or prerenderToNodeStream(), preserving the original validation
      failure even if producer cleanup throws.

  36. 0.7.0

    30 Sep 2026
    • 4c1ca88: Keep the state of a hook declared after an early exit on the DOM renderer. A
      hook's state lasts as long as the component, @for row, or directive arm that
      calls it; an exit only skips the rest of one render. On the DOM renderer, the
      rest of a directive arm after return;, return null;, or continue;, and the
      rest of a component whose early return guards a single host element, ran in a
      scope of its own. So taking the exit reset every hook after it, while the
      universal renderer, value-returning components, custom hooks, and plain if
      blocks kept that state. The DOM compiler now keeps it too: only the arm's output
      is removed when the exit is taken. An effect after the exit is still cleaned up
      while renders skip it and runs again once one reaches it.

      A class declared in setup is also passed to the directive arms nested below it
      on the client, where reading it threw a ReferenceError.

    • 4d8a93b: End a directive arm early on universal renderers the same way as on the DOM. A
      continue; in an @for row that no inner loop owns, at any nesting depth, now
      ends that row. Before, it reached the arm's compiled function unchanged and the
      module failed to load with "Illegal continue statement".

      A break that targets the @for or @switch around an arm failed to load the
      same way. It is now the DOM compiler's compile error, with its location.

      Returning a value from an arm, such as if (loading) return <Spinner />;, used
      to render that value on universal renderers and is now the same compile error as
      on the DOM. An arm's output is its final node on every renderer, and a component
      can mix DOM and universal regions across a renderer boundary. If the rule
      differed by renderer, the same arm would compile on one side of a boundary and
      fail on the other. Render the alternative from an @if/@else arm instead.

    • 55c2c01: Run each queued useActionState dispatch with the action that was current when
      it was dispatched, matching React 19. Before, a rerender that supplied a new
      action while a submission waited in the queue made that submission run the
      replacement action. Payloads dispatched after the rerender still use the new
      action, and an action error still continues the queue.

  37. 0.6.x
  38. 0.6.3

    28 Sep 2026
    • df0a086: JSX returned by a direct call of a named function declaration now resolves its non-literal props and children where the value renders, the same as JSX returned by an arrow function or method. Previously such a call read context and other values during the call, and the server rendered the value to HTML immediately, so a server-rendered fragment root or .map() row could disagree with the client. Rendering the same function as a component (<Row />) is unchanged.

    • 962ed16: Direct calls to hot-reloadable exports now behave the same in development as in production. Calling an exported return-JSX function directly with a second argument, as in renderRow(item, index), no longer makes the next hot update throw TypeError: Cannot read properties of undefined (reading 'disposed'), and a null second argument no longer throws at the call. Direct calls also receive their this and every argument unchanged, where development previously passed exactly three arguments, dropping extras and padding missing ones with undefined.

    • 9441ccb: Node now loads a build that reads process.env.NODE_ENV once per module instead of at every development check. ESM imports get it through a new node export condition, and require() gets it through the CommonJS build. Unbundled server rendering is faster, and deleting the process global after import no longer turns framework errors into ReferenceError: process is not defined. Set NODE_ENV before the first Octane import in Node. Browser bundles are unchanged.

  39. 0.6.2

    28 Sep 2026
    • 010c88c: Reduce production bundle overhead for modules that only report errors without arguments, while preserving development messages and parameterized errors.

  40. 0.6.1

    28 Sep 2026
    • 9b6c3a4: Include imported theme styles in server output when $class or a class-map entry was captured at module scope or cached during an earlier render. Collect the theme and its dependencies when the class is rendered, preserving request-specific styles, dependency order, and CSP nonces.

    • 5f58b63: Production builds now report signal-engine, hydration, and DOM-binding errors as compact Minified Octane error #<code> messages instead of shipping their full English text. Development messages are unchanged.

    • 1e4f1ee: createElement now accepts null as its config under strictNullChecks, matching React's props?: P | null signature. A bare null config infers props from the element type alone, and a non-null config still enforces required props. Fragment's props are exported as FragmentProps (as in React), so declarations emitted for createElement(Fragment, null) reference that type instead of inlining it.

  41. 0.6.0

    25 Sep 2026
    • 4b235d2: Add opt-in parser-time capture of native SSR form submissions. Forms naming a behavior owner can accept button, implicit Enter, and requestSubmit commands before client registration, preserving immutable accepted fields and submitter metadata for exactly-once behavior delivery. Behavior roots consume these commands with the optional captureFormSubmissions factory, keeping form routing out of ordinary behavior bundles. Unclaimed commands have a bounded lease, and forms without opt-in preserve native behavior.

    • 6e86908: Report unsupported JSX spread children in client and server compilation and in editor diagnostics. Assigned style blocks now keep all selectors, including element and descendant rules that apply to elements carrying a class entry from the block.

    • b9b0bc4: Support @{ … } blocks at JSX child position on universal renderers. Setup-bearing blocks now compile to a new universalBlock descriptor that materializes inside a persistent child scope at the block's sibling position, matching the DOM childSlot lowering: hook state survives parent re-renders and effect cleanup runs when the scope is discarded. Empty blocks are dropped and render-only blocks merge into the parent template, and the explicit {() => @{ … }} scoped-child spelling lowers to the same form. @{ … } inside @if/@for/@switch/@try bodies — previously emitted as a raw statement that failed printing — compiles through the same path.

  42. 0.5.x
  43. 0.5.0

    24 Sep 2026
    • 752d750: Allow custom SSR hosts to share an immutable initial document signal seed with root, deferred, independent and streamed hydration. Matching native historical reads use versioned manifest references, while differing histories retain their own entries and live writes remain authoritative after adoption commits.

    • 3390f40: Build newly visible fragment content inside an empty server hydration range without adopting its closing marker, preserving surrounding server nodes and mismatch diagnostics. Preserve immutable component framing across split Hydrate captures, retain separate server frames for mutable or shadowed component bindings, and build replacement component bodies as client DOM. Keep reassigned component declarations writable and decline callsite assumptions about their original bodies.

    • d285bd7: Diagnose actual eager imported signal .get() reads when activating compiled DOM
      bindings instead of silently presenting an unsubscribed snapshot. Pass a signal
      handle directly for a live binding, or provide a deliberate sample through the
      BindingSource snapshot. Props-based sampling, pure foreign .get() methods and
      already subscribed native attribute projections keep their existing behavior;
      ordinary SSR reads are unchanged.

  44. 0.4.x
  45. 0.4.3

    23 Sep 2026
    • d9ed0f4: Load compiled .ts and .tsx modules with Bun's TypeScript loader in
      octane/compiler/register.

      Compiled output for a .ts or .tsx source keeps the TypeScript constructs that
      have runtime semantics, such as enum. Vite's TypeScript transform consumes the
      same output. The Bun preload used to hand this output to Bun as plain
      JavaScript, so a component module that declared an enum failed with a syntax
      error. It now keeps the source file's loader. Compiled .tsrx output is still
      loaded as JavaScript.

    • 3fbe5b5: Specialize the common app-entry root shapes in production builds, not only
      createRoot(target).render(App) in a plain .ts module.

      A root whose whole lifetime renders compiled @{} components skips the
      returned-value reconciler and its bundle graph. That proof now covers:

      A one-component Vite entry that renders <App /> drops from about 70 KB to
      28 KB gzip, and a direct hydrateRoot entry from about 88 KB to 50 KB. On a
      proven root, <App a={x} /> with literal, function, or identifier attribute
      values is passed to the root as App plus its props, with live defaultProps
      applied as before. Keys, children, spreads, and other attribute expressions
      keep the element path.

    • ae7f970: Close four compiler soundness gaps in inferred proofs and generated code.

  46. 0.4.2

    22 Sep 2026
    • 4b0eac4: Compare deferred hydration attributes with historical native signal values in development diagnostics. Keep local signal comparison state disposable and isolated from live subscriptions, writes, refs, and effects.

  47. 0.4.1

    22 Sep 2026
    • 36d5f5e: Initialize dynamic iframe sources before connecting the frame to the document, avoiding a transient sandbox warning for foreign URLs while preserving source updates.

    • 3da41d5: Accept supported native lowercase HTML attribute names in development host-property diagnostics while preserving guidance for casing mistakes, framework-only props, and SVG attributes.

    • 4ac71d2: Keep roots added by initially empty sibling slots inside conditional and switch arms so replacing an arm removes all of its content.

  48. 0.4.0

    21 Sep 2026
    • 34e83ce: Recognize an octane.source manifest marker on linked and workspace packages. A package outside node_modules that receives Octane transitively from a shared toolkit can now declare "octane": { "source": true } instead of re-adding an octane version range it does not own, purely as a compiler marker. Installed packages under node_modules still require a declared octane dependency, and ownership stays explicit per package.

    • 3a859dd: Specialize DOM binding child programs for explicitly fixed primitive props so unused presentation branches do not ship. Caller propagation is opt-in through domBindingFixedProps; default child requests remain generic and shared. Dynamic values, literal defaults, DOM adoption, and renderer hydration handoff retain their existing behavior.

      Expose the fixed-prop binding benchmark in the MCP benchmark tool alongside the unified runner.

    • 620769b: Admit keyed @for item bodies whose only nested structure is host-only
      conditional content to the forBlock PURE fast path: an @if arm that renders
      only host output (including a narrowly proven nested keyed @for) carries
      nothing opaque, so with no parent captures the body is a pure function of the
      item and unchanged-identity survivors skip re-render entirely. The admission
      fails closed — a component tag inside the conditional, one hidden behind a
      function boundary such as a memoizable call's t => <Tag /> callback argument,
      a render-time hazard like an assignment in the @if test, or a live imported
      member read keeps the body off the pure path.

  49. 0.3.x
  50. 0.3.6

    21 Sep 2026
    • 28f31c3: Thread deferred native acceptance through suspense resume and hidden-reveal publication.

      commitResumeInner and attemptHiddenRevealInner discarded the result of acceptNativeCapture, so a capture whose acceptance the deferred-layout driver had staged still reached spliceOffscreenCapture with deferredNativeAcceptance === false. That splices an unaccepted capture and throws "A native capture must be accepted before publication." out of a suspense-retry or reveal commit, abandoning every effect, ref attach, and store sync queued on that commit. Both sites now pass the flag the way flushRootTransactions already did.

    • be361b4: Preserve the full resolution when the Vite plugin rewrites a client runtime
      request to its server counterpart during an SSR build.

      The hook returned only resolved.id, so external: true was dropped and
      rolldown tried to bundle an external specifier such as octane/signals/server
      as a path relative to the importer, failing the build with
      UNLOADABLE_DEPENDENCY. Returning the resolution keeps external along with
      moduleSideEffects and meta.

  51. 0.3.5

    21 Sep 2026
    • 8b95363: Reuse buffered streamed-result frame sizes when partially draining the browser mailbox, avoiding repeated serialization and UTF-8 encoding while preserving its byte limit.

  52. 0.3.4

    20 Sep 2026
    • 87f19a8: Clear a component's previous returned subtree when its next output is undefined, including optional ViewTransition children and lazy body handoffs, while preserving compiled imperative output.

    • e855d68: Fix focused DOM moves between parents in browsers without native moveBefore, including staged commits. Cross-parent insertions no longer enter the sibling-rotation fallback or incorrectly skip appending a node, while same-parent reorders retain editing continuity.

    • 2a952b8: Keep deferred hydration dormant when an unchanged native signal refresh rechecks a false condition. Preserve native subscriptions and early activation for parent capture or provider-context updates.

  53. 0.3.3

    20 Sep 2026
    • 138ec3c: Compare deferred hydration attribute diagnostics with the initial client captures while activating children with the latest values. Mounted parent updates no longer produce false development attribute mismatches, and genuine initial mismatches remain visible even when corrected before activation.

  54. 0.3.2

    20 Sep 2026
    • ec57015: Keep scalar binding caches coherent when hydration retains an early DOM binding's publication, so the next normal render can restore historical props after the early binding is released.

    • 167ee71: Adopt eventless restored textarea values into writable signals during initial binding, hydration, and accepted early-control takeover while preserving newer model and native-edit precedence.

    • 751d0de: Preserve native Undo/Redo grouping for controlled textarea edits by updating their existing baseline text node. Keep native form reset consistent with the current value for writable signals as well as ordinary controlled textareas.

  55. 0.3.1

    20 Sep 2026
    • c49ccb6: Skip dispatch and transaction snapshots for unchanged compiled native callback data while preserving ownership refresh, staged publication, and rollback for changed callbacks and captures.

    • eda8994: Production DOM compilation uses a smaller deferred hydration body for compiler-generated template children with no authored fallback. Boundaries with split={false} can omit generic returned-output and fallback rendering while retaining SSR adoption, interaction replay, suspension and cleanup. Descriptor children, spreads, explicit fallbacks, split loaders and development/HMR builds retain the general Hydrate path.

    • a44c082: Preserve matching server-rendered list ranges when hydration resumes a pending lazy child. First-fill adoption now starts inside the list's retained range, and only first-fill adoption discards extra server items. Genuine list mismatches still report recoverable errors and remove the extra items.

  56. 0.3.0

    19 Sep 2026
    • a6d7f49: Remove the legacy Context.Provider alias from client, server, and native contexts. Provide values with <Context value={value}> or createElement(Context, { value }, children) instead. The compiler rejects statically recognized legacy Provider access with migration guidance, and Octane bindings now use contexts directly. Binding peer ranges accept Octane 0.3 alongside their previously supported runtime lines.

    • debd7df: Specialize nonescaping function-local const roots in production JavaScript and TypeScript entries when every render uses an imported compiled void component. Keep writable component exports on the generic rendering path so authored replacements can return ordinary renderable values.

    • 873f4d2: Move native signal transition coordination behind the signals model capability so ordinary client applications no longer retain its preparation, retry, and publication policy. Preserve signals imported after an async Action awaits and atomic updates to consumers that receive signal handles through props.

      The model entry now retains this coordinator, increasing standalone signals and signal-using SSR bundle sizes.

  57. 0.2.x
  58. 0.2.16

    18 Sep 2026
    • 2049fa7: Keep native-only DOM presentation initialization separate from control and grouped-projection capabilities, so initializer-only compiled views do not retain unrelated host-operation helpers. Preserve initialization order, early edits, and older mount/adoption capability overrides.

    • 80d5fb6: Preserve scoped CSS selectors in split Hydrate children when production builds compile mutable parser ASTs. Deferred and independent activation now inject the same scoped stylesheet that matches the server DOM.

    • 3814f71: Preserve control-flow guards when inferring hook dependencies. Property reads behind a condition, an early return, or exception handling inspect own data values without invoking getters during render. Accessors and inherited properties track their receiver, while stable own fields and callbacks retain precise dependencies across fresh props and store snapshots. Optional receivers and guarded getters therefore retain their authored behavior.

  59. 0.2.15

    18 Sep 2026
    • 42a07b4: Preserve accepted scalar DOM-binding updates when hydrating older server-rendered state.

      Compile scalar text leaves and mixed structural/scalar projections independently, retain the current bound text, attributes, classes, and style properties during hydration, and release their ownership when the binding is disposed or aborted. Unrelated DOM mutations still receive normal hydration diagnostics and repair.

  60. 0.2.14

    18 Sep 2026
    • 44bd89f: Allow a compiler-proven native host to transfer its class and known-provider style bindings to normal hydration while its opaque children retain their own rendering and control ownership. Keep the early layout active during suspension or refusal, preserve the current presentation during accepted transfer, and validate the host and its source before publishing the successor.

      Keep the early scalar adapter's handoff symbol in the existing control registry so accessing the capability does not make cold renderer and event-lease helpers an eager dependency.

      Retry skipped native effects through the existing native-read scheduler when their surviving render has already completed, without weakening stale-publication checks or reviving disposed owners. Preserve suspended-island ownership and held-transition priority.

      Traverse lightweight DOM-context ancestors without treating them as hook-bearing blocks when locating a preserved hydration owner, so native effect retries remain safe while another island is suspended.

    • de270e3: Support explicit handoff of a standalone textarea signal value alongside an adopted native presentation. Hydration preserves live input and selection, transfers control ownership only at accepted publication, and keeps early bindings active when takeover is declined or suspended. Known-provider unbound style spreads retain direct compiled property bindings.

      Keep early ownership intact when preparing a successor subscription fails, and avoid masking interrupted mounts with a secondary ref-cleanup error.

      Release all prepared value successors when a later control invalidates presentation publication, preserving the original error and preventing stale input or model writers from being reclaimed by that root.

      Reject competing presentation bindings for fields supplied by an unbound known-provider spread, including class/className aliases.

      Type-check explicit scalar text intent against a signal handle's value in DOM templates, preserving direct bindings without application-side reads or unsafe casts.

      Transfer direct scalar text signals through presentation hydration using the existing prepared binding lifecycle, including initially empty text ranges and live updates after acceptance.

    • 44bd89f: Mark streamed signal selection and result scripts as renderer-owned transport so hydration can adopt the server HTML without reporting leftover protocol scripts as mismatched component output.

  61. 0.2.13

    16 Sep 2026
    • 5ead1ff: Allow adoptBindings(element, View, source) to resolve an eligible composite view that returns another view through exact adjacent compiler-owned wrappers. Preserve native node identity and existing binding lifetimes while rejecting ambiguous, mismatched, or sibling-containing ranges.

    • 5ead1ff: Add owner-bound signal declarations, async derivations and keyed streams, direct native signal bindings, and independent hydration infrastructure. Add request-local server-call context, bounded streamed RPC, and explicitly batched independent reads. Preserve operation identity and cancellation boundaries across navigation and uncertain acknowledgements.

      Allow a later widget activation to retry a failed framework-loaded stylesheet without discarding queued interactions or revealing the widget before CSS loads.

      Support renderer-free global signal and streamed-state activation for hosts that retain server-owned HTML. Adopt initial document seeds before behavior reads, preserve early edits, bind native control properties without reconciliation, and let envelope owners emit the early capture script before interactive markup without duplicating it in rendered fragments.

      Catalog the new core runtime diagnostics while preserving their error classes, and verify the published streaming bootstrap subpath and inline script export.

      Keep individual and batched server calls on the page's origin when an authored base element points to another origin.

      Keep reusable DOM, CSS, and component prop types scalar while allowing direct signal bindings at native JSX sites, preserving existing binding consumers. Use scalar public props for Zag's state-machine normalization results and to-print's imperative iframe options.

    • 5ead1ff: Specialize renderer-free child bindings to explicit caller prop shapes, allowing a proven destructured rest parameter to forward supported native properties. Preserve ordered shape identity through imported binding requests and share normal SSR annotation allocation without restricting the ordinary component API. Unknown spreads and unsupported native ownership conflicts still fail clearly.

      Allow proven conditional, child-view, slot, and primitive-text regions to transfer from early bindings to normal hydration without replacing their native nodes. Keep early interactions active through suspended or discarded attempts, validate the current presentation before publication, and retain explicit refusal for unsupported regions and writers.

  62. 0.2.12

    16 Sep 2026
    • ede01de: Accept native signal handles in DOM styles, including individual CSS properties and whole style values. Direct template styles update without rerunning component setup, and preserve signal cleanup, Suspense, server rendering, and hydration. Export SignalCSSProperties for signal-aware style objects while keeping CSSProperties compatible with ordinary CSS consumers.

      Keep binding CSS compatibility aliases pointed at plain CSSProperties when their layout helpers consume ordinary CSS values.

      Expose the signal style regression benchmark through the MCP benchmark tool.

    • 248af4e: Avoid redundant hydration lookups when updating existing conditional and switch branches.

    • cece195: Reuse unchanged populated SSR replay snapshots and pending streaming settlement recorders across retry waves. Preserve metadata rollback, promise identity, cancellation, and request cleanup. Add the SSR replay and streaming benchmark suite to repository automation.

  63. 0.2.11

    14 Sep 2026
    • fdb790a: Keep nested scoped JSX responsive to context changes, isolate hooks and memo caches across independently compiled render bodies, and invalidate stale output when lazy bodies change. Preserve component ownership across mixed compilation modes. Expose the production body-ownership benchmark through MCP.

    • 1bc1926: Resolve the renderer-region owner with a single lookup at the top of the block chain instead of a WeakMap read per ancestor on every provider-less context read, preserving context defaults and foreign-renderer routing.

    • 2789eab: Read descriptor list keys directly during reconciliation without creating a key callback for each list render, while preserving keyed identity and hydration behavior.

      Keep mapped component slots compatible when rendering switches between native array mapping and a custom map implementation, preserving hydrated inputs and component identity.

  64. 0.2.10

    11 Sep 2026
    • b7a2c47: Optimize inline style objects with repeated property names using targeted property updates. Preserve every authored value evaluation, the final value of each key, and its original insertion order across client rendering, SSR, and hydration.