@smileid/usesmileid 12.0.0-beta01 → 12.0.1

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.
Files changed (556) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +701 -89
  3. package/dist/camera/camera_defaults.d.ts +14 -9
  4. package/dist/camera/camera_defaults.d.ts.map +1 -1
  5. package/dist/camera/camera_defaults.js +11 -9
  6. package/dist/camera/camera_defaults.js.map +1 -1
  7. package/dist/camera/orientation_degrees.d.ts +5 -6
  8. package/dist/camera/orientation_degrees.d.ts.map +1 -1
  9. package/dist/camera/orientation_degrees.js +5 -6
  10. package/dist/camera/orientation_degrees.js.map +1 -1
  11. package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts +11 -0
  12. package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts.map +1 -0
  13. package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js +17 -0
  14. package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js.map +1 -0
  15. package/dist/core/exception/capture_validation_exceptions.d.ts +1 -0
  16. package/dist/core/exception/capture_validation_exceptions.d.ts.map +1 -1
  17. package/dist/core/exception/capture_validation_exceptions.js +1 -0
  18. package/dist/core/exception/capture_validation_exceptions.js.map +1 -1
  19. package/dist/core/exception/index.d.ts +1 -0
  20. package/dist/core/exception/index.d.ts.map +1 -1
  21. package/dist/core/exception/index.js +1 -0
  22. package/dist/core/exception/index.js.map +1 -1
  23. package/dist/core/exception/use_smile_id_error_code.d.ts +1 -0
  24. package/dist/core/exception/use_smile_id_error_code.d.ts.map +1 -1
  25. package/dist/core/exception/use_smile_id_error_code.js +1 -0
  26. package/dist/core/exception/use_smile_id_error_code.js.map +1 -1
  27. package/dist/core/models/config.d.ts +19 -0
  28. package/dist/core/models/config.d.ts.map +1 -1
  29. package/dist/core/models/document_capture_mode.d.ts +8 -0
  30. package/dist/core/models/document_capture_mode.d.ts.map +1 -1
  31. package/dist/core/models/document_capture_mode.js +24 -0
  32. package/dist/core/models/document_capture_mode.js.map +1 -1
  33. package/dist/core/models/document_type.d.ts +2 -2
  34. package/dist/core/models/document_type.d.ts.map +1 -1
  35. package/dist/core/models/document_type.js +7 -5
  36. package/dist/core/models/document_type.js.map +1 -1
  37. package/dist/core/models/global_privacy_control.d.ts +36 -0
  38. package/dist/core/models/global_privacy_control.d.ts.map +1 -0
  39. package/dist/core/models/global_privacy_control.js +39 -0
  40. package/dist/core/models/global_privacy_control.js.map +1 -0
  41. package/dist/core/models/network_config.d.ts +2 -2
  42. package/dist/core/models/network_config.js +2 -2
  43. package/dist/core/models/result.d.ts +9 -8
  44. package/dist/core/models/result.d.ts.map +1 -1
  45. package/dist/core/models/result.js +5 -6
  46. package/dist/core/models/result.js.map +1 -1
  47. package/dist/data/api/interceptors/smile_auth_interceptor.d.ts.map +1 -1
  48. package/dist/data/api/interceptors/smile_auth_interceptor.js +3 -17
  49. package/dist/data/api/interceptors/smile_auth_interceptor.js.map +1 -1
  50. package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts +11 -0
  51. package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts.map +1 -1
  52. package/dist/data/api/interceptors/smile_integrity_interceptor.js +13 -0
  53. package/dist/data/api/interceptors/smile_integrity_interceptor.js.map +1 -1
  54. package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts +8 -0
  55. package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts.map +1 -1
  56. package/dist/data/api/interceptors/smile_request_mac_interceptor.js +11 -0
  57. package/dist/data/api/interceptors/smile_request_mac_interceptor.js.map +1 -1
  58. package/dist/data/api/smile_id_api.d.ts +1 -1
  59. package/dist/data/api/smile_id_api.d.ts.map +1 -1
  60. package/dist/data/compression/compressible_asset.d.ts +41 -0
  61. package/dist/data/compression/compressible_asset.d.ts.map +1 -0
  62. package/dist/data/compression/compressible_asset.js +34 -0
  63. package/dist/data/compression/compressible_asset.js.map +1 -0
  64. package/dist/data/compression/payload_compression_config.d.ts +36 -0
  65. package/dist/data/compression/payload_compression_config.d.ts.map +1 -0
  66. package/dist/data/compression/payload_compression_config.js +52 -0
  67. package/dist/data/compression/payload_compression_config.js.map +1 -0
  68. package/dist/data/compression/payload_compression_runner.d.ts +29 -0
  69. package/dist/data/compression/payload_compression_runner.d.ts.map +1 -0
  70. package/dist/data/compression/payload_compression_runner.js +55 -0
  71. package/dist/data/compression/payload_compression_runner.js.map +1 -0
  72. package/dist/data/compression/payload_compressor.d.ts +40 -0
  73. package/dist/data/compression/payload_compressor.d.ts.map +1 -0
  74. package/dist/data/compression/payload_compressor.js +126 -0
  75. package/dist/data/compression/payload_compressor.js.map +1 -0
  76. package/dist/data/compression/uri_compressible_asset.d.ts +23 -0
  77. package/dist/data/compression/uri_compressible_asset.d.ts.map +1 -0
  78. package/dist/data/compression/uri_compressible_asset.js +77 -0
  79. package/dist/data/compression/uri_compressible_asset.js.map +1 -0
  80. package/dist/data/dsl/builder/cache_config_builder.d.ts +2 -1
  81. package/dist/data/dsl/builder/cache_config_builder.d.ts.map +1 -1
  82. package/dist/data/dsl/builder/cache_config_builder.js +2 -1
  83. package/dist/data/dsl/builder/cache_config_builder.js.map +1 -1
  84. package/dist/data/dsl/builder/config_builder.d.ts +40 -14
  85. package/dist/data/dsl/builder/config_builder.d.ts.map +1 -1
  86. package/dist/data/dsl/builder/config_builder.js +40 -14
  87. package/dist/data/dsl/builder/config_builder.js.map +1 -1
  88. package/dist/data/dsl/builder/interceptor_config_builder.d.ts +9 -7
  89. package/dist/data/dsl/builder/interceptor_config_builder.d.ts.map +1 -1
  90. package/dist/data/dsl/builder/interceptor_config_builder.js +9 -7
  91. package/dist/data/dsl/builder/interceptor_config_builder.js.map +1 -1
  92. package/dist/data/dsl/builder/retry_config_builder.d.ts +19 -4
  93. package/dist/data/dsl/builder/retry_config_builder.d.ts.map +1 -1
  94. package/dist/data/dsl/builder/retry_config_builder.js +21 -6
  95. package/dist/data/dsl/builder/retry_config_builder.js.map +1 -1
  96. package/dist/data/dsl/builder/timeout_config_builder.d.ts +4 -0
  97. package/dist/data/dsl/builder/timeout_config_builder.d.ts.map +1 -1
  98. package/dist/data/dsl/builder/timeout_config_builder.js +4 -0
  99. package/dist/data/dsl/builder/timeout_config_builder.js.map +1 -1
  100. package/dist/data/dsl/use_smile_id_network_builder.d.ts +17 -0
  101. package/dist/data/dsl/use_smile_id_network_builder.d.ts.map +1 -1
  102. package/dist/data/dsl/use_smile_id_network_builder.js +17 -0
  103. package/dist/data/dsl/use_smile_id_network_builder.js.map +1 -1
  104. package/dist/data/factory/networking_factory.d.ts.map +1 -1
  105. package/dist/data/factory/networking_factory.js +11 -1
  106. package/dist/data/factory/networking_factory.js.map +1 -1
  107. package/dist/data/repository/use_smile_id_repository_impl.d.ts +6 -0
  108. package/dist/data/repository/use_smile_id_repository_impl.d.ts.map +1 -1
  109. package/dist/data/repository/use_smile_id_repository_impl.js +82 -8
  110. package/dist/data/repository/use_smile_id_repository_impl.js.map +1 -1
  111. package/dist/data/security/request_canonicalizer.d.ts.map +1 -1
  112. package/dist/data/security/request_canonicalizer.js +14 -2
  113. package/dist/data/security/request_canonicalizer.js.map +1 -1
  114. package/dist/data/security/security_policy.d.ts +43 -0
  115. package/dist/data/security/security_policy.d.ts.map +1 -0
  116. package/dist/data/security/security_policy.js +61 -0
  117. package/dist/data/security/security_policy.js.map +1 -0
  118. package/dist/data/smile_id_urls.d.ts +1 -1
  119. package/dist/data/smile_id_urls.js +1 -1
  120. package/dist/data/smile_id_urls.js.map +1 -1
  121. package/dist/data/util/retry_util.d.ts +2 -2
  122. package/dist/data/util/retry_util.d.ts.map +1 -1
  123. package/dist/data/util/retry_util.js +7 -1
  124. package/dist/data/util/retry_util.js.map +1 -1
  125. package/dist/data/util/use_smile_id_token_decoder.d.ts +22 -0
  126. package/dist/data/util/use_smile_id_token_decoder.d.ts.map +1 -1
  127. package/dist/data/util/use_smile_id_token_decoder.js +58 -24
  128. package/dist/data/util/use_smile_id_token_decoder.js.map +1 -1
  129. package/dist/index.d.ts +2 -2
  130. package/dist/index.d.ts.map +1 -1
  131. package/dist/index.js +2 -2
  132. package/dist/index.js.map +1 -1
  133. package/dist/l10n/strings_en.d.ts +2 -1
  134. package/dist/l10n/strings_en.d.ts.map +1 -1
  135. package/dist/l10n/strings_en.js +2 -1
  136. package/dist/l10n/strings_en.js.map +1 -1
  137. package/dist/l10n/use_smile_id_localizations.d.ts +1 -0
  138. package/dist/l10n/use_smile_id_localizations.d.ts.map +1 -1
  139. package/dist/l10n/use_smile_id_localizations.js +3 -0
  140. package/dist/l10n/use_smile_id_localizations.js.map +1 -1
  141. package/dist/metadata/builder_configuration.d.ts +44 -0
  142. package/dist/metadata/builder_configuration.d.ts.map +1 -0
  143. package/dist/metadata/builder_configuration.js +35 -0
  144. package/dist/metadata/builder_configuration.js.map +1 -0
  145. package/dist/metadata/captured_image_properties.d.ts +11 -0
  146. package/dist/metadata/captured_image_properties.d.ts.map +1 -0
  147. package/dist/metadata/captured_image_properties.js +11 -0
  148. package/dist/metadata/captured_image_properties.js.map +1 -0
  149. package/dist/metadata/device_orientation_collector.d.ts +17 -0
  150. package/dist/metadata/device_orientation_collector.d.ts.map +1 -0
  151. package/dist/metadata/device_orientation_collector.js +66 -0
  152. package/dist/metadata/device_orientation_collector.js.map +1 -0
  153. package/dist/metadata/geolocation.d.ts +20 -0
  154. package/dist/metadata/geolocation.d.ts.map +1 -0
  155. package/dist/metadata/geolocation.js +40 -0
  156. package/dist/metadata/geolocation.js.map +1 -0
  157. package/dist/metadata/metadata_configuration_mappers.d.ts +47 -0
  158. package/dist/metadata/metadata_configuration_mappers.d.ts.map +1 -0
  159. package/dist/metadata/metadata_configuration_mappers.js +178 -0
  160. package/dist/metadata/metadata_configuration_mappers.js.map +1 -0
  161. package/dist/metadata/model_configuration.d.ts +41 -0
  162. package/dist/metadata/model_configuration.d.ts.map +1 -0
  163. package/dist/metadata/model_configuration.js +44 -0
  164. package/dist/metadata/model_configuration.js.map +1 -0
  165. package/dist/metadata/optional_native_modules.d.ts +79 -3
  166. package/dist/metadata/optional_native_modules.d.ts.map +1 -1
  167. package/dist/metadata/optional_native_modules.js +108 -3
  168. package/dist/metadata/optional_native_modules.js.map +1 -1
  169. package/dist/metadata/use_smile_id_metadata.d.ts +45 -7
  170. package/dist/metadata/use_smile_id_metadata.d.ts.map +1 -1
  171. package/dist/metadata/use_smile_id_metadata.js +85 -13
  172. package/dist/metadata/use_smile_id_metadata.js.map +1 -1
  173. package/dist/metadata/use_smile_id_metadata_factory.d.ts +37 -0
  174. package/dist/metadata/use_smile_id_metadata_factory.d.ts.map +1 -1
  175. package/dist/metadata/use_smile_id_metadata_factory.js +197 -16
  176. package/dist/metadata/use_smile_id_metadata_factory.js.map +1 -1
  177. package/dist/presentation/assets/svg/document_shimmer_strings.d.ts +14 -0
  178. package/dist/presentation/assets/svg/document_shimmer_strings.d.ts.map +1 -0
  179. package/dist/presentation/assets/svg/document_shimmer_strings.js +14 -0
  180. package/dist/presentation/assets/svg/document_shimmer_strings.js.map +1 -0
  181. package/dist/presentation/assets/svg/instruction_svg_strings.d.ts +12 -4
  182. package/dist/presentation/assets/svg/instruction_svg_strings.d.ts.map +1 -1
  183. package/dist/presentation/assets/svg/instruction_svg_strings.js +19 -8
  184. package/dist/presentation/assets/svg/instruction_svg_strings.js.map +1 -1
  185. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts +0 -5
  186. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts.map +1 -1
  187. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js +0 -5
  188. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js.map +1 -1
  189. package/dist/presentation/components/icons/index.d.ts +24 -8
  190. package/dist/presentation/components/icons/index.d.ts.map +1 -1
  191. package/dist/presentation/components/icons/index.js +31 -11
  192. package/dist/presentation/components/icons/index.js.map +1 -1
  193. package/dist/presentation/components/use_smile_id_attribution.d.ts +1 -1
  194. package/dist/presentation/components/use_smile_id_button.d.ts +2 -2
  195. package/dist/presentation/components/use_smile_id_button.js +4 -4
  196. package/dist/presentation/components/use_smile_id_button.js.map +1 -1
  197. package/dist/presentation/components/use_smile_id_capture_content.d.ts +13 -0
  198. package/dist/presentation/components/use_smile_id_capture_content.d.ts.map +1 -1
  199. package/dist/presentation/components/use_smile_id_capture_content.js +15 -9
  200. package/dist/presentation/components/use_smile_id_capture_content.js.map +1 -1
  201. package/dist/presentation/components/use_smile_id_captured_document_image.d.ts +2 -3
  202. package/dist/presentation/components/use_smile_id_captured_document_image.d.ts.map +1 -1
  203. package/dist/presentation/components/use_smile_id_captured_document_image.js +1 -3
  204. package/dist/presentation/components/use_smile_id_captured_document_image.js.map +1 -1
  205. package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts +12 -6
  206. package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts.map +1 -1
  207. package/dist/presentation/components/use_smile_id_document_capture_controls.js +59 -16
  208. package/dist/presentation/components/use_smile_id_document_capture_controls.js.map +1 -1
  209. package/dist/presentation/components/use_smile_id_document_overlay.d.ts +22 -5
  210. package/dist/presentation/components/use_smile_id_document_overlay.d.ts.map +1 -1
  211. package/dist/presentation/components/use_smile_id_document_overlay.js +80 -40
  212. package/dist/presentation/components/use_smile_id_document_overlay.js.map +1 -1
  213. package/dist/presentation/components/use_smile_id_document_shimmer.d.ts +15 -0
  214. package/dist/presentation/components/use_smile_id_document_shimmer.d.ts.map +1 -0
  215. package/dist/presentation/components/use_smile_id_document_shimmer.js +23 -0
  216. package/dist/presentation/components/use_smile_id_document_shimmer.js.map +1 -0
  217. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts +5 -2
  218. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts.map +1 -1
  219. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js +9 -6
  220. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js.map +1 -1
  221. package/dist/presentation/components/use_smile_id_guideline_thumbnail.d.ts.map +1 -1
  222. package/dist/presentation/components/use_smile_id_guideline_thumbnail.js +84 -1
  223. package/dist/presentation/components/use_smile_id_guideline_thumbnail.js.map +1 -1
  224. package/dist/presentation/components/use_smile_id_instructions_hero.d.ts +3 -1
  225. package/dist/presentation/components/use_smile_id_instructions_hero.d.ts.map +1 -1
  226. package/dist/presentation/components/use_smile_id_instructions_hero.js +25 -5
  227. package/dist/presentation/components/use_smile_id_instructions_hero.js.map +1 -1
  228. package/dist/presentation/components/use_smile_id_oval_border_palette.d.ts.map +1 -1
  229. package/dist/presentation/components/use_smile_id_oval_border_palette.js +7 -3
  230. package/dist/presentation/components/use_smile_id_oval_border_palette.js.map +1 -1
  231. package/dist/presentation/flow/dsl/builder/config_builder.d.ts +28 -0
  232. package/dist/presentation/flow/dsl/builder/config_builder.d.ts.map +1 -1
  233. package/dist/presentation/flow/dsl/builder/config_builder.js +30 -0
  234. package/dist/presentation/flow/dsl/builder/config_builder.js.map +1 -1
  235. package/dist/presentation/flow/dsl/builder/ml_builder.d.ts +13 -4
  236. package/dist/presentation/flow/dsl/builder/ml_builder.d.ts.map +1 -1
  237. package/dist/presentation/flow/dsl/builder/ml_builder.js +3 -2
  238. package/dist/presentation/flow/dsl/builder/ml_builder.js.map +1 -1
  239. package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +110 -12
  240. package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
  241. package/dist/presentation/flow/dsl/builder/screens_builder.js +110 -12
  242. package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
  243. package/dist/presentation/flow/dsl/builder/theme_builder.d.ts +15 -2
  244. package/dist/presentation/flow/dsl/builder/theme_builder.d.ts.map +1 -1
  245. package/dist/presentation/flow/dsl/builder/theme_builder.js +15 -2
  246. package/dist/presentation/flow/dsl/builder/theme_builder.js.map +1 -1
  247. package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts +6 -4
  248. package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts.map +1 -1
  249. package/dist/presentation/flow/dsl/use_smile_id_builder.js.map +1 -1
  250. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts +62 -36
  251. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts.map +1 -1
  252. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +62 -36
  253. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js.map +1 -1
  254. package/dist/presentation/flow/flow_navigation_manager.d.ts +44 -5
  255. package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
  256. package/dist/presentation/flow/flow_navigation_manager.js +148 -11
  257. package/dist/presentation/flow/flow_navigation_manager.js.map +1 -1
  258. package/dist/presentation/flow/model/instruction_guideline.d.ts +9 -0
  259. package/dist/presentation/flow/model/instruction_guideline.d.ts.map +1 -1
  260. package/dist/presentation/flow/model/instructions_defaults.d.ts +11 -2
  261. package/dist/presentation/flow/model/instructions_defaults.d.ts.map +1 -1
  262. package/dist/presentation/flow/model/instructions_defaults.js +74 -26
  263. package/dist/presentation/flow/model/instructions_defaults.js.map +1 -1
  264. package/dist/presentation/flow/screen/orchestrated_capture_screen.d.ts.map +1 -1
  265. package/dist/presentation/flow/screen/orchestrated_capture_screen.js +48 -14
  266. package/dist/presentation/flow/screen/orchestrated_capture_screen.js.map +1 -1
  267. package/dist/presentation/flow/screen/orchestrated_consent_screen.d.ts.map +1 -1
  268. package/dist/presentation/flow/screen/orchestrated_consent_screen.js +3 -1
  269. package/dist/presentation/flow/screen/orchestrated_consent_screen.js.map +1 -1
  270. package/dist/presentation/flow/screen/orchestrated_instructions_screen.js +1 -1
  271. package/dist/presentation/flow/screen/orchestrated_instructions_screen.js.map +1 -1
  272. package/dist/presentation/flow/screen/orchestrated_preview_screen.d.ts.map +1 -1
  273. package/dist/presentation/flow/screen/orchestrated_preview_screen.js +3 -9
  274. package/dist/presentation/flow/screen/orchestrated_preview_screen.js.map +1 -1
  275. package/dist/presentation/flow/screen/orchestrated_processing_screen.js +3 -3
  276. package/dist/presentation/flow/screen/orchestrated_processing_screen.js.map +1 -1
  277. package/dist/presentation/flow/use_smile_id_flow.d.ts.map +1 -1
  278. package/dist/presentation/flow/use_smile_id_flow.js +10 -4
  279. package/dist/presentation/flow/use_smile_id_flow.js.map +1 -1
  280. package/dist/presentation/flow/validation/flow_validator.d.ts.map +1 -1
  281. package/dist/presentation/flow/validation/flow_validator.js +42 -20
  282. package/dist/presentation/flow/validation/flow_validator.js.map +1 -1
  283. package/dist/presentation/flow/validation/job_type_validator.d.ts.map +1 -1
  284. package/dist/presentation/flow/validation/job_type_validator.js +14 -0
  285. package/dist/presentation/flow/validation/job_type_validator.js.map +1 -1
  286. package/dist/presentation/screen/helpers/capture_screen_helpers.d.ts.map +1 -1
  287. package/dist/presentation/screen/helpers/capture_screen_helpers.js +1 -0
  288. package/dist/presentation/screen/helpers/capture_screen_helpers.js.map +1 -1
  289. package/dist/presentation/screen/helpers/capture_ui_state.d.ts +6 -6
  290. package/dist/presentation/screen/helpers/capture_ui_state.d.ts.map +1 -1
  291. package/dist/presentation/screen/helpers/capture_ui_state.js +19 -19
  292. package/dist/presentation/screen/helpers/capture_ui_state.js.map +1 -1
  293. package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts +2 -2
  294. package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts.map +1 -1
  295. package/dist/presentation/screen/helpers/ess_turn_haptics.js +6 -6
  296. package/dist/presentation/screen/helpers/ess_turn_haptics.js.map +1 -1
  297. package/dist/presentation/screen/helpers/instructions_screen_helpers.d.ts +1 -0
  298. package/dist/presentation/screen/helpers/instructions_screen_helpers.d.ts.map +1 -1
  299. package/dist/presentation/screen/helpers/instructions_screen_helpers.js +6 -2
  300. package/dist/presentation/screen/helpers/instructions_screen_helpers.js.map +1 -1
  301. package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts +5 -5
  302. package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts.map +1 -1
  303. package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js +14 -11
  304. package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js.map +1 -1
  305. package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts +13 -3
  306. package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts.map +1 -1
  307. package/dist/presentation/screen/helpers/use_capture_orientation_lock.js +48 -6
  308. package/dist/presentation/screen/helpers/use_capture_orientation_lock.js.map +1 -1
  309. package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +21 -3
  310. package/dist/presentation/screen/use_smile_id_capture_screen.d.ts.map +1 -1
  311. package/dist/presentation/screen/use_smile_id_capture_screen.js +188 -32
  312. package/dist/presentation/screen/use_smile_id_capture_screen.js.map +1 -1
  313. package/dist/presentation/screen/use_smile_id_consent_screen.d.ts +7 -0
  314. package/dist/presentation/screen/use_smile_id_consent_screen.d.ts.map +1 -1
  315. package/dist/presentation/screen/use_smile_id_consent_screen.js +6 -5
  316. package/dist/presentation/screen/use_smile_id_consent_screen.js.map +1 -1
  317. package/dist/presentation/screen/use_smile_id_document_back_instructions.d.ts.map +1 -1
  318. package/dist/presentation/screen/use_smile_id_document_back_instructions.js +5 -13
  319. package/dist/presentation/screen/use_smile_id_document_back_instructions.js.map +1 -1
  320. package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts +2 -3
  321. package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts.map +1 -1
  322. package/dist/presentation/screen/use_smile_id_document_preview_screen.js +17 -12
  323. package/dist/presentation/screen/use_smile_id_document_preview_screen.js.map +1 -1
  324. package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts +2 -0
  325. package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts.map +1 -1
  326. package/dist/presentation/screen/use_smile_id_instructions_screen.js +2 -1
  327. package/dist/presentation/screen/use_smile_id_instructions_screen.js.map +1 -1
  328. package/dist/presentation/screen/use_smile_id_preview_screen.d.ts +7 -26
  329. package/dist/presentation/screen/use_smile_id_preview_screen.d.ts.map +1 -1
  330. package/dist/presentation/screen/use_smile_id_preview_screen.js +10 -20
  331. package/dist/presentation/screen/use_smile_id_preview_screen.js.map +1 -1
  332. package/dist/presentation/screen/use_smile_id_processing_screen.d.ts +2 -3
  333. package/dist/presentation/screen/use_smile_id_processing_screen.d.ts.map +1 -1
  334. package/dist/presentation/screen/use_smile_id_processing_screen.js +4 -3
  335. package/dist/presentation/screen/use_smile_id_processing_screen.js.map +1 -1
  336. package/dist/presentation/theme/theme.d.ts +1 -1
  337. package/dist/presentation/theme/theme.d.ts.map +1 -1
  338. package/dist/presentation/theme/theme.js +20 -18
  339. package/dist/presentation/theme/theme.js.map +1 -1
  340. package/dist/presentation/utils/force_max_brightness.d.ts +4 -4
  341. package/dist/presentation/utils/locale_utils.d.ts +10 -4
  342. package/dist/presentation/utils/locale_utils.d.ts.map +1 -1
  343. package/dist/presentation/utils/locale_utils.js +13 -5
  344. package/dist/presentation/utils/locale_utils.js.map +1 -1
  345. package/dist/testing/fake_face_analyzer.d.ts +43 -0
  346. package/dist/testing/fake_face_analyzer.d.ts.map +1 -0
  347. package/dist/testing/fake_face_analyzer.js +52 -0
  348. package/dist/testing/fake_face_analyzer.js.map +1 -0
  349. package/dist/testing/index.d.ts +5 -0
  350. package/dist/testing/index.d.ts.map +1 -0
  351. package/dist/testing/index.js +7 -0
  352. package/dist/testing/index.js.map +1 -0
  353. package/dist/testing/scenario_expectations.d.ts +28 -0
  354. package/dist/testing/scenario_expectations.d.ts.map +1 -0
  355. package/dist/testing/scenario_expectations.js +65 -0
  356. package/dist/testing/scenario_expectations.js.map +1 -0
  357. package/dist/testing/scenario_loader.d.ts +11 -0
  358. package/dist/testing/scenario_loader.d.ts.map +1 -0
  359. package/dist/testing/scenario_loader.js +64 -0
  360. package/dist/testing/scenario_loader.js.map +1 -0
  361. package/dist/testing/scripted_scan_results.d.ts +17 -0
  362. package/dist/testing/scripted_scan_results.d.ts.map +1 -0
  363. package/dist/testing/scripted_scan_results.js +52 -0
  364. package/dist/testing/scripted_scan_results.js.map +1 -0
  365. package/package.json +34 -7
  366. package/src/__tests__/dsl.test.ts +51 -1
  367. package/src/__tests__/react_native_mock.tsx +8 -0
  368. package/src/__tests__/setup_react_native.ts +17 -2
  369. package/src/__tests__/snapshots/__snapshots__/screens_structural.test.tsx.snap +5261 -0
  370. package/src/__tests__/snapshots/screens_structural.test.tsx +230 -0
  371. package/src/camera/__tests__/use_smile_id_camera_system.test.ts +103 -0
  372. package/src/camera/camera_defaults.ts +11 -9
  373. package/src/camera/orientation_degrees.ts +5 -6
  374. package/src/core/exception/__tests__/builder_validation_exceptions.test.ts +67 -0
  375. package/src/core/exception/agent_mode_with_enhanced_liveness_exception.ts +20 -0
  376. package/src/core/exception/capture_validation_exceptions.ts +1 -0
  377. package/src/core/exception/index.ts +1 -0
  378. package/src/core/exception/use_smile_id_error_code.ts +1 -0
  379. package/src/core/models/__tests__/document_type.test.ts +7 -5
  380. package/src/core/models/__tests__/flow_models.test.ts +26 -0
  381. package/src/core/models/config.ts +22 -0
  382. package/src/core/models/document_capture_mode.ts +27 -0
  383. package/src/core/models/document_type.ts +7 -5
  384. package/src/core/models/global_privacy_control.ts +45 -0
  385. package/src/core/models/network_config.ts +2 -2
  386. package/src/core/models/result.ts +9 -8
  387. package/src/data/api/__tests__/smile_id_api.test.ts +1 -1
  388. package/src/data/api/interceptors/__tests__/gzip_interceptor.test.ts +83 -0
  389. package/src/data/api/interceptors/__tests__/smile_integrity_interceptor.test.ts +37 -1
  390. package/src/data/api/interceptors/__tests__/smile_request_mac_interceptor.test.ts +59 -1
  391. package/src/data/api/interceptors/smile_auth_interceptor.ts +3 -18
  392. package/src/data/api/interceptors/smile_integrity_interceptor.ts +20 -0
  393. package/src/data/api/interceptors/smile_request_mac_interceptor.ts +13 -0
  394. package/src/data/compression/__tests__/payload_compressor.test.ts +200 -0
  395. package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +226 -0
  396. package/src/data/compression/compressible_asset.ts +62 -0
  397. package/src/data/compression/payload_compression_config.ts +53 -0
  398. package/src/data/compression/payload_compression_runner.ts +102 -0
  399. package/src/data/compression/payload_compressor.ts +164 -0
  400. package/src/data/compression/uri_compressible_asset.ts +85 -0
  401. package/src/data/dsl/builder/__tests__/config_builders.test.ts +62 -0
  402. package/src/data/dsl/builder/cache_config_builder.ts +3 -1
  403. package/src/data/dsl/builder/config_builder.ts +45 -14
  404. package/src/data/dsl/builder/interceptor_config_builder.ts +9 -7
  405. package/src/data/dsl/builder/retry_config_builder.ts +27 -6
  406. package/src/data/dsl/builder/timeout_config_builder.ts +7 -0
  407. package/src/data/dsl/use_smile_id_network_builder.ts +17 -0
  408. package/src/data/factory/__tests__/retry_gzip_mac_composition.test.ts +163 -0
  409. package/src/data/factory/__tests__/signed_job_submission_headers.test.ts +1 -1
  410. package/src/data/factory/networking_factory.ts +14 -1
  411. package/src/data/repository/__tests__/network_retries.test.ts +117 -0
  412. package/src/data/repository/__tests__/use_smile_id_repository.test.ts +1 -1
  413. package/src/data/repository/use_smile_id_repository_impl.ts +96 -9
  414. package/src/data/security/__tests__/request_canonicalizer.test.ts +132 -0
  415. package/src/data/security/__tests__/security_policy.test.ts +96 -0
  416. package/src/data/security/__tests__/smile_id_crypto_manager.test.ts +18 -0
  417. package/src/data/security/request_canonicalizer.ts +15 -2
  418. package/src/data/security/security_policy.ts +70 -0
  419. package/src/data/smile_id_urls.ts +1 -1
  420. package/src/data/util/__tests__/retry_util.test.ts +25 -0
  421. package/src/data/util/__tests__/use_smile_id_token_decoder.test.ts +57 -1
  422. package/src/data/util/retry_util.ts +12 -3
  423. package/src/data/util/use_smile_id_token_decoder.ts +76 -28
  424. package/src/index.ts +6 -4
  425. package/src/l10n/strings_en.ts +2 -1
  426. package/src/l10n/use_smile_id_localizations.ts +3 -0
  427. package/src/metadata/__tests__/device_orientation_collector.test.ts +15 -0
  428. package/src/metadata/__tests__/metadata_configuration_mappers.test.ts +254 -0
  429. package/src/metadata/__tests__/metadata_configuration_objects.test.ts +86 -0
  430. package/src/metadata/__tests__/metadata_device_context.test.ts +147 -0
  431. package/src/metadata/__tests__/metadata_device_os_android.test.ts +18 -0
  432. package/src/metadata/__tests__/metadata_golden_fixture.json +13 -0
  433. package/src/metadata/__tests__/metadata_payload_golden.test.ts +193 -0
  434. package/src/metadata/__tests__/use_smile_id_metadata.test.ts +19 -25
  435. package/src/metadata/builder_configuration.ts +69 -0
  436. package/src/metadata/captured_image_properties.ts +10 -0
  437. package/src/metadata/device_orientation_collector.ts +75 -0
  438. package/src/metadata/geolocation.ts +46 -0
  439. package/src/metadata/metadata_configuration_mappers.ts +248 -0
  440. package/src/metadata/model_configuration.ts +68 -0
  441. package/src/metadata/optional_native_modules.ts +157 -3
  442. package/src/metadata/use_smile_id_metadata.ts +140 -17
  443. package/src/metadata/use_smile_id_metadata_factory.ts +211 -16
  444. package/src/presentation/assets/si_document_green_book_hero_animation.json +1 -4668
  445. package/src/presentation/assets/si_document_hero_animation.json +1 -4799
  446. package/src/presentation/assets/si_document_hero_back_animation.json +1 -2039
  447. package/src/presentation/assets/si_document_passport_hero_animation.json +1 -14491
  448. package/src/presentation/assets/si_ess_all_directions_hero_animation.json +1 -0
  449. package/src/presentation/assets/si_ess_animation_all_directions.json +1 -5575
  450. package/src/presentation/assets/si_selfie_hero_animation.json +1 -1439
  451. package/src/presentation/assets/si_smile_to_capture_animation.json +1 -1439
  452. package/src/presentation/assets/svg/document_shimmer_strings.ts +17 -0
  453. package/src/presentation/assets/svg/instruction_svg_strings.ts +34 -12
  454. package/src/presentation/components/__tests__/enhanced_smart_selfie_animation_frames.test.ts +1 -3
  455. package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +12 -8
  456. package/src/presentation/components/__tests__/use_smile_id_guideline_thumbnail.test.tsx +34 -1
  457. package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +71 -0
  458. package/src/presentation/components/__tests__/use_smile_id_oval_border_palette.test.ts +7 -5
  459. package/src/presentation/components/helpers/enhanced_smart_selfie_animation_frames.ts +0 -6
  460. package/src/presentation/components/icons/index.tsx +65 -18
  461. package/src/presentation/components/use_smile_id_attribution.tsx +1 -1
  462. package/src/presentation/components/use_smile_id_button.tsx +4 -4
  463. package/src/presentation/components/use_smile_id_capture_content.tsx +36 -12
  464. package/src/presentation/components/use_smile_id_captured_document_image.tsx +3 -8
  465. package/src/presentation/components/use_smile_id_document_capture_controls.tsx +103 -39
  466. package/src/presentation/components/use_smile_id_document_overlay.tsx +134 -44
  467. package/src/presentation/components/use_smile_id_document_shimmer.tsx +51 -0
  468. package/src/presentation/components/use_smile_id_enhanced_smart_selfie_clip.tsx +9 -6
  469. package/src/presentation/components/use_smile_id_guideline_thumbnail.tsx +131 -2
  470. package/src/presentation/components/use_smile_id_instructions_hero.tsx +111 -60
  471. package/src/presentation/components/use_smile_id_oval_border_palette.ts +7 -3
  472. package/src/presentation/flow/__tests__/document_flow_navigation.test.ts +203 -4
  473. package/src/presentation/flow/__tests__/flow_navigation_manager.test.ts +49 -0
  474. package/src/presentation/flow/dsl/builder/__tests__/config_builder.test.ts +25 -0
  475. package/src/presentation/flow/dsl/builder/config_builder.ts +35 -0
  476. package/src/presentation/flow/dsl/builder/ml_builder.ts +13 -4
  477. package/src/presentation/flow/dsl/builder/screens_builder.ts +110 -12
  478. package/src/presentation/flow/dsl/builder/theme_builder.ts +19 -2
  479. package/src/presentation/flow/dsl/use_smile_id_builder.tsx +6 -4
  480. package/src/presentation/flow/dsl/use_smile_id_flow_builder.ts +62 -36
  481. package/src/presentation/flow/flow_navigation_manager.ts +185 -14
  482. package/src/presentation/flow/model/instruction_guideline.ts +6 -0
  483. package/src/presentation/flow/model/instructions_defaults.ts +104 -26
  484. package/src/presentation/flow/screen/orchestrated_capture_screen.tsx +60 -12
  485. package/src/presentation/flow/screen/orchestrated_consent_screen.tsx +5 -0
  486. package/src/presentation/flow/screen/orchestrated_instructions_screen.tsx +1 -0
  487. package/src/presentation/flow/screen/orchestrated_preview_screen.tsx +4 -14
  488. package/src/presentation/flow/screen/orchestrated_processing_screen.tsx +3 -3
  489. package/src/presentation/flow/use_smile_id_flow.tsx +11 -4
  490. package/src/presentation/flow/validation/__tests__/flow_validator.test.ts +61 -1
  491. package/src/presentation/flow/validation/__tests__/job_type_validator.test.ts +64 -0
  492. package/src/presentation/flow/validation/flow_validator.ts +55 -26
  493. package/src/presentation/flow/validation/job_type_validator.ts +24 -0
  494. package/src/presentation/screen/__tests__/capture_ui_state.test.ts +66 -47
  495. package/src/presentation/screen/__tests__/ess_turn_haptics.test.ts +15 -11
  496. package/src/presentation/screen/__tests__/instructions_screen_helpers.test.ts +15 -3
  497. package/src/presentation/screen/__tests__/scan_state_to_overlay_state.test.ts +47 -27
  498. package/src/presentation/screen/__tests__/use_smile_id_capture_screen.test.tsx +182 -18
  499. package/src/presentation/screen/__tests__/use_smile_id_document_back_instructions.test.tsx +1 -1
  500. package/src/presentation/screen/__tests__/use_smile_id_preview_screen.test.tsx +10 -40
  501. package/src/presentation/screen/helpers/__tests__/use_capture_orientation_lock.test.tsx +212 -0
  502. package/src/presentation/screen/helpers/capture_screen_helpers.ts +1 -0
  503. package/src/presentation/screen/helpers/capture_ui_state.ts +27 -27
  504. package/src/presentation/screen/helpers/ess_turn_haptics.ts +9 -9
  505. package/src/presentation/screen/helpers/instructions_screen_helpers.ts +7 -2
  506. package/src/presentation/screen/helpers/scan_state_to_overlay_state.ts +16 -13
  507. package/src/presentation/screen/helpers/use_capture_orientation_lock.ts +69 -7
  508. package/src/presentation/screen/use_smile_id_capture_screen.tsx +280 -54
  509. package/src/presentation/screen/use_smile_id_consent_screen.tsx +16 -5
  510. package/src/presentation/screen/use_smile_id_document_back_instructions.tsx +14 -23
  511. package/src/presentation/screen/use_smile_id_document_preview_screen.tsx +33 -23
  512. package/src/presentation/screen/use_smile_id_instructions_screen.tsx +4 -0
  513. package/src/presentation/screen/use_smile_id_preview_screen.tsx +21 -53
  514. package/src/presentation/screen/use_smile_id_processing_screen.tsx +8 -8
  515. package/src/presentation/theme/theme.ts +21 -19
  516. package/src/presentation/utils/__tests__/locale_utils.test.ts +46 -5
  517. package/src/presentation/utils/force_max_brightness.tsx +4 -4
  518. package/src/presentation/utils/locale_utils.ts +13 -4
  519. package/src/testing/__tests__/fake_face_analyzer.test.ts +42 -0
  520. package/src/testing/__tests__/scenario_expectations.test.ts +110 -0
  521. package/src/testing/__tests__/scenario_loader.test.ts +64 -0
  522. package/src/testing/fake_face_analyzer.ts +82 -0
  523. package/src/testing/index.ts +15 -0
  524. package/src/testing/scenario_expectations.ts +87 -0
  525. package/src/testing/scenario_loader.ts +83 -0
  526. package/src/testing/scripted_scan_results.ts +66 -0
  527. package/dist/camera/frame_processor_plugin.d.ts +0 -28
  528. package/dist/camera/frame_processor_plugin.d.ts.map +0 -1
  529. package/dist/camera/frame_processor_plugin.js +0 -21
  530. package/dist/camera/frame_processor_plugin.js.map +0 -1
  531. package/dist/camera/use_smile_id_frame_processor.d.ts +0 -38
  532. package/dist/camera/use_smile_id_frame_processor.d.ts.map +0 -1
  533. package/dist/camera/use_smile_id_frame_processor.js +0 -2
  534. package/dist/camera/use_smile_id_frame_processor.js.map +0 -1
  535. package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts +0 -17
  536. package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts.map +0 -1
  537. package/dist/presentation/components/use_smile_id_document_frame_glyph.js +0 -17
  538. package/dist/presentation/components/use_smile_id_document_frame_glyph.js.map +0 -1
  539. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts +0 -24
  540. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts.map +0 -1
  541. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js +0 -91
  542. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js.map +0 -1
  543. package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts +0 -15
  544. package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts.map +0 -1
  545. package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js +0 -19
  546. package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js.map +0 -1
  547. package/dist/presentation/components/use_smile_id_instruction_card.d.ts +0 -31
  548. package/dist/presentation/components/use_smile_id_instruction_card.d.ts.map +0 -1
  549. package/dist/presentation/components/use_smile_id_instruction_card.js +0 -43
  550. package/dist/presentation/components/use_smile_id_instruction_card.js.map +0 -1
  551. package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts +0 -24
  552. package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts.map +0 -1
  553. package/dist/presentation/screen/helpers/use_document_orientation_lock.js +0 -47
  554. package/dist/presentation/screen/helpers/use_document_orientation_lock.js.map +0 -1
  555. package/src/presentation/components/use_smile_id_document_frame_glyph.tsx +0 -162
  556. package/src/presentation/components/use_smile_id_face_silhouette_overlay.tsx +0 -27
