Skip to content

Releases: smileidentity/njia-spm

njia v0.0.1-SNAPSHOT.10

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 25 Oct 01:11

Snapshot of main at aee0f5549063760ec78e56f05c6c57bede39a7b2, for testing only, not for production.

Platform This snapshot
Android com.usesmileid:njia:0.0.1-SNAPSHOT, njia-compose and njia-testing from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS njia-spm exact: "0.0.1-SNAPSHOT.10"
Flutter usesmileid_njia: 0.0.1-SNAPSHOT.10, and usesmileid_njia_testing
React Native @smileid/njia@0.0.1-SNAPSHOT.10 and @smileid/njia-testing, dist-tag snapshot

Changes since the last release

Added

  • React Native's NjiaHost swipes a screen back from the host's leading edge on iOS, as UIKit's navigation does (SPEC §10.4): only on a settled screen over a screen in the same stack, never a sheet or a screen over one, while preview(back) from the top would pop it onto that screen with the tab bar as it is. While the swipe is held the screen below is mounted under the top with isTop false, hidden from screen readers and touch; let go past half way or flung, the top slides out and then sends back from its entry, otherwise it settles back. Right to left, the swipe comes from the right edge. A peek now mounts the screen below, so a React Native step starts on-screen work, such as a camera or a screen-view event, once isTop holds.
  • Flutter's NjiaHost swipes a screen back from its leading edge on iOS and macOS, as the platform's own navigation does (SPEC §10.3): only on a screen with a page below it, while preview(back) from the top would pop it; the screen follows the finger, and let go past half way or flung back it sends back from its entry, otherwise it settles back. Right to left, the swipe comes from the right edge. NjiaPage takes backSwipe, which the host sets.
  • Android's NjiaHost takes a sheetStyle, an NjiaSheetStyle with the scrim laid over the entries below a sheet and the shape its panel is clipped to, so an SDK draws sheets in its own design. The defaults are the ones before: a 32% black scrim and 28dp top corners.
  • Flutter's NjiaHost takes a sheetStyle too, an NjiaSheetStyle with the scrim and the shape (a ShapeBorder) the panel is clipped to. The defaults are the ones before: a 32% black scrim and 28-point top corners.
  • React Native's NjiaHost takes a sheetStyle too, an NjiaSheetStyle with the scrim and the shape (the panel's top radii and curve), exported from @smileid/njia/host with njia's own, njiaSheetStyle: a 32% black scrim and 28-point top corners, as before.
  • iOS's hosts present sheets in an NjiaSheetStyle, set with .njiaSheetStyle(_:) on a view that holds them: its heights, a set of NjiaSheetHeight (.half, .full), are where SwiftUI may rest a sheet. The default is both, as before; [.full] opens sheets at full height, as a plain SwiftUI sheet does. SwiftUI draws the scrim and corners, so there is nothing else to set.
  • Flutter's NjiaHost draws a sheet over a stacked group's bar, as a modal does: the screens under the first sheet share a page with the bar, and the sheet and anything pushed over it are pages above that one, so the scrim covers the bar and a tap on a tab under it selects nothing.
  • React Native's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • React Native's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar prop draws a stacked group's bar, from tabBar(graph, state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • React Native reads the shell: the fullScreen presentation, tabBar(graph, state) (NjiaTabBar), select(engine, tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as FakeNjiaCalls.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • Flutter's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • Flutter's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar builder draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • Flutter reads the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as FakeNjiaCall.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • iOS's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • SwiftUI's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; NjiaHost(engine:tabBar:content:) and NjiaHost(engine:steps:tabBar:) draw a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • iOS's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • iOS's core draws the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as .go with its argument redacted. Its suite runs the corpus's fullScreen section. go(_:arg:replace:) is a new NjiaNavigator requirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word.
  • Flutter's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • React Native's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • Android's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • A link to a step no move could ever bring on top opens nothing at once (SPEC §9): openLink follows the graph's go, select and next from the start's step before replaying, so a graph with many destinations, such as an app's shell, never searches every stack for a step the facts hide. The result is unchanged. The corpus's deepLinks.unreachable cases pin it, on conformance/graphs/links/wide.json.
  • Android's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • iOS's openLink takes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made through go, select and next (fewest moves, then fewest nexts), landing a target in its tab; a go into a node whose link names the parameter carries it. A stacked group's tab may carry a link. .badLinkParameter, and duplicateLink compares a link's pattern. Its suite runs the corpus's deepLinks section.
  • React Native validates links as amended: one parameter, any whole segment (flow/:productId/run), badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; @smileid/njia-testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • Compose's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its stores and retained values between looks until its group's entry is popped, closed inside that send; a tabBar slot draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries stay in Navigation 3's back stack beneath the drawn ones, undrawn, so their stores live until the group drops them.
  • iOS's core replaces and lands: .go's replace, a node's tab (NjiaStep.tab, NjiaSegment.tab) and NjiaIssueCode.unknownTab, and a go that pops down to the entry it replaces, leaves a stacked group from at or below its entry, and lands in its destination's tab, parking or popping the tab it leaves, under select's guards. Its suite runs the corpus's replace section.
  • Flutter validates links as amended: one parameter, any whole segment (flow/:productId/run), NjiaIssueCode.badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; usesmileid_njia_testing's ReferenceNjiaNative opens links by the shortest replay through go,...
Read more

njia v0.0.1-SNAPSHOT.9

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 23 Oct 20:10

Snapshot of main at edca202ea5476fde590eb03e99b0e0fbf2eb25ea, for testing only, not for production.

Platform This snapshot
Android com.usesmileid:njia:0.0.1-SNAPSHOT, njia-compose and njia-testing from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS njia-spm exact: "0.0.1-SNAPSHOT.9"
Flutter usesmileid_njia: 0.0.1-SNAPSHOT.9, and usesmileid_njia_testing
React Native @smileid/njia@0.0.1-SNAPSHOT.9 and @smileid/njia-testing, dist-tag snapshot

Changes since the last release

