Skip to content

NEXUS v0.17.0

Choose a tag to compare

@github-actions github-actions released this 31 Oct 06:41
· 9 commits to main since this release
c9543ce

NEXUS v0.17 release notes

v0.17.0

Prepared 2026-10-31 (nothing tagged or published: v0.16.0 is the latest release).

v0.17.0 is a minor release that shortens the first app (Tier 1; north-star audits T1.1 and T1.2) and widens the schema types of Command and Event (Tier 1 for the widening, Tier 2 for validate). All changes are additive: omitted arguments, defaulted type parameters, an optional options argument and a new cause field.

  • Runtime.make() needs no layer. The layer defaults to Layer.empty, so an application with no services yet writes Runtime.make(). (T1.1)
  • Application.define({ name }) needs no runtime. The input may omit it. The stored ApplicationDefinition still has runtime (filled with Layer.empty), so code that reads app.definition.runtime is unchanged. (T1.2)
  • Transforming schemas for Command and Event. Command.define and Event.define accept Schema.Schema<A, I> (for example Schema.NumberFromString). Command and EventDef gain a defaulted last type parameter (Encoded = A), so existing references such as EventDef<Tag, P> compile unchanged. Command.invoke takes the encoded input and the handler receives the decoded value. State is unchanged. (Tier 1; audit I2 ◐→P, with Valance B3)
  • Event.subscribe(def, { validate: true }) (Tier 2; audit I2). Opt-in: each payload is checked against the schema's decoded side (the bus carries decoded values; publish takes the decoded payload and never decodes), and a failing payload ends the stream with a ParseError. The default is unchanged.
  • CommandValidationError.cause. The structured ParseError now sits beside issues, which is unchanged.
  • examples/hello: the smallest runnable app, with no Service, Layer or Resource. The README's first app drops its Layer.empty argument.
  • Docs: the shutdown statements in ARCHITECTURE.md, primitives/capability.md and primitives/runtime.md that said termination does not wait for effects started with run or runFork are corrected: it waits up to the grace, then interrupts them (as since v0.12).

MESH 0.18: the occurrence rename and the context channel

Lands together with MESH 0.18.0 (prepared, not yet published) and Valance Task 19. The peer range gains ^0.18.0; 0.14 to 0.17 stay in it.

  • Occurrence, not instance (Tier 2; refinements C-4, Valance K30). MESH 0.18 names one occurrence of a component with a unit occurrence (Render.occurrences, intent.occurrence) where 0.15 to 0.17 said instance. Mesh.UnitOccurrence and Mesh.CommandIntent gain an optional occurrence (MESH 0.15 to 0.17 do not give it: read occurrence ?? instance to support both); their instance stays, marked @deprecated, because it is the only name an older MESH gives and MESH 0.18 keeps it as a non-enumerable alias for one release. Mesh.raise's second parameter is named occurrence (a positional rename: no call changes). The adapter passes both through and renames nothing itself. A host that matched the diagnostic runtime-unknown-instance must match runtime-unknown-occurrence (MESH retired the old code).
  • The context channel (Tier 2; refinements C-1, Valance K27). A value many distant components need (a theme, a locale, the current user), declared once in the manifest's context and read only by a component that lists it in uses. The host holds the values and the adapter hands them to the runtime beside the snapshot, as it does units: Mesh.render(program, snapshot, units?, context?), Mesh.update(previous, snapshot, units?, context?) (without context, MESH keeps the previous render's) and Mesh.host({ ..., context }), an Effect read each time the host renders. Like units, a change of context alone does not render: the host renders when its scope commits. New type Mesh.ContextValues. A program whose manifest has no context needs none of it, and an absent input is not passed, so an older MESH is called exactly as before.
  • Scorecard: M2 (one term per concept) ◐ → ◐: the unit sense of "instance" is gone from the adapter's names, other collisions remain. C1 (a value reaches a deep component without threading) Fail → Pass and C2 (the channel is explicit and checkable) not applicable → Pass, with MESH 0.18 (the adapter is the pass-through; the check is MESH's). No audit regresses.
  • Tests: tests/mesh-context.test.ts (render, update and host with context; a missing required value is MESH's diagnostic); tests/mesh-units.test.ts reads occurrences/occurrence and checks the deprecated alias passes through. The mesh-slice intent fixture is re-copied from MESH 0.18, whose intent carries argument names.

Behavior

  • Duplicate event tags are refused (audit I2). Each runtime registers an EventDef's tag at its first publish or subscribe; a second, distinct EventDef with the same tag dies with a Runtime.Refusal (code: "duplicate-event-tag", a new RefusalCode). This closes the documented _tag cross-delivery hazard, so a subscription only receives its own def's payloads. It refuses only programs that already had that hazard; one def used repeatedly, and distinct tags, are unchanged. In a long-lived runtime, an event re-created on hot reload (a re-evaluated module) is refused: define each EventDef once in a module that is not re-evaluated, or restart the runtime on reload. Lands together with Valance Task 25.

Compatibility

  • API and behavior: every existing call is unchanged, with one behavior change: a program that registers two distinct EventDefs under one tag is now refused (see "Behavior"). Beyond that, only omitted arguments, new defaulted type parameters (Encoded, and X on Mesh.bind), the optional subscribe options argument, the new CommandValidationError.cause field, and the optional context argument and option on Mesh.render, Mesh.update and Mesh.host are newly accepted. occurrence is added beside the deprecated instance on Mesh.UnitOccurrence and Mesh.CommandIntent.
  • MESH: needs MESH 0.18.0 for occurrence and context; the peer range still admits ^0.14.0 to ^0.17.0, where everything else works unchanged (without context, no context argument is passed).
  • RefusalCode gains a member. The Stable Runtime.RefusalCode union gains "duplicate-event-tag", so an exhaustive switch over it (one with a never default) stops compiling until it handles the new code.

Release steps

After MESH 0.18.0 is on npm: revert 538d8e2 (the local packs and pnpm-workspace.yaml overrides), run pnpm install, then pnpm typecheck, pnpm test and pnpm build, then tag v0.17.0.