@@ -3,6 +3,14 @@ import * as ScreenOrientation from "expo-screen-orientation";
3
3
  import { UseSmileIDCrashReporting } from "@smileid/usesmileid_bridge";
4
4
  import type { DocumentOrientation } from "../../../core/models/document_type";
5
5
 
6
+ export type CaptureOrientationOptions = {
7
+ /**
8
+ * Lock applied when the capture screen unmounts. Defaults to portrait-up;
9
+ * threaded from the builder's `exitOrientations`.
10
+ */
11
+ readonly exitLock?: ScreenOrientation.OrientationLock;
12
+ };
13
+
6
14
  /**
7
15
  * Lock device orientation for a capture screen, scoped to its lifetime
8
16
  * (`"Landscape"` → landscape, `"Portrait"` → portrait-up).
@@ -10,26 +18,76 @@ import type { DocumentOrientation } from "../../../core/models/document_type";
10
18
  * Each screen asserts its OWN orientation on mount, so document → selfie
11
19
  * reverts deterministically rather than depending on the previous
12
20
  * screen's teardown winning a race against the next camera initialising.
13
- * Unmount restores portrait-up as a safety net.
14
21
  *
15
22
  * Locks are global: the host app must permit the locked orientations at
16
23
  * the OS level (iOS `UISupportedInterfaceOrientations`, Android activity
17
- * `screenOrientation`) for the lock to take effect.
24
+ * `screenOrientation`) for the lock to take effect — a host that does not
25
+ * is warned about and reported rather than silently staying upright.
18
26
  */
