@smileid/usesmileid 12.0.0 → 12.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/dist/camera/camera_defaults.d.ts +2 -0
- package/dist/camera/camera_defaults.d.ts.map +1 -1
- package/dist/camera/camera_defaults.js +2 -0
- package/dist/camera/camera_defaults.js.map +1 -1
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts +11 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts.map +1 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js +17 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js.map +1 -0
- package/dist/core/exception/capture_validation_exceptions.d.ts +1 -0
- package/dist/core/exception/capture_validation_exceptions.d.ts.map +1 -1
- package/dist/core/exception/capture_validation_exceptions.js +1 -0
- package/dist/core/exception/capture_validation_exceptions.js.map +1 -1
- package/dist/core/exception/flow_exceptions.d.ts +4 -2
- package/dist/core/exception/flow_exceptions.d.ts.map +1 -1
- package/dist/core/exception/flow_exceptions.js +3 -2
- package/dist/core/exception/flow_exceptions.js.map +1 -1
- package/dist/core/exception/index.d.ts +1 -0
- package/dist/core/exception/index.d.ts.map +1 -1
- package/dist/core/exception/index.js +1 -0
- package/dist/core/exception/index.js.map +1 -1
- package/dist/core/exception/missing_job_type_exception.d.ts +1 -3
- package/dist/core/exception/missing_job_type_exception.d.ts.map +1 -1
- package/dist/core/exception/missing_job_type_exception.js +2 -4
- package/dist/core/exception/missing_job_type_exception.js.map +1 -1
- package/dist/core/exception/use_smile_id_error_code.d.ts +1 -0
- package/dist/core/exception/use_smile_id_error_code.d.ts.map +1 -1
- package/dist/core/exception/use_smile_id_error_code.js +1 -0
- package/dist/core/exception/use_smile_id_error_code.js.map +1 -1
- package/dist/core/models/config.d.ts +19 -0
- package/dist/core/models/config.d.ts.map +1 -1
- package/dist/core/models/document_type.d.ts +1 -1
- package/dist/core/models/document_type.d.ts.map +1 -1
- package/dist/core/models/document_type.js +2 -2
- package/dist/core/models/document_type.js.map +1 -1
- package/dist/core/models/global_privacy_control.d.ts +36 -0
- package/dist/core/models/global_privacy_control.d.ts.map +1 -0
- package/dist/core/models/global_privacy_control.js +39 -0
- package/dist/core/models/global_privacy_control.js.map +1 -0
- package/dist/core/models/network_config.d.ts +2 -2
- package/dist/core/models/network_config.js +2 -2
- package/dist/data/api/interceptors/smile_auth_interceptor.d.ts.map +1 -1
- package/dist/data/api/interceptors/smile_auth_interceptor.js +3 -17
- package/dist/data/api/interceptors/smile_auth_interceptor.js.map +1 -1
- package/dist/data/api/smile_id_api.d.ts +5 -1
- package/dist/data/api/smile_id_api.d.ts.map +1 -1
- package/dist/data/api/smile_id_api.js +30 -27
- package/dist/data/api/smile_id_api.js.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.d.ts +4 -4
- package/dist/data/dsl/builder/retry_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.js +6 -6
- package/dist/data/dsl/builder/retry_config_builder.js.map +1 -1
- package/dist/data/model/job_request.d.ts +28 -12
- package/dist/data/model/job_request.d.ts.map +1 -1
- package/dist/data/model/token_payload.d.ts +78 -0
- package/dist/data/model/token_payload.d.ts.map +1 -0
- package/dist/data/model/token_payload.js +132 -0
- package/dist/data/model/token_payload.js.map +1 -0
- package/dist/data/model/user_details_payload.d.ts +39 -0
- package/dist/data/model/user_details_payload.d.ts.map +1 -0
- package/dist/data/model/user_details_payload.js +53 -0
- package/dist/data/model/user_details_payload.js.map +1 -0
- package/dist/data/smile_id_urls.d.ts +1 -1
- package/dist/data/smile_id_urls.js +1 -1
- package/dist/data/smile_id_urls.js.map +1 -1
- package/dist/data/util/retry_util.d.ts +1 -1
- package/dist/data/util/retry_util.d.ts.map +1 -1
- package/dist/data/util/retry_util.js +5 -0
- package/dist/data/util/retry_util.js.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.d.ts +15 -3
- package/dist/data/util/use_smile_id_token_decoder.d.ts.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.js +20 -8
- package/dist/data/util/use_smile_id_token_decoder.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/l10n/strings_en.d.ts +4 -1
- package/dist/l10n/strings_en.d.ts.map +1 -1
- package/dist/l10n/strings_en.js +4 -1
- package/dist/l10n/strings_en.js.map +1 -1
- package/dist/l10n/use_smile_id_localizations.d.ts +10 -0
- package/dist/l10n/use_smile_id_localizations.d.ts.map +1 -1
- package/dist/l10n/use_smile_id_localizations.js +59 -3
- package/dist/l10n/use_smile_id_localizations.js.map +1 -1
- package/dist/metadata/builder_configuration.d.ts +5 -0
- package/dist/metadata/builder_configuration.d.ts.map +1 -1
- package/dist/metadata/builder_configuration.js +1 -0
- package/dist/metadata/builder_configuration.js.map +1 -1
- package/dist/metadata/metadata_configuration_mappers.d.ts +2 -3
- package/dist/metadata/metadata_configuration_mappers.d.ts.map +1 -1
- package/dist/metadata/metadata_configuration_mappers.js +13 -6
- package/dist/metadata/metadata_configuration_mappers.js.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.d.ts.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.js +14 -5
- package/dist/metadata/use_smile_id_metadata_factory.js.map +1 -1
- package/dist/presentation/components/use_smile_id_button.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_button.js +8 -2
- package/dist/presentation/components/use_smile_id_button.js.map +1 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts +5 -2
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js +8 -3
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.js +8 -3
- package/dist/presentation/components/use_smile_id_instructions_hero.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts +16 -0
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.js +18 -0
- package/dist/presentation/flow/dsl/builder/config_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +6 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.js +7 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +23 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.d.ts +22 -3
- package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.js +84 -46
- package/dist/presentation/flow/flow_navigation_manager.js.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.d.ts.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_capture_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js +13 -3
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.js +3 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js +0 -8
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js +25 -5
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js.map +1 -1
- package/dist/presentation/flow/use_smile_id_flow.d.ts.map +1 -1
- package/dist/presentation/flow/use_smile_id_flow.js +45 -12
- package/dist/presentation/flow/use_smile_id_flow.js.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.d.ts +16 -2
- package/dist/presentation/flow/validation/flow_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.js +61 -47
- package/dist/presentation/flow/validation/flow_validator.js.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.d.ts +7 -0
- package/dist/presentation/flow/validation/job_type_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.js +52 -27
- package/dist/presentation/flow/validation/job_type_validator.js.map +1 -1
- package/dist/presentation/flow/validation/user_details_validator.d.ts +9 -0
- package/dist/presentation/flow/validation/user_details_validator.d.ts.map +1 -0
- package/dist/presentation/flow/validation/user_details_validator.js +40 -0
- package/dist/presentation/flow/validation/user_details_validator.js.map +1 -0
- package/dist/presentation/screen/helpers/capture_screen_helpers.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/capture_screen_helpers.js +1 -0
- package/dist/presentation/screen/helpers/capture_screen_helpers.js.map +1 -1
- package/dist/presentation/screen/helpers/capture_ui_state.d.ts +6 -6
- package/dist/presentation/screen/helpers/capture_ui_state.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/capture_ui_state.js +19 -19
- package/dist/presentation/screen/helpers/capture_ui_state.js.map +1 -1
- package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts +2 -2
- package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/ess_turn_haptics.js +6 -6
- package/dist/presentation/screen/helpers/ess_turn_haptics.js.map +1 -1
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts +5 -5
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js +11 -11
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js.map +1 -1
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts +13 -3
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.js +48 -6
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +4 -2
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.js +90 -23
- package/dist/presentation/screen/use_smile_id_capture_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_consent_screen.d.ts +7 -0
- package/dist/presentation/screen/use_smile_id_consent_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_consent_screen.js +6 -5
- package/dist/presentation/screen/use_smile_id_consent_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_back_instructions.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_back_instructions.js +5 -13
- package/dist/presentation/screen/use_smile_id_document_back_instructions.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts +1 -21
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.js +3 -14
- package/dist/presentation/screen/use_smile_id_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js.map +1 -1
- package/dist/presentation/utils/locale_utils.d.ts +10 -4
- package/dist/presentation/utils/locale_utils.d.ts.map +1 -1
- package/dist/presentation/utils/locale_utils.js +13 -5
- package/dist/presentation/utils/locale_utils.js.map +1 -1
- package/dist/testing/fake_face_analyzer.d.ts +43 -0
- package/dist/testing/fake_face_analyzer.d.ts.map +1 -0
- package/dist/testing/fake_face_analyzer.js +52 -0
- package/dist/testing/fake_face_analyzer.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +7 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/scenario_expectations.d.ts +28 -0
- package/dist/testing/scenario_expectations.d.ts.map +1 -0
- package/dist/testing/scenario_expectations.js +65 -0
- package/dist/testing/scenario_expectations.js.map +1 -0
- package/dist/testing/scenario_loader.d.ts +11 -0
- package/dist/testing/scenario_loader.d.ts.map +1 -0
- package/dist/testing/scenario_loader.js +64 -0
- package/dist/testing/scenario_loader.js.map +1 -0
- package/dist/testing/scripted_scan_results.d.ts +17 -0
- package/dist/testing/scripted_scan_results.d.ts.map +1 -0
- package/dist/testing/scripted_scan_results.js +52 -0
- package/dist/testing/scripted_scan_results.js.map +1 -0
- package/package.json +11 -4
- package/src/__tests__/dsl.test.ts +51 -1
- package/src/__tests__/react_native_mock.tsx +22 -0
- package/src/__tests__/setup_react_native.ts +17 -2
- package/src/__tests__/snapshots/__snapshots__/screens_structural.test.tsx.snap +5267 -0
- package/src/__tests__/snapshots/screens_structural.test.tsx +230 -0
- package/src/camera/__tests__/camera_permissions.test.ts +72 -0
- package/src/camera/__tests__/camera_system_focus.test.ts +173 -0
- package/src/camera/__tests__/use_smile_id_camera_preview.test.tsx +461 -0
- package/src/camera/__tests__/use_smile_id_camera_system.test.ts +103 -0
- package/src/camera/__tests__/use_smile_id_frame_stream_hook.test.tsx +229 -0
- package/src/camera/camera_defaults.ts +3 -0
- package/src/core/exception/__tests__/builder_validation_exceptions.test.ts +81 -0
- package/src/core/exception/agent_mode_with_enhanced_liveness_exception.ts +20 -0
- package/src/core/exception/capture_validation_exceptions.ts +1 -0
- package/src/core/exception/flow_exceptions.test.ts +10 -0
- package/src/core/exception/flow_exceptions.ts +3 -2
- package/src/core/exception/index.ts +1 -0
- package/src/core/exception/missing_job_type_exception.ts +2 -4
- package/src/core/exception/use_smile_id_error_code.ts +1 -0
- package/src/core/models/__tests__/document_type.test.ts +2 -2
- package/src/core/models/__tests__/flow_models.test.ts +26 -0
- package/src/core/models/config.ts +22 -0
- package/src/core/models/document_type.ts +2 -2
- package/src/core/models/global_privacy_control.ts +45 -0
- package/src/core/models/network_config.ts +2 -2
- package/src/data/api/__tests__/smile_id_api.test.ts +275 -1
- package/src/data/api/interceptors/__tests__/credential_header_redaction.test.ts +144 -0
- package/src/data/api/interceptors/__tests__/gzip_interceptor.test.ts +83 -0
- package/src/data/api/interceptors/smile_auth_interceptor.ts +3 -18
- package/src/data/api/smile_id_api.ts +36 -49
- package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +6 -2
- package/src/data/dsl/__tests__/use_smile_id_network_builder.test.ts +157 -0
- package/src/data/dsl/builder/__tests__/config_builders.test.ts +62 -0
- package/src/data/dsl/builder/retry_config_builder.ts +6 -6
- package/src/data/factory/__tests__/retry_gzip_mac_composition.test.ts +163 -0
- package/src/data/factory/__tests__/signed_job_submission_headers.test.ts +1 -1
- package/src/data/model/__tests__/token_payload.test.ts +224 -0
- package/src/data/model/__tests__/user_details_payload.test.ts +100 -0
- package/src/data/model/job_request.ts +27 -12
- package/src/data/model/token_payload.ts +182 -0
- package/src/data/model/user_details_payload.ts +84 -0
- package/src/data/repository/__tests__/network_retries.test.ts +1 -1
- package/src/data/repository/__tests__/repository_dispatch.test.ts +366 -0
- package/src/data/repository/__tests__/use_smile_id_repository.test.ts +1 -1
- package/src/data/security/__tests__/request_canonicalizer.test.ts +132 -0
- package/src/data/security/__tests__/signing_crypto.test.ts +203 -0
- package/src/data/smile_id_urls.ts +1 -1
- package/src/data/util/__tests__/retry_util.test.ts +25 -0
- package/src/data/util/__tests__/use_smile_id_token_decoder.test.ts +179 -0
- package/src/data/util/retry_util.ts +9 -1
- package/src/data/util/use_smile_id_token_decoder.ts +29 -8
- package/src/index.ts +6 -4
- package/src/l10n/__tests__/use_smile_id_localizations.test.ts +122 -5
- package/src/l10n/__tests__/use_smile_id_localizations_provider.test.tsx +112 -0
- package/src/l10n/__tests__/use_smile_id_localizations_surface.test.ts +231 -0
- package/src/l10n/strings_en.ts +5 -1
- package/src/l10n/use_smile_id_localizations.ts +80 -3
- package/src/metadata/__tests__/device_orientation_sampling.test.ts +165 -0
- package/src/metadata/__tests__/geolocation.test.ts +150 -0
- package/src/metadata/__tests__/metadata_configuration_mappers.test.ts +39 -0
- package/src/metadata/__tests__/metadata_configuration_objects.test.ts +2 -1
- package/src/metadata/__tests__/metadata_device_context.test.ts +3 -3
- package/src/metadata/__tests__/metadata_device_os_android.test.ts +18 -0
- package/src/metadata/__tests__/metadata_golden_fixture.json +1 -1
- package/src/metadata/__tests__/metadata_payload_golden.test.ts +4 -4
- package/src/metadata/__tests__/optional_native_modules.test.ts +234 -0
- package/src/metadata/__tests__/use_smile_id_metadata.test.ts +1 -1
- package/src/metadata/__tests__/use_smile_id_metadata_factory.test.ts +615 -0
- package/src/metadata/builder_configuration.ts +6 -0
- package/src/metadata/metadata_configuration_mappers.ts +21 -7
- package/src/metadata/use_smile_id_metadata_factory.ts +17 -6
- package/src/presentation/assets/si_document_green_book_hero_animation.json +1 -4668
- package/src/presentation/assets/si_document_hero_animation.json +1 -4799
- package/src/presentation/assets/si_document_hero_back_animation.json +1 -2039
- package/src/presentation/assets/si_document_passport_hero_animation.json +1 -14491
- package/src/presentation/assets/si_ess_all_directions_hero_animation.json +1 -0
- package/src/presentation/assets/si_ess_animation_all_directions.json +1 -6589
- package/src/presentation/assets/si_selfie_hero_animation.json +1 -1439
- package/src/presentation/assets/si_smile_to_capture_animation.json +1 -1439
- package/src/presentation/components/__tests__/use_smile_id_content_card.test.tsx +112 -0
- package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +9 -4
- package/src/presentation/components/__tests__/use_smile_id_face_oval_image.test.tsx +190 -0
- package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +44 -0
- package/src/presentation/components/__tests__/use_smile_id_learn_more_content.test.tsx +159 -0
- package/src/presentation/components/__tests__/use_smile_id_processing_center_indicator.test.tsx +88 -0
- package/src/presentation/components/use_smile_id_button.tsx +7 -2
- package/src/presentation/components/use_smile_id_enhanced_smart_selfie_clip.tsx +9 -3
- package/src/presentation/components/use_smile_id_instructions_hero.tsx +10 -0
- package/src/presentation/flow/__tests__/document_flow_navigation.test.ts +3 -3
- package/src/presentation/flow/__tests__/flow_navigation_manager.test.ts +372 -1
- package/src/presentation/flow/__tests__/use_smile_id_flow.test.tsx +651 -0
- package/src/presentation/flow/dsl/__tests__/use_smile_id_builder_component.test.tsx +120 -0
- package/src/presentation/flow/dsl/builder/__tests__/config_builder.test.ts +25 -0
- package/src/presentation/flow/dsl/builder/config_builder.ts +21 -0
- package/src/presentation/flow/dsl/builder/screens_builder.ts +7 -12
- package/src/presentation/flow/dsl/use_smile_id_flow_builder.ts +27 -1
- package/src/presentation/flow/flow_navigation_manager.ts +108 -93
- package/src/presentation/flow/graph/__tests__/screen_renderer.test.tsx +102 -0
- package/src/presentation/flow/model/instructions_defaults.ts +1 -1
- package/src/presentation/flow/screen/__tests__/orchestrated_capture_screen.test.tsx +836 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_consent_screen.test.tsx +165 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_instructions_screen.test.tsx +163 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_preview_screen.test.tsx +224 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_processing_screen.test.tsx +338 -0
- package/src/presentation/flow/screen/orchestrated_capture_screen.tsx +18 -3
- package/src/presentation/flow/screen/orchestrated_consent_screen.tsx +5 -0
- package/src/presentation/flow/screen/orchestrated_preview_screen.tsx +0 -12
- package/src/presentation/flow/screen/orchestrated_processing_screen.tsx +42 -5
- package/src/presentation/flow/use_smile_id_flow.tsx +63 -12
- package/src/presentation/flow/validation/__tests__/flow_validator.test.ts +219 -1
- package/src/presentation/flow/validation/__tests__/job_type_validator.test.ts +200 -0
- package/src/presentation/flow/validation/flow_validator.ts +85 -57
- package/src/presentation/flow/validation/job_type_validator.ts +73 -39
- package/src/presentation/flow/validation/user_details_validator.ts +53 -0
- package/src/presentation/screen/__tests__/capture_ui_state.test.ts +66 -47
- package/src/presentation/screen/__tests__/ess_turn_haptics.test.ts +15 -11
- package/src/presentation/screen/__tests__/feedback_copy_table.test.ts +145 -0
- package/src/presentation/screen/__tests__/scan_state_to_overlay_state.test.ts +47 -27
- package/src/presentation/screen/__tests__/use_smile_id_capture_screen.test.tsx +524 -14
- package/src/presentation/screen/__tests__/use_smile_id_document_back_instructions.test.tsx +4 -2
- package/src/presentation/screen/__tests__/use_smile_id_permission_screen.test.tsx +68 -0
- package/src/presentation/screen/__tests__/use_smile_id_preview_screen.test.tsx +10 -40
- package/src/presentation/screen/helpers/__tests__/use_capture_orientation_lock.test.tsx +212 -0
- package/src/presentation/screen/helpers/capture_screen_helpers.ts +1 -0
- package/src/presentation/screen/helpers/capture_ui_state.ts +27 -27
- package/src/presentation/screen/helpers/ess_turn_haptics.ts +9 -9
- package/src/presentation/screen/helpers/scan_state_to_overlay_state.ts +13 -13
- package/src/presentation/screen/helpers/use_capture_orientation_lock.ts +69 -7
- package/src/presentation/screen/use_smile_id_capture_screen.tsx +107 -28
- package/src/presentation/screen/use_smile_id_consent_screen.tsx +16 -5
- package/src/presentation/screen/use_smile_id_document_back_instructions.tsx +14 -23
- package/src/presentation/screen/use_smile_id_document_preview_screen.tsx +1 -1
- package/src/presentation/screen/use_smile_id_preview_screen.tsx +13 -45
- package/src/presentation/screen/use_smile_id_processing_screen.tsx +1 -1
- package/src/presentation/theme/__tests__/use_use_smile_id_fonts.test.tsx +166 -0
- package/src/presentation/utils/__tests__/locale_utils.test.ts +46 -5
- package/src/presentation/utils/locale_utils.ts +13 -4
- package/src/testing/__tests__/fake_face_analyzer.test.ts +42 -0
- package/src/testing/__tests__/scenario_expectations.test.ts +110 -0
- package/src/testing/__tests__/scenario_loader.test.ts +64 -0
- package/src/testing/fake_face_analyzer.ts +82 -0
- package/src/testing/index.ts +15 -0
- package/src/testing/scenario_expectations.ts +87 -0
- package/src/testing/scenario_loader.ts +83 -0
- package/src/testing/scripted_scan_results.ts +66 -0
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts +0 -15
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js +0 -19
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js.map +0 -1
- package/src/presentation/components/use_smile_id_face_silhouette_overlay.tsx +0 -27
|
@@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
Animated,
|
|
4
4
|
Easing,
|
|
5
|
+
Platform,
|
|
5
6
|
StyleSheet,
|
|
6
7
|
View,
|
|
7
8
|
type LayoutChangeEvent,
|
|
@@ -160,6 +161,13 @@ export function UseSmileIDInstructionsHero({
|
|
|
160
161
|
// motion is reduced; otherwise let it play on its own clock (autoPlay+loop).
|
|
161
162
|
const lottieDrivenByProgress = showOvalProgress || reducedMotion;
|
|
162
163
|
|
|
164
|
+
// lottie-ios's Core Animation engine mis-renders the document heroes' track mattes,
|
|
165
|
+
// so oval-less heroes use the main-thread engine on iOS; Android keeps its default.
|
|
166
|
+
const renderModeProps =
|
|
167
|
+
Platform.OS === "ios" && !showOval
|
|
168
|
+
? ({ renderMode: "SOFTWARE" } as const)
|
|
169
|
+
: {};
|
|
170
|
+
|
|
163
171
|
// Inset the ring by half the stroke so it isn't clipped at the SVG edge.
|
|
164
172
|
const ellipseProps = {
|
|
165
173
|
cx: ovalWidth / 2,
|
|
@@ -196,6 +204,7 @@ export function UseSmileIDInstructionsHero({
|
|
|
196
204
|
autoPlay={!lottieDrivenByProgress}
|
|
197
205
|
loop={!lottieDrivenByProgress}
|
|
198
206
|
{...(lottieDrivenByProgress ? { progress: heroProgress } : {})}
|
|
207
|
+
{...renderModeProps}
|
|
199
208
|
resizeMode="contain"
|
|
200
209
|
style={{ width: cardWidth, height: cardHeight }}
|
|
201
210
|
/>
|
|
@@ -266,6 +275,7 @@ export function UseSmileIDInstructionsHero({
|
|
|
266
275
|
autoPlay={!lottieDrivenByProgress}
|
|
267
276
|
loop={!lottieDrivenByProgress}
|
|
268
277
|
{...(lottieDrivenByProgress ? { progress: heroProgress } : {})}
|
|
278
|
+
{...renderModeProps}
|
|
269
279
|
style={{
|
|
270
280
|
position: "absolute",
|
|
271
281
|
width: animationSize,
|
|
@@ -74,15 +74,15 @@ describe("FlowNavigationManager — document per-side preview loop", () => {
|
|
|
74
74
|
true,
|
|
75
75
|
);
|
|
76
76
|
|
|
77
|
-
const
|
|
77
|
+
const greenBookFlow = buildScreens((screens) => {
|
|
78
78
|
screens.capture((capture) => {
|
|
79
79
|
capture.captureType = CaptureType.document;
|
|
80
80
|
capture.document((document) => {
|
|
81
|
-
document.documentType = DocumentType.
|
|
81
|
+
document.documentType = DocumentType.SouthAfricaGreenBook; // no back side
|
|
82
82
|
});
|
|
83
83
|
});
|
|
84
84
|
});
|
|
85
|
-
expect(makeManager(
|
|
85
|
+
expect(makeManager(greenBookFlow).documentCapturesBack()).toBe(false);
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
it("after the FRONT preview, routes back to the document capture for the BACK", () => {
|
|
@@ -21,7 +21,12 @@ import {
|
|
|
21
21
|
} from "../../../core/models/result";
|
|
22
22
|
import { JobType } from "../../../core/models/job_type";
|
|
23
23
|
import { DocumentType } from "../../../core/models/document_type";
|
|
24
|
-
import {
|
|
24
|
+
import { GlobalPrivacyControl } from "../../../core/models/global_privacy_control";
|
|
25
|
+
import {
|
|
26
|
+
MissingJobTypeException,
|
|
27
|
+
MissingRequiredFieldException,
|
|
28
|
+
UseSmileIDErrorCode,
|
|
29
|
+
} from "../../../core/exception";
|
|
25
30
|
import type { UseSmileIDAnalyticsEvent } from "../analytics/use_smile_id_analytics_event";
|
|
26
31
|
|
|
27
32
|
function buildScreens(block: (s: ScreensBuilder) => void): ScreensConfig {
|
|
@@ -528,6 +533,41 @@ describe("FlowNavigationManager — submission lifecycle", () => {
|
|
|
528
533
|
expect(manager.jobSubmissionState.kind).toBe("failure");
|
|
529
534
|
});
|
|
530
535
|
|
|
536
|
+
it("an unrecognised jobType fails submission with the typed builder exception", async () => {
|
|
537
|
+
const repository = new StubRepository();
|
|
538
|
+
const manager = makeManager(
|
|
539
|
+
buildScreens((screens) => screens.processing()),
|
|
540
|
+
vi.fn(),
|
|
541
|
+
{
|
|
542
|
+
userDetails: SAMPLE_USER_DETAILS,
|
|
543
|
+
network: {
|
|
544
|
+
config: {
|
|
545
|
+
jobType: 99 as JobType,
|
|
546
|
+
token: "k",
|
|
547
|
+
partnerConfig: {
|
|
548
|
+
partnerId: "p",
|
|
549
|
+
callbackUrl: "",
|
|
550
|
+
useSandbox: true,
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
repository,
|
|
556
|
+
);
|
|
557
|
+
|
|
558
|
+
manager.beginSubmissionIfNeeded();
|
|
559
|
+
await flushMicrotasks();
|
|
560
|
+
expect(manager.jobSubmissionState.kind).toBe("failure");
|
|
561
|
+
if (manager.jobSubmissionState.kind === "failure") {
|
|
562
|
+
expect(manager.jobSubmissionState.error).toBeInstanceOf(
|
|
563
|
+
MissingJobTypeException,
|
|
564
|
+
);
|
|
565
|
+
expect(
|
|
566
|
+
(manager.jobSubmissionState.error as MissingJobTypeException).errorCode,
|
|
567
|
+
).toBe(UseSmileIDErrorCode.Builder.MissingJobType);
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
|
|
531
571
|
it("beginSubmissionIfNeeded is idempotent — second call while loading is a no-op", async () => {
|
|
532
572
|
const repository = new StubRepository();
|
|
533
573
|
repository.manual = true;
|
|
@@ -602,6 +642,55 @@ describe("FlowNavigationManager — submission lifecycle", () => {
|
|
|
602
642
|
expect(manager.jobSubmissionState.kind).toBe("success");
|
|
603
643
|
});
|
|
604
644
|
|
|
645
|
+
it("retrySubmission double-trigger fires exactly one new submission", async () => {
|
|
646
|
+
// Concrete scenario: the processing screen's retry button is
|
|
647
|
+
// double-tapped after a failed submission. The second tap must not
|
|
648
|
+
// reset the in-flight `loading` latch and launch a duplicate job.
|
|
649
|
+
const repository = new StubRepository();
|
|
650
|
+
repository.result = failure(new Error("transient"));
|
|
651
|
+
const manager = makeManager(
|
|
652
|
+
buildScreens((screens) => screens.processing()),
|
|
653
|
+
vi.fn(),
|
|
654
|
+
{
|
|
655
|
+
enhancedKYCParams: {
|
|
656
|
+
idType: "BVN",
|
|
657
|
+
idNumber: "1",
|
|
658
|
+
country: "NG",
|
|
659
|
+
},
|
|
660
|
+
userDetails: SAMPLE_USER_DETAILS,
|
|
661
|
+
network: {
|
|
662
|
+
config: {
|
|
663
|
+
jobType: JobType.enhancedKyc,
|
|
664
|
+
token: "k",
|
|
665
|
+
partnerConfig: {
|
|
666
|
+
partnerId: "p",
|
|
667
|
+
callbackUrl: "",
|
|
668
|
+
useSandbox: true,
|
|
669
|
+
},
|
|
670
|
+
},
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
repository,
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
// Initial attempt fails, leaving the retry affordance visible.
|
|
677
|
+
manager.beginSubmissionIfNeeded();
|
|
678
|
+
await flushMicrotasks();
|
|
679
|
+
expect(manager.jobSubmissionState.kind).toBe("failure");
|
|
680
|
+
expect(repository.received).toHaveLength(1);
|
|
681
|
+
|
|
682
|
+
// The retried submission stays in flight so both taps land while
|
|
683
|
+
// the request is loading.
|
|
684
|
+
repository.manual = true;
|
|
685
|
+
manager.retrySubmission();
|
|
686
|
+
manager.retrySubmission(); // double-tap — ignored while in flight
|
|
687
|
+
|
|
688
|
+
await flushMicrotasks();
|
|
689
|
+
expect(manager.jobSubmissionState.kind).toBe("loading");
|
|
690
|
+
// Exactly one new submission: the initial failure plus one retry.
|
|
691
|
+
expect(repository.received).toHaveLength(2);
|
|
692
|
+
});
|
|
693
|
+
|
|
605
694
|
it("does not update state if the manager is disposed mid-submission", async () => {
|
|
606
695
|
const repository = new StubRepository();
|
|
607
696
|
repository.manual = true;
|
|
@@ -889,6 +978,288 @@ describe("FlowNavigationManager — request assembly per JobType", () => {
|
|
|
889
978
|
});
|
|
890
979
|
});
|
|
891
980
|
|
|
981
|
+
describe("FlowNavigationManager — token-provided user details & consent (assembly)", () => {
|
|
982
|
+
// Mint a structurally valid JWT with a caller-supplied payload — only
|
|
983
|
+
// the base64url-encoded middle segment is decoded.
|
|
984
|
+
function makeJwt(payload: Record<string, unknown>): string {
|
|
985
|
+
const payloadSegment = Buffer.from(JSON.stringify(payload)).toString(
|
|
986
|
+
"base64url",
|
|
987
|
+
);
|
|
988
|
+
return `eyJhbGciOiJub25lIn0.${payloadSegment}.stub-sig`;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
const completeConsentClaim = {
|
|
992
|
+
granted: true,
|
|
993
|
+
granted_at: "2026-01-01T09:00:00.000Z",
|
|
994
|
+
notice_language: "EN",
|
|
995
|
+
notice_privacy_policy_url: "https://partner.test/privacy",
|
|
996
|
+
} as const;
|
|
997
|
+
|
|
998
|
+
const fullBindingToken = makeJwt({
|
|
999
|
+
payload: {
|
|
1000
|
+
given_names: "pii_abc",
|
|
1001
|
+
last_name: "pii_def",
|
|
1002
|
+
email: "pii_ghi",
|
|
1003
|
+
phone_number: "pii_jkl",
|
|
1004
|
+
consent: completeConsentClaim,
|
|
1005
|
+
},
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
// Real tokens minted by the /v3/token deployment (same fixtures as
|
|
1009
|
+
// use_smile_id_token_decoder.test.ts): ES256-signed, expired minutes
|
|
1010
|
+
// after minting, PII values as opaque vault references. Decoded through
|
|
1011
|
+
// the production decoder so the whole flow — decode, screen skip,
|
|
1012
|
+
// assembly reduction — runs exactly as in production.
|
|
1013
|
+
const MINTED_FULL_BINDING_TOKEN =
|
|
1014
|
+
"eyJhbGciOiJFUzI1NiIsImtpZCI6ImtleV8wMWtibWd6bXczZXloOW5jdjlqcG1kNDlqZiIsInR5cCI6IkpXVCJ9." +
|
|
1015
|
+
"eyJhcGlfdXJsIjoiaHR0cHM6Ly92My10b2tlbi1jb25zZW50LXBheWxvYWQuYXBpLnNtaWxlaWQuY28vdjMiLCJrZXlfaWQiOiIyY2NjOWMyMy01Y2U3LTRkMGUtYWRkYy1lN2I1NGQ4YjkxZGQiLCJwYXlsb2FkIjp7ImNvbnNlbnQiOnsiZ3JhbnRlZCI6dHJ1ZSwiZ3JhbnRlZF9hdCI6IjIwMjYtMDEtMDFUMDk6MDA6MDAuMDAwWiIsIm5vdGljZV9sYW5ndWFnZSI6IkVOIiwibm90aWNlX3ByaXZhY3lfcG9saWN5X3VybCI6Imh0dHBzOi8vanVtYS5wcml2YWN5LXBvbGljeS5jb20ifSwiY291bnRyeSI6Ik5HIiwiaWRfdHlwZSI6Ik5JTl9WMiIsImVtYWlsIjoicGlpXzAxa3Azczl0NzhmZXg5MXFoNDZ5cDg3cmpxIiwiZ2l2ZW5fbmFtZXMiOiJwaWlfMDFrenJtMTcwdGY2OXJxOTUzOHJ6Z2V0eXoiLCJpZF9udW1iZXIiOiJwaWlfMDFra2dhYTliNWZ2Z2EyMnllZXM1ZjRyNnQiLCJsYXN0X25hbWUiOiJwaWlfMDFrcDNzOXQ3cmU4aHI2ZGVyOXEzbnB6N2MiLCJwaG9uZV9udW1iZXIiOiJwaWlfMDFrenJtdHdkeGZlenJ0dGRmOXQzc3Rzem4iLCJjYWxsYmFja191cmwiOiJjYWxsYmFja18wMWt6cm10d2VmZTV5YWgzbmR2NW03MDc3ZyJ9LCJwYXJ0bmVyX2lkIjoiMTQ4MyIsInBvbGljeSI6MTUsImF1ZCI6InNtaWxlaWQtYXBpIiwiZXhwIjoxNzg2NDYwNzEyLCJpYXQiOjE3ODY0NTk4MTIsImlzcyI6InNtaWxlaWQtYXV0aCJ9." +
|
|
1016
|
+
"cuZgo64eEt5vNvND_RvCVpJyTv4rqax9ebkLV4i4uI4raz6fBhazxspbaoErYC0wxwRmn5EhPAdAdDnNKI6tEQ";
|
|
1017
|
+
|
|
1018
|
+
const MINTED_NAMES_AND_EMAIL_TOKEN =
|
|
1019
|
+
"eyJhbGciOiJFUzI1NiIsImtpZCI6ImtleV8wMWtibWd6bXczZXloOW5jdjlqcG1kNDlqZiIsInR5cCI6IkpXVCJ9." +
|
|
1020
|
+
"eyJhcGlfdXJsIjoiaHR0cHM6Ly92My10b2tlbi1jb25zZW50LXBheWxvYWQuYXBpLnNtaWxlaWQuY28vdjMiLCJrZXlfaWQiOiIyY2NjOWMyMy01Y2U3LTRkMGUtYWRkYy1lN2I1NGQ4YjkxZGQiLCJwYXlsb2FkIjp7ImNvbnNlbnQiOnsiZ3JhbnRlZCI6dHJ1ZSwiZ3JhbnRlZF9hdCI6IjIwMjYtMDEtMDFUMDk6MDA6MDAuMDAwWiIsIm5vdGljZV9sYW5ndWFnZSI6IkVOIiwibm90aWNlX3ByaXZhY3lfcG9saWN5X3VybCI6Imh0dHBzOi8vanVtYS5wcml2YWN5LXBvbGljeS5jb20ifSwiZW1haWwiOiJwaWlfMDFrcDNzOXQ3OGZleDkxcWg0NnlwODdyanEiLCJnaXZlbl9uYW1lcyI6InBpaV8wMWt6cm0xNzB0ZjY5cnE5NTM4cnpnZXR5eiIsImxhc3RfbmFtZSI6InBpaV8wMWtwM3M5dDdyZThocjZkZXI5cTNucHo3YyJ9LCJwYXJ0bmVyX2lkIjoiMTQ4MyIsInBvbGljeSI6MTUsImF1ZCI6InNtaWxlaWQtYXBpIiwiZXhwIjoxNzg2NDU5ODcxLCJpYXQiOjE3ODY0NTg5NzEsImlzcyI6InNtaWxlaWQtYXV0aCJ9." +
|
|
1021
|
+
"s5BFthU2B1aKxYDYyyWYDmRpLoHibH34r2Lk4OS-wZQC8pmYROjWBiORx6n2_0srmxz_SA2eZo_FHyAr-ew_Zg";
|
|
1022
|
+
|
|
1023
|
+
function assemble(
|
|
1024
|
+
token: string,
|
|
1025
|
+
extraConfig: Partial<FlowConfigurationSnapshot> = {},
|
|
1026
|
+
seedManager: (m: FlowNavigationManager) => void = () => {},
|
|
1027
|
+
): {
|
|
1028
|
+
readonly repository: StubRepository;
|
|
1029
|
+
readonly manager: FlowNavigationManager;
|
|
1030
|
+
} {
|
|
1031
|
+
const repository = new StubRepository();
|
|
1032
|
+
const manager = makeManager(
|
|
1033
|
+
buildScreens((screens) => screens.processing()),
|
|
1034
|
+
vi.fn(),
|
|
1035
|
+
{
|
|
1036
|
+
enhancedKYCParams: {
|
|
1037
|
+
idType: "PASSPORT",
|
|
1038
|
+
idNumber: "X1",
|
|
1039
|
+
country: "NG",
|
|
1040
|
+
},
|
|
1041
|
+
...extraConfig,
|
|
1042
|
+
network: {
|
|
1043
|
+
config: {
|
|
1044
|
+
jobType: JobType.enhancedKyc,
|
|
1045
|
+
token,
|
|
1046
|
+
partnerConfig: {
|
|
1047
|
+
partnerId: "p",
|
|
1048
|
+
callbackUrl: "",
|
|
1049
|
+
useSandbox: true,
|
|
1050
|
+
},
|
|
1051
|
+
},
|
|
1052
|
+
},
|
|
1053
|
+
},
|
|
1054
|
+
repository,
|
|
1055
|
+
);
|
|
1056
|
+
seedManager(manager);
|
|
1057
|
+
manager.beginSubmissionIfNeeded();
|
|
1058
|
+
return { repository, manager };
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
it("assembles without userDetails when the token binds names + a contact field", () => {
|
|
1062
|
+
const { repository } = assemble(fullBindingToken);
|
|
1063
|
+
expect(repository.received).toHaveLength(1);
|
|
1064
|
+
const request = repository.received[0]!;
|
|
1065
|
+
expect(request.userDetails).toBeUndefined();
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
it("omits the consent record when token consent is complete and no local source exists", () => {
|
|
1069
|
+
// The DEFAULT_CONSENT granted:false placeholder must NOT be emitted
|
|
1070
|
+
// on the token-complete path — the server injects the token's consent.
|
|
1071
|
+
const { repository } = assemble(fullBindingToken, {
|
|
1072
|
+
userDetails: SAMPLE_USER_DETAILS,
|
|
1073
|
+
});
|
|
1074
|
+
const request = repository.received[0]!;
|
|
1075
|
+
expect(request.consent).toBeUndefined();
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
it("still throws MissingRequiredFieldException(userDetails) when the token binds names only", async () => {
|
|
1079
|
+
const namesOnlyToken = makeJwt({
|
|
1080
|
+
payload: { given_names: "pii_abc", last_name: "pii_def" },
|
|
1081
|
+
});
|
|
1082
|
+
const { repository, manager } = assemble(namesOnlyToken);
|
|
1083
|
+
await flushMicrotasks();
|
|
1084
|
+
expect(repository.received).toHaveLength(0);
|
|
1085
|
+
const state = manager.jobSubmissionState;
|
|
1086
|
+
expect(state.kind).toBe("failure");
|
|
1087
|
+
if (state.kind === "failure") {
|
|
1088
|
+
expect(state.error).toBeInstanceOf(MissingRequiredFieldException);
|
|
1089
|
+
expect(
|
|
1090
|
+
(state.error as MissingRequiredFieldException).errorDetails,
|
|
1091
|
+
).toEqual({ fieldName: "userDetails" });
|
|
1092
|
+
}
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
it("keeps the granted:false placeholder when token consent is only partial", () => {
|
|
1096
|
+
const partialConsentToken = makeJwt({
|
|
1097
|
+
payload: {
|
|
1098
|
+
given_names: "pii_abc",
|
|
1099
|
+
last_name: "pii_def",
|
|
1100
|
+
email: "pii_ghi",
|
|
1101
|
+
consent: { granted: true, granted_at: "2026-01-01T09:00:00.000Z" },
|
|
1102
|
+
},
|
|
1103
|
+
});
|
|
1104
|
+
const { repository } = assemble(partialConsentToken);
|
|
1105
|
+
const request = repository.received[0]!;
|
|
1106
|
+
expect(request.consent).toEqual({
|
|
1107
|
+
granted: false,
|
|
1108
|
+
grantedAt: "",
|
|
1109
|
+
noticeLanguage: "",
|
|
1110
|
+
noticePrivacyPolicyUrl: "",
|
|
1111
|
+
});
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
it("a complete token consent omits the consent record even when a local one exists", () => {
|
|
1115
|
+
// Token data always wins: even a captured local consent is not sent —
|
|
1116
|
+
// the part is omitted and the server injects the token's record.
|
|
1117
|
+
const { repository } = assemble(
|
|
1118
|
+
fullBindingToken,
|
|
1119
|
+
{ userDetails: SAMPLE_USER_DETAILS },
|
|
1120
|
+
(m) => m.setConsent(consentInfo),
|
|
1121
|
+
);
|
|
1122
|
+
const request = repository.received[0]!;
|
|
1123
|
+
expect(request.consent).toBeUndefined();
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
it("a complete token consent drops the consent screen from the flow", () => {
|
|
1127
|
+
const repository = new StubRepository();
|
|
1128
|
+
const manager = makeManager(
|
|
1129
|
+
buildScreens((screens) => {
|
|
1130
|
+
screens.consent((c) => {
|
|
1131
|
+
c.partnerName = "Acme";
|
|
1132
|
+
c.partnerPrivacyPolicyUrl = "https://example.test/privacy";
|
|
1133
|
+
});
|
|
1134
|
+
screens.capture((c) => {
|
|
1135
|
+
c.captureType = CaptureType.selfie;
|
|
1136
|
+
});
|
|
1137
|
+
}),
|
|
1138
|
+
vi.fn(),
|
|
1139
|
+
{
|
|
1140
|
+
userDetails: SAMPLE_USER_DETAILS,
|
|
1141
|
+
network: {
|
|
1142
|
+
config: {
|
|
1143
|
+
jobType: JobType.smartSelfieEnrollment,
|
|
1144
|
+
token: fullBindingToken,
|
|
1145
|
+
partnerConfig: {
|
|
1146
|
+
partnerId: "p",
|
|
1147
|
+
callbackUrl: "",
|
|
1148
|
+
useSandbox: true,
|
|
1149
|
+
},
|
|
1150
|
+
},
|
|
1151
|
+
},
|
|
1152
|
+
},
|
|
1153
|
+
repository,
|
|
1154
|
+
);
|
|
1155
|
+
expect(manager.currentScreen?.kind).toBe("capture");
|
|
1156
|
+
expect(manager.navigationPath.some((step) => step.kind === "consent")).toBe(
|
|
1157
|
+
false,
|
|
1158
|
+
);
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
it("a preset consentInformation is still sent in full when token consent is partial", () => {
|
|
1162
|
+
const partialConsentToken = makeJwt({
|
|
1163
|
+
payload: { consent: { granted: true } },
|
|
1164
|
+
});
|
|
1165
|
+
const { repository } = assemble(partialConsentToken, {
|
|
1166
|
+
userDetails: SAMPLE_USER_DETAILS,
|
|
1167
|
+
consentInformation: consentInfo,
|
|
1168
|
+
});
|
|
1169
|
+
const request = repository.received[0]!;
|
|
1170
|
+
expect(request.consent).toEqual(consentInfo);
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
it("the minted full-binding token drives the flow end to end with nothing local", () => {
|
|
1174
|
+
const repository = new StubRepository();
|
|
1175
|
+
const manager = makeManager(
|
|
1176
|
+
buildScreens((screens) => {
|
|
1177
|
+
screens.consent((c) => {
|
|
1178
|
+
c.partnerName = "Acme";
|
|
1179
|
+
c.partnerPrivacyPolicyUrl = "https://example.test/privacy";
|
|
1180
|
+
});
|
|
1181
|
+
screens.capture((c) => {
|
|
1182
|
+
c.captureType = CaptureType.selfie;
|
|
1183
|
+
});
|
|
1184
|
+
screens.processing();
|
|
1185
|
+
}),
|
|
1186
|
+
vi.fn(),
|
|
1187
|
+
{
|
|
1188
|
+
network: {
|
|
1189
|
+
config: {
|
|
1190
|
+
jobType: JobType.smartSelfieEnrollment,
|
|
1191
|
+
token: MINTED_FULL_BINDING_TOKEN,
|
|
1192
|
+
partnerConfig: {
|
|
1193
|
+
partnerId: "p",
|
|
1194
|
+
callbackUrl: "",
|
|
1195
|
+
useSandbox: true,
|
|
1196
|
+
},
|
|
1197
|
+
},
|
|
1198
|
+
},
|
|
1199
|
+
},
|
|
1200
|
+
repository,
|
|
1201
|
+
);
|
|
1202
|
+
|
|
1203
|
+
expect(manager.currentScreen?.kind).toBe("capture");
|
|
1204
|
+
expect(manager.navigationPath.some((step) => step.kind === "consent")).toBe(
|
|
1205
|
+
false,
|
|
1206
|
+
);
|
|
1207
|
+
|
|
1208
|
+
manager.setCapturedSelfie("file:///selfie.jpg", ["file:///l1.jpg"]);
|
|
1209
|
+
manager.beginSubmissionIfNeeded();
|
|
1210
|
+
|
|
1211
|
+
expect(repository.received).toHaveLength(1);
|
|
1212
|
+
const request = repository.received[0]!;
|
|
1213
|
+
expect(request.userDetails).toBeUndefined();
|
|
1214
|
+
expect(request.consent).toBeUndefined();
|
|
1215
|
+
});
|
|
1216
|
+
|
|
1217
|
+
it("the minted names-and-email token reduces builder details to the unbound phone number", () => {
|
|
1218
|
+
const { repository } = assemble(MINTED_NAMES_AND_EMAIL_TOKEN, {
|
|
1219
|
+
userDetails: SAMPLE_USER_DETAILS,
|
|
1220
|
+
});
|
|
1221
|
+
const request = repository.received[0]!;
|
|
1222
|
+
expect(request.userDetails).toEqual({ phoneNumber: "+2348000000000" });
|
|
1223
|
+
expect(request.consent).toBeUndefined();
|
|
1224
|
+
});
|
|
1225
|
+
|
|
1226
|
+
it("regression: without a payload claim the request carries userDetails and the placeholder consent", () => {
|
|
1227
|
+
const legacyToken = makeJwt({ sdk_config: { livenessImageCount: 5 } });
|
|
1228
|
+
const { repository } = assemble(legacyToken, {
|
|
1229
|
+
userDetails: SAMPLE_USER_DETAILS,
|
|
1230
|
+
});
|
|
1231
|
+
const request = repository.received[0]!;
|
|
1232
|
+
expect(request.userDetails).toEqual(SAMPLE_USER_DETAILS);
|
|
1233
|
+
expect(request.tokenPayload).toBeUndefined();
|
|
1234
|
+
expect(request.consent).toEqual({
|
|
1235
|
+
granted: false,
|
|
1236
|
+
grantedAt: "",
|
|
1237
|
+
noticeLanguage: "",
|
|
1238
|
+
noticePrivacyPolicyUrl: "",
|
|
1239
|
+
});
|
|
1240
|
+
});
|
|
1241
|
+
|
|
1242
|
+
it("allowOfflineMode skips the token decode — strict legacy assembly applies", async () => {
|
|
1243
|
+
const { repository, manager } = assemble(fullBindingToken, {
|
|
1244
|
+
config: {
|
|
1245
|
+
enableCrashReporting: false,
|
|
1246
|
+
enableDebugMode: false,
|
|
1247
|
+
allowOfflineMode: true,
|
|
1248
|
+
globalPrivacyControl: GlobalPrivacyControl.OptOut,
|
|
1249
|
+
},
|
|
1250
|
+
});
|
|
1251
|
+
await flushMicrotasks();
|
|
1252
|
+
// Token binds everything, but offline mode never reads it — the
|
|
1253
|
+
// missing builder userDetails still fails assembly.
|
|
1254
|
+
expect(repository.received).toHaveLength(0);
|
|
1255
|
+
const state = manager.jobSubmissionState;
|
|
1256
|
+
expect(state.kind).toBe("failure");
|
|
1257
|
+
if (state.kind === "failure") {
|
|
1258
|
+
expect(state.error).toBeInstanceOf(MissingRequiredFieldException);
|
|
1259
|
+
}
|
|
1260
|
+
});
|
|
1261
|
+
});
|
|
1262
|
+
|
|
892
1263
|
describe("FlowNavigationManager — typed missing-field validation (parity)", () => {
|
|
893
1264
|
// Drives a submission to its failure state and returns the surfaced
|
|
894
1265
|
// error so we can assert the typed `MissingRequiredFieldException`
|