Added

  • Flutter's NjiaHost swipes a screen back from its leading edge on iOS and macOS, as the platform's own navigation does (SPEC §10.3): only on a screen with a page below it, while preview(back) from the top would pop it; the screen follows the finger, and let go past half way or flung back it sends back from its entry, otherwise it settles back. Right to left, the swipe comes from the right edge. NjiaPage takes backSwipe, which the host sets.
  • Android's NjiaDisplay takes a sheetStyle, an NjiaSheetStyle with the scrim laid over the entries below a sheet and the shape its panel is clipped to, so an SDK draws sheets in its own design. The defaults are the ones before: a 32% black scrim and 28dp top corners.
  • Flutter's NjiaHost takes a sheetStyle too, an NjiaSheetStyle with the scrim and the shape (a ShapeBorder) the panel is clipped to. The defaults are the ones before: a 32% black scrim and 28-point top corners.
  • React Native's NjiaHost takes a sheetStyle too, an NjiaSheetStyle with the scrim and the shape (the panel's top radii and curve), exported from @smileid/njia/host with njia's own, njiaSheetStyle: a 32% black scrim and 28-point top corners, as before.
  • iOS's hosts present sheets in an NjiaSheetStyle, set with .njiaSheetStyle(_:) on a view that holds them: its heights, a set of NjiaSheetHeight (.half, .full), are where SwiftUI may rest a sheet. The default is both, as before; [.full] opens sheets at full height, as a plain SwiftUI sheet does. SwiftUI draws the scrim and corners, so there is nothing else to set.
  • Flutter's NjiaHost draws a sheet over a stacked group's bar, as a modal does: the screens under the first sheet share a page with the bar, and the sheet and anything pushed over it are pages above that one, so the scrim covers the bar and a tap on a tab under it selects nothing.
  • React Native's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • React Native's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar prop draws a stacked group's bar, from tabBar(graph, state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • React Native reads the shell: the fullScreen presentation, tabBar(graph, state) (NjiaTabBar), select(engine, tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as FakeNjiaCalls.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • Flutter's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • Flutter's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar builder draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • Flutter reads the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as FakeNjiaCall.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • iOS's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • SwiftUI's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; NjiaHost(engine:tabBar:content:) and NjiaHost(engine:steps:tabBar:) draw a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • iOS's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • iOS's core draws the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as .go with its argument redacted. Its suite runs the corpus's fullScreen section. go(_:arg:replace:) is a new NjiaNavigator requirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word.
  • Flutter's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • React Native's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • Android's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • A link to a step no move could ever bring on top opens nothing at once (SPEC §9): openLink follows the graph's go, select and next from the start's step before replaying, so a graph with many destinations, such as an app's shell, never searches every stack for a step the facts hide. The result is unchanged. The corpus's deepLinks.unreachable cases pin it, on conformance/graphs/links/wide.json.
  • Android's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • iOS's openLink takes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made through go, select and next (fewest moves, then fewest nexts), landing a target in its tab; a go into a node whose link names the parameter carries it. A stacked group's tab may carry a link. .badLinkParameter, and duplicateLink compares a link's pattern. Its suite runs the corpus's deepLinks section.
  • React Native validates links as amended: one parameter, any whole segment (flow/:productId/run), badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; @smileid/njia-testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • Compose's NjiaDisplay draws tab groups and the shell (SPEC §10): each tab keeps its stores and retained values between looks until its group's entry is popped, closed inside that send; a tabBar slot draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries stay in Navigation 3's back stack beneath the drawn ones, undrawn, so their stores live until the group drops them.
  • iOS's core replaces and lands: .go's replace, a node's tab (NjiaStep.tab, NjiaSegment.tab) and NjiaIssueCode.unknownTab, and a go that pops down to the entry it replaces, leaves a stacked group from at or below its entry, and lands in its destination's tab, parking or popping the tab it leaves, under select's guards. Its suite runs the corpus's replace section.
  • Flutter validates links as amended: one parameter, any whole segment (flow/:productId/run), NjiaIssueCode.badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; usesmileid_njia_testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • React Native replaces and lands, which reaches a device with the Android and iOS cores that do: NjiaIntents.go's replace, a node's tab (njiaStep and njiaSegment's tab) and the unknownTab issue; and @smileid/njia-testing's ReferenceNjiaNative pops, leaves, lands and guards a go as the native cores do, running the corpus's replace section.
  • Android's core draws the shell: NjiaPresentation.FullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as Call.Go with its argument redacted. Its suite runs the corpus's `fullScreen...
Read more

njia v0.0.1-SNAPSHOT.8

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 23 Oct 19:35

Snapshot of main at 25118e3113831c1fbe132ee39267bd23e37e7b98, for testing only, not for production.

Platform This snapshot
Android com.usesmileid:njia:0.0.1-SNAPSHOT, njia-compose and njia-testing from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS njia-spm exact: "0.0.1-SNAPSHOT.8"
Flutter usesmileid_njia: 0.0.1-SNAPSHOT.8, and usesmileid_njia_testing
React Native @smileid/njia@0.0.1-SNAPSHOT.8 and @smileid/njia-testing, dist-tag snapshot

Changes since the last release

Added

  • Flutter's NjiaHost swipes a screen back from its leading edge on iOS and macOS, as the platform's own navigation does (SPEC §10.3): only on a screen with a page below it, while preview(back) from the top would pop it; the screen follows the finger, and let go past half way or flung back it sends back from its entry, otherwise it settles back. Right to left, the swipe comes from the right edge. NjiaPage takes backSwipe, which the host sets.
  • Android's NjiaDisplay takes a sheetStyle, an NjiaSheetStyle with the scrim laid over the entries below a sheet and the shape its panel is clipped to, so an SDK draws sheets in its own design. The defaults are the ones before: a 32% black scrim and 28dp top corners.
  • Flutter's NjiaHost takes a sheetStyle too, an NjiaSheetStyle with the scrim and the shape (a ShapeBorder) the panel is clipped to. The defaults are the ones before: a 32% black scrim and 28-point top corners.
  • React Native's NjiaHost takes a sheetStyle too, an NjiaSheetStyle with the scrim and the shape (the panel's top radii and curve), exported from @smileid/njia/host with njia's own, njiaSheetStyle: a 32% black scrim and 28-point top corners, as before.
  • iOS's hosts present sheets in an NjiaSheetStyle, set with .njiaSheetStyle(_:) on a view that holds them: its heights, a set of NjiaSheetHeight (.half, .full), are where SwiftUI may rest a sheet. The default is both, as before; [.full] opens sheets at full height, as a plain SwiftUI sheet does. SwiftUI draws the scrim and corners, so there is nothing else to set.
  • Flutter's NjiaHost draws a sheet over a stacked group's bar, as a modal does: the screens under the first sheet share a page with the bar, and the sheet and anything pushed over it are pages above that one, so the scrim covers the bar and a tap on a tab under it selects nothing.
  • React Native's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • React Native's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar prop draws a stacked group's bar, from tabBar(graph, state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • React Native reads the shell: the fullScreen presentation, tabBar(graph, state) (NjiaTabBar), select(engine, tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as FakeNjiaCalls.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • Flutter's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • Flutter's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar builder draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • Flutter reads the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as FakeNjiaCall.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • iOS's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • SwiftUI's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; NjiaHost(engine:tabBar:content:) and NjiaHost(engine:steps:tabBar:) draw a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • iOS's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • iOS's core draws the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as .go with its argument redacted. Its suite runs the corpus's fullScreen section. go(_:arg:replace:) is a new NjiaNavigator requirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word.
  • Flutter's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • React Native's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • Android's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • A link to a step no move could ever bring on top opens nothing at once (SPEC §9): openLink follows the graph's go, select and next from the start's step before replaying, so a graph with many destinations, such as an app's shell, never searches every stack for a step the facts hide. The result is unchanged. The corpus's deepLinks.unreachable cases pin it, on conformance/graphs/links/wide.json.
  • Android's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • iOS's openLink takes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made through go, select and next (fewest moves, then fewest nexts), landing a target in its tab; a go into a node whose link names the parameter carries it. A stacked group's tab may carry a link. .badLinkParameter, and duplicateLink compares a link's pattern. Its suite runs the corpus's deepLinks section.
  • React Native validates links as amended: one parameter, any whole segment (flow/:productId/run), badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; @smileid/njia-testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • Compose's NjiaDisplay draws tab groups and the shell (SPEC §10): each tab keeps its stores and retained values between looks until its group's entry is popped, closed inside that send; a tabBar slot draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries stay in Navigation 3's back stack beneath the drawn ones, undrawn, so their stores live until the group drops them.
  • iOS's core replaces and lands: .go's replace, a node's tab (NjiaStep.tab, NjiaSegment.tab) and NjiaIssueCode.unknownTab, and a go that pops down to the entry it replaces, leaves a stacked group from at or below its entry, and lands in its destination's tab, parking or popping the tab it leaves, under select's guards. Its suite runs the corpus's replace section.
  • Flutter validates links as amended: one parameter, any whole segment (flow/:productId/run), NjiaIssueCode.badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; usesmileid_njia_testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • React Native replaces and lands, which reaches a device with the Android and iOS cores that do: NjiaIntents.go's replace, a node's tab (njiaStep and njiaSegment's tab) and the unknownTab issue; and @smileid/njia-testing's ReferenceNjiaNative pops, leaves, lands and guards a go as the native cores do, running the corpus's replace section.
  • Android's core draws the shell: NjiaPresentation.FullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as Call.Go with its argument redacted. Its suite runs the corpus's `fullScreen...
Read more

njia v0.0.1-SNAPSHOT.7

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 23 Oct 14:56

Snapshot of main at a759281071b4a0d0e254916dbd8be20e8dfbb20f, for testing only, not for production.

Platform This snapshot
Android com.usesmileid:njia:0.0.1-SNAPSHOT, njia-compose and njia-testing from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS njia-spm exact: "0.0.1-SNAPSHOT.7"
Flutter usesmileid_njia: 0.0.1-SNAPSHOT.7, and usesmileid_njia_testing
React Native @smileid/njia@0.0.1-SNAPSHOT.7 and @smileid/njia-testing, dist-tag snapshot

Changes since the last release

Added

  • Android's NjiaDisplay takes a sheetStyle, an NjiaSheetStyle with the scrim laid over the entries below a sheet and the shape its panel is clipped to, so an SDK draws sheets in its own design. The defaults are the ones before: a 32% black scrim and 28dp top corners.
  • Flutter's NjiaHost takes a sheetStyle too, an NjiaSheetStyle with the scrim and the shape (a ShapeBorder) the panel is clipped to. The defaults are the ones before: a 32% black scrim and 28-point top corners.
  • React Native's NjiaHost takes a sheetStyle too, an NjiaSheetStyle with the scrim and the shape (the panel's top radii and curve), exported from @smileid/njia/host with njia's own, njiaSheetStyle: a 32% black scrim and 28-point top corners, as before.
  • iOS's hosts present sheets in an NjiaSheetStyle, set with .njiaSheetStyle(_:) on a view that holds them: its heights, a set of NjiaSheetHeight (.half, .full), are where SwiftUI may rest a sheet. The default is both, as before; [.full] opens sheets at full height, as a plain SwiftUI sheet does. SwiftUI draws the scrim and corners, so there is nothing else to set.
  • Flutter's NjiaHost draws a sheet over a stacked group's bar, as a modal does: the screens under the first sheet share a page with the bar, and the sheet and anything pushed over it are pages above that one, so the scrim covers the bar and a tap on a tab under it selects nothing.
  • React Native's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • React Native's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar prop draws a stacked group's bar, from tabBar(graph, state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • React Native reads the shell: the fullScreen presentation, tabBar(graph, state) (NjiaTabBar), select(engine, tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as FakeNjiaCalls.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • Flutter's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • Flutter's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar builder draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • Flutter reads the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as FakeNjiaCall.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • iOS's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • SwiftUI's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; NjiaHost(engine:tabBar:content:) and NjiaHost(engine:steps:tabBar:) draw a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • iOS's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • iOS's core draws the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as .go with its argument redacted. Its suite runs the corpus's fullScreen section. go(_:arg:replace:) is a new NjiaNavigator requirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word.
  • Flutter's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • React Native's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • Android's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • A link to a step no move could ever bring on top opens nothing at once (SPEC §9): openLink follows the graph's go, select and next from the start's step before replaying, so a graph with many destinations, such as an app's shell, never searches every stack for a step the facts hide. The result is unchanged. The corpus's deepLinks.unreachable cases pin it, on conformance/graphs/links/wide.json.
  • Android's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • iOS's openLink takes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made through go, select and next (fewest moves, then fewest nexts), landing a target in its tab; a go into a node whose link names the parameter carries it. A stacked group's tab may carry a link. .badLinkParameter, and duplicateLink compares a link's pattern. Its suite runs the corpus's deepLinks section.
  • React Native validates links as amended: one parameter, any whole segment (flow/:productId/run), badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; @smileid/njia-testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • Compose's NjiaDisplay draws tab groups and the shell (SPEC §10): each tab keeps its stores and retained values between looks until its group's entry is popped, closed inside that send; a tabBar slot draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries stay in Navigation 3's back stack beneath the drawn ones, undrawn, so their stores live until the group drops them.
  • iOS's core replaces and lands: .go's replace, a node's tab (NjiaStep.tab, NjiaSegment.tab) and NjiaIssueCode.unknownTab, and a go that pops down to the entry it replaces, leaves a stacked group from at or below its entry, and lands in its destination's tab, parking or popping the tab it leaves, under select's guards. Its suite runs the corpus's replace section.
  • Flutter validates links as amended: one parameter, any whole segment (flow/:productId/run), NjiaIssueCode.badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; usesmileid_njia_testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • React Native replaces and lands, which reaches a device with the Android and iOS cores that do: NjiaIntents.go's replace, a node's tab (njiaStep and njiaSegment's tab) and the unknownTab issue; and @smileid/njia-testing's ReferenceNjiaNative pops, leaves, lands and guards a go as the native cores do, running the corpus's replace section.
  • Android's core draws the shell: NjiaPresentation.FullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as Call.Go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • Android's openLink takes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made through go, select and next (fewest moves, then fewest nexts), landing a target in its tab; a go into a node whose link names the parameter carries it. A stacked group's tab may carry a link. NjiaIssueCode.BadLinkParameter, and duplicateLink compares a link's pattern. Its suite runs the c...
Read more

njia v0.0.1-SNAPSHOT.6

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 23 Oct 00:35

Snapshot of main at b8496f0159b4cd0afe444ddd46d0c002b274591e, for testing only, not for production.

Platform This snapshot
Android com.usesmileid:njia:0.0.1-SNAPSHOT, njia-compose and njia-testing from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS njia-spm exact: "0.0.1-SNAPSHOT.6"
Flutter usesmileid_njia: 0.0.1-SNAPSHOT.6, and usesmileid_njia_testing
React Native @smileid/njia@0.0.1-SNAPSHOT.6 and @smileid/njia-testing, dist-tag snapshot

Changes since the last release

Added

  • Android's NjiaDisplay takes a sheetStyle, an NjiaSheetStyle with the scrim laid over the entries below a sheet and the shape its panel is clipped to, so an SDK draws sheets in its own design. The defaults are the ones before: a 32% black scrim and 28dp top corners.
  • Flutter's NjiaHost draws a sheet over a stacked group's bar, as a modal does: the screens under the first sheet share a page with the bar, and the sheet and anything pushed over it are pages above that one, so the scrim covers the bar and a tap on a tab under it selects nothing.
  • React Native's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • React Native's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar prop draws a stacked group's bar, from tabBar(graph, state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • React Native reads the shell: the fullScreen presentation, tabBar(graph, state) (NjiaTabBar), select(engine, tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as FakeNjiaCalls.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • Flutter's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • Flutter's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar builder draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • Flutter reads the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as FakeNjiaCall.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • iOS's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • SwiftUI's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; NjiaHost(engine:tabBar:content:) and NjiaHost(engine:steps:tabBar:) draw a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • iOS's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • iOS's core draws the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as .go with its argument redacted. Its suite runs the corpus's fullScreen section. go(_:arg:replace:) is a new NjiaNavigator requirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word.
  • Flutter's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • React Native's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • Android's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • A link to a step no move could ever bring on top opens nothing at once (SPEC §9): openLink follows the graph's go, select and next from the start's step before replaying, so a graph with many destinations, such as an app's shell, never searches every stack for a step the facts hide. The result is unchanged. The corpus's deepLinks.unreachable cases pin it, on conformance/graphs/links/wide.json.
  • Android's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • iOS's openLink takes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made through go, select and next (fewest moves, then fewest nexts), landing a target in its tab; a go into a node whose link names the parameter carries it. A stacked group's tab may carry a link. .badLinkParameter, and duplicateLink compares a link's pattern. Its suite runs the corpus's deepLinks section.
  • React Native validates links as amended: one parameter, any whole segment (flow/:productId/run), badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; @smileid/njia-testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • Compose's NjiaDisplay draws tab groups and the shell (SPEC §10): each tab keeps its stores and retained values between looks until its group's entry is popped, closed inside that send; a tabBar slot draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries stay in Navigation 3's back stack beneath the drawn ones, undrawn, so their stores live until the group drops them.
  • iOS's core replaces and lands: .go's replace, a node's tab (NjiaStep.tab, NjiaSegment.tab) and NjiaIssueCode.unknownTab, and a go that pops down to the entry it replaces, leaves a stacked group from at or below its entry, and lands in its destination's tab, parking or popping the tab it leaves, under select's guards. Its suite runs the corpus's replace section.
  • Flutter validates links as amended: one parameter, any whole segment (flow/:productId/run), NjiaIssueCode.badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; usesmileid_njia_testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • React Native replaces and lands, which reaches a device with the Android and iOS cores that do: NjiaIntents.go's replace, a node's tab (njiaStep and njiaSegment's tab) and the unknownTab issue; and @smileid/njia-testing's ReferenceNjiaNative pops, leaves, lands and guards a go as the native cores do, running the corpus's replace section.
  • Android's core draws the shell: NjiaPresentation.FullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as Call.Go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • Android's openLink takes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made through go, select and next (fewest moves, then fewest nexts), landing a target in its tab; a go into a node whose link names the parameter carries it. A stacked group's tab may carry a link. NjiaIssueCode.BadLinkParameter, and duplicateLink compares a link's pattern. Its suite runs the corpus's deepLinks section.
  • Flutter replaces and lands, which reaches a device with the Android and iOS cores that do: NjiaIntent.go's replace, a node's tab (NjiaStep.tab, NjiaSegment.tab) and NjiaIssueCode.unknownTab; and usesmileid_njia_testing's ReferenceNjiaNative pops, leaves, lands and guards a go as the native cores do, running the corpus's replace section.
  • Flutter carries arguments, which reach a device with the Android and iOS cores that carry them: NjiaEntry.arg and NjiaIntent.go's arg, in the codecs and equality, redacted by toString and traces (which now keep a redacted answer's tab); and usesmileid_njia_testing's ReferenceNjiaNative pushes, caps and checks them as the native cores do, running the corpus's args section.
  • Android's core replaces and lands: NjiaIntent.Go.replace, a node's tab (`NjiaStep....
Read more

njia v0.0.1-SNAPSHOT.5

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 22 Oct 22:48

Snapshot of main at 0f5edc3a84a744843d75e9f4acf0ac140150ab16, for testing only, not for production.

Platform This snapshot
Android com.usesmileid:njia:0.0.1-SNAPSHOT, njia-compose and njia-testing from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS njia-spm exact: "0.0.1-SNAPSHOT.5"
Flutter usesmileid_njia: 0.0.1-SNAPSHOT.5, and usesmileid_njia_testing
React Native @smileid/njia@0.0.1-SNAPSHOT.5 and @smileid/njia-testing, dist-tag snapshot

Changes since the last release

Added

  • Flutter's NjiaHost draws a sheet over a stacked group's bar, as a modal does: the screens under the first sheet share a page with the bar, and the sheet and anything pushed over it are pages above that one, so the scrim covers the bar and a tap on a tab under it selects nothing.
  • React Native's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • React Native's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar prop draws a stacked group's bar, from tabBar(graph, state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • React Native reads the shell: the fullScreen presentation, tabBar(graph, state) (NjiaTabBar), select(engine, tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as FakeNjiaCalls.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • Flutter's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • Flutter's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; a tabBar builder draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • Flutter reads the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as FakeNjiaCall.go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • iOS's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • SwiftUI's NjiaHost draws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; NjiaHost(engine:tabBar:content:) and NjiaHost(engine:steps:tabBar:) draw a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries keep their values, undrawn, until the group drops them.
  • iOS's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • iOS's core draws the shell: NjiaPresentation.fullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg:, replace:), which FakeNjiaNavigator records as .go with its argument redacted. Its suite runs the corpus's fullScreen section. go(_:arg:replace:) is a new NjiaNavigator requirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word.
  • Flutter's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • React Native's ReferenceNjiaNative checks a link's target can ever come on top before replaying (SPEC §9), as the native cores do, so a link to a step the facts hide opens nothing at once. Its suite runs the corpus's deepLinks.unreachable cases.
  • Android's openLink checks a link's target can ever come on top before replaying (SPEC §9), so a link to a step the facts hide opens nothing at once on a graph with many destinations. Its suite runs the corpus's deepLinks.unreachable cases.
  • A link to a step no move could ever bring on top opens nothing at once (SPEC §9): openLink follows the graph's go, select and next from the start's step before replaying, so a graph with many destinations, such as an app's shell, never searches every stack for a step the facts hide. The result is unchanged. The corpus's deepLinks.unreachable cases pin it, on conformance/graphs/links/wide.json.
  • Android's Lab runs the tab group and app shell graphs (tabs/, shell/): a stacked group's bar of njia.tab.<tab> pills under the steps, a go <destination> pill (njia.go.<destination>) for each of a step's to, and the entry's arg on its card.
  • iOS's openLink takes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made through go, select and next (fewest moves, then fewest nexts), landing a target in its tab; a go into a node whose link names the parameter carries it. A stacked group's tab may carry a link. .badLinkParameter, and duplicateLink compares a link's pattern. Its suite runs the corpus's deepLinks section.
  • React Native validates links as amended: one parameter, any whole segment (flow/:productId/run), badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; @smileid/njia-testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • Compose's NjiaDisplay draws tab groups and the shell (SPEC §10): each tab keeps its stores and retained values between looks until its group's entry is popped, closed inside that send; a tabBar slot draws a stacked group's bar, from graph.tabBar(state), under every entry of the selected tab's stack and not over a fullScreen step; parked entries stay in Navigation 3's back stack beneath the drawn ones, undrawn, so their stores live until the group drops them.
  • iOS's core replaces and lands: .go's replace, a node's tab (NjiaStep.tab, NjiaSegment.tab) and NjiaIssueCode.unknownTab, and a go that pops down to the entry it replaces, leaves a stacked group from at or below its entry, and lands in its destination's tab, parking or popping the tab it leaves, under select's guards. Its suite runs the corpus's replace section.
  • Flutter validates links as amended: one parameter, any whole segment (flow/:productId/run), NjiaIssueCode.badLinkParameter, duplicateLink comparing a link's pattern, and a stacked group's tab may carry a link; usesmileid_njia_testing's ReferenceNjiaNative opens links by the shortest replay through go, select and next, as the native cores do, running the corpus's deepLinks section.
  • React Native replaces and lands, which reaches a device with the Android and iOS cores that do: NjiaIntents.go's replace, a node's tab (njiaStep and njiaSegment's tab) and the unknownTab issue; and @smileid/njia-testing's ReferenceNjiaNative pops, leaves, lands and guards a go as the native cores do, running the corpus's replace section.
  • Android's core draws the shell: NjiaPresentation.FullScreen, graph.tabBar(state) (NjiaTabBar), engine.select(tab) from the top, and navigator.go(step, arg, replace), which FakeNjiaNavigator records as Call.Go with its argument redacted. Its suite runs the corpus's fullScreen section.
  • Android's openLink takes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made through go, select and next (fewest moves, then fewest nexts), landing a target in its tab; a go into a node whose link names the parameter carries it. A stacked group's tab may carry a link. NjiaIssueCode.BadLinkParameter, and duplicateLink compares a link's pattern. Its suite runs the corpus's deepLinks section.
  • Flutter replaces and lands, which reaches a device with the Android and iOS cores that do: NjiaIntent.go's replace, a node's tab (NjiaStep.tab, NjiaSegment.tab) and NjiaIssueCode.unknownTab; and usesmileid_njia_testing's ReferenceNjiaNative pops, leaves, lands and guards a go as the native cores do, running the corpus's replace section.
  • Flutter carries arguments, which reach a device with the Android and iOS cores that carry them: NjiaEntry.arg and NjiaIntent.go's arg, in the codecs and equality, redacted by toString and traces (which now keep a redacted answer's tab); and usesmileid_njia_testing's ReferenceNjiaNative pushes, caps and checks them as the native cores do, running the corpus's args section.
  • Android's core replaces and lands: NjiaIntent.Go.replace, a node's tab (NjiaStep.tab, NjiaSegment.tab) and NjiaIssueCode.UnknownTab, and a go that pops down to the entry it replaces, leaves a stacked group from at or below its entry, and lands in its destination's tab, parking or popping the tab it leaves, under select's guards. Its suite runs ...
Read more

njia v0.0.1-SNAPSHOT.4

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 13 Oct 18:54

Snapshot of main at 76e2b95dd2721a5ce471bc3e2f95720f61effc99, for testing only, not for production.

Platform This snapshot
Android com.usesmileid:njia:0.0.1-SNAPSHOT, njia-compose and njia-testing from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS njia-spm exact: "0.0.1-SNAPSHOT.4"
Flutter usesmileid_njia: 0.0.1-SNAPSHOT.4, and usesmileid_njia_testing
React Native @smileid/njia@0.0.1-SNAPSHOT.4 and @smileid/njia-testing, dist-tag snapshot

Changes since the last release

Added

  • The njia contract, docs/SPEC.md: the graph schema (steps, segments, conditions, guards), the state, intents and effects, routing, the delivery gate, hosts and bridges.
  • The conformance corpus: 32 reducer scenarios, 11 engine cases, 15 invalid graphs, 7 inconsistent states, 7 startAt cases, codec cases and 12 delivery-gate cases, checked against a reference reducer in CI.
  • Strict JSON (SPEC §4.5): the native decoders reject trailing data, duplicate keys, comments, hex, leading zeros, NaN, signed unicode escapes, raw control characters, half a surrogate pair and nesting deeper than 64 (23 raw-text cases). Integers stay within ±(2^53−1), and the native decoders reject 1.0 or 1e0 for one. Every decoder rejects an explicit null where the schema doesn't allow one (14 cases), and an integer out of range (3 structured cases every platform runs), and ignores keys a type doesn't define, whatever their value (5 cases, plus 2 at the integer limits).
  • startAt(graph, step, facts) (SPEC §9) opens a flow at any step, with the back stack a user would have had, or that step alone when it can't be reached, for previews, tests and end-to-end launches.
  • Hosts label each step they draw njia.step.<step> (SPEC §10), on by default, so UI tests and Maestro find steps by id on every SDK.
  • Hosts say when a step learns it has moved (SPEC §10): a covered entry reads isTop false from the transition's first frame, a popped entry's retained values close at the transition, and listeners hear a transition before its step is drawn, so a capture leaving the screen releases its camera before the next one starts and an SDK can lock the orientation for a step before it draws.
  • Maestro flows for every reducer scenario (maestro/flows/, generated by scripts/gen_maestro.py), and the harness app each host provides to run them (SPEC §12), so one flow file checks every host on Android and iOS.
  • Deep links (SPEC §9): a graph step can carry a link name, validated by three new issues (blankLink, duplicateLink, linkInsideSegment), and openLink(graph, link, facts) opens a flow at that step by replaying it with the given facts, refusing rather than falling back when the flow wouldn't reach it. 8 links cases; the bridges gain openLink.
  • The harness contract (SPEC §12) opens deep links: njiaharness://link/<name>?graph=<file>&facts=<JSON list> runs openLink, showing the flow or njia.refused. gen_maestro.py writes one flow per links case into maestro/links/, which the harness lanes run once each harness opens links.
  • Bridge errors (SPEC §11): a refusal crosses a bridge as an error coded by its wire name (invalidJson, invalidGraph with its issues, inconsistentState, wrongThread, unknownHandle), listed in the corpus's wire.errors; disposing an unknown handle does nothing.
  • Replies (SPEC §11.1): a synchronous TurboModule method can't reject, and its exceptions reach JavaScript with their message only, so the React Native module returns every result or refusal as a reply, { "ok": value } or { "error": { "code", "message", "issues" } }, which the cores build.
  • Typed vocabularies (SPEC §9): every package is generic over the SDK's step kinds and facts, mapped to the wire's strings by a NjiaWire.
  • The engine refuses calls from another thread (wrongThread), reports whether it was restored, and can preview an intent without applying it; the bridges gain restore and preview too. The delivery gate lets go of its receiver after teardown and ignores a later attach. SPEC §9 says teardown doesn't wait for a delivery already handed out on another thread, and that a listener removed during a notification isn't called for it (11 engine cases). A navigator's cancel() does nothing unless its entry is the top. Swift listeners don't throw, so iOS skips the engine case about a throwing listener.
  • NjiaKit (SPEC §9), each package's front door: NjiaKit.start, NjiaKit.restore and NjiaKit.openLink create an engine as NjiaEngine's factories do, and NjiaKit.version names the release, the same string on all four. It isn't Njia, the iOS module's name: a type named after its module breaks Swift code that qualifies a type by module.
  • Graph diagrams: scripts/gen_diagrams.py draws a graph as a Mermaid flowchart, following the reference reducer's routing (next, skipWhen, repeatWhile, skip), with its guards and links in tables. docs/graphs/ holds one page per conformance graph, and CI redraws them and fails on drift. Given a graph file, it prints that graph's flowchart, so an SDK can draw its own from encodeGraph.
  • Answers (SPEC §6): a step returns a value to the flow with answer(value), which its entry keeps until it is popped and every effect that carries the entry shows. answered reports it, state.answer(step) reads it, and NjiaAnswerFormat<R> types it. Its codec cases are in codec, its 5 scenarios in conformance/scenarios/ with Maestro flows, after a staged rollout.
  • Android: answers: NjiaIntent.Answer, NjiaEffect.Answered, NjiaEntry.answer (redacted from toString, like an outcome's detail), state.answer(step), NjiaNavigator.answer(value) and engine.answer(from, value), with NjiaAnswerFormat<R> for typed answers. FakeNjiaNavigator records them as Call.Answer(value) and hands one back with expectAnswer().
  • Tracing (SPEC §9): NjiaTrace(capacity, redact, clock), given to an engine when it's created, keeps its last records (creation, then every applied intent with its effects and state) for bug reports, redacting answers and outcome details by default, and writes them as a document with the graph. scripts/replay_trace.py checks a document against the reference reducer. The corpus's trace section holds 8 cases and 11 replays.
  • The step registry (SPEC §10): NjiaSteps<K, F> registers each kind's renderer once, with a fallback or a refusal that names unregistered kinds, shared decorators (the first outermost) and per-entry dependencies (provide, scope.dependency, typed by NjiaDependencyKey<T>). Every host also gives a step scope.retained(key) { value }, kept until its entry is popped and closed then, and a pausable value that holds while its step is covered.
  • Flutter: the njia-flutter package (usesmileid_njia) and its strict JSON reader and writer (NjiaJsonText), with the Flutter SDK only. It reads over UTF-16 code units and refuses what the native readers refuse, and it writes control characters as \u escapes like they do, where dart:convert writes \b and \f.
  • Flutter: the graph layer of usesmileid_njia, generic over step kinds and facts like Android's and iOS's: NjiaGraph and its nodes, conditions and guards, NjiaIntentKind, NjiaWire (with NjiaWire.ofEnum(values) and NjiaWire.strings), and NjiaCodec's decodeGraph / encodeGraph, passing the corpus's graph codec cases. Conditions are built with NjiaCondition.allOf([…]) and NjiaCondition.noneOf([…]).
  • Flutter: validate() with the SPEC §4.4 issue codes (NjiaGraphIssue, NjiaIssueCode) and NjiaInvalidGraphException, so a Dart SDK sees the same issues, in the same order, as the native engine that refuses its graph. All 15 invalid graphs pass.
  • Flutter: the state, typed by the SDK's facts (NjiaState<F>, NjiaEntry, a sealed NjiaPhase of NjiaRunningPhase, NjiaBusyPhase and NjiaDonePhase, NjiaOutcome), with top, isBusy, isDone, has and the graph's stepOf, and NjiaCodec's decodeState, encodeState and decodeFacts. NjiaOutcome redacts its detail when printed.
  • Flutter: the intents, typed by the SDK's facts: a sealed NjiaIntent<F>, built with NjiaIntent.next(from:), back, skip, cancel, finish, busy, idle and facts(set:, clear:) and matched on its <Case>Intent classes, with kind and from, and NjiaCodec's decodeIntent and encodeIntent. All the corpus's intent codec cases pass.
  • Flutter: the effects and transitions: a sealed NjiaEffect, with the four entry effects under NjiaEntryEffect, entry and isRefusal, NjiaTransition<F> with applied, and NjiaCodec's decodeEffect, encodeEffect, encodeTransition and decodeTransition, which reads what a native engine returns across the bridge. All the corpus's effect and transition cases pass.
  • Flutter: NjiaEngine<K, F>, the native engine driven from Dart through a Pigeon bridge to the core's NjiaBridge (SPEC §11): start, restore and openLink with the SDK's codec, send and preview returning transitions asynchronously and in order, listeners, and dispose. A refusal comes back as NjiaJsonException, NjiaInvalidGraphException (with its issues) or the new NjiaInconsistentStateException; a disposed engine or unknown handle is a StateError.
  • Flutter: the plugin's Android side: NjiaPlugin forwards each call to the core's NjiaBridge and turns a refusal into a FlutterError coded by its wire name. example/ runs integration tests against the real native engine, which the flutter lane runs on an emulator.
  • Flutter: the plugin's iOS side, a Swift package (usesmileid_njia) whose NjiaPlugin forwards each call to the core's NjiaBridge and turns a refusal into a PigeonError coded by its wire name. The example's integrat...
Read more

njia v0.0.1-SNAPSHOT.3

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 13 Oct 08:31

Snapshot of main at 76e2b95dd2721a5ce471bc3e2f95720f61effc99, for testing only, not for production.

Platform This snapshot
Android com.usesmileid:njia:0.0.1-SNAPSHOT, njia-compose and njia-testing from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS njia-spm exact: "0.0.1-SNAPSHOT.3"
Flutter usesmileid_njia: 0.0.1-SNAPSHOT.3, and usesmileid_njia_testing
React Native @smileid/njia@0.0.1-SNAPSHOT.3 and @smileid/njia-testing, dist-tag snapshot

Changes since the last release

Added

  • The njia contract, docs/SPEC.md: the graph schema (steps, segments, conditions, guards), the state, intents and effects, routing, the delivery gate, hosts and bridges.
  • The conformance corpus: 32 reducer scenarios, 11 engine cases, 15 invalid graphs, 7 inconsistent states, 7 startAt cases, codec cases and 12 delivery-gate cases, checked against a reference reducer in CI.
  • Strict JSON (SPEC §4.5): the native decoders reject trailing data, duplicate keys, comments, hex, leading zeros, NaN, signed unicode escapes, raw control characters, half a surrogate pair and nesting deeper than 64 (23 raw-text cases). Integers stay within ±(2^53−1), and the native decoders reject 1.0 or 1e0 for one. Every decoder rejects an explicit null where the schema doesn't allow one (14 cases), and an integer out of range (3 structured cases every platform runs), and ignores keys a type doesn't define, whatever their value (5 cases, plus 2 at the integer limits).
  • startAt(graph, step, facts) (SPEC §9) opens a flow at any step, with the back stack a user would have had, or that step alone when it can't be reached, for previews, tests and end-to-end launches.
  • Hosts label each step they draw njia.step.<step> (SPEC §10), on by default, so UI tests and Maestro find steps by id on every SDK.
  • Hosts say when a step learns it has moved (SPEC §10): a covered entry reads isTop false from the transition's first frame, a popped entry's retained values close at the transition, and listeners hear a transition before its step is drawn, so a capture leaving the screen releases its camera before the next one starts and an SDK can lock the orientation for a step before it draws.
  • Maestro flows for every reducer scenario (maestro/flows/, generated by scripts/gen_maestro.py), and the harness app each host provides to run them (SPEC §12), so one flow file checks every host on Android and iOS.
  • Deep links (SPEC §9): a graph step can carry a link name, validated by three new issues (blankLink, duplicateLink, linkInsideSegment), and openLink(graph, link, facts) opens a flow at that step by replaying it with the given facts, refusing rather than falling back when the flow wouldn't reach it. 8 links cases; the bridges gain openLink.
  • The harness contract (SPEC §12) opens deep links: njiaharness://link/<name>?graph=<file>&facts=<JSON list> runs openLink, showing the flow or njia.refused. gen_maestro.py writes one flow per links case into maestro/links/, which the harness lanes run once each harness opens links.
  • Bridge errors (SPEC §11): a refusal crosses a bridge as an error coded by its wire name (invalidJson, invalidGraph with its issues, inconsistentState, wrongThread, unknownHandle), listed in the corpus's wire.errors; disposing an unknown handle does nothing.
  • Replies (SPEC §11.1): a synchronous TurboModule method can't reject, and its exceptions reach JavaScript with their message only, so the React Native module returns every result or refusal as a reply, { "ok": value } or { "error": { "code", "message", "issues" } }, which the cores build.
  • Typed vocabularies (SPEC §9): every package is generic over the SDK's step kinds and facts, mapped to the wire's strings by a NjiaWire.
  • The engine refuses calls from another thread (wrongThread), reports whether it was restored, and can preview an intent without applying it; the bridges gain restore and preview too. The delivery gate lets go of its receiver after teardown and ignores a later attach. SPEC §9 says teardown doesn't wait for a delivery already handed out on another thread, and that a listener removed during a notification isn't called for it (11 engine cases). A navigator's cancel() does nothing unless its entry is the top. Swift listeners don't throw, so iOS skips the engine case about a throwing listener.
  • NjiaKit (SPEC §9), each package's front door: NjiaKit.start, NjiaKit.restore and NjiaKit.openLink create an engine as NjiaEngine's factories do, and NjiaKit.version names the release, the same string on all four. It isn't Njia, the iOS module's name: a type named after its module breaks Swift code that qualifies a type by module.
  • Graph diagrams: scripts/gen_diagrams.py draws a graph as a Mermaid flowchart, following the reference reducer's routing (next, skipWhen, repeatWhile, skip), with its guards and links in tables. docs/graphs/ holds one page per conformance graph, and CI redraws them and fails on drift. Given a graph file, it prints that graph's flowchart, so an SDK can draw its own from encodeGraph.
  • Answers (SPEC §6): a step returns a value to the flow with answer(value), which its entry keeps until it is popped and every effect that carries the entry shows. answered reports it, state.answer(step) reads it, and NjiaAnswerFormat<R> types it. Its codec cases are in codec, its 5 scenarios in conformance/scenarios/ with Maestro flows, after a staged rollout.
  • Android: answers: NjiaIntent.Answer, NjiaEffect.Answered, NjiaEntry.answer (redacted from toString, like an outcome's detail), state.answer(step), NjiaNavigator.answer(value) and engine.answer(from, value), with NjiaAnswerFormat<R> for typed answers. FakeNjiaNavigator records them as Call.Answer(value) and hands one back with expectAnswer().
  • Tracing (SPEC §9): NjiaTrace(capacity, redact, clock), given to an engine when it's created, keeps its last records (creation, then every applied intent with its effects and state) for bug reports, redacting answers and outcome details by default, and writes them as a document with the graph. scripts/replay_trace.py checks a document against the reference reducer. The corpus's trace section holds 8 cases and 11 replays.
  • The step registry (SPEC §10): NjiaSteps<K, F> registers each kind's renderer once, with a fallback or a refusal that names unregistered kinds, shared decorators (the first outermost) and per-entry dependencies (provide, scope.dependency, typed by NjiaDependencyKey<T>). Every host also gives a step scope.retained(key) { value }, kept until its entry is popped and closed then, and a pausable value that holds while its step is covered.
  • Flutter: the njia-flutter package (usesmileid_njia) and its strict JSON reader and writer (NjiaJsonText), with the Flutter SDK only. It reads over UTF-16 code units and refuses what the native readers refuse, and it writes control characters as \u escapes like they do, where dart:convert writes \b and \f.
  • Flutter: the graph layer of usesmileid_njia, generic over step kinds and facts like Android's and iOS's: NjiaGraph and its nodes, conditions and guards, NjiaIntentKind, NjiaWire (with NjiaWire.ofEnum(values) and NjiaWire.strings), and NjiaCodec's decodeGraph / encodeGraph, passing the corpus's graph codec cases. Conditions are built with NjiaCondition.allOf([…]) and NjiaCondition.noneOf([…]).
  • Flutter: validate() with the SPEC §4.4 issue codes (NjiaGraphIssue, NjiaIssueCode) and NjiaInvalidGraphException, so a Dart SDK sees the same issues, in the same order, as the native engine that refuses its graph. All 15 invalid graphs pass.
  • Flutter: the state, typed by the SDK's facts (NjiaState<F>, NjiaEntry, a sealed NjiaPhase of NjiaRunningPhase, NjiaBusyPhase and NjiaDonePhase, NjiaOutcome), with top, isBusy, isDone, has and the graph's stepOf, and NjiaCodec's decodeState, encodeState and decodeFacts. NjiaOutcome redacts its detail when printed.
  • Flutter: the intents, typed by the SDK's facts: a sealed NjiaIntent<F>, built with NjiaIntent.next(from:), back, skip, cancel, finish, busy, idle and facts(set:, clear:) and matched on its <Case>Intent classes, with kind and from, and NjiaCodec's decodeIntent and encodeIntent. All the corpus's intent codec cases pass.
  • Flutter: the effects and transitions: a sealed NjiaEffect, with the four entry effects under NjiaEntryEffect, entry and isRefusal, NjiaTransition<F> with applied, and NjiaCodec's decodeEffect, encodeEffect, encodeTransition and decodeTransition, which reads what a native engine returns across the bridge. All the corpus's effect and transition cases pass.
  • Flutter: NjiaEngine<K, F>, the native engine driven from Dart through a Pigeon bridge to the core's NjiaBridge (SPEC §11): start, restore and openLink with the SDK's codec, send and preview returning transitions asynchronously and in order, listeners, and dispose. A refusal comes back as NjiaJsonException, NjiaInvalidGraphException (with its issues) or the new NjiaInconsistentStateException; a disposed engine or unknown handle is a StateError.
  • Flutter: the plugin's Android side: NjiaPlugin forwards each call to the core's NjiaBridge and turns a refusal into a FlutterError coded by its wire name. example/ runs integration tests against the real native engine, which the flutter lane runs on an emulator.
  • Flutter: the plugin's iOS side, a Swift package (usesmileid_njia) whose NjiaPlugin forwards each call to the core's NjiaBridge and turns a refusal into a PigeonError coded by its wire name. The example's integrat...
Read more

njia v0.0.1-SNAPSHOT.2

Pre-release

Choose a tag to compare

@jumaallan jumaallan released this 12 Oct 08:44

Snapshot of main at 5a9f2f8f900a7456c25828372d48d18fe86311c4, for testing only, not for production.

Platform This snapshot
Android com.usesmileid:njia:0.0.1-SNAPSHOT, njia-compose and njia-testing from Maven Central's snapshot repository, https://central.sonatype.com/repository/maven-snapshots/
iOS njia-spm exact: "0.0.1-SNAPSHOT.2"
Flutter usesmileid_njia: 0.0.1-SNAPSHOT.2, and usesmileid_njia_testing
React Native @smileid/njia@0.0.1-SNAPSHOT.2 and @smileid/njia-testing, dist-tag snapshot

Changes since the last release

Added

  • The njia contract, docs/SPEC.md: the graph schema (steps, segments, conditions, guards), the state, intents and effects, routing, the delivery gate, hosts and bridges.
  • The conformance corpus: 32 reducer scenarios, 11 engine cases, 15 invalid graphs, 7 inconsistent states, 7 startAt cases, codec cases and 12 delivery-gate cases, checked against a reference reducer in CI.
  • Strict JSON (SPEC §4.5): the native decoders reject trailing data, duplicate keys, comments, hex, leading zeros, NaN, signed unicode escapes, raw control characters, half a surrogate pair and nesting deeper than 64 (23 raw-text cases). Integers stay within ±(2^53−1), and the native decoders reject 1.0 or 1e0 for one. Every decoder rejects an explicit null where the schema doesn't allow one (14 cases), and an integer out of range (3 structured cases every platform runs), and ignores keys a type doesn't define, whatever their value (5 cases, plus 2 at the integer limits).
  • startAt(graph, step, facts) (SPEC §9) opens a flow at any step, with the back stack a user would have had, or that step alone when it can't be reached, for previews, tests and end-to-end launches.
  • Hosts label each step they draw njia.step.<step> (SPEC §10), on by default, so UI tests and Maestro find steps by id on every SDK.
  • Maestro flows for every reducer scenario (maestro/flows/, generated by scripts/gen_maestro.py), and the harness app each host provides to run them (SPEC §12), so one flow file checks every host on Android and iOS.
  • Deep links (SPEC §9): a graph step can carry a link name, validated by three new issues (blankLink, duplicateLink, linkInsideSegment), and openLink(graph, link, facts) opens a flow at that step by replaying it with the given facts, refusing rather than falling back when the flow wouldn't reach it. 8 links cases; the bridges gain openLink.
  • The harness contract (SPEC §12) opens deep links: njiaharness://link/<name>?graph=<file>&facts=<JSON list> runs openLink, showing the flow or njia.refused. gen_maestro.py writes one flow per links case into maestro/links/, which the harness lanes run once each harness opens links.
  • Bridge errors (SPEC §11): a refusal crosses a bridge as an error coded by its wire name (invalidJson, invalidGraph with its issues, inconsistentState, wrongThread, unknownHandle), listed in the corpus's wire.errors; disposing an unknown handle does nothing.
  • Replies (SPEC §11.1): a synchronous TurboModule method can't reject, and its exceptions reach JavaScript with their message only, so the React Native module returns every result or refusal as a reply, { "ok": value } or { "error": { "code", "message", "issues" } }, which the cores build.
  • Typed vocabularies (SPEC §9): every package is generic over the SDK's step kinds and facts, mapped to the wire's strings by a NjiaWire.
  • The engine refuses calls from another thread (wrongThread), reports whether it was restored, and can preview an intent without applying it; the bridges gain restore and preview too. The delivery gate lets go of its receiver after teardown and ignores a later attach. SPEC §9 says teardown doesn't wait for a delivery already handed out on another thread, and that a listener removed during a notification isn't called for it (11 engine cases). A navigator's cancel() does nothing unless its entry is the top. Swift listeners don't throw, so iOS skips the engine case about a throwing listener.
  • NjiaKit (SPEC §9), each package's front door: NjiaKit.start, NjiaKit.restore and NjiaKit.openLink create an engine as NjiaEngine's factories do, and NjiaKit.version names the release, the same string on all four. It isn't Njia, the iOS module's name: a type named after its module breaks Swift code that qualifies a type by module.
  • Graph diagrams: scripts/gen_diagrams.py draws a graph as a Mermaid flowchart, following the reference reducer's routing (next, skipWhen, repeatWhile, skip), with its guards and links in tables. docs/graphs/ holds one page per conformance graph, and CI redraws them and fails on drift. Given a graph file, it prints that graph's flowchart, so an SDK can draw its own from encodeGraph.
  • Answers (SPEC §6): a step returns a value to the flow with answer(value), which its entry keeps until it is popped and every effect that carries the entry shows. answered reports it, state.answer(step) reads it, and NjiaAnswerFormat<R> types it. Its codec cases are in codec, its 5 scenarios in conformance/scenarios/ with Maestro flows, after a staged rollout.
  • Android: answers: NjiaIntent.Answer, NjiaEffect.Answered, NjiaEntry.answer (redacted from toString, like an outcome's detail), state.answer(step), NjiaNavigator.answer(value) and engine.answer(from, value), with NjiaAnswerFormat<R> for typed answers. FakeNjiaNavigator records them as Call.Answer(value) and hands one back with expectAnswer().
  • Tracing (SPEC §9): NjiaTrace(capacity, redact, clock), given to an engine when it's created, keeps its last records (creation, then every applied intent with its effects and state) for bug reports, redacting answers and outcome details by default, and writes them as a document with the graph. scripts/replay_trace.py checks a document against the reference reducer. The corpus's trace section holds 8 cases and 11 replays.
  • The step registry (SPEC §10): NjiaSteps<K, F> registers each kind's renderer once, with a fallback or a refusal that names unregistered kinds, shared decorators (the first outermost) and per-entry dependencies (provide, scope.dependency, typed by NjiaDependencyKey<T>). Every host also gives a step scope.retained(key) { value }, kept until its entry is popped and closed then, and a pausable value that holds while its step is covered.
  • Flutter: the njia-flutter package (usesmileid_njia) and its strict JSON reader and writer (NjiaJsonText), with the Flutter SDK only. It reads over UTF-16 code units and refuses what the native readers refuse, and it writes control characters as \u escapes like they do, where dart:convert writes \b and \f.
  • Flutter: the graph layer of usesmileid_njia, generic over step kinds and facts like Android's and iOS's: NjiaGraph and its nodes, conditions and guards, NjiaIntentKind, NjiaWire (with NjiaWire.ofEnum(values) and NjiaWire.strings), and NjiaCodec's decodeGraph / encodeGraph, passing the corpus's graph codec cases. Conditions are built with NjiaCondition.allOf([…]) and NjiaCondition.noneOf([…]).
  • Flutter: validate() with the SPEC §4.4 issue codes (NjiaGraphIssue, NjiaIssueCode) and NjiaInvalidGraphException, so a Dart SDK sees the same issues, in the same order, as the native engine that refuses its graph. All 15 invalid graphs pass.
  • Flutter: the state, typed by the SDK's facts (NjiaState<F>, NjiaEntry, a sealed NjiaPhase of NjiaRunningPhase, NjiaBusyPhase and NjiaDonePhase, NjiaOutcome), with top, isBusy, isDone, has and the graph's stepOf, and NjiaCodec's decodeState, encodeState and decodeFacts. NjiaOutcome redacts its detail when printed.
  • Flutter: the intents, typed by the SDK's facts: a sealed NjiaIntent<F>, built with NjiaIntent.next(from:), back, skip, cancel, finish, busy, idle and facts(set:, clear:) and matched on its <Case>Intent classes, with kind and from, and NjiaCodec's decodeIntent and encodeIntent. All the corpus's intent codec cases pass.
  • Flutter: the effects and transitions: a sealed NjiaEffect, with the four entry effects under NjiaEntryEffect, entry and isRefusal, NjiaTransition<F> with applied, and NjiaCodec's decodeEffect, encodeEffect, encodeTransition and decodeTransition, which reads what a native engine returns across the bridge. All the corpus's effect and transition cases pass.
  • Flutter: NjiaEngine<K, F>, the native engine driven from Dart through a Pigeon bridge to the core's NjiaBridge (SPEC §11): start, restore and openLink with the SDK's codec, send and preview returning transitions asynchronously and in order, listeners, and dispose. A refusal comes back as NjiaJsonException, NjiaInvalidGraphException (with its issues) or the new NjiaInconsistentStateException; a disposed engine or unknown handle is a StateError.
  • Flutter: the plugin's Android side: NjiaPlugin forwards each call to the core's NjiaBridge and turns a refusal into a FlutterError coded by its wire name. example/ runs integration tests against the real native engine, which the flutter lane runs on an emulator.
  • Flutter: the plugin's iOS side, a Swift package (usesmileid_njia) whose NjiaPlugin forwards each call to the core's NjiaBridge and turns a refusal into a PigeonError coded by its wire name. The example's integration tests run on an iOS simulator too, on Xcode 26.4.
  • Flutter: NjiaHost, the Flutter host (SPEC §10.3): a Navigator whose pages are the engine's entries, keyed by entry id, with the shared fade-and-slide motion (none under reduced motion), the njia.step.<step> semantics identifier (stepIds), and a PopScope that sends back from the top; a step that pops its own route s...
Read more