19
27
  export function useCaptureOrientationLock(
20
28
  orientation: DocumentOrientation,
29
+ {
30
+ exitLock = ScreenOrientation.OrientationLock.PORTRAIT_UP,
31
+ }: CaptureOrientationOptions = {},
21
32
  ): void {
22
33
  useEffect(() => {
23
34
  const target =
24
35
  orientation === "Landscape"
25
36
  ? ScreenOrientation.OrientationLock.LANDSCAPE
26
37
  : ScreenOrientation.OrientationLock.PORTRAIT_UP;
38
+ void reportIfLockUnsupported(target);
27
39
  void lockOrientation(target);
28
40
 
29
41
  return () => {
30
- void lockOrientation(ScreenOrientation.OrientationLock.PORTRAIT_UP);
42
+ void lockOrientation(exitLock);
31
43
  };
32
- }, [orientation]);
44
+ }, [orientation, exitLock]);
45
+ }
46
+
47
+ /**
48
+ * Surface a host build that cannot honour `target`. `lockAsync` resolves
49
+ * successfully in that case, so without this preflight the capture screen
50
+ * just stays in the wrong orientation with no signal. (Expo's `app.json`
51
+ * `orientation` value is not such a case: the module's app-delegate hook
52
+ * outranks the baked `Info.plist` on iOS — device-verified.)
53
+ */
54
+ async function reportIfLockUnsupported(
55
+ target: ScreenOrientation.OrientationLock,
56
+ ): Promise<void> {
57
+ let supported: boolean;
58
+ try {
59
+ supported = await ScreenOrientation.supportsOrientationLockAsync(target);
60
+ } catch (error) {
61
+ reportOrientationFailure(error);
62
+ return;
63
+ }
64
+ if (supported) return;
65
+
66
+ // `typeof` guard: `__DEV__` is bundler-injected and absent outside Metro-like
67
+ // environments, where a bare reference throws rather than reading falsy.
68
+ const isDevBuild = typeof __DEV__ !== "undefined" && __DEV__;
69
+ if (isDevBuild && !warnedUnsupportedTargets.has(target)) {
70
+ warnedUnsupportedTargets.add(target);
71
+ console.warn(
72
+ "[UseSmileID] The capture screen needs to lock the device orientation, " +
73
+ "but this build does not permit it. Allow the required orientations " +
74
+ "in your app's iOS Info.plist / Android manifest.",
75
+ );
76
+ }
77
+ reportOrientationFailure(
78
+ new Error(`orientation lock unsupported by host build: ${target}`),
79
+ );
80
+ }
81
+
82
+ /**
83
+ * Dedupes the dev warning per target: a flow remounts the capture screen for the back
84
+ * side and interstitial, and the misconfiguration can't change mid-session.
85
+ */
86
+ const warnedUnsupportedTargets = new Set<ScreenOrientation.OrientationLock>();
87
+
88
+ /** Test seam: clears the once-per-target dev-warning dedupe. */
89
+ export function resetUnsupportedLockWarningsForTesting(): void {
90
+ warnedUnsupportedTargets.clear();
33
91
  }
