@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
|
@@ -18,6 +18,12 @@ import {
|
|
|
18
18
|
MissingCaptureForPreviewException,
|
|
19
19
|
} from "../../../core/exception/screen_config_validation_exceptions";
|
|
20
20
|
import { IssueSeverity } from "../../../core/exception/issue_severity";
|
|
21
|
+
import {
|
|
22
|
+
tokenConsentMissingSubfields,
|
|
23
|
+
bindsRequiredUserDetails,
|
|
24
|
+
type TokenPayload,
|
|
25
|
+
} from "../../../data/model/token_payload";
|
|
26
|
+
import { missingUserDetailsFieldIssues } from "./user_details_validator";
|
|
21
27
|
import type { ValidationIssue } from "./validation_state";
|
|
22
28
|
|
|
23
29
|
/**
|
|
@@ -66,6 +72,12 @@ export type JobTypeValidatorInput = {
|
|
|
66
72
|
| EnhancedDocumentVerificationParams
|
|
67
73
|
| undefined;
|
|
68
74
|
readonly userDetails?: UserDetails | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* User-detail/consent bindings decoded from the JWT `payload` claim.
|
|
77
|
+
* `undefined` (no token, offline mode, legacy token) keeps every rule
|
|
78
|
+
* exactly as strict as before token support existed.
|
|
79
|
+
*/
|
|
80
|
+
readonly tokenPayload?: TokenPayload | undefined;
|
|
69
81
|
};
|
|
70
82
|
|
|
71
83
|
/**
|
|
@@ -93,9 +105,13 @@ function jobTypeName(jobType: JobType): string {
|
|
|
93
105
|
}
|
|
94
106
|
|
|
95
107
|
/**
|
|
96
|
-
* Consent rule:
|
|
97
|
-
*
|
|
98
|
-
*
|
|
108
|
+
* Consent rule: token consent always wins. A token that carries a
|
|
109
|
+
* consent binding must carry all four subfields — the local sources
|
|
110
|
+
* are then ignored (the consent screen is skipped and any preset is
|
|
111
|
+
* not sent), so an incomplete binding is a build-time error rather
|
|
112
|
+
* than a silent fallback. Without a token binding, exactly one local
|
|
113
|
+
* form of consent is required — either a Consent screen or
|
|
114
|
+
* pre-supplied `consentInformation`, never both.
|
|
99
115
|
*/
|
|
100
116
|
function appendConsentRule(
|
|
101
117
|
jobType: JobType,
|
|
@@ -104,6 +120,33 @@ function appendConsentRule(
|
|
|
104
120
|
): void {
|
|
105
121
|
const hasConsentScreen = input.steps.some((s) => s.kind === "consent");
|
|
106
122
|
const hasConsentInformation = input.consentInformation !== undefined;
|
|
123
|
+
if (hasConsentScreen && hasConsentInformation) {
|
|
124
|
+
issues.push(
|
|
125
|
+
InvalidJobTypeScreenConfigException.forJob({
|
|
126
|
+
jobType,
|
|
127
|
+
reason:
|
|
128
|
+
"must not include both a Consent screen and a pre-supplied consentInformation — use one or the other",
|
|
129
|
+
suggestedFix:
|
|
130
|
+
"Remove the consent { } screen if supplying consentInformation, or clear consentInformation if using the consent screen",
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const tokenConsent = input.tokenPayload?.consent;
|
|
136
|
+
if (tokenConsent !== undefined) {
|
|
137
|
+
const missing = tokenConsentMissingSubfields(tokenConsent);
|
|
138
|
+
if (missing.length > 0) {
|
|
139
|
+
issues.push(
|
|
140
|
+
InvalidJobTypeScreenConfigException.forJob({
|
|
141
|
+
jobType,
|
|
142
|
+
reason: `the token's consent binding is incomplete — missing: ${missing.join(", ")}`,
|
|
143
|
+
suggestedFix:
|
|
144
|
+
"Bind all four consent fields when minting the token at /v3/token, or bind none and collect consent in the app",
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
107
150
|
if (!hasConsentScreen && !hasConsentInformation) {
|
|
108
151
|
issues.push(
|
|
109
152
|
InvalidJobTypeScreenConfigException.forJob({
|
|
@@ -114,17 +157,36 @@ function appendConsentRule(
|
|
|
114
157
|
"Add a consent { } screen to your flow, or supply consentInformation via the builder",
|
|
115
158
|
}),
|
|
116
159
|
);
|
|
117
|
-
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* userDetails rule: the token and the builder fill the requirement
|
|
165
|
+
* together — token-bound fields (see `bindsRequiredUserDetails`) count
|
|
166
|
+
* as supplied and the builder must cover the rest. With no token
|
|
167
|
+
* binding and no builder value the legacy blanket error fires; with a
|
|
168
|
+
* partial token binding the per-field errors name exactly what neither
|
|
169
|
+
* side provided.
|
|
170
|
+
*/
|
|
171
|
+
function appendUserDetailsRequiredRule(
|
|
172
|
+
jobType: JobType,
|
|
173
|
+
input: JobTypeValidatorInput,
|
|
174
|
+
issues: ValidationIssue[],
|
|
175
|
+
): void {
|
|
176
|
+
if (input.userDetails !== undefined) return;
|
|
177
|
+
if (bindsRequiredUserDetails(input.tokenPayload)) return;
|
|
178
|
+
if (input.tokenPayload === undefined) {
|
|
118
179
|
issues.push(
|
|
119
180
|
InvalidJobTypeScreenConfigException.forJob({
|
|
120
181
|
jobType,
|
|
121
|
-
reason:
|
|
122
|
-
"must not include both a Consent screen and a pre-supplied consentInformation — use one or the other",
|
|
182
|
+
reason: `userDetails is required for ${jobTypeName(jobType)} jobs`,
|
|
123
183
|
suggestedFix:
|
|
124
|
-
"
|
|
184
|
+
"Set builder.userDetails with the end user PII before building",
|
|
125
185
|
}),
|
|
126
186
|
);
|
|
187
|
+
return;
|
|
127
188
|
}
|
|
189
|
+
issues.push(...missingUserDetailsFieldIssues(undefined, input.tokenPayload));
|
|
128
190
|
}
|
|
129
191
|
|
|
130
192
|
/**
|
|
@@ -381,16 +443,7 @@ export class SelfieJobTypeValidator implements JobTypeValidator {
|
|
|
381
443
|
);
|
|
382
444
|
}
|
|
383
445
|
|
|
384
|
-
|
|
385
|
-
issues.push(
|
|
386
|
-
InvalidJobTypeScreenConfigException.forJob({
|
|
387
|
-
jobType: this.jobType,
|
|
388
|
-
reason: `userDetails is required for ${jobTypeName(this.jobType)} jobs`,
|
|
389
|
-
suggestedFix:
|
|
390
|
-
"Set builder.userDetails with the end user PII before building",
|
|
391
|
-
}),
|
|
392
|
-
);
|
|
393
|
-
}
|
|
446
|
+
appendUserDetailsRequiredRule(this.jobType, input, issues);
|
|
394
447
|
}
|
|
395
448
|
}
|
|
396
449
|
|
|
@@ -477,16 +530,7 @@ export class DocumentJobTypeValidator implements JobTypeValidator {
|
|
|
477
530
|
);
|
|
478
531
|
}
|
|
479
532
|
|
|
480
|
-
|
|
481
|
-
issues.push(
|
|
482
|
-
InvalidJobTypeScreenConfigException.forJob({
|
|
483
|
-
jobType: this.jobType,
|
|
484
|
-
reason: `userDetails is required for ${jobTypeName(this.jobType)} jobs`,
|
|
485
|
-
suggestedFix:
|
|
486
|
-
"Set builder.userDetails with the end user PII before building",
|
|
487
|
-
}),
|
|
488
|
-
);
|
|
489
|
-
}
|
|
533
|
+
appendUserDetailsRequiredRule(this.jobType, input, issues);
|
|
490
534
|
}
|
|
491
535
|
|
|
492
536
|
/**
|
|
@@ -578,18 +622,8 @@ export class NonCaptureJobTypeValidator implements JobTypeValidator {
|
|
|
578
622
|
);
|
|
579
623
|
}
|
|
580
624
|
|
|
581
|
-
if (
|
|
582
|
-
this.jobType
|
|
583
|
-
input.userDetails === undefined
|
|
584
|
-
) {
|
|
585
|
-
issues.push(
|
|
586
|
-
InvalidJobTypeScreenConfigException.forJob({
|
|
587
|
-
jobType: this.jobType,
|
|
588
|
-
reason: "userDetails is required for EnhancedKyc jobs",
|
|
589
|
-
suggestedFix:
|
|
590
|
-
"Set builder.userDetails with the end user PII before building",
|
|
591
|
-
}),
|
|
592
|
-
);
|
|
625
|
+
if (this.jobType === JobType.enhancedKyc) {
|
|
626
|
+
appendUserDetailsRequiredRule(this.jobType, input, issues);
|
|
593
627
|
}
|
|
594
628
|
}
|
|
595
629
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { UserDetails } from "../../../core/models/params";
|
|
2
|
+
import { InvalidFieldValueException } from "../../../core/exception/job_validation_exceptions";
|
|
3
|
+
import type { TokenPayload } from "../../../data/model/token_payload";
|
|
4
|
+
import type { ValidationIssue } from "./validation_state";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Field-union rule shared by the content validator and the job-type required
|
|
8
|
+
* rule: a field is covered when the token binds it or the builder supplies it.
|
|
9
|
+
*/
|
|
10
|
+
export function missingUserDetailsFieldIssues(
|
|
11
|
+
userDetails: UserDetails | undefined,
|
|
12
|
+
tokenPayload: TokenPayload | undefined,
|
|
13
|
+
): ValidationIssue[] {
|
|
14
|
+
const issues: ValidationIssue[] = [];
|
|
15
|
+
const fieldReason =
|
|
16
|
+
tokenPayload === undefined
|
|
17
|
+
? "must not be blank"
|
|
18
|
+
: "not bound by the token and not supplied on the builder";
|
|
19
|
+
const tokenBindsField = {
|
|
20
|
+
givenNames: tokenPayload?.hasGivenNames === true,
|
|
21
|
+
lastName: tokenPayload?.hasLastName === true,
|
|
22
|
+
} as const;
|
|
23
|
+
for (const field of ["givenNames", "lastName"] as const) {
|
|
24
|
+
if (tokenBindsField[field]) continue;
|
|
25
|
+
const value = userDetails?.[field];
|
|
26
|
+
if (!value || !value.trim()) {
|
|
27
|
+
issues.push(
|
|
28
|
+
new InvalidFieldValueException({
|
|
29
|
+
fieldName: `userDetails.${field}`,
|
|
30
|
+
reason: fieldReason,
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// email and phoneNumber are each optional, but one must come from the builder or the token.
|
|
36
|
+
const hasEmail = !!userDetails?.email && userDetails.email.trim().length > 0;
|
|
37
|
+
const hasPhone =
|
|
38
|
+
!!userDetails?.phoneNumber && userDetails.phoneNumber.trim().length > 0;
|
|
39
|
+
const tokenHasContact =
|
|
40
|
+
tokenPayload?.hasEmail === true || tokenPayload?.hasPhoneNumber === true;
|
|
41
|
+
if (!hasEmail && !hasPhone && !tokenHasContact) {
|
|
42
|
+
issues.push(
|
|
43
|
+
new InvalidFieldValueException({
|
|
44
|
+
fieldName: "userDetails",
|
|
45
|
+
reason:
|
|
46
|
+
tokenPayload === undefined
|
|
47
|
+
? "at least one of email or phoneNumber must be non blank"
|
|
48
|
+
: "at least one contact field must be bound by the token or supplied on the builder",
|
|
49
|
+
}),
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return issues;
|
|
53
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
2
|
+
import type { UseSmileIDScanState } from "@smileid/usesmileid_bridge";
|
|
3
|
+
import { UseSmileIDScanStateType } from "@smileid/usesmileid_bridge";
|
|
4
4
|
import { CaptureType } from "../../../core/models/ml_config";
|
|
5
5
|
import { UseSmileIDOverlayState } from "../../state/use_smile_id_overlay_state";
|
|
6
6
|
import {
|
|
@@ -16,7 +16,10 @@ import {
|
|
|
16
16
|
|
|
17
17
|
describe("mapSelfieUiState — standard flow", () => {
|
|
18
18
|
it("maps initial to the standard primer", () => {
|
|
19
|
-
const ui = mapSelfieUiState(
|
|
19
|
+
const ui = mapSelfieUiState(
|
|
20
|
+
{ type: UseSmileIDScanStateType.Initial },
|
|
21
|
+
false,
|
|
22
|
+
);
|
|
20
23
|
expect(ui.overlayState).toBe(UseSmileIDOverlayState.INSTRUCTION);
|
|
21
24
|
expect(ui.feedbackKey).toBe("si_capture_initial_instruction");
|
|
22
25
|
expect(ui.captureProgress).toBe(0);
|
|
@@ -26,7 +29,7 @@ describe("mapSelfieUiState — standard flow", () => {
|
|
|
26
29
|
it("passes the analyzer feedback key through on found", () => {
|
|
27
30
|
const ui = mapSelfieUiState(
|
|
28
31
|
{
|
|
29
|
-
type:
|
|
32
|
+
type: UseSmileIDScanStateType.Found,
|
|
30
33
|
feedback: "si_capture_move_left",
|
|
31
34
|
captureProgress: 0.4,
|
|
32
35
|
},
|
|
@@ -40,10 +43,13 @@ describe("mapSelfieUiState — standard flow", () => {
|
|
|
40
43
|
it("shows the in-capture copy on found-default and satisfied", () => {
|
|
41
44
|
// All checks passing means frames are being collected — the
|
|
42
45
|
// guidance reads "Capturing…", never the pre-start instruction.
|
|
43
|
-
const found = mapSelfieUiState(
|
|
46
|
+
const found = mapSelfieUiState(
|
|
47
|
+
{ type: UseSmileIDScanStateType.Found },
|
|
48
|
+
false,
|
|
49
|
+
);
|
|
44
50
|
expect(found.feedbackKey).toBe("si_capturing");
|
|
45
51
|
const satisfied = mapSelfieUiState(
|
|
46
|
-
{ type:
|
|
52
|
+
{ type: UseSmileIDScanStateType.Satisfied },
|
|
47
53
|
false,
|
|
48
54
|
);
|
|
49
55
|
expect(satisfied.feedbackKey).toBe("si_capturing");
|
|
@@ -54,14 +60,20 @@ describe("mapSelfieUiState — standard flow", () => {
|
|
|
54
60
|
});
|
|
55
61
|
|
|
56
62
|
it("maps finished through the shared terminal snapshot", () => {
|
|
57
|
-
const ui = mapSelfieUiState(
|
|
63
|
+
const ui = mapSelfieUiState(
|
|
64
|
+
{ type: UseSmileIDScanStateType.Finished },
|
|
65
|
+
false,
|
|
66
|
+
);
|
|
58
67
|
expect(ui).toEqual(scannedUiState(false));
|
|
59
68
|
expect(ui.feedbackKey).toBe("si_selfie_capture_complete");
|
|
60
69
|
expect(ui.captureProgress).toBe(1);
|
|
61
70
|
});
|
|
62
71
|
|
|
63
72
|
it("maps timeout to idle with the timeout copy", () => {
|
|
64
|
-
const ui = mapSelfieUiState(
|
|
73
|
+
const ui = mapSelfieUiState(
|
|
74
|
+
{ type: UseSmileIDScanStateType.Timeout },
|
|
75
|
+
false,
|
|
76
|
+
);
|
|
65
77
|
expect(ui.overlayState).toBe(UseSmileIDOverlayState.IDLE);
|
|
66
78
|
expect(ui.feedbackKey).toBe("si_capture_timeout");
|
|
67
79
|
});
|
|
@@ -69,15 +81,18 @@ describe("mapSelfieUiState — standard flow", () => {
|
|
|
69
81
|
|
|
70
82
|
describe("mapSelfieUiState — Enhanced Smart Selfie", () => {
|
|
71
83
|
it("swaps the initial primer for the head-turn instruction", () => {
|
|
72
|
-
const ui = mapSelfieUiState(
|
|
84
|
+
const ui = mapSelfieUiState(
|
|
85
|
+
{ type: UseSmileIDScanStateType.Initial },
|
|
86
|
+
true,
|
|
87
|
+
);
|
|
73
88
|
expect(ui.feedbackKey).toBe("si_ess_capture_initial_instruction");
|
|
74
89
|
});
|
|
75
90
|
|
|
76
91
|
it("shows hold-still through active capture (found-default / satisfied)", () => {
|
|
77
92
|
for (const scanState of [
|
|
78
|
-
{ type:
|
|
79
|
-
{ type:
|
|
80
|
-
] satisfies
|
|
93
|
+
{ type: UseSmileIDScanStateType.Found },
|
|
94
|
+
{ type: UseSmileIDScanStateType.Satisfied },
|
|
95
|
+
] satisfies UseSmileIDScanState[]) {
|
|
81
96
|
expect(mapSelfieUiState(scanState, true).feedbackKey).toBe(
|
|
82
97
|
"si_ess_hold_still",
|
|
83
98
|
);
|
|
@@ -85,24 +100,25 @@ describe("mapSelfieUiState — Enhanced Smart Selfie", () => {
|
|
|
85
100
|
// Finished shows the completion copy in both modes; only the oval
|
|
86
101
|
// fill differs under Enhanced Smart Selfie.
|
|
87
102
|
expect(
|
|
88
|
-
mapSelfieUiState({ type:
|
|
103
|
+
mapSelfieUiState({ type: UseSmileIDScanStateType.Finished }, true)
|
|
104
|
+
.feedbackKey,
|
|
89
105
|
).toBe("si_selfie_capture_complete");
|
|
90
106
|
});
|
|
91
107
|
|
|
92
108
|
it("zeroes captureProgress everywhere — the oval never fills under ESS", () => {
|
|
93
109
|
for (const scanState of [
|
|
94
|
-
{ type:
|
|
95
|
-
{ type:
|
|
96
|
-
{ type:
|
|
97
|
-
{ type:
|
|
98
|
-
] satisfies
|
|
110
|
+
{ type: UseSmileIDScanStateType.Found, captureProgress: 0.6 },
|
|
111
|
+
{ type: UseSmileIDScanStateType.Satisfied },
|
|
112
|
+
{ type: UseSmileIDScanStateType.Finished },
|
|
113
|
+
{ type: UseSmileIDScanStateType.HeadTurn, currentDirection: "left" },
|
|
114
|
+
] satisfies UseSmileIDScanState[]) {
|
|
99
115
|
expect(mapSelfieUiState(scanState, true).captureProgress).toBe(0);
|
|
100
116
|
}
|
|
101
117
|
});
|
|
102
118
|
|
|
103
119
|
it("keeps explicit guidance keys ahead of hold-still during found", () => {
|
|
104
120
|
const ui = mapSelfieUiState(
|
|
105
|
-
{ type:
|
|
121
|
+
{ type: UseSmileIDScanStateType.Found, feedback: "si_capture_too_close" },
|
|
106
122
|
true,
|
|
107
123
|
);
|
|
108
124
|
expect(ui.feedbackKey).toBe("si_capture_too_close");
|
|
@@ -116,7 +132,7 @@ describe("mapSelfieUiState — Enhanced Smart Selfie", () => {
|
|
|
116
132
|
] as const;
|
|
117
133
|
for (const [direction, expectedKey] of directions) {
|
|
118
134
|
const ui = mapSelfieUiState(
|
|
119
|
-
{ type:
|
|
135
|
+
{ type: UseSmileIDScanStateType.HeadTurn, currentDirection: direction },
|
|
120
136
|
true,
|
|
121
137
|
);
|
|
122
138
|
expect(ui.overlayState).toBe(UseSmileIDOverlayState.HEAD_TURN);
|
|
@@ -127,7 +143,10 @@ describe("mapSelfieUiState — Enhanced Smart Selfie", () => {
|
|
|
127
143
|
});
|
|
128
144
|
|
|
129
145
|
it("falls back to hold-steady when headTurn arrives without a direction", () => {
|
|
130
|
-
const ui = mapSelfieUiState(
|
|
146
|
+
const ui = mapSelfieUiState(
|
|
147
|
+
{ type: UseSmileIDScanStateType.HeadTurn },
|
|
148
|
+
true,
|
|
149
|
+
);
|
|
131
150
|
expect(ui.feedbackKey).toBe("si_capture_hold_steady");
|
|
132
151
|
expect(ui.animationDirection).toBeNull();
|
|
133
152
|
});
|
|
@@ -135,7 +154,7 @@ describe("mapSelfieUiState — Enhanced Smart Selfie", () => {
|
|
|
135
154
|
it("threads poseMatched into the head-turn state (drives grey→green)", () => {
|
|
136
155
|
const matched = mapSelfieUiState(
|
|
137
156
|
{
|
|
138
|
-
type:
|
|
157
|
+
type: UseSmileIDScanStateType.HeadTurn,
|
|
139
158
|
currentDirection: "left",
|
|
140
159
|
poseMatched: true,
|
|
141
160
|
},
|
|
@@ -145,7 +164,7 @@ describe("mapSelfieUiState — Enhanced Smart Selfie", () => {
|
|
|
145
164
|
expect(matched.poseMatched).toBe(true);
|
|
146
165
|
|
|
147
166
|
const pending = mapSelfieUiState(
|
|
148
|
-
{ type:
|
|
167
|
+
{ type: UseSmileIDScanStateType.HeadTurn, currentDirection: "left" },
|
|
149
168
|
true,
|
|
150
169
|
);
|
|
151
170
|
expect(pending.poseMatched).toBe(false);
|
|
@@ -159,7 +178,7 @@ describe("mapSelfieUiState — Enhanced Smart Selfie", () => {
|
|
|
159
178
|
] as const) {
|
|
160
179
|
const ui = mapSelfieUiState(
|
|
161
180
|
{
|
|
162
|
-
type:
|
|
181
|
+
type: UseSmileIDScanStateType.HeadTurn,
|
|
163
182
|
currentDirection: "left",
|
|
164
183
|
feedback,
|
|
165
184
|
poseMatched: true,
|
|
@@ -182,7 +201,7 @@ describe("mapSelfieUiState — Enhanced Smart Selfie", () => {
|
|
|
182
201
|
] as const) {
|
|
183
202
|
const ui = mapSelfieUiState(
|
|
184
203
|
{
|
|
185
|
-
type:
|
|
204
|
+
type: UseSmileIDScanStateType.HeadTurn,
|
|
186
205
|
currentDirection: "up",
|
|
187
206
|
feedback,
|
|
188
207
|
poseMatched: true,
|
|
@@ -203,7 +222,7 @@ describe("mapSelfieUiState — Enhanced Smart Selfie", () => {
|
|
|
203
222
|
] as const) {
|
|
204
223
|
const ui = mapSelfieUiState(
|
|
205
224
|
{
|
|
206
|
-
type:
|
|
225
|
+
type: UseSmileIDScanStateType.HeadTurn,
|
|
207
226
|
currentDirection: "right",
|
|
208
227
|
feedback,
|
|
209
228
|
poseMatched: true,
|
|
@@ -241,7 +260,7 @@ describe("withEnhancedLivenessPolicy", () => {
|
|
|
241
260
|
|
|
242
261
|
describe("document mapping", () => {
|
|
243
262
|
it("maps finished through the shared document terminal snapshot", () => {
|
|
244
|
-
const ui = mapDocumentUiState({ type:
|
|
263
|
+
const ui = mapDocumentUiState({ type: UseSmileIDScanStateType.Finished });
|
|
245
264
|
expect(ui).toEqual(scannedDocumentUiState());
|
|
246
265
|
expect(ui.feedbackKey).toBe("si_document_capture_complete");
|
|
247
266
|
expect(ui.captureProgress).toBe(1);
|
|
@@ -249,7 +268,7 @@ describe("document mapping", () => {
|
|
|
249
268
|
|
|
250
269
|
it("passes document feedback keys through on found", () => {
|
|
251
270
|
const ui = mapDocumentUiState({
|
|
252
|
-
type:
|
|
271
|
+
type: UseSmileIDScanStateType.Found,
|
|
253
272
|
feedback: "si_document_too_far",
|
|
254
273
|
});
|
|
255
274
|
expect(ui.overlayState).toBe(UseSmileIDOverlayState.DOCUMENT_TOO_FAR);
|
|
@@ -257,7 +276,7 @@ describe("document mapping", () => {
|
|
|
257
276
|
});
|
|
258
277
|
|
|
259
278
|
it("treats a degenerate headTurn as the pre-capture instruction", () => {
|
|
260
|
-
const ui = mapDocumentUiState({ type:
|
|
279
|
+
const ui = mapDocumentUiState({ type: UseSmileIDScanStateType.HeadTurn });
|
|
261
280
|
expect(ui.overlayState).toBe(UseSmileIDOverlayState.INSTRUCTION);
|
|
262
281
|
expect(ui.feedbackKey).toBe("si_document_initial_instruction");
|
|
263
282
|
});
|
|
@@ -287,14 +306,14 @@ describe("mapCaptureUiState dispatch", () => {
|
|
|
287
306
|
it("routes by capture type", () => {
|
|
288
307
|
expect(
|
|
289
308
|
mapCaptureUiState(
|
|
290
|
-
{ type:
|
|
309
|
+
{ type: UseSmileIDScanStateType.Initial },
|
|
291
310
|
CaptureType.selfie,
|
|
292
311
|
true,
|
|
293
312
|
).feedbackKey,
|
|
294
313
|
).toBe("si_ess_capture_initial_instruction");
|
|
295
314
|
expect(
|
|
296
315
|
mapCaptureUiState(
|
|
297
|
-
{ type:
|
|
316
|
+
{ type: UseSmileIDScanStateType.Initial },
|
|
298
317
|
CaptureType.document,
|
|
299
318
|
// ESS is a selfie-only concept; the flag must not leak into
|
|
300
319
|
// the document mapping.
|
|
@@ -308,8 +327,8 @@ describe("isSessionBoundary", () => {
|
|
|
308
327
|
it("returns true for unsatisfied → found (leaving unsatisfied is a boundary)", () => {
|
|
309
328
|
expect(
|
|
310
329
|
isSessionBoundary(
|
|
311
|
-
{ type:
|
|
312
|
-
{ type:
|
|
330
|
+
{ type: UseSmileIDScanStateType.Unsatisfied },
|
|
331
|
+
{ type: UseSmileIDScanStateType.Found },
|
|
313
332
|
),
|
|
314
333
|
).toBe(true);
|
|
315
334
|
});
|
|
@@ -317,8 +336,8 @@ describe("isSessionBoundary", () => {
|
|
|
317
336
|
it("returns true for unsatisfied → initial", () => {
|
|
318
337
|
expect(
|
|
319
338
|
isSessionBoundary(
|
|
320
|
-
{ type:
|
|
321
|
-
{ type:
|
|
339
|
+
{ type: UseSmileIDScanStateType.Unsatisfied },
|
|
340
|
+
{ type: UseSmileIDScanStateType.Initial },
|
|
322
341
|
),
|
|
323
342
|
).toBe(true);
|
|
324
343
|
});
|
|
@@ -326,8 +345,8 @@ describe("isSessionBoundary", () => {
|
|
|
326
345
|
it("returns true for timeout → initial (session restart)", () => {
|
|
327
346
|
expect(
|
|
328
347
|
isSessionBoundary(
|
|
329
|
-
{ type:
|
|
330
|
-
{ type:
|
|
348
|
+
{ type: UseSmileIDScanStateType.Timeout },
|
|
349
|
+
{ type: UseSmileIDScanStateType.Initial },
|
|
331
350
|
),
|
|
332
351
|
).toBe(true);
|
|
333
352
|
});
|
|
@@ -335,8 +354,8 @@ describe("isSessionBoundary", () => {
|
|
|
335
354
|
it("returns true for finished → initial (session restart)", () => {
|
|
336
355
|
expect(
|
|
337
356
|
isSessionBoundary(
|
|
338
|
-
{ type:
|
|
339
|
-
{ type:
|
|
357
|
+
{ type: UseSmileIDScanStateType.Finished },
|
|
358
|
+
{ type: UseSmileIDScanStateType.Initial },
|
|
340
359
|
),
|
|
341
360
|
).toBe(true);
|
|
342
361
|
});
|
|
@@ -344,8 +363,8 @@ describe("isSessionBoundary", () => {
|
|
|
344
363
|
it("returns false for found → unsatisfied (entering unsatisfied, not leaving)", () => {
|
|
345
364
|
expect(
|
|
346
365
|
isSessionBoundary(
|
|
347
|
-
{ type:
|
|
348
|
-
{ type:
|
|
366
|
+
{ type: UseSmileIDScanStateType.Found },
|
|
367
|
+
{ type: UseSmileIDScanStateType.Unsatisfied },
|
|
349
368
|
),
|
|
350
369
|
).toBe(false);
|
|
351
370
|
});
|
|
@@ -353,8 +372,8 @@ describe("isSessionBoundary", () => {
|
|
|
353
372
|
it("returns false for same-type transition (found → found)", () => {
|
|
354
373
|
expect(
|
|
355
374
|
isSessionBoundary(
|
|
356
|
-
{ type:
|
|
357
|
-
{ type:
|
|
375
|
+
{ type: UseSmileIDScanStateType.Found },
|
|
376
|
+
{ type: UseSmileIDScanStateType.Found },
|
|
358
377
|
),
|
|
359
378
|
).toBe(false);
|
|
360
379
|
});
|
|
@@ -362,8 +381,8 @@ describe("isSessionBoundary", () => {
|
|
|
362
381
|
it("returns false for initial → found (normal forward progression)", () => {
|
|
363
382
|
expect(
|
|
364
383
|
isSessionBoundary(
|
|
365
|
-
{ type:
|
|
366
|
-
{ type:
|
|
384
|
+
{ type: UseSmileIDScanStateType.Initial },
|
|
385
|
+
{ type: UseSmileIDScanStateType.Found },
|
|
367
386
|
),
|
|
368
387
|
).toBe(false);
|
|
369
388
|
});
|
|
@@ -371,8 +390,8 @@ describe("isSessionBoundary", () => {
|
|
|
371
390
|
it("returns false for timeout → found (only initial restarts after a terminal state)", () => {
|
|
372
391
|
expect(
|
|
373
392
|
isSessionBoundary(
|
|
374
|
-
{ type:
|
|
375
|
-
{ type:
|
|
393
|
+
{ type: UseSmileIDScanStateType.Timeout },
|
|
394
|
+
{ type: UseSmileIDScanStateType.Found },
|
|
376
395
|
),
|
|
377
396
|
).toBe(false);
|
|
378
397
|
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
2
2
|
import * as Haptics from "expo-haptics";
|
|
3
|
-
import type {
|
|
4
|
-
import {
|
|
3
|
+
import type { UseSmileIDScanState } from "@smileid/usesmileid_bridge";
|
|
4
|
+
import { UseSmileIDScanStateType } from "@smileid/usesmileid_bridge";
|
|
5
5
|
import {
|
|
6
6
|
essTurnHaptic,
|
|
7
7
|
triggerEssTurnHaptic,
|
|
8
8
|
} from "../helpers/ess_turn_haptics";
|
|
9
9
|
|
|
10
|
-
const headTurn = (direction?: "left" | "right" | "up"):
|
|
10
|
+
const headTurn = (direction?: "left" | "right" | "up"): UseSmileIDScanState =>
|
|
11
11
|
direction === undefined
|
|
12
|
-
? { type:
|
|
13
|
-
: { type:
|
|
12
|
+
? { type: UseSmileIDScanStateType.HeadTurn }
|
|
13
|
+
: { type: UseSmileIDScanStateType.HeadTurn, currentDirection: direction };
|
|
14
14
|
|
|
15
15
|
describe("essTurnHaptic", () => {
|
|
16
16
|
it("fires intermediate when the requested direction advances", () => {
|
|
@@ -24,9 +24,9 @@ describe("essTurnHaptic", () => {
|
|
|
24
24
|
|
|
25
25
|
it("fires final when leaving the head-turn phase toward capture", () => {
|
|
26
26
|
for (const next of [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
UseSmileIDScanStateType.Found,
|
|
28
|
+
UseSmileIDScanStateType.Satisfied,
|
|
29
|
+
UseSmileIDScanStateType.Finished,
|
|
30
30
|
] as const) {
|
|
31
31
|
expect(essTurnHaptic(headTurn("up"), { type: next })).toBe("final");
|
|
32
32
|
}
|
|
@@ -34,10 +34,14 @@ describe("essTurnHaptic", () => {
|
|
|
34
34
|
|
|
35
35
|
it("never fires on a reset (head turn abandoned to initial / timeout)", () => {
|
|
36
36
|
expect(
|
|
37
|
-
essTurnHaptic(headTurn("left"), {
|
|
37
|
+
essTurnHaptic(headTurn("left"), {
|
|
38
|
+
type: UseSmileIDScanStateType.Initial,
|
|
39
|
+
}),
|
|
38
40
|
).toBeNull();
|
|
39
41
|
expect(
|
|
40
|
-
essTurnHaptic(headTurn("left"), {
|
|
42
|
+
essTurnHaptic(headTurn("left"), {
|
|
43
|
+
type: UseSmileIDScanStateType.Timeout,
|
|
44
|
+
}),
|
|
41
45
|
).toBeNull();
|
|
42
46
|
});
|
|
43
47
|
|
|
@@ -48,7 +52,7 @@ describe("essTurnHaptic", () => {
|
|
|
48
52
|
it("does not fire when the previous state was not a directed head turn", () => {
|
|
49
53
|
// Entering a head turn is not completing one.
|
|
50
54
|
expect(
|
|
51
|
-
essTurnHaptic({ type:
|
|
55
|
+
essTurnHaptic({ type: UseSmileIDScanStateType.Found }, headTurn("left")),
|
|
52
56
|
).toBeNull();
|
|
53
57
|
// A head turn with no direction yet has nothing to complete.
|
|
54
58
|
expect(essTurnHaptic(headTurn(), headTurn("left"))).toBeNull();
|