First stable release. The API surface is frozen under semantic versioning:
breaking changes now require a major version and will ship with migration
notes. Functionally identical to 0.23.0 — sealed value routes, the
stack-as-state KaiselRouter with guards, typed results, modal flows,
onTransition, and the URL codec layer.
KaiselRouter.onTransition— an optional callback invoked with the old and new stacks (as route values) after every committed change: push, pop,replaceTop,set, and Navigator-driven removals (system back). It does not fire for no-op or guard-vetoed navigations. Because the stacks are values, a master-detail detail swap is directly detectable (from.length == to.length && from.last != to.last) — including at wide widths, where no Navigator route event exists for observers to see. Also available onKaiselRouter.fromStack.
KaiselRoute.restorationId— a stable id (defaults torouteNamefor parameterless routes,nullfor routes withprops) set as each page'srestorationId, so the page's inner widget state (scroll, text fields viaRestorationMixin) survives process death. Override with a param-aware id (e.g.'product-$id') to opt parameterized routes in.
pop/popUntiladd a browser-history entry again, reversing the0.20.0change (#27). Popping now pushes a new history entry like a normalNavigatorpop instead of overwriting the entry it returns to, so the browser's forward button behaves as expected. History-aligned back navigation that mirrors the app stack moved to the opt-incontext.back()/context.historyGo()inkaisel.replaceTop/set(#25) and nested replaces (#28) still report a replace.
KaiselRouter.replacesHistoryEntry— whether the most recent committed stack change should overwrite the browser history entry (replaceTop/set/pop) rather than add one (push). The Flutter layer's route-information provider reads it to report a replace instead of a new entry. (#25)KaiselNavigator.replacesHistoryEntryandKaiselNestedHandle.replacesHistoryEntry— the same hint on the non-generic router view and on a nested handle, so a shell container can read its active branch's disposition and the host can report a nested replace as a replace.KaiselNestedHandledefaults it tofalse. (#28)KaiselRootSnapshot.replacesHistory— the inspector snapshot now carries the last committed change's history disposition (truewhen it overwrote the entry rather than added one), so DevTools can show whether a navigation was a push or a replace. Defaults tofalse.
pop/popUntilnow mark the change as a history replace. Popping back to a screen overwrites the entry it returns to instead of adding one, so the browser's forward button no longer resurfaces the popped screen. (#27)
KaiselBranchSnapshot.built— the inspector snapshot now reports whether a shell branch is materialised, so a lazy shell can show which branches are built and which are still dormant. An unbuilt branch carries an empty stack.
pushForResult<T>— typed results from a main-stack screen. Push a route onto the router's own stack and await a typed value:final r = await router.pushForResult<T>(route). The screen returns the value by popping with one (pop(result)); the future resolves when the pushed entry leaves the stack — with the popped value, ornullif it is popped without one, replaced byset/replaceTop, removed by system back, the router is disposed, or a guard prevents it from landing. Unlikerun<T>, the screen is a normal route in the same navigator, so a shared observer sees it and a root-navigator dialog renders above it.popnow accepts an optionalObject? result, delivered to a matchingpushForResultawaiter.
- Navigation origin tracking for DevTools. Each committed navigation now
records the app call site that issued it:
KaiselNavigatorexposesdebugLastTransitionOrigin(the capturedStackTrace) and a monotonicdebugLastTransitionSeq, andKaiselRootSnapshotcarries anoriginlist of the app frames behind the most recent transition. Two helpers back it —kaiselNextOriginSeq()andkaiselOriginFrames()(trims kaisel, Flutter, and SDK frames to the caller) — exposed viakaisel_core/framework.dart. Each frame is aKaiselOriginFramecarrying its display line plus a parseduri/line/column(when locatable), so a DevTools host can open it in an editor. Capture isassert-gated, so it costs nothing and is null in release.
KaiselRoute.name→KaiselRoute.routeName. Renamed so the getter can't clash with a domain field namedname(a route may legitimately carry its own). If you overrodenamefor a custom screen name, rename the override torouteName.
- DevTools read-write surface, for the kaisel DevTools extension's "drive the
app" controls:
KaiselInspectable.debugApplyCommandand anext.kaisel.commandservice extension onKaiselInspector. KaiselRouter.debugHistory— a capped, debug-only history of the stacks the router has held (real routes), powering DevTools time-travel.KaiselRootSnapshot.history— the stringified history, on the snapshot.KaiselRoute.name— a name for the route (defaults to the runtime type), set asRouteSettings.nameon the page kaisel builds soNavigatorObserver-based analytics can identify the screen. Override for a custom or obfuscation-stable name.
KaiselInspectablegains adebugApplyCommandmember. Breaking only for code that implements the (framework-facing) interface directly; the kaisel delegate is updated.
- Debug-only inspector surface, consumed by the kaisel DevTools extension:
KaiselInspector(a dormant registry) and theKaiselInspectableinterface, plus the renderer-agnostic snapshot model (KaiselNavSnapshotand friends). KaiselRouterdebug fields for the same:debugLastGuardRun/KaiselGuardRun/KaiselGuardStep(guard-pipeline trace),debugLastNoOp/KaiselNoOp(no-opreplaceTopdetection — the missing-propssymptom), anddebugAbsorbedPositions/debugSetAbsorbedPositions(adaptive master-detail absorption). All gated so they cost nothing in release.
These are additive; existing APIs are unchanged.
Renamed from gate_core to kaisel_core as part of the gate → kaisel
rebrand. Mechanical rename, no behavioural change: every Gate* type is
now Kaisel*, and imports move from package:gate_core/... to
package:kaisel_core/.... See the
kaisel changelog
for the full migration note.
Initial release of kaisel_core, extracted from the kaisel package as its
pure-Dart navigation core. Contains the sealed-route base, the KaiselRouter
stack container (now built on a Flutter-free change-notifier), the guard
pipeline, and the URL codecs — with no Flutter dependency.
Versioned in lockstep with kaisel; see the
kaisel changelog
for the history of these APIs prior to the split.