@smileid/usesmileid 12.0.0-beta01 → 12.0.0
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 +11 -0
- package/README.md +701 -89
- package/dist/camera/camera_defaults.d.ts +14 -9
- package/dist/camera/camera_defaults.d.ts.map +1 -1
- package/dist/camera/camera_defaults.js +11 -9
- package/dist/camera/camera_defaults.js.map +1 -1
- package/dist/camera/orientation_degrees.d.ts +5 -6
- package/dist/camera/orientation_degrees.d.ts.map +1 -1
- package/dist/camera/orientation_degrees.js +5 -6
- package/dist/camera/orientation_degrees.js.map +1 -1
- package/dist/core/models/document_capture_mode.d.ts +8 -0
- package/dist/core/models/document_capture_mode.d.ts.map +1 -1
- package/dist/core/models/document_capture_mode.js +24 -0
- package/dist/core/models/document_capture_mode.js.map +1 -1
- package/dist/core/models/document_type.d.ts +2 -2
- package/dist/core/models/document_type.d.ts.map +1 -1
- package/dist/core/models/document_type.js +6 -4
- package/dist/core/models/document_type.js.map +1 -1
- package/dist/core/models/result.d.ts +9 -8
- package/dist/core/models/result.d.ts.map +1 -1
- package/dist/core/models/result.js +5 -6
- package/dist/core/models/result.js.map +1 -1
- package/dist/data/api/interceptors/smile_auth_interceptor.js +1 -1
- package/dist/data/api/interceptors/smile_auth_interceptor.js.map +1 -1
- package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts +11 -0
- package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts.map +1 -1
- package/dist/data/api/interceptors/smile_integrity_interceptor.js +13 -0
- package/dist/data/api/interceptors/smile_integrity_interceptor.js.map +1 -1
- package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts +8 -0
- package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts.map +1 -1
- package/dist/data/api/interceptors/smile_request_mac_interceptor.js +11 -0
- package/dist/data/api/interceptors/smile_request_mac_interceptor.js.map +1 -1
- package/dist/data/compression/compressible_asset.d.ts +41 -0
- package/dist/data/compression/compressible_asset.d.ts.map +1 -0
- package/dist/data/compression/compressible_asset.js +34 -0
- package/dist/data/compression/compressible_asset.js.map +1 -0
- package/dist/data/compression/payload_compression_config.d.ts +36 -0
- package/dist/data/compression/payload_compression_config.d.ts.map +1 -0
- package/dist/data/compression/payload_compression_config.js +52 -0
- package/dist/data/compression/payload_compression_config.js.map +1 -0
- package/dist/data/compression/payload_compression_runner.d.ts +29 -0
- package/dist/data/compression/payload_compression_runner.d.ts.map +1 -0
- package/dist/data/compression/payload_compression_runner.js +55 -0
- package/dist/data/compression/payload_compression_runner.js.map +1 -0
- package/dist/data/compression/payload_compressor.d.ts +40 -0
- package/dist/data/compression/payload_compressor.d.ts.map +1 -0
- package/dist/data/compression/payload_compressor.js +126 -0
- package/dist/data/compression/payload_compressor.js.map +1 -0
- package/dist/data/compression/uri_compressible_asset.d.ts +23 -0
- package/dist/data/compression/uri_compressible_asset.d.ts.map +1 -0
- package/dist/data/compression/uri_compressible_asset.js +77 -0
- package/dist/data/compression/uri_compressible_asset.js.map +1 -0
- package/dist/data/dsl/builder/cache_config_builder.d.ts +2 -1
- package/dist/data/dsl/builder/cache_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/cache_config_builder.js +2 -1
- package/dist/data/dsl/builder/cache_config_builder.js.map +1 -1
- package/dist/data/dsl/builder/config_builder.d.ts +40 -14
- package/dist/data/dsl/builder/config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/config_builder.js +40 -14
- package/dist/data/dsl/builder/config_builder.js.map +1 -1
- package/dist/data/dsl/builder/interceptor_config_builder.d.ts +9 -7
- package/dist/data/dsl/builder/interceptor_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/interceptor_config_builder.js +9 -7
- package/dist/data/dsl/builder/interceptor_config_builder.js.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.d.ts +16 -1
- package/dist/data/dsl/builder/retry_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.js +16 -1
- package/dist/data/dsl/builder/retry_config_builder.js.map +1 -1
- package/dist/data/dsl/builder/timeout_config_builder.d.ts +4 -0
- package/dist/data/dsl/builder/timeout_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/timeout_config_builder.js +4 -0
- package/dist/data/dsl/builder/timeout_config_builder.js.map +1 -1
- package/dist/data/dsl/use_smile_id_network_builder.d.ts +17 -0
- package/dist/data/dsl/use_smile_id_network_builder.d.ts.map +1 -1
- package/dist/data/dsl/use_smile_id_network_builder.js +17 -0
- package/dist/data/dsl/use_smile_id_network_builder.js.map +1 -1
- package/dist/data/factory/networking_factory.d.ts.map +1 -1
- package/dist/data/factory/networking_factory.js +11 -1
- package/dist/data/factory/networking_factory.js.map +1 -1
- package/dist/data/repository/use_smile_id_repository_impl.d.ts +6 -0
- package/dist/data/repository/use_smile_id_repository_impl.d.ts.map +1 -1
- package/dist/data/repository/use_smile_id_repository_impl.js +82 -8
- package/dist/data/repository/use_smile_id_repository_impl.js.map +1 -1
- package/dist/data/security/request_canonicalizer.d.ts.map +1 -1
- package/dist/data/security/request_canonicalizer.js +14 -2
- package/dist/data/security/request_canonicalizer.js.map +1 -1
- package/dist/data/security/security_policy.d.ts +43 -0
- package/dist/data/security/security_policy.d.ts.map +1 -0
- package/dist/data/security/security_policy.js +61 -0
- package/dist/data/security/security_policy.js.map +1 -0
- 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 +2 -1
- package/dist/data/util/retry_util.js.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.d.ts +22 -0
- package/dist/data/util/use_smile_id_token_decoder.d.ts.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.js +58 -24
- package/dist/data/util/use_smile_id_token_decoder.js.map +1 -1
- package/dist/l10n/strings_en.d.ts +2 -1
- package/dist/l10n/strings_en.d.ts.map +1 -1
- package/dist/l10n/strings_en.js +2 -1
- package/dist/l10n/strings_en.js.map +1 -1
- package/dist/l10n/use_smile_id_localizations.d.ts +1 -0
- package/dist/l10n/use_smile_id_localizations.d.ts.map +1 -1
- package/dist/l10n/use_smile_id_localizations.js +3 -0
- package/dist/l10n/use_smile_id_localizations.js.map +1 -1
- package/dist/metadata/builder_configuration.d.ts +39 -0
- package/dist/metadata/builder_configuration.d.ts.map +1 -0
- package/dist/metadata/builder_configuration.js +34 -0
- package/dist/metadata/builder_configuration.js.map +1 -0
- package/dist/metadata/captured_image_properties.d.ts +11 -0
- package/dist/metadata/captured_image_properties.d.ts.map +1 -0
- package/dist/metadata/captured_image_properties.js +11 -0
- package/dist/metadata/captured_image_properties.js.map +1 -0
- package/dist/metadata/device_orientation_collector.d.ts +17 -0
- package/dist/metadata/device_orientation_collector.d.ts.map +1 -0
- package/dist/metadata/device_orientation_collector.js +66 -0
- package/dist/metadata/device_orientation_collector.js.map +1 -0
- package/dist/metadata/geolocation.d.ts +20 -0
- package/dist/metadata/geolocation.d.ts.map +1 -0
- package/dist/metadata/geolocation.js +40 -0
- package/dist/metadata/geolocation.js.map +1 -0
- package/dist/metadata/metadata_configuration_mappers.d.ts +48 -0
- package/dist/metadata/metadata_configuration_mappers.d.ts.map +1 -0
- package/dist/metadata/metadata_configuration_mappers.js +171 -0
- package/dist/metadata/metadata_configuration_mappers.js.map +1 -0
- package/dist/metadata/model_configuration.d.ts +41 -0
- package/dist/metadata/model_configuration.d.ts.map +1 -0
- package/dist/metadata/model_configuration.js +44 -0
- package/dist/metadata/model_configuration.js.map +1 -0
- package/dist/metadata/optional_native_modules.d.ts +79 -3
- package/dist/metadata/optional_native_modules.d.ts.map +1 -1
- package/dist/metadata/optional_native_modules.js +108 -3
- package/dist/metadata/optional_native_modules.js.map +1 -1
- package/dist/metadata/use_smile_id_metadata.d.ts +45 -7
- package/dist/metadata/use_smile_id_metadata.d.ts.map +1 -1
- package/dist/metadata/use_smile_id_metadata.js +85 -13
- package/dist/metadata/use_smile_id_metadata.js.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.d.ts +37 -0
- package/dist/metadata/use_smile_id_metadata_factory.d.ts.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.js +184 -12
- package/dist/metadata/use_smile_id_metadata_factory.js.map +1 -1
- package/dist/presentation/assets/svg/document_shimmer_strings.d.ts +14 -0
- package/dist/presentation/assets/svg/document_shimmer_strings.d.ts.map +1 -0
- package/dist/presentation/assets/svg/document_shimmer_strings.js +14 -0
- package/dist/presentation/assets/svg/document_shimmer_strings.js.map +1 -0
- package/dist/presentation/assets/svg/instruction_svg_strings.d.ts +12 -4
- package/dist/presentation/assets/svg/instruction_svg_strings.d.ts.map +1 -1
- package/dist/presentation/assets/svg/instruction_svg_strings.js +19 -8
- package/dist/presentation/assets/svg/instruction_svg_strings.js.map +1 -1
- package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts +0 -5
- package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts.map +1 -1
- package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js +0 -5
- package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js.map +1 -1
- package/dist/presentation/components/icons/index.d.ts +24 -8
- package/dist/presentation/components/icons/index.d.ts.map +1 -1
- package/dist/presentation/components/icons/index.js +31 -11
- package/dist/presentation/components/icons/index.js.map +1 -1
- package/dist/presentation/components/use_smile_id_attribution.d.ts +1 -1
- package/dist/presentation/components/use_smile_id_button.d.ts +2 -2
- package/dist/presentation/components/use_smile_id_button.js +4 -4
- package/dist/presentation/components/use_smile_id_button.js.map +1 -1
- package/dist/presentation/components/use_smile_id_capture_content.d.ts +13 -0
- package/dist/presentation/components/use_smile_id_capture_content.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_capture_content.js +15 -9
- package/dist/presentation/components/use_smile_id_capture_content.js.map +1 -1
- package/dist/presentation/components/use_smile_id_captured_document_image.d.ts +2 -3
- package/dist/presentation/components/use_smile_id_captured_document_image.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_captured_document_image.js +1 -3
- package/dist/presentation/components/use_smile_id_captured_document_image.js.map +1 -1
- package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts +12 -6
- package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_document_capture_controls.js +59 -16
- package/dist/presentation/components/use_smile_id_document_capture_controls.js.map +1 -1
- package/dist/presentation/components/use_smile_id_document_overlay.d.ts +22 -5
- package/dist/presentation/components/use_smile_id_document_overlay.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_document_overlay.js +80 -40
- package/dist/presentation/components/use_smile_id_document_overlay.js.map +1 -1
- package/dist/presentation/components/use_smile_id_document_shimmer.d.ts +15 -0
- package/dist/presentation/components/use_smile_id_document_shimmer.d.ts.map +1 -0
- package/dist/presentation/components/use_smile_id_document_shimmer.js +23 -0
- package/dist/presentation/components/use_smile_id_document_shimmer.js.map +1 -0
- 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 +1 -3
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js.map +1 -1
- package/dist/presentation/components/use_smile_id_guideline_thumbnail.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_guideline_thumbnail.js +84 -1
- package/dist/presentation/components/use_smile_id_guideline_thumbnail.js.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.d.ts +3 -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 +18 -3
- package/dist/presentation/components/use_smile_id_instructions_hero.js.map +1 -1
- package/dist/presentation/components/use_smile_id_oval_border_palette.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_oval_border_palette.js +7 -3
- package/dist/presentation/components/use_smile_id_oval_border_palette.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts +12 -0
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.js +12 -0
- package/dist/presentation/flow/dsl/builder/config_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/ml_builder.d.ts +13 -4
- package/dist/presentation/flow/dsl/builder/ml_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/ml_builder.js +3 -2
- package/dist/presentation/flow/dsl/builder/ml_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +111 -10
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.js +111 -10
- package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/theme_builder.d.ts +15 -2
- package/dist/presentation/flow/dsl/builder/theme_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/theme_builder.js +15 -2
- package/dist/presentation/flow/dsl/builder/theme_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts +6 -4
- package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts +62 -36
- 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 +62 -36
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.d.ts +39 -4
- package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.js +141 -10
- package/dist/presentation/flow/flow_navigation_manager.js.map +1 -1
- package/dist/presentation/flow/model/instruction_guideline.d.ts +9 -0
- package/dist/presentation/flow/model/instruction_guideline.d.ts.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.d.ts +11 -2
- package/dist/presentation/flow/model/instructions_defaults.d.ts.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js +73 -25
- 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 +36 -12
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_instructions_screen.js +1 -1
- package/dist/presentation/flow/screen/orchestrated_instructions_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 +3 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js +3 -3
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.js +14 -0
- package/dist/presentation/flow/validation/job_type_validator.js.map +1 -1
- 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/instructions_screen_helpers.d.ts +1 -0
- package/dist/presentation/screen/helpers/instructions_screen_helpers.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/instructions_screen_helpers.js +6 -2
- package/dist/presentation/screen/helpers/instructions_screen_helpers.js.map +1 -1
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js +3 -0
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +17 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.js +153 -18
- package/dist/presentation/screen/use_smile_id_capture_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts +2 -3
- package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js +16 -11
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts +2 -0
- package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_instructions_screen.js +2 -1
- package/dist/presentation/screen/use_smile_id_instructions_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts +7 -6
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.js +9 -8
- package/dist/presentation/screen/use_smile_id_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.d.ts +2 -3
- package/dist/presentation/screen/use_smile_id_processing_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js +3 -2
- package/dist/presentation/screen/use_smile_id_processing_screen.js.map +1 -1
- package/dist/presentation/theme/theme.d.ts +1 -1
- package/dist/presentation/theme/theme.d.ts.map +1 -1
- package/dist/presentation/theme/theme.js +20 -18
- package/dist/presentation/theme/theme.js.map +1 -1
- package/dist/presentation/utils/force_max_brightness.d.ts +4 -4
- package/package.json +26 -6
- package/src/__tests__/react_native_mock.tsx +8 -0
- package/src/camera/camera_defaults.ts +11 -9
- package/src/camera/orientation_degrees.ts +5 -6
- package/src/core/models/__tests__/document_type.test.ts +6 -4
- package/src/core/models/document_capture_mode.ts +27 -0
- package/src/core/models/document_type.ts +6 -4
- package/src/core/models/result.ts +9 -8
- package/src/data/api/interceptors/__tests__/smile_integrity_interceptor.test.ts +37 -1
- package/src/data/api/interceptors/__tests__/smile_request_mac_interceptor.test.ts +59 -1
- package/src/data/api/interceptors/smile_auth_interceptor.ts +1 -1
- package/src/data/api/interceptors/smile_integrity_interceptor.ts +20 -0
- package/src/data/api/interceptors/smile_request_mac_interceptor.ts +13 -0
- package/src/data/compression/__tests__/payload_compressor.test.ts +200 -0
- package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +222 -0
- package/src/data/compression/compressible_asset.ts +62 -0
- package/src/data/compression/payload_compression_config.ts +53 -0
- package/src/data/compression/payload_compression_runner.ts +102 -0
- package/src/data/compression/payload_compressor.ts +164 -0
- package/src/data/compression/uri_compressible_asset.ts +85 -0
- package/src/data/dsl/builder/cache_config_builder.ts +3 -1
- package/src/data/dsl/builder/config_builder.ts +45 -14
- package/src/data/dsl/builder/interceptor_config_builder.ts +9 -7
- package/src/data/dsl/builder/retry_config_builder.ts +22 -1
- package/src/data/dsl/builder/timeout_config_builder.ts +7 -0
- package/src/data/dsl/use_smile_id_network_builder.ts +17 -0
- package/src/data/factory/networking_factory.ts +14 -1
- package/src/data/repository/__tests__/network_retries.test.ts +117 -0
- package/src/data/repository/use_smile_id_repository_impl.ts +96 -9
- package/src/data/security/__tests__/security_policy.test.ts +96 -0
- package/src/data/security/__tests__/smile_id_crypto_manager.test.ts +18 -0
- package/src/data/security/request_canonicalizer.ts +15 -2
- package/src/data/security/security_policy.ts +70 -0
- package/src/data/util/__tests__/use_smile_id_token_decoder.test.ts +57 -1
- package/src/data/util/retry_util.ts +3 -2
- package/src/data/util/use_smile_id_token_decoder.ts +76 -28
- package/src/l10n/strings_en.ts +2 -1
- package/src/l10n/use_smile_id_localizations.ts +3 -0
- package/src/metadata/__tests__/device_orientation_collector.test.ts +15 -0
- package/src/metadata/__tests__/metadata_configuration_mappers.test.ts +215 -0
- package/src/metadata/__tests__/metadata_configuration_objects.test.ts +85 -0
- package/src/metadata/__tests__/metadata_device_context.test.ts +147 -0
- package/src/metadata/__tests__/metadata_golden_fixture.json +13 -0
- package/src/metadata/__tests__/metadata_payload_golden.test.ts +193 -0
- package/src/metadata/__tests__/use_smile_id_metadata.test.ts +18 -24
- package/src/metadata/builder_configuration.ts +63 -0
- package/src/metadata/captured_image_properties.ts +10 -0
- package/src/metadata/device_orientation_collector.ts +75 -0
- package/src/metadata/geolocation.ts +46 -0
- package/src/metadata/metadata_configuration_mappers.ts +234 -0
- package/src/metadata/model_configuration.ts +68 -0
- package/src/metadata/optional_native_modules.ts +157 -3
- package/src/metadata/use_smile_id_metadata.ts +140 -17
- package/src/metadata/use_smile_id_metadata_factory.ts +195 -11
- package/src/presentation/assets/si_ess_animation_all_directions.json +1300 -286
- package/src/presentation/assets/svg/document_shimmer_strings.ts +17 -0
- package/src/presentation/assets/svg/instruction_svg_strings.ts +34 -12
- package/src/presentation/components/__tests__/enhanced_smart_selfie_animation_frames.test.ts +1 -3
- package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +3 -4
- package/src/presentation/components/__tests__/use_smile_id_guideline_thumbnail.test.tsx +34 -1
- package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +27 -0
- package/src/presentation/components/__tests__/use_smile_id_oval_border_palette.test.ts +7 -5
- package/src/presentation/components/helpers/enhanced_smart_selfie_animation_frames.ts +0 -6
- package/src/presentation/components/icons/index.tsx +65 -18
- package/src/presentation/components/use_smile_id_attribution.tsx +1 -1
- package/src/presentation/components/use_smile_id_button.tsx +4 -4
- package/src/presentation/components/use_smile_id_capture_content.tsx +36 -12
- package/src/presentation/components/use_smile_id_captured_document_image.tsx +3 -8
- package/src/presentation/components/use_smile_id_document_capture_controls.tsx +103 -39
- package/src/presentation/components/use_smile_id_document_overlay.tsx +134 -44
- package/src/presentation/components/use_smile_id_document_shimmer.tsx +51 -0
- package/src/presentation/components/use_smile_id_enhanced_smart_selfie_clip.tsx +0 -3
- package/src/presentation/components/use_smile_id_guideline_thumbnail.tsx +131 -2
- package/src/presentation/components/use_smile_id_instructions_hero.tsx +100 -59
- package/src/presentation/components/use_smile_id_oval_border_palette.ts +7 -3
- package/src/presentation/flow/__tests__/document_flow_navigation.test.ts +200 -1
- package/src/presentation/flow/dsl/builder/config_builder.ts +14 -0
- package/src/presentation/flow/dsl/builder/ml_builder.ts +13 -4
- package/src/presentation/flow/dsl/builder/screens_builder.ts +111 -10
- package/src/presentation/flow/dsl/builder/theme_builder.ts +19 -2
- package/src/presentation/flow/dsl/use_smile_id_builder.tsx +6 -4
- package/src/presentation/flow/dsl/use_smile_id_flow_builder.ts +62 -36
- package/src/presentation/flow/flow_navigation_manager.ts +179 -13
- package/src/presentation/flow/model/instruction_guideline.ts +6 -0
- package/src/presentation/flow/model/instructions_defaults.ts +103 -25
- package/src/presentation/flow/screen/orchestrated_capture_screen.tsx +43 -10
- package/src/presentation/flow/screen/orchestrated_instructions_screen.tsx +1 -0
- package/src/presentation/flow/screen/orchestrated_preview_screen.tsx +4 -2
- package/src/presentation/flow/screen/orchestrated_processing_screen.tsx +3 -3
- package/src/presentation/flow/validation/__tests__/job_type_validator.test.ts +64 -0
- package/src/presentation/flow/validation/job_type_validator.ts +24 -0
- package/src/presentation/screen/__tests__/instructions_screen_helpers.test.ts +15 -3
- package/src/presentation/screen/__tests__/use_smile_id_capture_screen.test.tsx +6 -4
- package/src/presentation/screen/helpers/capture_screen_helpers.ts +1 -0
- package/src/presentation/screen/helpers/instructions_screen_helpers.ts +7 -2
- package/src/presentation/screen/helpers/scan_state_to_overlay_state.ts +3 -0
- package/src/presentation/screen/use_smile_id_capture_screen.tsx +234 -36
- package/src/presentation/screen/use_smile_id_document_preview_screen.tsx +32 -22
- package/src/presentation/screen/use_smile_id_instructions_screen.tsx +4 -0
- package/src/presentation/screen/use_smile_id_preview_screen.tsx +9 -9
- package/src/presentation/screen/use_smile_id_processing_screen.tsx +7 -7
- package/src/presentation/theme/theme.ts +21 -19
- package/src/presentation/utils/force_max_brightness.tsx +4 -4
- package/dist/camera/frame_processor_plugin.d.ts +0 -28
- package/dist/camera/frame_processor_plugin.d.ts.map +0 -1
- package/dist/camera/frame_processor_plugin.js +0 -21
- package/dist/camera/frame_processor_plugin.js.map +0 -1
- package/dist/camera/use_smile_id_frame_processor.d.ts +0 -38
- package/dist/camera/use_smile_id_frame_processor.d.ts.map +0 -1
- package/dist/camera/use_smile_id_frame_processor.js +0 -2
- package/dist/camera/use_smile_id_frame_processor.js.map +0 -1
- package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts +0 -17
- package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_document_frame_glyph.js +0 -17
- package/dist/presentation/components/use_smile_id_document_frame_glyph.js.map +0 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts +0 -24
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js +0 -91
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js.map +0 -1
- package/dist/presentation/components/use_smile_id_instruction_card.d.ts +0 -31
- package/dist/presentation/components/use_smile_id_instruction_card.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_instruction_card.js +0 -43
- package/dist/presentation/components/use_smile_id_instruction_card.js.map +0 -1
- package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts +0 -24
- package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts.map +0 -1
- package/dist/presentation/screen/helpers/use_document_orientation_lock.js +0 -47
- package/dist/presentation/screen/helpers/use_document_orientation_lock.js.map +0 -1
- package/src/presentation/components/use_smile_id_document_frame_glyph.tsx +0 -162
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { base64Encode, utf8Bytes } from "./signing_crypto";
|
|
2
|
+
import { SmileIDCryptoError } from "./smile_id_crypto_error";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Reduces a request to the canonical bytes that get signed: the signed headers
|
|
@@ -86,8 +87,20 @@ async function canonicalBody(body: unknown): Promise<Uint8Array> {
|
|
|
86
87
|
/** File parts (a `uri`) → Base64 of bytes; JSON fields → parsed; else string with bool coercion. */
|
|
87
88
|
async function partValue(part: FormDataPart): Promise<unknown> {
|
|
88
89
|
if (part.uri != null) {
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
// Reading a file part can reject — e.g. the captured-image `file://` URI is
|
|
91
|
+
// unreadable, or the RN runtime rejects a local-file `fetch` when the device
|
|
92
|
+
// is offline (behaviour differs between the Expo and bare-RN runtimes).
|
|
93
|
+
// Surface it as a SmileIDCryptoError so the signing interceptor's narrow
|
|
94
|
+
// catch fails open (ships the request unsigned) instead of letting the
|
|
95
|
+
// rejection escape and crash the submission flow.
|
|
96
|
+
try {
|
|
97
|
+
const response = await fetch(part.uri);
|
|
98
|
+
return base64Encode(new Uint8Array(await response.arrayBuffer()));
|
|
99
|
+
} catch (cause) {
|
|
100
|
+
throw new SmileIDCryptoError(
|
|
101
|
+
`Failed to read request part "${part.fieldName}" for signing: ${String(cause)}`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
91
104
|
}
|
|
92
105
|
const value = part.string ?? "";
|
|
93
106
|
if (JSON_FIELDS.has(part.fieldName)) {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-driven security policy decoded from the integer `policy` bit-code carried as a top-level
|
|
3
|
+
* claim on the SmileID JWT — a sibling of the `sdk_config` claim, not nested inside it (see
|
|
4
|
+
* `decodeSecurityPolicyBitCode` and `docs/Policy.md`).
|
|
5
|
+
*
|
|
6
|
+
* Each bit toggles one SDK security behaviour, so the backend can dial protection up or down per
|
|
7
|
+
* session without shipping a new SDK build. The bit-code contract — which bit means what — is
|
|
8
|
+
* documented in `docs/Policy.md`, not here, so the four SDKs share one source of truth.
|
|
9
|
+
*
|
|
10
|
+
* **Fail-secure:** an absent (`undefined`) bit-code enables every behaviour, so a token that omits
|
|
11
|
+
* the claim — or a malformed token that fails to decode — runs with full protection rather than
|
|
12
|
+
* silently dropping security. This matches the value `undefined` produces in
|
|
13
|
+
* {@link SecurityPolicy.fromBitCode}.
|
|
14
|
+
*
|
|
15
|
+
* **Internal by design:** this class is not exported from the package entrypoint (`src/index.ts`),
|
|
16
|
+
* so it never becomes part of the partner-facing API; it exists only so the SDK can gate its own
|
|
17
|
+
* request signing and device attestation.
|
|
18
|
+
*/
|
|
19
|
+
export class SecurityPolicy {
|
|
20
|
+
private static readonly _BIT_PAYLOAD_SIGNING = 0;
|
|
21
|
+
private static readonly _BIT_PAYLOAD_ENCRYPTION = 1;
|
|
22
|
+
private static readonly _BIT_ROOTED_DEVICE_CHECK = 2;
|
|
23
|
+
private static readonly _BIT_PLAY_INTEGRITY_CHECK = 3;
|
|
24
|
+
|
|
25
|
+
// Fail-secure default for an absent bit-code: every known behaviour active.
|
|
26
|
+
private static readonly _ALL_ACTIVE =
|
|
27
|
+
(1 << SecurityPolicy._BIT_PAYLOAD_SIGNING) |
|
|
28
|
+
(1 << SecurityPolicy._BIT_PAYLOAD_ENCRYPTION) |
|
|
29
|
+
(1 << SecurityPolicy._BIT_ROOTED_DEVICE_CHECK) |
|
|
30
|
+
(1 << SecurityPolicy._BIT_PLAY_INTEGRITY_CHECK);
|
|
31
|
+
|
|
32
|
+
private readonly _bitCode: number;
|
|
33
|
+
|
|
34
|
+
private constructor(bitCode: number) {
|
|
35
|
+
this._bitCode = bitCode;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Decode a `bitCode` into a typed policy. An `undefined` code is fail-secure — every behaviour
|
|
40
|
+
* is active. For a defined code, behaviour `b` is active when bit `b` is set, least-significant
|
|
41
|
+
* bit first.
|
|
42
|
+
*/
|
|
43
|
+
static fromBitCode(bitCode: number | undefined): SecurityPolicy {
|
|
44
|
+
return new SecurityPolicy(bitCode ?? SecurityPolicy._ALL_ACTIVE);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** True when the server enabled request-payload HMAC signing for this session. */
|
|
48
|
+
isPayloadSigningActive(): boolean {
|
|
49
|
+
return this._isSet(SecurityPolicy._BIT_PAYLOAD_SIGNING);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** True when the server enabled request-payload encryption for this session. */
|
|
53
|
+
isPayloadEncryptionActive(): boolean {
|
|
54
|
+
return this._isSet(SecurityPolicy._BIT_PAYLOAD_ENCRYPTION);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** True when the server enabled the rooted / jailbroken device check for this session. */
|
|
58
|
+
isRootedDeviceCheckActive(): boolean {
|
|
59
|
+
return this._isSet(SecurityPolicy._BIT_ROOTED_DEVICE_CHECK);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** True when the server enabled device attestation for this session. */
|
|
63
|
+
isPlayIntegrityCheckActive(): boolean {
|
|
64
|
+
return this._isSet(SecurityPolicy._BIT_PLAY_INTEGRITY_CHECK);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private _isSet(bit: number): boolean {
|
|
68
|
+
return ((this._bitCode >> bit) & 1) === 1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
decodeSmileIDToken,
|
|
4
|
+
decodeSecurityPolicyBitCode,
|
|
5
|
+
} from "../use_smile_id_token_decoder";
|
|
3
6
|
|
|
4
7
|
// ---------------------------------------------------------------------------
|
|
5
8
|
// Helper — mint a structurally valid JWT with a caller-supplied payload.
|
|
@@ -14,6 +17,59 @@ function makeJwt(payload: Record<string, unknown>): string {
|
|
|
14
17
|
return `eyJhbGciOiJub25lIn0.${payloadSegment}.stub-sig`;
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Security policy bit-code extraction
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
describe("decodeSecurityPolicyBitCode", () => {
|
|
24
|
+
it("parses the top-level policy bit-code alongside sdk_config", () => {
|
|
25
|
+
const token = makeJwt({
|
|
26
|
+
policy: 9,
|
|
27
|
+
sdk_config: { selfie: { quality: 85 } },
|
|
28
|
+
});
|
|
29
|
+
expect(decodeSecurityPolicyBitCode(token)).toBe(9);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("parses the top-level policy bit-code when sdk_config is absent", () => {
|
|
33
|
+
const token = makeJwt({ policy: 0 });
|
|
34
|
+
expect(decodeSecurityPolicyBitCode(token)).toBe(0);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("returns undefined when the token omits policy", () => {
|
|
38
|
+
const token = makeJwt({ sdk_config: { selfie: { quality: 85 } } });
|
|
39
|
+
expect(decodeSecurityPolicyBitCode(token)).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("returns undefined for a structurally invalid token", () => {
|
|
43
|
+
expect(decodeSecurityPolicyBitCode("not-a-jwt")).toBeUndefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns undefined when policy is not a number", () => {
|
|
47
|
+
const token = makeJwt({ policy: "9" });
|
|
48
|
+
expect(decodeSecurityPolicyBitCode(token)).toBeUndefined();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("decodeSmileIDToken — partner_id claim (stamped onto the EXIF tag)", () => {
|
|
53
|
+
it("parses the canonical top-level partner_id claim", () => {
|
|
54
|
+
// The EXIF tagger keys on this, so it must be the server-canonical form (e.g. "002").
|
|
55
|
+
const token = makeJwt({
|
|
56
|
+
partner_id: "002",
|
|
57
|
+
sdk_config: { selfie: { width: 640 } },
|
|
58
|
+
});
|
|
59
|
+
expect(decodeSmileIDToken(token)?.partnerId).toBe("002");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("leaves partnerId undefined when the claim is absent", () => {
|
|
63
|
+
const token = makeJwt({ sdk_config: { selfie: { quality: 85 } } });
|
|
64
|
+
expect(decodeSmileIDToken(token)?.partnerId).toBeUndefined();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("leaves partnerId undefined when the claim is not a string", () => {
|
|
68
|
+
const token = makeJwt({ partner_id: 2 });
|
|
69
|
+
expect(decodeSmileIDToken(token)?.partnerId).toBeUndefined();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
17
73
|
// ---------------------------------------------------------------------------
|
|
18
74
|
// Structural failure paths → undefined
|
|
19
75
|
// ---------------------------------------------------------------------------
|
|
@@ -13,12 +13,13 @@ import type { RetryConfig } from "../../core/models/network_config";
|
|
|
13
13
|
*/
|
|
14
14
|
export async function withRetry<T>(
|
|
15
15
|
config: RetryConfig,
|
|
16
|
-
block: () => Promise<T>,
|
|
16
|
+
block: (attempt: number) => Promise<T>,
|
|
17
17
|
): Promise<T> {
|
|
18
18
|
let lastError: unknown;
|
|
19
19
|
for (let attempt = 0; attempt < config.maxAttempts; attempt++) {
|
|
20
20
|
try {
|
|
21
|
-
|
|
21
|
+
// `attempt` is the number of retries that preceded this try (0 first).
|
|
22
|
+
return await block(attempt);
|
|
22
23
|
} catch (error) {
|
|
23
24
|
lastError = error;
|
|
24
25
|
if (!isRetryable(error) || attempt === config.maxAttempts - 1) {
|
|
@@ -20,6 +20,14 @@ declare function atob(data: string): string;
|
|
|
20
20
|
*/
|
|
21
21
|
export type DecodedToken = {
|
|
22
22
|
readonly sdkConfig?: SdkConfig;
|
|
23
|
+
/**
|
|
24
|
+
* Canonical `partner_id` from the top-level JWT claim (server-padded form,
|
|
25
|
+
* e.g. `"002"`), which can differ from the partner-supplied config string
|
|
26
|
+
* (`"2"`). The Smile EXIF tagger keys its HMAC/AES derivation on this so the
|
|
27
|
+
* stamped value matches the partner_id the backend validates against.
|
|
28
|
+
* `undefined` when the claim is absent.
|
|
29
|
+
*/
|
|
30
|
+
readonly partnerId?: string;
|
|
23
31
|
};
|
|
24
32
|
|
|
25
33
|
/**
|
|
@@ -40,6 +48,73 @@ export type DecodedToken = {
|
|
|
40
48
|
* This function never throws — all failure paths return a value.
|
|
41
49
|
*/
|
|
42
50
|
export function decodeSmileIDToken(token: string): DecodedToken | undefined {
|
|
51
|
+
const payloadObject = parseJwtPayloadObject(token);
|
|
52
|
+
if (payloadObject === undefined) return undefined;
|
|
53
|
+
|
|
54
|
+
// Canonical partner_id — a TOP-LEVEL claim (server-padded form, e.g. "002"), a sibling of
|
|
55
|
+
// `sdk_config`. The EXIF tagger keys on this so the stamped value matches the backend. Spread
|
|
56
|
+
// in only when present so `exactOptionalPropertyTypes` isn't violated by an explicit undefined.
|
|
57
|
+
const rawPartnerId = payloadObject["partner_id"];
|
|
58
|
+
const partnerIdField =
|
|
59
|
+
typeof rawPartnerId === "string" ? { partnerId: rawPartnerId } : {};
|
|
60
|
+
|
|
61
|
+
const rawClaim = payloadObject["sdk_config"];
|
|
62
|
+
|
|
63
|
+
if (rawClaim === undefined || rawClaim === null) {
|
|
64
|
+
// No claim present — defaults apply throughout the flow.
|
|
65
|
+
return { ...partnerIdField };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof rawClaim !== "object" || Array.isArray(rawClaim)) {
|
|
69
|
+
// Claim exists but is not an object — treat as absent.
|
|
70
|
+
return { ...partnerIdField };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const parseResult = sdkConfigSchema.safeParse(rawClaim);
|
|
74
|
+
if (!parseResult.success) {
|
|
75
|
+
// Zod rejected the claim shape — degrade to defaults.
|
|
76
|
+
if (!(parseResult.error instanceof ZodError)) {
|
|
77
|
+
// Unreachable in practice (safeParse always gives ZodError on
|
|
78
|
+
// failure), but degrade gracefully to preserve the never-throws
|
|
79
|
+
// contract rather than surfacing an unexpected error type.
|
|
80
|
+
return { ...partnerIdField };
|
|
81
|
+
}
|
|
82
|
+
return { ...partnerIdField };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return { sdkConfig: parseResult.data, ...partnerIdField };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Extract the server-driven security policy bit-code from the token's **top-level** `policy` claim
|
|
90
|
+
* (a sibling of `sdk_config`, not nested inside it — mirroring the backend and the v11
|
|
91
|
+
* `/v1/auth_smile` response).
|
|
92
|
+
*
|
|
93
|
+
* Internal-only: deliberately NOT re-exported from the package entrypoint (`src/index.ts`), so the
|
|
94
|
+
* policy never widens the partner-facing API. It rides here — alongside the decoder — rather than
|
|
95
|
+
* on the exported {@link DecodedToken} for the same reason. See `SecurityPolicy` and
|
|
96
|
+
* `docs/Policy.md`.
|
|
97
|
+
*
|
|
98
|
+
* Returns `undefined` when the token is unparseable or carries no numeric top-level `policy`. The
|
|
99
|
+
* caller treats `undefined` as fail-secure (every behaviour active), so this never throws.
|
|
100
|
+
*/
|
|
101
|
+
export function decodeSecurityPolicyBitCode(token: string): number | undefined {
|
|
102
|
+
const payloadObject = parseJwtPayloadObject(token);
|
|
103
|
+
if (payloadObject === undefined) return undefined;
|
|
104
|
+
|
|
105
|
+
const policy = payloadObject["policy"];
|
|
106
|
+
return typeof policy === "number" ? policy : undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Parse the JWT payload (middle segment) into a JSON object, or `undefined` when the token is
|
|
111
|
+
* structurally invalid (not exactly three `.`-delimited segments, non-base64url payload, or a
|
|
112
|
+
* non-object JSON payload). Shared by {@link decodeSmileIDToken} and
|
|
113
|
+
* {@link decodeSecurityPolicyBitCode} so both read the payload the same way.
|
|
114
|
+
*/
|
|
115
|
+
function parseJwtPayloadObject(
|
|
116
|
+
token: string,
|
|
117
|
+
): Record<string, unknown> | undefined {
|
|
43
118
|
const segments = token.split(".");
|
|
44
119
|
if (segments.length !== 3) return undefined;
|
|
45
120
|
|
|
@@ -74,34 +149,7 @@ export function decodeSmileIDToken(token: string): DecodedToken | undefined {
|
|
|
74
149
|
return undefined;
|
|
75
150
|
}
|
|
76
151
|
|
|
77
|
-
|
|
78
|
-
// empty DecodedToken (sdkConfig unset) rather than returning undefined.
|
|
79
|
-
const payloadObject = payload as Record<string, unknown>;
|
|
80
|
-
const rawClaim = payloadObject["sdk_config"];
|
|
81
|
-
|
|
82
|
-
if (rawClaim === undefined || rawClaim === null) {
|
|
83
|
-
// No claim present — defaults apply throughout the flow.
|
|
84
|
-
return {};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (typeof rawClaim !== "object" || Array.isArray(rawClaim)) {
|
|
88
|
-
// Claim exists but is not an object — treat as absent.
|
|
89
|
-
return {};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const parseResult = sdkConfigSchema.safeParse(rawClaim);
|
|
93
|
-
if (!parseResult.success) {
|
|
94
|
-
// Zod rejected the claim shape — degrade to defaults.
|
|
95
|
-
if (!(parseResult.error instanceof ZodError)) {
|
|
96
|
-
// Unreachable in practice (safeParse always gives ZodError on
|
|
97
|
-
// failure), but degrade gracefully to preserve the never-throws
|
|
98
|
-
// contract rather than surfacing an unexpected error type.
|
|
99
|
-
return {};
|
|
100
|
-
}
|
|
101
|
-
return {};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return { sdkConfig: parseResult.data };
|
|
152
|
+
return payload as Record<string, unknown>;
|
|
105
153
|
}
|
|
106
154
|
|
|
107
155
|
/**
|
package/src/l10n/strings_en.ts
CHANGED
|
@@ -160,6 +160,7 @@ export const enStrings = {
|
|
|
160
160
|
si_ess_look_left: "Turn your head to the left",
|
|
161
161
|
si_ess_look_right: "Turn your head to the right",
|
|
162
162
|
si_ess_look_up: "Turn your head slightly upwards",
|
|
163
|
+
si_ess_look_at_camera: "Look at the camera",
|
|
163
164
|
si_ess_capture_initial_instruction:
|
|
164
165
|
"Centre your face in the frame and turn your head in the direction of the arrow.",
|
|
165
166
|
si_ess_hold_still: "Hold still…",
|
|
@@ -168,4 +169,4 @@ export const enStrings = {
|
|
|
168
169
|
export type SiKey = keyof typeof enStrings;
|
|
169
170
|
|
|
170
171
|
/** Total canonical key count — pinned in tests to catch a missed addition/deletion at PR time. */
|
|
171
|
-
export const CANONICAL_KEY_COUNT =
|
|
172
|
+
export const CANONICAL_KEY_COUNT = 119 as const;
|
|
@@ -676,6 +676,9 @@ export class UseSmileIDLocalizations {
|
|
|
676
676
|
get siEssLookUp(): string {
|
|
677
677
|
return this._s("si_ess_look_up", enStrings.si_ess_look_up);
|
|
678
678
|
}
|
|
679
|
+
get siEssLookAtCamera(): string {
|
|
680
|
+
return this._s("si_ess_look_at_camera", enStrings.si_ess_look_at_camera);
|
|
681
|
+
}
|
|
679
682
|
get siEssCaptureInitialInstruction(): string {
|
|
680
683
|
return this._s(
|
|
681
684
|
"si_ess_capture_initial_instruction",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { DeviceOrientationCollector } from "../device_orientation_collector";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Regression guard: with no accelerometer samples, `device_movement_detected` must be absent
|
|
7
|
+
* (`null`) and `device_positions` empty — never a sentinel. Mirrored across all four SDKs.
|
|
8
|
+
*/
|
|
9
|
+
describe("DeviceOrientationCollector", () => {
|
|
10
|
+
it("omits movement (null) and positions when no samples were collected", () => {
|
|
11
|
+
const collector = new DeviceOrientationCollector();
|
|
12
|
+
expect(collector.deviceMovementDetected).toBeNull();
|
|
13
|
+
expect(collector.devicePositions).toHaveLength(0);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AnalyzerFactoryKey,
|
|
3
|
+
faceConfigSchema,
|
|
4
|
+
} from "@smileid/usesmileid_bridge";
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { DocumentCaptureMode } from "../../core/models/document_capture_mode";
|
|
8
|
+
import { CaptureType } from "../../core/models/ml_config";
|
|
9
|
+
import type { FlowConfiguration } from "../../presentation/flow/config/flow_configuration";
|
|
10
|
+
import { ScreensBuilder } from "../../presentation/flow/dsl/builder/screens_builder";
|
|
11
|
+
import {
|
|
12
|
+
ModelProvider,
|
|
13
|
+
MODEL_DESCRIPTOR_UNKNOWN,
|
|
14
|
+
} from "../model_configuration";
|
|
15
|
+
import {
|
|
16
|
+
flowConfigurationToBuilderConfiguration,
|
|
17
|
+
flowConfigurationToModelConfiguration,
|
|
18
|
+
flowConfigurationToSelfieLivenessTelemetry,
|
|
19
|
+
} from "../metadata_configuration_mappers";
|
|
20
|
+
|
|
21
|
+
function flow(
|
|
22
|
+
buildScreens: (screens: ScreensBuilder) => void,
|
|
23
|
+
ml?: FlowConfiguration["ml"],
|
|
24
|
+
): FlowConfiguration {
|
|
25
|
+
const screensBuilder = new ScreensBuilder();
|
|
26
|
+
buildScreens(screensBuilder);
|
|
27
|
+
return {
|
|
28
|
+
screens: screensBuilder.build(),
|
|
29
|
+
...(ml ? { ml } : {}),
|
|
30
|
+
onResult: () => {},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe("flowConfigurationToBuilderConfiguration", () => {
|
|
35
|
+
it("reflects the consent screen", () => {
|
|
36
|
+
const config = flowConfigurationToBuilderConfiguration(
|
|
37
|
+
flow((screens) => {
|
|
38
|
+
screens.consent((consent) => {
|
|
39
|
+
consent.partnerIcon = "icon";
|
|
40
|
+
consent.showAttribution = false;
|
|
41
|
+
});
|
|
42
|
+
}),
|
|
43
|
+
);
|
|
44
|
+
expect(config.consentScreenUsed).toBe(true);
|
|
45
|
+
expect(config.consentIconProvided).toBe(true);
|
|
46
|
+
// A React Native consent icon is a ReactNode with no measurable pixel size.
|
|
47
|
+
expect(config.consentIconDimensions).toBeNull();
|
|
48
|
+
expect(config.consentAttributionShown).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("reports consent absent when there is no consent screen", () => {
|
|
52
|
+
const config = flowConfigurationToBuilderConfiguration(
|
|
53
|
+
flow((screens) => screens.instructions()),
|
|
54
|
+
);
|
|
55
|
+
expect(config.consentScreenUsed).toBe(false);
|
|
56
|
+
expect(config.consentIconProvided).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("maps selfie capture flags", () => {
|
|
60
|
+
const config = flowConfigurationToBuilderConfiguration(
|
|
61
|
+
flow((screens) => {
|
|
62
|
+
screens.capture((capture) => {
|
|
63
|
+
capture.captureType = CaptureType.selfie;
|
|
64
|
+
capture.selfie((selfie) => {
|
|
65
|
+
selfie.allowAgentMode = true;
|
|
66
|
+
selfie.enableEnhancedLiveness = true;
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
screens.preview();
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
expect(config.allowAgentMode).toBe(true);
|
|
73
|
+
expect(config.enhancedLivenessEnabled).toBe(true);
|
|
74
|
+
expect(config.selfiePreviewEnabled).toBe(true);
|
|
75
|
+
expect(config.documentPreviewEnabled).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("maps document capture flags and capture mode", () => {
|
|
79
|
+
const config = flowConfigurationToBuilderConfiguration(
|
|
80
|
+
flow((screens) => {
|
|
81
|
+
screens.capture((capture) => {
|
|
82
|
+
capture.captureType = CaptureType.document;
|
|
83
|
+
capture.document((document) => {
|
|
84
|
+
document.captureMode = DocumentCaptureMode.ManualCapture;
|
|
85
|
+
document.allowGalleryUpload = true;
|
|
86
|
+
document.captureBothSides = false;
|
|
87
|
+
document.allowSkipBack = true;
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
screens.preview();
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
93
|
+
expect(config.autoCaptureEnabled).toBe("manual");
|
|
94
|
+
expect(config.allowGalleryUpload).toBe(true);
|
|
95
|
+
expect(config.captureBothSides).toBe(false);
|
|
96
|
+
expect(config.allowSkipBack).toBe(true);
|
|
97
|
+
expect(config.documentPreviewEnabled).toBe(true);
|
|
98
|
+
expect(config.selfiePreviewEnabled).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("maps each document capture mode to the wire enum", () => {
|
|
102
|
+
const modeFor = (captureMode: DocumentCaptureMode): string =>
|
|
103
|
+
flowConfigurationToBuilderConfiguration(
|
|
104
|
+
flow((screens) => {
|
|
105
|
+
screens.capture((capture) => {
|
|
106
|
+
capture.captureType = CaptureType.document;
|
|
107
|
+
capture.document((document) => {
|
|
108
|
+
document.captureMode = captureMode;
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}),
|
|
112
|
+
).autoCaptureEnabled;
|
|
113
|
+
|
|
114
|
+
expect(modeFor(DocumentCaptureMode.AutoCapture)).toBe("auto_capture_only");
|
|
115
|
+
expect(modeFor(DocumentCaptureMode.ManualCapture)).toBe("manual");
|
|
116
|
+
expect(modeFor(DocumentCaptureMode.AutoCaptureWithManualFallback())).toBe(
|
|
117
|
+
"autocapture_default",
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("reports submission skipped without a processing screen", () => {
|
|
122
|
+
const selfieOnly = (screens: ScreensBuilder) =>
|
|
123
|
+
screens.capture((capture) => {
|
|
124
|
+
capture.captureType = CaptureType.selfie;
|
|
125
|
+
});
|
|
126
|
+
expect(
|
|
127
|
+
flowConfigurationToBuilderConfiguration(flow(selfieOnly))
|
|
128
|
+
.submissionSkipped,
|
|
129
|
+
).toBe(true);
|
|
130
|
+
expect(
|
|
131
|
+
flowConfigurationToBuilderConfiguration(
|
|
132
|
+
flow((screens) => {
|
|
133
|
+
selfieOnly(screens);
|
|
134
|
+
screens.processing();
|
|
135
|
+
}),
|
|
136
|
+
).submissionSkipped,
|
|
137
|
+
).toBe(false);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe("flowConfigurationToModelConfiguration", () => {
|
|
142
|
+
it("maps the face backend key with the noop document fallback", () => {
|
|
143
|
+
const config = flow(
|
|
144
|
+
(screens) =>
|
|
145
|
+
screens.capture((capture) => {
|
|
146
|
+
capture.captureType = CaptureType.selfie;
|
|
147
|
+
}),
|
|
148
|
+
{
|
|
149
|
+
analyzers: {
|
|
150
|
+
selfieConfig: faceConfigSchema.parse({
|
|
151
|
+
analyzerFactoryKey: AnalyzerFactoryKey.MLKitFace,
|
|
152
|
+
}),
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
const model = flowConfigurationToModelConfiguration(config);
|
|
157
|
+
expect(model.faceModel.provider).toBe(ModelProvider.Google);
|
|
158
|
+
expect(model.faceModel.name).toBe("play-services-mlkit-face-detection");
|
|
159
|
+
expect(model.documentModel.provider).toBe(ModelProvider.Smile);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("falls back to unknown for an ML-free flow", () => {
|
|
163
|
+
const model = flowConfigurationToModelConfiguration(
|
|
164
|
+
flow((screens) =>
|
|
165
|
+
screens.capture((capture) => {
|
|
166
|
+
capture.captureType = CaptureType.selfie;
|
|
167
|
+
}),
|
|
168
|
+
),
|
|
169
|
+
);
|
|
170
|
+
expect(model.faceModel).toEqual(MODEL_DESCRIPTOR_UNKNOWN);
|
|
171
|
+
expect(model.documentModel.provider).toBe(ModelProvider.Smile);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe("flowConfigurationToSelfieLivenessTelemetry", () => {
|
|
176
|
+
it("reports smile for a standard selfie flow", () => {
|
|
177
|
+
const telemetry = flowConfigurationToSelfieLivenessTelemetry(
|
|
178
|
+
flow((screens) =>
|
|
179
|
+
screens.capture((capture) => {
|
|
180
|
+
capture.captureType = CaptureType.selfie;
|
|
181
|
+
capture.selfie(() => {});
|
|
182
|
+
}),
|
|
183
|
+
),
|
|
184
|
+
);
|
|
185
|
+
expect(telemetry.activeLivenessType).toBe("smile");
|
|
186
|
+
expect(telemetry.activeLivenessVersion).toBe("2.0.0");
|
|
187
|
+
expect(telemetry.selfieImageOrigin).toBe("front_camera");
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("reports head_pose when enhanced liveness is on", () => {
|
|
191
|
+
const telemetry = flowConfigurationToSelfieLivenessTelemetry(
|
|
192
|
+
flow((screens) =>
|
|
193
|
+
screens.capture((capture) => {
|
|
194
|
+
capture.captureType = CaptureType.selfie;
|
|
195
|
+
capture.selfie((selfie) => {
|
|
196
|
+
selfie.enableEnhancedLiveness = true;
|
|
197
|
+
});
|
|
198
|
+
}),
|
|
199
|
+
),
|
|
200
|
+
);
|
|
201
|
+
expect(telemetry.activeLivenessType).toBe("head_pose");
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("is all-null for a document-only flow", () => {
|
|
205
|
+
const telemetry = flowConfigurationToSelfieLivenessTelemetry(
|
|
206
|
+
flow((screens) =>
|
|
207
|
+
screens.capture((capture) => {
|
|
208
|
+
capture.captureType = CaptureType.document;
|
|
209
|
+
}),
|
|
210
|
+
),
|
|
211
|
+
);
|
|
212
|
+
expect(telemetry.activeLivenessType).toBeNull();
|
|
213
|
+
expect(telemetry.selfieImageOrigin).toBeNull();
|
|
214
|
+
});
|
|
215
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type BuilderConfiguration,
|
|
5
|
+
builderConfigurationToJson,
|
|
6
|
+
} from "../builder_configuration";
|
|
7
|
+
import {
|
|
8
|
+
type ModelConfiguration,
|
|
9
|
+
ModelProvider,
|
|
10
|
+
modelConfigurationToJson,
|
|
11
|
+
} from "../model_configuration";
|
|
12
|
+
|
|
13
|
+
const builderConfiguration: BuilderConfiguration = {
|
|
14
|
+
consentScreenUsed: true,
|
|
15
|
+
consentIconProvided: true,
|
|
16
|
+
consentIconDimensions: { width: 120, height: 80 },
|
|
17
|
+
consentAttributionShown: true,
|
|
18
|
+
instructionsScreenUsed: true,
|
|
19
|
+
selfiePreviewEnabled: true,
|
|
20
|
+
documentPreviewEnabled: false,
|
|
21
|
+
submissionSkipped: false,
|
|
22
|
+
allowAgentMode: true,
|
|
23
|
+
enhancedLivenessEnabled: false,
|
|
24
|
+
autoCaptureEnabled: "autocapture_default",
|
|
25
|
+
allowGalleryUpload: true,
|
|
26
|
+
captureBothSides: true,
|
|
27
|
+
allowSkipBack: false,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const modelConfiguration: ModelConfiguration = {
|
|
31
|
+
faceModel: {
|
|
32
|
+
provider: ModelProvider.Google,
|
|
33
|
+
name: "play-services-mlkit-face-detection",
|
|
34
|
+
version: "17.1.0",
|
|
35
|
+
bundled: false,
|
|
36
|
+
},
|
|
37
|
+
documentModel: {
|
|
38
|
+
provider: ModelProvider.Smile,
|
|
39
|
+
name: "noop_document_detector",
|
|
40
|
+
version: "12.0.0",
|
|
41
|
+
bundled: true,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
describe("builder_configuration_object", () => {
|
|
46
|
+
it("serialises the full schema with snake_case keys", () => {
|
|
47
|
+
const json = builderConfigurationToJson(builderConfiguration);
|
|
48
|
+
expect(json.consent_screen_used).toBe(true);
|
|
49
|
+
expect(json.consent_icon_provided).toBe(true);
|
|
50
|
+
expect(json.consent_icon_dimensions).toEqual({ width: 120, height: 80 });
|
|
51
|
+
expect(json.auto_capture_enabled).toBe("autocapture_default");
|
|
52
|
+
expect(json.allow_gallery_upload).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("emits consent_icon_dimensions as null when absent", () => {
|
|
56
|
+
const json = builderConfigurationToJson({
|
|
57
|
+
...builderConfiguration,
|
|
58
|
+
consentIconProvided: false,
|
|
59
|
+
consentIconDimensions: null,
|
|
60
|
+
});
|
|
61
|
+
expect(json.consent_icon_dimensions).toBeNull();
|
|
62
|
+
// round-trips through JSON.stringify as an explicit null, not an omitted key
|
|
63
|
+
const reparsed = JSON.parse(JSON.stringify(json)) as Record<
|
|
64
|
+
string,
|
|
65
|
+
unknown
|
|
66
|
+
>;
|
|
67
|
+
expect("consent_icon_dimensions" in reparsed).toBe(true);
|
|
68
|
+
expect(reparsed.consent_icon_dimensions).toBeNull();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("model_configuration_object", () => {
|
|
73
|
+
it("serialises both model descriptors", () => {
|
|
74
|
+
const json = modelConfigurationToJson(modelConfiguration);
|
|
75
|
+
const face = json.face_model as Record<string, unknown>;
|
|
76
|
+
expect(face.provider).toBe("google");
|
|
77
|
+
expect(face.name).toBe("play-services-mlkit-face-detection");
|
|
78
|
+
expect(face.version).toBe("17.1.0");
|
|
79
|
+
expect(face.bundled).toBe(false);
|
|
80
|
+
|
|
81
|
+
const document = json.document_model as Record<string, unknown>;
|
|
82
|
+
expect(document.provider).toBe("smile");
|
|
83
|
+
expect(document.bundled).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
});
|