feat(IT-Wallet): [SIW-4149] Credential offer from third channel#8047
Open
riccardosacco99 wants to merge 50 commits into
Open
feat(IT-Wallet): [SIW-4149] Credential offer from third channel#8047riccardosacco99 wants to merge 50 commits into
riccardosacco99 wants to merge 50 commits into
Conversation
Contributor
Jira Pull Request LinkThis Pull Request refers to Jira issues: |
Contributor
PR Title Validation for conventional commit type✅ All good! PR title follows the conventional commit type. |
… and close actions
…ayout and loading handling
# Conflicts: # apps/main-app/ts/features/itwallet/machine/credential/__tests__/actors.test.ts # apps/main-app/ts/utils/__tests__/internalLink.test.ts
…edential offer intro
…nd deep link normalization
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new “credential offer” issuance entry point for IT-Wallet, allowing users to start credential issuance by scanning a credential-offer QR code or opening a credential-offer deep link (custom scheme / universal link), normalizing and routing the incoming URL into the existing issuance state machine.
Changes:
- Added credential-offer deep link normalization + routing (warm/cold start) and corresponding navigation route registration.
- Extended the ITW credential issuance machine with credential-offer validation/resolution states and a new intro screen that kicks off the offer processing.
- Added a new barcode type/decoder for credential offers, with unit/integration tests for normalization and navigation replay behavior.
Reviewed changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/main-app/ts/navigation/linkingSubscription.ts | Normalizes credential-offer links on warm-start subscription before passing them to React Navigation. |
| apps/main-app/ts/navigation/AppStackNavigator.tsx | Adds credential-offer prefixes and normalizes initial URL before storing for replay. |
| apps/main-app/ts/navigation/test/linkingSubscription.test.ts | Tests normalization behavior for credential-offer URLs on subscription events. |
| apps/main-app/ts/features/linking/sagas/index.ts | Replays stored credential-offer URLs after login by navigating to the ITW intro screen. |
| apps/main-app/ts/features/linking/sagas/test/index.test.ts | Tests stored-link replay navigation for credential-offer URLs. |
| apps/main-app/ts/features/itwallet/offer/utils/index.ts | Adds detection/normalization helpers for credential-offer invocations and extraction. |
| apps/main-app/ts/features/itwallet/offer/utils/tests/index.test.ts | Unit tests for credential-offer invocation detection + normalization helper. |
| apps/main-app/ts/features/itwallet/offer/screens/ItwIssuanceCredentialOfferIntro.tsx | New intro screen that starts offer resolution and continues into the issuance flow. |
| apps/main-app/ts/features/itwallet/offer/screens/tests/ItwIssuanceCredentialOfferIntro.test.tsx | Screen test ensuring redirection behavior when wallet lifecycle requires discovery. |
| apps/main-app/ts/features/itwallet/navigation/useItwLinkingOptions.tsx | Registers the universal-link path for credential-offer intro screen. |
| apps/main-app/ts/features/itwallet/navigation/routes.ts | Adds the new ITW issuance route constant for credential-offer intro. |
| apps/main-app/ts/features/itwallet/navigation/ItwStackNavigator.tsx | Registers the new intro screen in the ITW stack with hidden header. |
| apps/main-app/ts/features/itwallet/navigation/ItwParamsList.ts | Adds route params typing for the credential-offer intro route. |
| apps/main-app/ts/features/itwallet/machine/credential/selectors.ts | Adds selector to expose resolved credential-offer data from machine context. |
| apps/main-app/ts/features/itwallet/machine/credential/machine.ts | Introduces offer validation/resolution states and wires resolved offer into later steps. |
| apps/main-app/ts/features/itwallet/machine/credential/events.ts | Adds start/confirm events for credential-offer flow. |
| apps/main-app/ts/features/itwallet/machine/credential/context.ts | Extends machine context with credentialOfferUri + resolvedCredentialOffer. |
| apps/main-app/ts/features/itwallet/machine/credential/actors.ts | Adds actor to resolve/extract grant details from credential-offer URIs and passes offer context through. |
| apps/main-app/ts/features/itwallet/machine/credential/tests/machine.test.ts | Adds test coverage for credential-offer machine paths and context propagation. |
| apps/main-app/ts/features/itwallet/common/utils/itwTypesUtils.ts | Introduces a CredentialOfferResolved type used across machine + issuance utils. |
| apps/main-app/ts/features/itwallet/common/utils/itwCredentialIssuanceUtils.ts | Allows requesting credentials using issuer/config IDs from a resolved offer. |
| apps/main-app/ts/features/itwallet/common/utils/tests/itwCredentialIssuanceUtils.test.ts | Adds unit test coverage for offer-driven issuer/config selection in requestCredential. |
| apps/main-app/ts/features/barcode/utils/tests/imageDecodingTask.test.ts | Updates mocked state to include ITW specs version for new barcode decoder behavior. |
| apps/main-app/ts/features/barcode/types/decoders.ts | Adds ITW_CREDENTIAL_OFFER barcode type + decoder gated by supported specs version. |
| apps/main-app/ts/features/barcode/types/tests/decoders.test.ts | Adds coverage for credential-offer barcode decoding across valid/invalid cases. |
| apps/main-app/ts/features/barcode/screens/BarcodeScanScreen.tsx | Routes credential-offer scans into the ITW credential-offer intro screen. |
| apps/main-app/locales/it/index.json | Adds i18n fallback title for credential-offer intro. |
| apps/main-app/ios/IO/Info.plist | Registers iOS custom URL schemes for credential-offer invocation. |
| apps/main-app/android/app/src/main/AndroidManifest.xml | Registers Android intent-filters for credential-offer custom schemes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
14cd0c0 to
a244796
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds the credential offer issuance channel, allowing the user to start an IT-Wallet credential issuance by scanning a credential offer QR code or opening a credential offer deep link / universal link. The incoming URI is
validated, resolved through the IT-Wallet SDK, and then fed into the existing
itwCredentialIssuanceMachine, which drives the user to the new intro screen before continuing with the standard issuance flow.List of changes proposed in this pull request
Credential machine:
CredentialOfferValidationandCredentialOfferResolvedstates toitwCredentialIssuanceMachineprocessCredentialOfferactor that resolves the offer URI and extracts grant details via@pagopa/io-react-native-walletcredentialOfferUriandresolvedCredentialOfferto the machine context, plusselectResolvedCredentialOfferOptionstart-credential-offerandconfirm-credential-offereventswaitForSessionRefreshstub tofromCallbackto match the sharedcreateCommonActorsImplementationcontract (unblocks the typecheck broken by the test-side provider)Screens:
ItwIssuanceCredentialOfferIntroScreen— on focus it dispatchesstart-credential-offerto the machine, shows a loading state while the offer is resolved, and on user confirmation dispatchesconfirm-credential-offertocontinue into the standard issuance flow
Barcode:
ITW_CREDENTIAL_OFFERbarcode type anddecodeItwCredentialOfferBarcodeinbarcode/types/decoders.tsisPotentialCredentialOfferInvocationutility that detects the three supported formats (openid-credential-offer://,haip-vci://, andhttps://withcredential_offer/credential_offer_uriquery params)BarcodeScanScreento route decoded offers to the new intro screenNavigation:
ITW_ISSUANCE_CREDENTIAL_OFFER_INTROroute inItwParamsList,ItwStackNavigator, andnavigation/routes.tsoptions={hiddenHeader}), aligning it with the rest of the ITW stack and preventing a flash of the raw route name beforeuseHeaderSecondLevelmounts the custom headerDeep link support:
openid-credential-offer://andhaip-vci://custom URL schemes natively (ios/IO/Info.plistCFBundleURLTypes,android/app/src/main/AndroidManifest.xmlintent-filters)credential-offerpath touseItwLinkingOptions, so universal links likehttps://continua.io.pagopa.it/itw/credential-offer?itwCredentialOfferUri=…are routed to the intro screengetInternalRouteto rewrite credential offer custom schemes — which carry the full payload in the query string and have no real path — intoioit://itw/credential-offer?itwCredentialOfferUri=<encoded>, reusingisPotentialCredentialOfferInvocationso QR, custom scheme and universal link share a single validation source of truthlinkingSubscription(warm start — app in background) and a customgetInitialURLinAppStackNavigator(cold start — app killed, which React Navigation would otherwise ignorebecause the custom scheme doesn't match its configured prefixes)
Tests:
internalLink.test.tscovering the three credential offer URI shapes plus a non-regression case for unrelated URLslinkingSubscription.test.tsverifying that both the React Navigation listener andstoreLinkingUrl(post-login replay) receive the normalized URL when a credential offer is receivedHow to test
IoWallet.CredentialsOffer.resolveCredentialOffer, available in@pagopa/io-react-native-walletonly from IT-Wallet specs v1.3.3 onwards. On lower versions the flow intentionally returns anUNEXPECTEDerror with"Missing v1.x.x compatible implementation for resolveCredentialOffer". This is the intended behaviour until the prod specs version is upgraded.QR code — main flow:
Scan the following QR code to verify the credential offer start flow reaches
ItwIssuanceCredentialOfferIntroScreen, resolves the offer, and — on confirmation — continues into the standard issuance flow:QR code — decoding validation:
To verify that non-offer barcodes are correctly ignored, scan a QR code whose payload does not match any supported scheme or query parameter (e.g. a plain URL like
https://example.com). Expected: the scanner falls back to its defaulthandling — no navigation to the intro screen.
Deep link — from external camera app:
Scan the QR code above from the default camera app of your smartphone. Expected: the OS opens IO and routes to
ItwIssuanceCredentialOfferIntroScreen(after login if not authenticated), the offer is resolved and shown.Deep link — custom scheme (cold start):
With IO killed, trigger the URL directly:
Expected: IO launches and lands on the intro screen with the offer resolved.
Deep link — custom scheme (warm start):
With IO in the background, trigger the same commands. Expected: IO returns to foreground on the intro screen.
Universal link:
xcrun simctl openurl booted "https://continua.io.pagopa.it/itw/credential-offer?itwCredentialOfferUri=openid-credential-offer%3A%2F%2F%3F..."Expected: same as above. Requires the universal link /itw/credential-offer path to be handled by the Apple App Site Association / Android Digital Asset Links config on continua.io.pagopa.it (backend coordination).
2026-04-23_scrcpy_002200.mp4