34
92
 
35
93
  /** Lock to `target`, routing a native failure through crash reporting. */
@@ -39,8 +97,12 @@ async function lockOrientation(
39
97
  try {
40
98
  await ScreenOrientation.lockAsync(target);
41
99
  } catch (error) {
42
- UseSmileIDCrashReporting.captureException(
43
- error instanceof Error ? error : new Error(String(error)),
44
- );
100
+ reportOrientationFailure(error);
45
101
  }
46
102
  }
103
+
104
+ function reportOrientationFailure(error: unknown): void {
105
+ UseSmileIDCrashReporting.captureException(
106
+ error instanceof Error ? error : new Error(String(error)),
107
+ );
108
+ }
@@ -6,7 +6,13 @@ import {
6
6
  useState,
7
7
  type ReactNode,
8
8
  } from "react";
9
- import { StatusBar, StyleSheet, View } from "react-native";
9
+ import {
10
+ Platform,
11
+ StatusBar,
12
+ StyleSheet,
13
+ View,
14
+ useWindowDimensions,
15
+ } from "react-native";
10
16
  import {
11
17
  Camera,
12
18
  useCameraDevice,
@@ -22,25 +28,35 @@ import type {
22
28
  DocumentAnalyzer,
23
29
  FaceAnalyzer,
24
30
  } from "@smileid/usesmileid_platform_interface";
25
- import type { CaptureReadyEvent, ScanState } from "@smileid/usesmileid_bridge";
31
+ import type {
32
+ CaptureReadyEvent,
33
+ UseSmileIDScanState,
34
+ } from "@smileid/usesmileid_bridge";
26
35
  import {
27
36
  CaptureReadyEventKind,
28
37
  DocumentSide,
29
- ScanStateType,
38
+ UseSmileIDScanStateType,
30
39
  } from "@smileid/usesmileid_bridge";
31
40
  import { CaptureType } from "../../core/models/ml_config";
32
41
  import type { DocumentCaptureMode } from "../../core/models/document_capture_mode";
42
+ import type { DocumentType } from "../../core/models/document_type";
33
43
  import { resampleImportedDocument } from "../../camera/document_image_pipeline";
34
44
  import { defaultLightTheme, type UseSmileIDTheme } from "../theme/theme";
45
+ import { UseSmileIDThemeProvider } from "../theme/theme_context";
35
46
  import {
36
47
  UseSmileIDCaptureContent,
37
48
  type UseSmileIDCaptureContentState,
38
49
  } from "../components/use_smile_id_capture_content";
50
+ import {
51
+ DEFAULT_DOCUMENT_ASPECT,
52
+ documentGuideRect,
53
+ } from "../components/use_smile_id_document_overlay";
39
54
  import { UseSmileIDCrashReporting } from "@smileid/usesmileid_bridge";
40
55
  import { ForceMaxBrightness } from "../utils/force_max_brightness";
41
56
  import { CameraDefaults } from "../../camera/camera_defaults";
42
57
  import type { SiKey } from "../../l10n/strings_en";
43
58
  import { DocumentImageOrigin } from "../../metadata/document_image_origin";
59
+ import { DeviceOrientationCollector } from "../../metadata/device_orientation_collector";
44
60
  import { useSmileIDFrameStream } from "../../camera/use_smile_id_frame_stream";
45
61
  import { orientationToDegrees } from "../../camera/orientation_degrees";
46
62
  import {
@@ -55,6 +71,20 @@ import {
55
71
  triggerEssTurnHaptic,
56
72
  } from "./helpers/ess_turn_haptics";
57
73
 
74
+ /** Capture telemetry surfaced alongside the captured artifacts at completion. */
75
+ export interface CaptureTelemetry {
76
+ /** Elapsed time in ms from the first analyzed frame to completion. */
77
+ readonly durationMs: number;
78
+ /** Count of face/document-lost resets (rising edges of `unsatisfied`). */
79
+ readonly retries: number;
80
+ /** Identifier of the camera used for capture (`CameraDevice.id`); `undefined` until resolved. */
81
+ readonly cameraName?: string;
82
+ /** Accelerometer `"epochMs,x,y,z"` samples collected during capture. */
83
+ readonly devicePositions: readonly string[];
84
+ /** Span of movement magnitude during capture; `null` when no samples ran. */
85
+ readonly deviceMovementDetected: number | null;
86
+ }
87
+
58
88
  export type UseSmileIDCaptureScreenProps = {
59
89
  readonly captureType: CaptureType;
60
90
 
@@ -73,12 +103,15 @@ export type UseSmileIDCaptureScreenProps = {
73
103
  * settled, with every `CaptureReadyEvent` of the session (one
74
104
  * `"selfie"` + N `"liveness"` for face, one `"document"` for document).
75
105
  */
76
- readonly onCaptureComplete?: (events: readonly CaptureReadyEvent[]) => void;
106
+ readonly onCaptureComplete?: (
107
+ events: readonly CaptureReadyEvent[],
108
+ telemetry: CaptureTelemetry,
109
+ ) => void;
77
110
  /** Records how a document side was produced (auto/manual/gallery), fired just before delivery. */
78
111
  readonly onDocumentOrigin?: (origin: DocumentImageOrigin) => void;
79
112
 
80
113
  /** Fires when the state machine reaches `"timeout"`; the screen stops streaming. */
81
- readonly onCaptureTimeout?: (state: ScanState) => void;
114
+ readonly onCaptureTimeout?: (state: UseSmileIDScanState) => void;
82
115
 
83
116
  readonly onBack?: () => void;
84
117
  readonly showAttribution?: boolean;
@@ -86,6 +119,9 @@ export type UseSmileIDCaptureScreenProps = {
86
119
  /** Keeps the oval rim neutral through CAPTURING/PROCESSING — ESS has no green oval treatment. */
87
120
  readonly enableEnhancedLiveness?: boolean;
88
121
 
122
+ /** Runs a selfie capture on the rear camera. Ignored for document capture. */
123
+ readonly allowAgentMode?: boolean;
124
+
89
125
  /**
90
126
  * Document aspect ratio (width / height) for the document capture
91
127
  * guide cutout. Ignored for selfie capture. Omitted ⇒ the overlay's
@@ -106,6 +142,8 @@ export type UseSmileIDCaptureScreenProps = {
106
142
  * `document_front.jpg` / `document_back.jpg`. Ignored for selfie capture.
107
143
  */
108
144
  readonly documentSide?: DocumentSide;
145
+ /** Document type — selects the in-frame capture shimmer skeleton. Ignored for selfie. */
146
+ readonly documentTypeKind?: DocumentType["kind"];
109
147
  /** Close/cancel the whole flow (document capture chrome — top-right X). */
110
148
  readonly onClose?: () => void;
111
149
 
@@ -130,9 +168,12 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
130
168
  const theme = props.theme ?? defaultLightTheme;
131
169
  const showAttribution = props.showAttribution ?? true;
132
170
  const enableEnhancedLiveness = props.enableEnhancedLiveness ?? false;
171
+ const allowAgentMode = props.allowAgentMode ?? false;
133
172
  // Literal union — useCameraDevice takes the lowercase string directly.
134
173
  const cameraFacing: "front" | "back" =
135
- props.captureType === CaptureType.selfie ? "front" : "back";
174
+ props.captureType === CaptureType.selfie && !allowAgentMode
175
+ ? "front"
176
+ : "back";
136
177
 
137
178
  const { hasPermission, requestPermission } = useCameraPermission();
138
179
  const device = useCameraDevice(cameraFacing);
@@ -140,15 +181,24 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
140
181
  const cameraRef = useRef<Camera>(null);
141
182
  // Pin an explicit format: the "highest supported" heuristic can pick 4K,
142
183
  // stalling the frame-processor thread and stuttering the pipeline.
184
+ // Document capture uses 16:9 so the analysis FOV matches the visible 16:9
185
+ // preview — keeping the guide-rectangle crop aligned with the framed document
186
+ // (mirrors the native Android SDK's RATIO_16_9 + 1280×720 pin). Selfie keeps
187
+ // 4:3: the face geometry + smile heuristic are calibrated on 4:3, and 16:9
188
+ // skews normalized landmark ratios and shifts every threshold.
189
+ const isDocumentFormat = props.captureType === CaptureType.document;
143
190
  const format = useCameraFormat(device, [
144
- // 4:3 first: geometry checks + smile heuristic are calibrated on 4:3;
145
- // 16:9 skews normalized landmark ratios and shifts every threshold.
146
- { videoAspectRatio: 4 / 3 },
191
+ { videoAspectRatio: isDocumentFormat ? 16 / 9 : 4 / 3 },
147
192
  {
148
- videoResolution: {
149
- width: CameraDefaults.analysisTargetResolution.width,
150
- height: CameraDefaults.analysisTargetResolution.height,
151
- },
193
+ videoResolution: isDocumentFormat
194
+ ? {
195
+ width: CameraDefaults.documentAnalysisResolution.width,
196
+ height: CameraDefaults.documentAnalysisResolution.height,
197
+ }
198
+ : {
199
+ width: CameraDefaults.analysisTargetResolution.width,
200
+ height: CameraDefaults.analysisTargetResolution.height,
201
+ },
152
202
  },
153
203
  { fps: CameraDefaults.analysisTargetFps },
154
204
  ]);
@@ -161,8 +211,8 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
161
211
  }, [hasPermission, requestPermission]);
162
212
 
163
213
  // Per-frame scan state drives the overlay + feedback bubble.
164
- const [scanState, setScanState] = useState<ScanState>({
165
- type: ScanStateType.Initial,
214
+ const [scanState, setScanState] = useState<UseSmileIDScanState>({
215
+ type: UseSmileIDScanStateType.Initial,
166
216
  });
167
217
  const [streaming, setStreaming] = useState<boolean>(false);
168
218
  // Bumped on every Start tap to reset the feedback debouncer.
@@ -172,6 +222,11 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
172
222
  const [hasAnalyzedFrame, setHasAnalyzedFrame] = useState<boolean>(false);
173
223
  // Fallback shutter, revealed after activateManualAfterMs. Resets per mount.
174
224
  const [manualShutterRevealed, setManualShutterRevealed] = useState(false);
225
+ // Set when a document scan times out, so the recovery controls stay on screen
226
+ // after the scan (and `streaming`) stops. `timedOutRef` keeps the terminal
227
+ // branch idempotent without latching the one-shot delivery gate.
228
+ const [captureTimedOut, setCaptureTimedOut] = useState(false);
229
+ const timedOutRef = useRef(false);
175
230
  // True while a manual/gallery delivery is in flight — disables the controls.
176
231
  const [deliveringDocument, setDeliveringDocument] = useState(false);
177
232
  // Transient gallery-import error; overrides the live chip, self-clears so the user can re-pick.
@@ -191,7 +246,34 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
191
246
  const completedRef = useRef<boolean>(false);
192
247
  // Raw (not committed) frame state for the session-boundary check, so
193
248
  // transitions the 1% bucketing skips committing are still seen.
194
- const previousScanStateRef = useRef<ScanState | null>(null);
249
+ const previousScanStateRef = useRef<UseSmileIDScanState | null>(null);
250
+
251
+ // Capture telemetry: wall-clock start (first analyzed frame) and a
252
+ // rising-edge `unsatisfied` retry counter, surfaced via onCaptureComplete.
253
+ const captureStartedAtRef = useRef<number | null>(null);
254
+ const captureRetriesRef = useRef<number>(0);
255
+ const wasUnsatisfiedRef = useRef<boolean>(false);
256
+ // Accelerometer sampler for device_positions / device_movement_detected, run only
257
+ // while the live capture loop is streaming.
258
+ const deviceOrientationRef = useRef<DeviceOrientationCollector>(
259
+ new DeviceOrientationCollector(),
260
+ );
261
+
262
+ const captureTelemetry = useCallback(
263
+ (): CaptureTelemetry => ({
264
+ durationMs:
265
+ captureStartedAtRef.current === null
266
+ ? 0
267
+ : Date.now() - captureStartedAtRef.current,
268
+ retries: captureRetriesRef.current,
269
+ devicePositions: deviceOrientationRef.current.devicePositions,
270
+ deviceMovementDetected:
271
+ deviceOrientationRef.current.deviceMovementDetected,
272
+ // Omit (not set to undefined) when unresolved — exactOptionalPropertyTypes.
273
+ ...(device?.id !== undefined ? { cameraName: device.id } : {}),
274
+ }),
275
+ [device],
276
+ );
195
277
 
196
278
  const onStartCapture = props.onStartCapture;
197
279
  const handleStart = useCallback(() => {
@@ -213,6 +295,23 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
213
295
  const documentSide = props.documentSide ?? DocumentSide.Front;
214
296
  const isDocumentCapture = props.captureType === CaptureType.document;
215
297
 
298
+ // Reset capture telemetry per side so each document side reports its own
299
+ // duration / retries (the screen instance is reused across the front→back flip).
300
+ useEffect(() => {
301
+ captureStartedAtRef.current = null;
302
+ captureRetriesRef.current = 0;
303
+ wasUnsatisfiedRef.current = false;
304
+ }, [documentSide]);
305
+
306
+ // Sample the accelerometer only while the live capture loop streams. start()
307
+ // clears prior samples, so a retry / side switch begins fresh; cleanup stops it.
308
+ useEffect(() => {
309
+ if (streaming) {
310
+ deviceOrientationRef.current.start();
311
+ }
312
+ return () => deviceOrientationRef.current.stop();
313
+ }, [streaming]);
314
+
216
315
  // Reveal the fallback shutter after the delay once streaming begins.
217
316
  // Bound to `streaming`: any capture clears it, tearing this effect down
218
317
  // and clearing the timer, so it can't fire post-capture or leak.
@@ -249,13 +348,16 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
249
348
  documentSide,
250
349
  );
251
350
  onDocumentOrigin?.(DocumentImageOrigin.CameraManualCapture);
252
- onCaptureComplete?.([
253
- {
254
- kind: CaptureReadyEventKind.Document,
255
- captureIndex: 0,
256
- url: processedUri,
257
- },
258
- ]);
351
+ onCaptureComplete?.(
352
+ [
353
+ {
354
+ kind: CaptureReadyEventKind.Document,
355
+ captureIndex: 0,
356
+ url: processedUri,
357
+ },
358
+ ],
359
+ captureTelemetry(),
360
+ );
259
361
  } catch (error) {
260
362
  UseSmileIDCrashReporting.captureException(
261
363
  error instanceof Error ? error : new Error(String(error)),
@@ -318,13 +420,16 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
318
420
  documentSide,
319
421
  );
320
422
  onDocumentOrigin?.(DocumentImageOrigin.Gallery);
321
- onCaptureComplete?.([
322
- {
323
- kind: CaptureReadyEventKind.Document,
324
- captureIndex: 0,
325
- url: processedUri,
326
- },
327
- ]);
423
+ onCaptureComplete?.(
424
+ [
425
+ {
426
+ kind: CaptureReadyEventKind.Document,
427
+ captureIndex: 0,
428
+ url: processedUri,
429
+ },
430
+ ],
431
+ captureTelemetry(),
432
+ );
328
433
  } catch (error) {
329
434
  UseSmileIDCrashReporting.captureException(
330
435
  error instanceof Error ? error : new Error(String(error)),
@@ -379,7 +484,19 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
379
484
  // Unsatisfied = native session reset; drop accumulated events so it
380
485
  // can't leak stale liveness frames. `else` so a reset frame can't
381
486
  // re-add its own stale events on the same pass.
382
- if (result.state.type === ScanStateType.Unsatisfied) {
487
+ // Capture telemetry: anchor the start clock on the first analyzed frame,
488
+ // and count rising edges of `unsatisfied` as retries.
489
+ if (captureStartedAtRef.current === null) {
490
+ captureStartedAtRef.current = Date.now();
491
+ }
492
+ const isUnsatisfied =
493
+ result.state.type === UseSmileIDScanStateType.Unsatisfied;
494
+ if (isUnsatisfied && !wasUnsatisfiedRef.current) {
495
+ captureRetriesRef.current += 1;
496
+ }
497
+ wasUnsatisfiedRef.current = isUnsatisfied;
498
+
499
+ if (result.state.type === UseSmileIDScanStateType.Unsatisfied) {
383
500
  capturedEventsRef.current = [];
384
501
  } else if (result.capturedEvents.length > 0) {
385
502
  capturedEventsRef.current = [
@@ -405,7 +522,7 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
405
522
 
406
523
  // Terminal states: finished → flush + complete; timeout → failure
407
524
  // without flushing (no captured artifacts to wait on).
408
- if (result.state.type === ScanStateType.Finished) {
525
+ if (result.state.type === UseSmileIDScanStateType.Finished) {
409
526
  if (completedRef.current) return;
410
527
  completedRef.current = true;
411
528
  setStreaming(false);
@@ -420,12 +537,20 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
420
537
  .finally(() => {
421
538
  // No-op for selfie (callback unset).
422
539
  onDocumentOrigin?.(DocumentImageOrigin.CameraAutoCapture);
423
- onCaptureComplete?.(capturedEventsRef.current);
540
+ onCaptureComplete?.(capturedEventsRef.current, captureTelemetry());
424
541
  });
425
- } else if (result.state.type === ScanStateType.Timeout) {
426
- if (completedRef.current) return;
427
- completedRef.current = true;
542
+ } else if (result.state.type === UseSmileIDScanStateType.Timeout) {
543
+ if (completedRef.current || timedOutRef.current) return;
428
544
  setStreaming(false);
545
+ if (isDocumentCapture) {
546
+ // Document capture has no Start button, so a timeout must leave a way
547
+ // forward: reveal the manual shutter and keep the delivery gate open
548
+ // so the tap can still produce a capture.
549
+ timedOutRef.current = true;
550
+ setCaptureTimedOut(true);
551
+ } else {
552
+ completedRef.current = true;
553
+ }
429
554
  onCaptureTimeout?.(result.state);
430
555
  }
431
556
  },
@@ -447,7 +572,7 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
447
572
  sessionEpoch,
448
573
  );
449
574
  const isInstructionState =
450
- scanState.type === ScanStateType.Initial && !streaming;
575
+ scanState.type === UseSmileIDScanStateType.Initial && !streaming;
451
576
  const canStart = !streaming && !completedRef.current;
452
577
 
453
578
  const previewReady = hasPermission && device != null;
@@ -487,33 +612,116 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
487
612
  });
488
613
  }, [onFrameResult]);
489
614
 
490
- // Physical device tilt (0 = upright portrait) for the native
491
- // session's upright validator and head-pose math; gravity-sourced,
492
- // never derived from `frame.orientation` (fixed sensor mounting).
615
+ // Physical device tilt (0 = portrait) for the native upright validator /
616
+ // head-pose math; gravity-sourced, never from `frame.orientation`.
493
617
  const [deviceOrientationDegrees, setDeviceOrientationDegrees] = useState(0);
494
618
 
619
+ // Locked INTERFACE orientation (0/90/270) — the axis the preview and guide are
620
+ // drawn against, from VisionCamera's preview orientation, NOT device gravity
621
+ // (the document screen locks the interface while the phone is held flat, so
622
+ // gravity disagrees). iOS uprights the saved document to this axis.
623
+ const [previewOrientationDegrees, setPreviewOrientationDegrees] = useState(0);
624
+
625
+ // VisionCamera derives its iOS preview orientation from the interface
626
+ // orientation but only refreshes it on a PHYSICAL rotation — a programmatic
627
+ // lock (the document landscape lock) never fires that, so the preview stays
628
+ // portrait in the rotated UI. Remounting <Camera> when the interface flips
629
+ // forces a re-read. iOS only — Android's preview already tracks the lock.
630
+ const { width: windowWidth, height: windowHeight } = useWindowDimensions();
631
+ const cameraOrientationKey =
632
+ Platform.OS === "ios"
633
+ ? windowWidth > windowHeight
634
+ ? "landscape"
635
+ : "portrait"
636
+ : "camera";
637
+
638
+ // Camera viewport size, reported by the capture content on layout. Drives the
639
+ // document crop region so the saved capture matches the on-screen frame.
640
+ const [viewport, setViewport] = useState({ width: 0, height: 0 });
641
+ const handleViewportLayout = useCallback(
642
+ (size: { width: number; height: number }) => {
643
+ setViewport((previous) =>
644
+ previous.width === size.width && previous.height === size.height
645
+ ? previous
646
+ : size,
647
+ );
648
+ },
649
+ [],
650
+ );
651
+
652
+ // The document guide rectangle as a native crop region — viewport fractions +
653
+ // size + cover scale — derived from the SAME geometry the overlay draws
654
+ // (documentGuideRect), so the native side crops the saved document to exactly
655
+ // the framed rectangle. undefined for selfie or before the viewport is known.
656
+ const documentCropRegion = useMemo(() => {
657
+ if (!isDocumentCapture || viewport.width <= 0 || viewport.height <= 0) {
658
+ return undefined;
659
+ }
660
+ const aspect = props.knownIdAspectRatio ?? DEFAULT_DOCUMENT_ASPECT;
661
+ const rect = documentGuideRect(aspect, viewport.width, viewport.height);
662
+ return {
663
+ left: rect.left / viewport.width,
664
+ top: rect.top / viewport.height,
665
+ width: rect.width / viewport.width,
666
+ height: rect.height / viewport.height,
667
+ viewportWidthPx: Math.round(viewport.width),
668
+ viewportHeightPx: Math.round(viewport.height),
669
+ };
670
+ }, [isDocumentCapture, viewport, props.knownIdAspectRatio]);
671
+
495
672
  const frameProcessor = useFrameProcessor(
496
673
  (frame) => {
497
674
  "worklet";
498
675
  if (!plugin) return;
676
+ // Crop region passed as FLAT numeric args — frame-processor arguments
677
+ // don't reliably accept nested objects. cropWidth <= 0 signals "no region"
678
+ // (selfie, or before the viewport is measured), leaving it uncropped.
679
+ //
680
+ // The saved document uprights to the LOCKED INTERFACE axis (what the
681
+ // preview and guide are drawn against), never device gravity (the phone is
682
+ // held flat): iOS uprights to `viewportOrientation`, Android via its
683
+ // display-tracking `rotationDegrees`. `rotation` stays the RAW gravity
684
+ // tilt the native upright validator needs.
499
685
  const rawResult = plugin.call(frame, {
500
686
  rotation: deviceOrientationDegrees,
687
+ viewportOrientation: previewOrientationDegrees,
688
+ cropLeft: documentCropRegion ? documentCropRegion.left : 0,
689
+ cropTop: documentCropRegion ? documentCropRegion.top : 0,
690
+ cropWidth: documentCropRegion ? documentCropRegion.width : 0,
691
+ cropHeight: documentCropRegion ? documentCropRegion.height : 0,
692
+ cropViewportWidth: documentCropRegion
693
+ ? documentCropRegion.viewportWidthPx
694
+ : 0,
695
+ cropViewportHeight: documentCropRegion
696
+ ? documentCropRegion.viewportHeightPx
697
+ : 0,
501
698
  });
502
699
  onFrameResultRunOnJS(rawResult);
503
700
  },
504
- [plugin, onFrameResultRunOnJS, deviceOrientationDegrees],
701
+ [
702
+ plugin,
703
+ onFrameResultRunOnJS,
704
+ deviceOrientationDegrees,
705
+ previewOrientationDegrees,
706
+ documentCropRegion,
707
+ ],
505
708
  );
506
709
 
507
710
  // Document controls — live capture only (after Start). Manual shutter
508
711
  // follows the capture mode + fallback timer; gallery follows
509
712
  // allowGalleryUpload. Renderer also hides both during CAPTURING/PROCESSING.
713
+ // A timeout offers the shutter in every capture mode — it is the recovery
714
+ // affordance, so it outranks `captureMode` and survives `streaming` going
715
+ // false with the scan.
510
716
  const manualShutterAvailable =
511
717
  isDocumentCapture &&
512
- streaming &&
513
- (captureMode?.kind === "manualCapture" ||
514
- (captureMode?.kind === "autoCaptureWithManualFallback" &&
515
- manualShutterRevealed));
516
- const galleryAvailable = isDocumentCapture && streaming && allowGalleryUpload;
718
+ (captureTimedOut ||
719
+ (streaming &&
720
+ (captureMode?.kind === "manualCapture" ||
721
+ (captureMode?.kind === "autoCaptureWithManualFallback" &&
722
+ manualShutterRevealed))));
723
+ const galleryAvailable =
724
+ isDocumentCapture && (streaming || captureTimedOut) && allowGalleryUpload;
517
725
 
518
726
  // Deps are scalar fields (mapCaptureUiState returns a fresh object per
519
727
  // render). captureProgress intentionally stays a separate per-frame prop.
@@ -530,9 +738,13 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
530
738
  showCaptureButton: isInstructionState && !isDocumentCapture,
531
739
  showManualShutter: manualShutterAvailable,
532
740
  showGalleryUpload: galleryAvailable,
741
+ isBackSide: documentSide === DocumentSide.Back,
533
742
  ...(props.knownIdAspectRatio !== undefined
534
743
  ? { knownIdAspectRatio: props.knownIdAspectRatio }
535
744
  : {}),
745
+ ...(props.documentTypeKind !== undefined
746
+ ? { documentTypeKind: props.documentTypeKind }
747
+ : {}),
536
748
  }),
537
749
  [
538
750
  props.captureType,
@@ -546,7 +758,9 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
546
758
  isDocumentCapture,
547
759
  manualShutterAvailable,
548
760
  galleryAvailable,
761
+ documentSide,
549
762
  props.knownIdAspectRatio,
763
+ props.documentTypeKind,
550
764
  ],
551
765
  );
552
766
 
@@ -554,14 +768,14 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
554
768
  const cameraPreview = useMemo(
555
769
  () => (
556
770
  <>
557
- {/* Selfie uses the front camera with the screen as fill light, so
558
- force max brightness on selfie only; document uses the rear
559
- camera, where screen brightness doesn't help. */}
560
- <ForceMaxBrightness
561
- enabled={props.captureType === CaptureType.selfie}
562
- />
771
+ {/* Every capture screen runs at max brightness with the screen kept
772
+ awake, restored on unmount. Selfie uses the front camera with the
773
+ screen as fill light; document capture keeps the same guarantee so
774
+ the preview never dims or auto-locks mid-scan. */}
775
+ <ForceMaxBrightness />
563
776
  {previewReady ? (
564
777
  <Camera
778
+ key={cameraOrientationKey}
565
779
  ref={cameraRef}
566
780
  style={StyleSheet.absoluteFill}
567
781
  device={device}
@@ -576,6 +790,11 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
576
790
  onOutputOrientationChanged={(orientation) => {
577
791
  setDeviceOrientationDegrees(orientationToDegrees(orientation));
578
792
  }}
793
+ // The LOCKED interface orientation (follows the screen even under a
794
+ // programmatic lock) — the axis the saved document uprights to.
795
+ onPreviewOrientationChanged={(orientation) => {
796
+ setPreviewOrientationDegrees(orientationToDegrees(orientation));
797
+ }}
579
798
  // Attach the frame processor only while streaming (skip pre-Start
580
799
  // preview). Spread idiom because exactOptionalPropertyTypes rejects
581
800
  // passing `undefined` to an optional prop directly.
@@ -602,11 +821,17 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
602
821
  streaming,
603
822
  frameProcessor,
604
823
  theme.colors.offBlack,
824
+ cameraOrientationKey,
605
825
  ],
606
826
  );
607
827
 
608
828
  return (
609
- <>
829
+ // The capture screen is always light, regardless of the system dark-mode
830
+ // setting (every other screen tracks the system). Providing the light theme
831
+ // here forces every descendant that reads it from context — not only the
832
+ // ones passing `forceLightMode` — to render light; partner colours still
833
+ // apply because `theme` carries the partner's resolved light tokens.
834
+ <UseSmileIDThemeProvider value={theme}>
610
835
  {/* Translucent status bar → full-bleed window so the oval's reference
611
836
  frame is the full screen (no-op on iOS). On-device-pending: residual
612
837
  inset also depends on the host SafeAreaProvider config. */}
@@ -620,6 +845,7 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
620
845
  onBack={props.onBack}
621
846
  showAttribution={showAttribution}
622
847
  startButton={props.startButton}
848
+ onViewportLayout={handleViewportLayout}
623
849
  {...(isDocumentCapture
624
850
  ? {
625
851
  onManualShutter: handleManualShutter,
@@ -630,6 +856,6 @@ export function UseSmileIDCaptureScreen(props: UseSmileIDCaptureScreenProps) {
630
856
  : {})}
631
857
  theme={theme}
632
858
  />
633
- </>
859
+ </UseSmileIDThemeProvider>
634
860
  );
635
861
  }