Repository navigation
Releases: smileidentity/njia-spm
Release list
njia v0.0.1-SNAPSHOT.10
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
NjiaHostswipes 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, whilepreview(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 withisTopfalse, hidden from screen readers and touch; let go past half way or flung, the top slides out and then sendsbackfrom 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, onceisTopholds. - Flutter's
NjiaHostswipes 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, whilepreview(back)from the top would pop it; the screen follows the finger, and let go past half way or flung back it sendsbackfrom its entry, otherwise it settles back. Right to left, the swipe comes from the right edge.NjiaPagetakesbackSwipe, which the host sets. - Android's
NjiaHosttakes asheetStyle, anNjiaSheetStylewith 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
NjiaHosttakes asheetStyletoo, anNjiaSheetStylewith thescrimand theshape(aShapeBorder) the panel is clipped to. The defaults are the ones before: a 32% black scrim and 28-point top corners. - React Native's
NjiaHosttakes asheetStyletoo, anNjiaSheetStylewith thescrimand theshape(the panel's top radii and curve), exported from@smileid/njia/hostwith 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: itsheights, a set ofNjiaSheetHeight(.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
NjiaHostdraws 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 ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - React Native's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarprop draws a stacked group's bar, fromtabBar(graph, state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - React Native reads the shell: the
fullScreenpresentation,tabBar(graph, state)(NjiaTabBar),select(engine, tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asFakeNjiaCalls.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - Flutter's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - Flutter's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarbuilder draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords asFakeNjiaCall.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - iOS's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - SwiftUI's
NjiaHostdraws 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:)andNjiaHost(engine:steps:tabBar:)draw a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - iOS's
openLinkchecks 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'sdeepLinks.unreachablecases. - iOS's core draws the shell:
NjiaPresentation.fullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords as.gowith its argument redacted. Its suite runs the corpus'sfullScreensection.go(_:arg:replace:)is a newNjiaNavigatorrequirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word. - Flutter's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - React Native's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - Android's
openLinkchecks 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'sdeepLinks.unreachablecases. - A link to a step no move could ever bring on top opens nothing at once (SPEC §9):
openLinkfollows the graph'sgo,selectandnextfrom 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'sdeepLinks.unreachablecases pin it, onconformance/graphs/links/wide.json. - Android's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - iOS's
openLinktakes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made throughgo,selectandnext(fewest moves, then fewestnexts), landing a target in itstab; agointo a node whose link names the parameter carries it. A stacked group's tab may carry a link..badLinkParameter, andduplicateLinkcompares a link's pattern. Its suite runs the corpus'sdeepLinkssection. - React Native validates links as amended: one parameter, any whole segment (
flow/:productId/run),badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;@smileid/njia-testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - Compose's
NjiaHostdraws 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; atabBarslot draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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'sreplace, a node'stab(NjiaStep.tab,NjiaSegment.tab) andNjiaIssueCode.unknownTab, and agothat 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, underselect's guards. Its suite runs the corpus'sreplacesection. - Flutter validates links as amended: one parameter, any whole segment (
flow/:productId/run),NjiaIssueCode.badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;usesmileid_njia_testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,...
njia v0.0.1-SNAPSHOT.9
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
NjiaHostswipes 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, whilepreview(back)from the top would pop it; the screen follows the finger, and let go past half way or flung back it sendsbackfrom its entry, otherwise it settles back. Right to left, the swipe comes from the right edge.NjiaPagetakesbackSwipe, which the host sets. - Android's
NjiaDisplaytakes asheetStyle, anNjiaSheetStylewith 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
NjiaHosttakes asheetStyletoo, anNjiaSheetStylewith thescrimand theshape(aShapeBorder) the panel is clipped to. The defaults are the ones before: a 32% black scrim and 28-point top corners. - React Native's
NjiaHosttakes asheetStyletoo, anNjiaSheetStylewith thescrimand theshape(the panel's top radii and curve), exported from@smileid/njia/hostwith 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: itsheights, a set ofNjiaSheetHeight(.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
NjiaHostdraws 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 ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - React Native's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarprop draws a stacked group's bar, fromtabBar(graph, state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - React Native reads the shell: the
fullScreenpresentation,tabBar(graph, state)(NjiaTabBar),select(engine, tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asFakeNjiaCalls.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - Flutter's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - Flutter's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarbuilder draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords asFakeNjiaCall.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - iOS's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - SwiftUI's
NjiaHostdraws 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:)andNjiaHost(engine:steps:tabBar:)draw a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - iOS's
openLinkchecks 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'sdeepLinks.unreachablecases. - iOS's core draws the shell:
NjiaPresentation.fullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords as.gowith its argument redacted. Its suite runs the corpus'sfullScreensection.go(_:arg:replace:)is a newNjiaNavigatorrequirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word. - Flutter's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - React Native's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - Android's
openLinkchecks 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'sdeepLinks.unreachablecases. - A link to a step no move could ever bring on top opens nothing at once (SPEC §9):
openLinkfollows the graph'sgo,selectandnextfrom 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'sdeepLinks.unreachablecases pin it, onconformance/graphs/links/wide.json. - Android's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - iOS's
openLinktakes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made throughgo,selectandnext(fewest moves, then fewestnexts), landing a target in itstab; agointo a node whose link names the parameter carries it. A stacked group's tab may carry a link..badLinkParameter, andduplicateLinkcompares a link's pattern. Its suite runs the corpus'sdeepLinkssection. - React Native validates links as amended: one parameter, any whole segment (
flow/:productId/run),badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;@smileid/njia-testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - Compose's
NjiaDisplaydraws 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; atabBarslot draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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'sreplace, a node'stab(NjiaStep.tab,NjiaSegment.tab) andNjiaIssueCode.unknownTab, and agothat 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, underselect's guards. Its suite runs the corpus'sreplacesection. - Flutter validates links as amended: one parameter, any whole segment (
flow/:productId/run),NjiaIssueCode.badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;usesmileid_njia_testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - React Native replaces and lands, which reaches a device with the Android and iOS cores that do:
NjiaIntents.go'sreplace, a node'stab(njiaStepandnjiaSegment'stab) and theunknownTabissue; and@smileid/njia-testing'sReferenceNjiaNativepops, leaves, lands and guards agoas the native cores do, running the corpus'sreplacesection. - Android's core draws the shell:
NjiaPresentation.FullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asCall.Gowith its argument redacted. Its suite runs the corpus's `fullScreen...
njia v0.0.1-SNAPSHOT.8
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
NjiaHostswipes 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, whilepreview(back)from the top would pop it; the screen follows the finger, and let go past half way or flung back it sendsbackfrom its entry, otherwise it settles back. Right to left, the swipe comes from the right edge.NjiaPagetakesbackSwipe, which the host sets. - Android's
NjiaDisplaytakes asheetStyle, anNjiaSheetStylewith 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
NjiaHosttakes asheetStyletoo, anNjiaSheetStylewith thescrimand theshape(aShapeBorder) the panel is clipped to. The defaults are the ones before: a 32% black scrim and 28-point top corners. - React Native's
NjiaHosttakes asheetStyletoo, anNjiaSheetStylewith thescrimand theshape(the panel's top radii and curve), exported from@smileid/njia/hostwith 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: itsheights, a set ofNjiaSheetHeight(.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
NjiaHostdraws 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 ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - React Native's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarprop draws a stacked group's bar, fromtabBar(graph, state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - React Native reads the shell: the
fullScreenpresentation,tabBar(graph, state)(NjiaTabBar),select(engine, tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asFakeNjiaCalls.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - Flutter's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - Flutter's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarbuilder draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords asFakeNjiaCall.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - iOS's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - SwiftUI's
NjiaHostdraws 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:)andNjiaHost(engine:steps:tabBar:)draw a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - iOS's
openLinkchecks 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'sdeepLinks.unreachablecases. - iOS's core draws the shell:
NjiaPresentation.fullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords as.gowith its argument redacted. Its suite runs the corpus'sfullScreensection.go(_:arg:replace:)is a newNjiaNavigatorrequirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word. - Flutter's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - React Native's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - Android's
openLinkchecks 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'sdeepLinks.unreachablecases. - A link to a step no move could ever bring on top opens nothing at once (SPEC §9):
openLinkfollows the graph'sgo,selectandnextfrom 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'sdeepLinks.unreachablecases pin it, onconformance/graphs/links/wide.json. - Android's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - iOS's
openLinktakes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made throughgo,selectandnext(fewest moves, then fewestnexts), landing a target in itstab; agointo a node whose link names the parameter carries it. A stacked group's tab may carry a link..badLinkParameter, andduplicateLinkcompares a link's pattern. Its suite runs the corpus'sdeepLinkssection. - React Native validates links as amended: one parameter, any whole segment (
flow/:productId/run),badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;@smileid/njia-testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - Compose's
NjiaDisplaydraws 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; atabBarslot draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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'sreplace, a node'stab(NjiaStep.tab,NjiaSegment.tab) andNjiaIssueCode.unknownTab, and agothat 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, underselect's guards. Its suite runs the corpus'sreplacesection. - Flutter validates links as amended: one parameter, any whole segment (
flow/:productId/run),NjiaIssueCode.badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;usesmileid_njia_testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - React Native replaces and lands, which reaches a device with the Android and iOS cores that do:
NjiaIntents.go'sreplace, a node'stab(njiaStepandnjiaSegment'stab) and theunknownTabissue; and@smileid/njia-testing'sReferenceNjiaNativepops, leaves, lands and guards agoas the native cores do, running the corpus'sreplacesection. - Android's core draws the shell:
NjiaPresentation.FullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asCall.Gowith its argument redacted. Its suite runs the corpus's `fullScreen...
njia v0.0.1-SNAPSHOT.7
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
NjiaDisplaytakes asheetStyle, anNjiaSheetStylewith 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
NjiaHosttakes asheetStyletoo, anNjiaSheetStylewith thescrimand theshape(aShapeBorder) the panel is clipped to. The defaults are the ones before: a 32% black scrim and 28-point top corners. - React Native's
NjiaHosttakes asheetStyletoo, anNjiaSheetStylewith thescrimand theshape(the panel's top radii and curve), exported from@smileid/njia/hostwith 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: itsheights, a set ofNjiaSheetHeight(.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
NjiaHostdraws 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 ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - React Native's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarprop draws a stacked group's bar, fromtabBar(graph, state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - React Native reads the shell: the
fullScreenpresentation,tabBar(graph, state)(NjiaTabBar),select(engine, tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asFakeNjiaCalls.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - Flutter's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - Flutter's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarbuilder draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords asFakeNjiaCall.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - iOS's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - SwiftUI's
NjiaHostdraws 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:)andNjiaHost(engine:steps:tabBar:)draw a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - iOS's
openLinkchecks 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'sdeepLinks.unreachablecases. - iOS's core draws the shell:
NjiaPresentation.fullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords as.gowith its argument redacted. Its suite runs the corpus'sfullScreensection.go(_:arg:replace:)is a newNjiaNavigatorrequirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word. - Flutter's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - React Native's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - Android's
openLinkchecks 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'sdeepLinks.unreachablecases. - A link to a step no move could ever bring on top opens nothing at once (SPEC §9):
openLinkfollows the graph'sgo,selectandnextfrom 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'sdeepLinks.unreachablecases pin it, onconformance/graphs/links/wide.json. - Android's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - iOS's
openLinktakes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made throughgo,selectandnext(fewest moves, then fewestnexts), landing a target in itstab; agointo a node whose link names the parameter carries it. A stacked group's tab may carry a link..badLinkParameter, andduplicateLinkcompares a link's pattern. Its suite runs the corpus'sdeepLinkssection. - React Native validates links as amended: one parameter, any whole segment (
flow/:productId/run),badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;@smileid/njia-testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - Compose's
NjiaDisplaydraws 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; atabBarslot draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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'sreplace, a node'stab(NjiaStep.tab,NjiaSegment.tab) andNjiaIssueCode.unknownTab, and agothat 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, underselect's guards. Its suite runs the corpus'sreplacesection. - Flutter validates links as amended: one parameter, any whole segment (
flow/:productId/run),NjiaIssueCode.badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;usesmileid_njia_testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - React Native replaces and lands, which reaches a device with the Android and iOS cores that do:
NjiaIntents.go'sreplace, a node'stab(njiaStepandnjiaSegment'stab) and theunknownTabissue; and@smileid/njia-testing'sReferenceNjiaNativepops, leaves, lands and guards agoas the native cores do, running the corpus'sreplacesection. - Android's core draws the shell:
NjiaPresentation.FullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asCall.Gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - Android's
openLinktakes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made throughgo,selectandnext(fewest moves, then fewestnexts), landing a target in itstab; agointo a node whose link names the parameter carries it. A stacked group's tab may carry a link.NjiaIssueCode.BadLinkParameter, andduplicateLinkcompares a link's pattern. Its suite runs the c...
njia v0.0.1-SNAPSHOT.6
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
NjiaDisplaytakes asheetStyle, anNjiaSheetStylewith 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
NjiaHostdraws 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 ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - React Native's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarprop draws a stacked group's bar, fromtabBar(graph, state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - React Native reads the shell: the
fullScreenpresentation,tabBar(graph, state)(NjiaTabBar),select(engine, tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asFakeNjiaCalls.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - Flutter's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - Flutter's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarbuilder draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords asFakeNjiaCall.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - iOS's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - SwiftUI's
NjiaHostdraws 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:)andNjiaHost(engine:steps:tabBar:)draw a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - iOS's
openLinkchecks 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'sdeepLinks.unreachablecases. - iOS's core draws the shell:
NjiaPresentation.fullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords as.gowith its argument redacted. Its suite runs the corpus'sfullScreensection.go(_:arg:replace:)is a newNjiaNavigatorrequirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word. - Flutter's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - React Native's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - Android's
openLinkchecks 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'sdeepLinks.unreachablecases. - A link to a step no move could ever bring on top opens nothing at once (SPEC §9):
openLinkfollows the graph'sgo,selectandnextfrom 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'sdeepLinks.unreachablecases pin it, onconformance/graphs/links/wide.json. - Android's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - iOS's
openLinktakes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made throughgo,selectandnext(fewest moves, then fewestnexts), landing a target in itstab; agointo a node whose link names the parameter carries it. A stacked group's tab may carry a link..badLinkParameter, andduplicateLinkcompares a link's pattern. Its suite runs the corpus'sdeepLinkssection. - React Native validates links as amended: one parameter, any whole segment (
flow/:productId/run),badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;@smileid/njia-testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - Compose's
NjiaDisplaydraws 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; atabBarslot draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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'sreplace, a node'stab(NjiaStep.tab,NjiaSegment.tab) andNjiaIssueCode.unknownTab, and agothat 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, underselect's guards. Its suite runs the corpus'sreplacesection. - Flutter validates links as amended: one parameter, any whole segment (
flow/:productId/run),NjiaIssueCode.badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;usesmileid_njia_testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - React Native replaces and lands, which reaches a device with the Android and iOS cores that do:
NjiaIntents.go'sreplace, a node'stab(njiaStepandnjiaSegment'stab) and theunknownTabissue; and@smileid/njia-testing'sReferenceNjiaNativepops, leaves, lands and guards agoas the native cores do, running the corpus'sreplacesection. - Android's core draws the shell:
NjiaPresentation.FullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asCall.Gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - Android's
openLinktakes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made throughgo,selectandnext(fewest moves, then fewestnexts), landing a target in itstab; agointo a node whose link names the parameter carries it. A stacked group's tab may carry a link.NjiaIssueCode.BadLinkParameter, andduplicateLinkcompares a link's pattern. Its suite runs the corpus'sdeepLinkssection. - Flutter replaces and lands, which reaches a device with the Android and iOS cores that do:
NjiaIntent.go'sreplace, a node'stab(NjiaStep.tab,NjiaSegment.tab) andNjiaIssueCode.unknownTab; andusesmileid_njia_testing'sReferenceNjiaNativepops, leaves, lands and guards agoas the native cores do, running the corpus'sreplacesection. - Flutter carries arguments, which reach a device with the Android and iOS cores that carry them:
NjiaEntry.argandNjiaIntent.go'sarg, in the codecs and equality, redacted bytoStringand traces (which now keep a redacted answer'stab); andusesmileid_njia_testing'sReferenceNjiaNativepushes, caps and checks them as the native cores do, running the corpus'sargssection. - Android's core replaces and lands:
NjiaIntent.Go.replace, a node'stab(`NjiaStep....
njia v0.0.1-SNAPSHOT.5
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
NjiaHostdraws 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 ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - React Native's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarprop draws a stacked group's bar, fromtabBar(graph, state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - React Native reads the shell: the
fullScreenpresentation,tabBar(graph, state)(NjiaTabBar),select(engine, tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asFakeNjiaCalls.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - Flutter's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - Flutter's
NjiaHostdraws tab groups and the shell (SPEC §10): each tab keeps its retained values between looks until its group's entry is popped; atabBarbuilder draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords asFakeNjiaCall.gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - iOS's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - SwiftUI's
NjiaHostdraws 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:)andNjiaHost(engine:steps:tabBar:)draw a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; parked entries keep their values, undrawn, until the group drops them. - iOS's
openLinkchecks 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'sdeepLinks.unreachablecases. - iOS's core draws the shell:
NjiaPresentation.fullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg:, replace:), whichFakeNjiaNavigatorrecords as.gowith its argument redacted. Its suite runs the corpus'sfullScreensection.go(_:arg:replace:)is a newNjiaNavigatorrequirement with no default, so a navigator of your own must implement it: a default would drop the intent without a word. - Flutter's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - React Native's
ReferenceNjiaNativechecks 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'sdeepLinks.unreachablecases. - Android's
openLinkchecks 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'sdeepLinks.unreachablecases. - A link to a step no move could ever bring on top opens nothing at once (SPEC §9):
openLinkfollows the graph'sgo,selectandnextfrom 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'sdeepLinks.unreachablecases pin it, onconformance/graphs/links/wide.json. - Android's Lab runs the tab group and app shell graphs (
tabs/,shell/): a stacked group's bar ofnjia.tab.<tab>pills under the steps, ago <destination>pill (njia.go.<destination>) for each of a step'sto, and the entry'sargon its card. - iOS's
openLinktakes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made throughgo,selectandnext(fewest moves, then fewestnexts), landing a target in itstab; agointo a node whose link names the parameter carries it. A stacked group's tab may carry a link..badLinkParameter, andduplicateLinkcompares a link's pattern. Its suite runs the corpus'sdeepLinkssection. - React Native validates links as amended: one parameter, any whole segment (
flow/:productId/run),badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;@smileid/njia-testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - Compose's
NjiaDisplaydraws 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; atabBarslot draws a stacked group's bar, fromgraph.tabBar(state), under every entry of the selected tab's stack and not over afullScreenstep; 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'sreplace, a node'stab(NjiaStep.tab,NjiaSegment.tab) andNjiaIssueCode.unknownTab, and agothat 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, underselect's guards. Its suite runs the corpus'sreplacesection. - Flutter validates links as amended: one parameter, any whole segment (
flow/:productId/run),NjiaIssueCode.badLinkParameter,duplicateLinkcomparing a link's pattern, and a stacked group's tab may carry a link;usesmileid_njia_testing'sReferenceNjiaNativeopens links by the shortest replay throughgo,selectandnext, as the native cores do, running the corpus'sdeepLinkssection. - React Native replaces and lands, which reaches a device with the Android and iOS cores that do:
NjiaIntents.go'sreplace, a node'stab(njiaStepandnjiaSegment'stab) and theunknownTabissue; and@smileid/njia-testing'sReferenceNjiaNativepops, leaves, lands and guards agoas the native cores do, running the corpus'sreplacesection. - Android's core draws the shell:
NjiaPresentation.FullScreen,graph.tabBar(state)(NjiaTabBar),engine.select(tab)from the top, andnavigator.go(step, arg, replace), whichFakeNjiaNavigatorrecords asCall.Gowith its argument redacted. Its suite runs the corpus'sfullScreensection. - Android's
openLinktakes one parameter, any whole segment (flow/:productId/run), and takes the shortest replay a user could have made throughgo,selectandnext(fewest moves, then fewestnexts), landing a target in itstab; agointo a node whose link names the parameter carries it. A stacked group's tab may carry a link.NjiaIssueCode.BadLinkParameter, andduplicateLinkcompares a link's pattern. Its suite runs the corpus'sdeepLinkssection. - Flutter replaces and lands, which reaches a device with the Android and iOS cores that do:
NjiaIntent.go'sreplace, a node'stab(NjiaStep.tab,NjiaSegment.tab) andNjiaIssueCode.unknownTab; andusesmileid_njia_testing'sReferenceNjiaNativepops, leaves, lands and guards agoas the native cores do, running the corpus'sreplacesection. - Flutter carries arguments, which reach a device with the Android and iOS cores that carry them:
NjiaEntry.argandNjiaIntent.go'sarg, in the codecs and equality, redacted bytoStringand traces (which now keep a redacted answer'stab); andusesmileid_njia_testing'sReferenceNjiaNativepushes, caps and checks them as the native cores do, running the corpus'sargssection. - Android's core replaces and lands:
NjiaIntent.Go.replace, a node'stab(NjiaStep.tab,NjiaSegment.tab) andNjiaIssueCode.UnknownTab, and agothat 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, underselect's guards. Its suite runs ...
njia v0.0.1-SNAPSHOT.4
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
startAtcases, 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.0or1e0for one. Every decoder rejects an explicitnullwhere 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
isTopfalse 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 byscripts/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
linkname, validated by three new issues (blankLink,duplicateLink,linkInsideSegment), andopenLink(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. 8linkscases; the bridges gainopenLink. - The harness contract (SPEC §12) opens deep links:
njiaharness://link/<name>?graph=<file>&facts=<JSON list>runsopenLink, showing the flow ornjia.refused.gen_maestro.pywrites one flow perlinkscase intomaestro/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,invalidGraphwith its issues,inconsistentState,wrongThread,unknownHandle), listed in the corpus'swire.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 wasrestored, and canpreviewan intent without applying it; the bridges gainrestoreandpreviewtoo. The delivery gate lets go of its receiver after teardown and ignores a laterattach. SPEC §9 saysteardowndoesn'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'scancel()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.restoreandNjiaKit.openLinkcreate an engine asNjiaEngine's factories do, andNjiaKit.versionnames the release, the same string on all four. It isn'tNjia, 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.pydraws 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 fromencodeGraph. - 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.answeredreports it,state.answer(step)reads it, andNjiaAnswerFormat<R>types it. Its codec cases are incodec, its 5 scenarios inconformance/scenarios/with Maestro flows, after a staged rollout. - Android: answers:
NjiaIntent.Answer,NjiaEffect.Answered,NjiaEntry.answer(redacted fromtoString, like an outcome's detail),state.answer(step),NjiaNavigator.answer(value)andengine.answer(from, value), withNjiaAnswerFormat<R>for typed answers.FakeNjiaNavigatorrecords them asCall.Answer(value)and hands one back withexpectAnswer(). - 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.pychecks a document against the reference reducer. The corpus'stracesection 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 byNjiaDependencyKey<T>). Every host also gives a stepscope.retained(key) { value }, kept until its entry is popped and closed then, and apausablevalue that holds while its step is covered. - Flutter: the
njia-flutterpackage (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\uescapes like they do, wheredart:convertwrites\band\f. - Flutter: the graph layer of
usesmileid_njia, generic over step kinds and facts like Android's and iOS's:NjiaGraphand its nodes, conditions and guards,NjiaIntentKind,NjiaWire(withNjiaWire.ofEnum(values)andNjiaWire.strings), andNjiaCodec'sdecodeGraph/encodeGraph, passing the corpus's graph codec cases. Conditions are built withNjiaCondition.allOf([…])andNjiaCondition.noneOf([…]). - Flutter:
validate()with the SPEC §4.4 issue codes (NjiaGraphIssue,NjiaIssueCode) andNjiaInvalidGraphException, 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 sealedNjiaPhaseofNjiaRunningPhase,NjiaBusyPhaseandNjiaDonePhase,NjiaOutcome), withtop,isBusy,isDone,hasand the graph'sstepOf, andNjiaCodec'sdecodeState,encodeStateanddecodeFacts.NjiaOutcomeredacts its detail when printed. - Flutter: the intents, typed by the SDK's facts: a sealed
NjiaIntent<F>, built withNjiaIntent.next(from:),back,skip,cancel,finish,busy,idleandfacts(set:, clear:)and matched on its<Case>Intentclasses, withkindandfrom, andNjiaCodec'sdecodeIntentandencodeIntent. All the corpus's intent codec cases pass. - Flutter: the effects and transitions: a sealed
NjiaEffect, with the four entry effects underNjiaEntryEffect,entryandisRefusal,NjiaTransition<F>withapplied, andNjiaCodec'sdecodeEffect,encodeEffect,encodeTransitionanddecodeTransition, 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'sNjiaBridge(SPEC §11):start,restoreandopenLinkwith the SDK's codec,sendandpreviewreturning transitions asynchronously and in order, listeners, anddispose. A refusal comes back asNjiaJsonException,NjiaInvalidGraphException(with its issues) or the newNjiaInconsistentStateException; a disposed engine or unknown handle is aStateError. - Flutter: the plugin's Android side:
NjiaPluginforwards each call to the core'sNjiaBridgeand turns a refusal into aFlutterErrorcoded by its wire name.example/runs integration tests against the real native engine, which theflutterlane runs on an emulator. - Flutter: the plugin's iOS side, a Swift package (
usesmileid_njia) whoseNjiaPluginforwards each call to the core'sNjiaBridgeand turns a refusal into aPigeonErrorcoded by its wire name. The example's integrat...
njia v0.0.1-SNAPSHOT.3
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
startAtcases, 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.0or1e0for one. Every decoder rejects an explicitnullwhere 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
isTopfalse 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 byscripts/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
linkname, validated by three new issues (blankLink,duplicateLink,linkInsideSegment), andopenLink(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. 8linkscases; the bridges gainopenLink. - The harness contract (SPEC §12) opens deep links:
njiaharness://link/<name>?graph=<file>&facts=<JSON list>runsopenLink, showing the flow ornjia.refused.gen_maestro.pywrites one flow perlinkscase intomaestro/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,invalidGraphwith its issues,inconsistentState,wrongThread,unknownHandle), listed in the corpus'swire.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 wasrestored, and canpreviewan intent without applying it; the bridges gainrestoreandpreviewtoo. The delivery gate lets go of its receiver after teardown and ignores a laterattach. SPEC §9 saysteardowndoesn'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'scancel()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.restoreandNjiaKit.openLinkcreate an engine asNjiaEngine's factories do, andNjiaKit.versionnames the release, the same string on all four. It isn'tNjia, 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.pydraws 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 fromencodeGraph. - 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.answeredreports it,state.answer(step)reads it, andNjiaAnswerFormat<R>types it. Its codec cases are incodec, its 5 scenarios inconformance/scenarios/with Maestro flows, after a staged rollout. - Android: answers:
NjiaIntent.Answer,NjiaEffect.Answered,NjiaEntry.answer(redacted fromtoString, like an outcome's detail),state.answer(step),NjiaNavigator.answer(value)andengine.answer(from, value), withNjiaAnswerFormat<R>for typed answers.FakeNjiaNavigatorrecords them asCall.Answer(value)and hands one back withexpectAnswer(). - 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.pychecks a document against the reference reducer. The corpus'stracesection 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 byNjiaDependencyKey<T>). Every host also gives a stepscope.retained(key) { value }, kept until its entry is popped and closed then, and apausablevalue that holds while its step is covered. - Flutter: the
njia-flutterpackage (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\uescapes like they do, wheredart:convertwrites\band\f. - Flutter: the graph layer of
usesmileid_njia, generic over step kinds and facts like Android's and iOS's:NjiaGraphand its nodes, conditions and guards,NjiaIntentKind,NjiaWire(withNjiaWire.ofEnum(values)andNjiaWire.strings), andNjiaCodec'sdecodeGraph/encodeGraph, passing the corpus's graph codec cases. Conditions are built withNjiaCondition.allOf([…])andNjiaCondition.noneOf([…]). - Flutter:
validate()with the SPEC §4.4 issue codes (NjiaGraphIssue,NjiaIssueCode) andNjiaInvalidGraphException, 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 sealedNjiaPhaseofNjiaRunningPhase,NjiaBusyPhaseandNjiaDonePhase,NjiaOutcome), withtop,isBusy,isDone,hasand the graph'sstepOf, andNjiaCodec'sdecodeState,encodeStateanddecodeFacts.NjiaOutcomeredacts its detail when printed. - Flutter: the intents, typed by the SDK's facts: a sealed
NjiaIntent<F>, built withNjiaIntent.next(from:),back,skip,cancel,finish,busy,idleandfacts(set:, clear:)and matched on its<Case>Intentclasses, withkindandfrom, andNjiaCodec'sdecodeIntentandencodeIntent. All the corpus's intent codec cases pass. - Flutter: the effects and transitions: a sealed
NjiaEffect, with the four entry effects underNjiaEntryEffect,entryandisRefusal,NjiaTransition<F>withapplied, andNjiaCodec'sdecodeEffect,encodeEffect,encodeTransitionanddecodeTransition, 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'sNjiaBridge(SPEC §11):start,restoreandopenLinkwith the SDK's codec,sendandpreviewreturning transitions asynchronously and in order, listeners, anddispose. A refusal comes back asNjiaJsonException,NjiaInvalidGraphException(with its issues) or the newNjiaInconsistentStateException; a disposed engine or unknown handle is aStateError. - Flutter: the plugin's Android side:
NjiaPluginforwards each call to the core'sNjiaBridgeand turns a refusal into aFlutterErrorcoded by its wire name.example/runs integration tests against the real native engine, which theflutterlane runs on an emulator. - Flutter: the plugin's iOS side, a Swift package (
usesmileid_njia) whoseNjiaPluginforwards each call to the core'sNjiaBridgeand turns a refusal into aPigeonErrorcoded by its wire name. The example's integrat...
njia v0.0.1-SNAPSHOT.2
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
startAtcases, 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.0or1e0for one. Every decoder rejects an explicitnullwhere 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 byscripts/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
linkname, validated by three new issues (blankLink,duplicateLink,linkInsideSegment), andopenLink(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. 8linkscases; the bridges gainopenLink. - The harness contract (SPEC §12) opens deep links:
njiaharness://link/<name>?graph=<file>&facts=<JSON list>runsopenLink, showing the flow ornjia.refused.gen_maestro.pywrites one flow perlinkscase intomaestro/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,invalidGraphwith its issues,inconsistentState,wrongThread,unknownHandle), listed in the corpus'swire.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 wasrestored, and canpreviewan intent without applying it; the bridges gainrestoreandpreviewtoo. The delivery gate lets go of its receiver after teardown and ignores a laterattach. SPEC §9 saysteardowndoesn'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'scancel()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.restoreandNjiaKit.openLinkcreate an engine asNjiaEngine's factories do, andNjiaKit.versionnames the release, the same string on all four. It isn'tNjia, 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.pydraws 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 fromencodeGraph. - 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.answeredreports it,state.answer(step)reads it, andNjiaAnswerFormat<R>types it. Its codec cases are incodec, its 5 scenarios inconformance/scenarios/with Maestro flows, after a staged rollout. - Android: answers:
NjiaIntent.Answer,NjiaEffect.Answered,NjiaEntry.answer(redacted fromtoString, like an outcome's detail),state.answer(step),NjiaNavigator.answer(value)andengine.answer(from, value), withNjiaAnswerFormat<R>for typed answers.FakeNjiaNavigatorrecords them asCall.Answer(value)and hands one back withexpectAnswer(). - 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.pychecks a document against the reference reducer. The corpus'stracesection 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 byNjiaDependencyKey<T>). Every host also gives a stepscope.retained(key) { value }, kept until its entry is popped and closed then, and apausablevalue that holds while its step is covered. - Flutter: the
njia-flutterpackage (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\uescapes like they do, wheredart:convertwrites\band\f. - Flutter: the graph layer of
usesmileid_njia, generic over step kinds and facts like Android's and iOS's:NjiaGraphand its nodes, conditions and guards,NjiaIntentKind,NjiaWire(withNjiaWire.ofEnum(values)andNjiaWire.strings), andNjiaCodec'sdecodeGraph/encodeGraph, passing the corpus's graph codec cases. Conditions are built withNjiaCondition.allOf([…])andNjiaCondition.noneOf([…]). - Flutter:
validate()with the SPEC §4.4 issue codes (NjiaGraphIssue,NjiaIssueCode) andNjiaInvalidGraphException, 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 sealedNjiaPhaseofNjiaRunningPhase,NjiaBusyPhaseandNjiaDonePhase,NjiaOutcome), withtop,isBusy,isDone,hasand the graph'sstepOf, andNjiaCodec'sdecodeState,encodeStateanddecodeFacts.NjiaOutcomeredacts its detail when printed. - Flutter: the intents, typed by the SDK's facts: a sealed
NjiaIntent<F>, built withNjiaIntent.next(from:),back,skip,cancel,finish,busy,idleandfacts(set:, clear:)and matched on its<Case>Intentclasses, withkindandfrom, andNjiaCodec'sdecodeIntentandencodeIntent. All the corpus's intent codec cases pass. - Flutter: the effects and transitions: a sealed
NjiaEffect, with the four entry effects underNjiaEntryEffect,entryandisRefusal,NjiaTransition<F>withapplied, andNjiaCodec'sdecodeEffect,encodeEffect,encodeTransitionanddecodeTransition, 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'sNjiaBridge(SPEC §11):start,restoreandopenLinkwith the SDK's codec,sendandpreviewreturning transitions asynchronously and in order, listeners, anddispose. A refusal comes back asNjiaJsonException,NjiaInvalidGraphException(with its issues) or the newNjiaInconsistentStateException; a disposed engine or unknown handle is aStateError. - Flutter: the plugin's Android side:
NjiaPluginforwards each call to the core'sNjiaBridgeand turns a refusal into aFlutterErrorcoded by its wire name.example/runs integration tests against the real native engine, which theflutterlane runs on an emulator. - Flutter: the plugin's iOS side, a Swift package (
usesmileid_njia) whoseNjiaPluginforwards each call to the core'sNjiaBridgeand turns a refusal into aPigeonErrorcoded 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): aNavigatorwhose pages are the engine's entries, keyed by entry id, with the shared fade-and-slide motion (none under reduced motion), thenjia.step.<step>semantics identifier (stepIds), and aPopScopethat sends back from the top; a step that pops its own route s...