@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.
Files changed (403) hide show
  1. package/CHANGELOG.md +11 -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/models/document_capture_mode.d.ts +8 -0
  12. package/dist/core/models/document_capture_mode.d.ts.map +1 -1
  13. package/dist/core/models/document_capture_mode.js +24 -0
  14. package/dist/core/models/document_capture_mode.js.map +1 -1
  15. package/dist/core/models/document_type.d.ts +2 -2
  16. package/dist/core/models/document_type.d.ts.map +1 -1
  17. package/dist/core/models/document_type.js +6 -4
  18. package/dist/core/models/document_type.js.map +1 -1
  19. package/dist/core/models/result.d.ts +9 -8
  20. package/dist/core/models/result.d.ts.map +1 -1
  21. package/dist/core/models/result.js +5 -6
  22. package/dist/core/models/result.js.map +1 -1
  23. package/dist/data/api/interceptors/smile_auth_interceptor.js +1 -1
  24. package/dist/data/api/interceptors/smile_auth_interceptor.js.map +1 -1
  25. package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts +11 -0
  26. package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts.map +1 -1
  27. package/dist/data/api/interceptors/smile_integrity_interceptor.js +13 -0
  28. package/dist/data/api/interceptors/smile_integrity_interceptor.js.map +1 -1
  29. package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts +8 -0
  30. package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts.map +1 -1
  31. package/dist/data/api/interceptors/smile_request_mac_interceptor.js +11 -0
  32. package/dist/data/api/interceptors/smile_request_mac_interceptor.js.map +1 -1
  33. package/dist/data/compression/compressible_asset.d.ts +41 -0
  34. package/dist/data/compression/compressible_asset.d.ts.map +1 -0
  35. package/dist/data/compression/compressible_asset.js +34 -0
  36. package/dist/data/compression/compressible_asset.js.map +1 -0
  37. package/dist/data/compression/payload_compression_config.d.ts +36 -0
  38. package/dist/data/compression/payload_compression_config.d.ts.map +1 -0
  39. package/dist/data/compression/payload_compression_config.js +52 -0
  40. package/dist/data/compression/payload_compression_config.js.map +1 -0
  41. package/dist/data/compression/payload_compression_runner.d.ts +29 -0
  42. package/dist/data/compression/payload_compression_runner.d.ts.map +1 -0
  43. package/dist/data/compression/payload_compression_runner.js +55 -0
  44. package/dist/data/compression/payload_compression_runner.js.map +1 -0
  45. package/dist/data/compression/payload_compressor.d.ts +40 -0
  46. package/dist/data/compression/payload_compressor.d.ts.map +1 -0
  47. package/dist/data/compression/payload_compressor.js +126 -0
  48. package/dist/data/compression/payload_compressor.js.map +1 -0
  49. package/dist/data/compression/uri_compressible_asset.d.ts +23 -0
  50. package/dist/data/compression/uri_compressible_asset.d.ts.map +1 -0
  51. package/dist/data/compression/uri_compressible_asset.js +77 -0
  52. package/dist/data/compression/uri_compressible_asset.js.map +1 -0
  53. package/dist/data/dsl/builder/cache_config_builder.d.ts +2 -1
  54. package/dist/data/dsl/builder/cache_config_builder.d.ts.map +1 -1
  55. package/dist/data/dsl/builder/cache_config_builder.js +2 -1
  56. package/dist/data/dsl/builder/cache_config_builder.js.map +1 -1
  57. package/dist/data/dsl/builder/config_builder.d.ts +40 -14
  58. package/dist/data/dsl/builder/config_builder.d.ts.map +1 -1
  59. package/dist/data/dsl/builder/config_builder.js +40 -14
  60. package/dist/data/dsl/builder/config_builder.js.map +1 -1
  61. package/dist/data/dsl/builder/interceptor_config_builder.d.ts +9 -7
  62. package/dist/data/dsl/builder/interceptor_config_builder.d.ts.map +1 -1
  63. package/dist/data/dsl/builder/interceptor_config_builder.js +9 -7
  64. package/dist/data/dsl/builder/interceptor_config_builder.js.map +1 -1
  65. package/dist/data/dsl/builder/retry_config_builder.d.ts +16 -1
  66. package/dist/data/dsl/builder/retry_config_builder.d.ts.map +1 -1
  67. package/dist/data/dsl/builder/retry_config_builder.js +16 -1
  68. package/dist/data/dsl/builder/retry_config_builder.js.map +1 -1
  69. package/dist/data/dsl/builder/timeout_config_builder.d.ts +4 -0
  70. package/dist/data/dsl/builder/timeout_config_builder.d.ts.map +1 -1
  71. package/dist/data/dsl/builder/timeout_config_builder.js +4 -0
  72. package/dist/data/dsl/builder/timeout_config_builder.js.map +1 -1
  73. package/dist/data/dsl/use_smile_id_network_builder.d.ts +17 -0
  74. package/dist/data/dsl/use_smile_id_network_builder.d.ts.map +1 -1
  75. package/dist/data/dsl/use_smile_id_network_builder.js +17 -0
  76. package/dist/data/dsl/use_smile_id_network_builder.js.map +1 -1
  77. package/dist/data/factory/networking_factory.d.ts.map +1 -1
  78. package/dist/data/factory/networking_factory.js +11 -1
  79. package/dist/data/factory/networking_factory.js.map +1 -1
  80. package/dist/data/repository/use_smile_id_repository_impl.d.ts +6 -0
  81. package/dist/data/repository/use_smile_id_repository_impl.d.ts.map +1 -1
  82. package/dist/data/repository/use_smile_id_repository_impl.js +82 -8
  83. package/dist/data/repository/use_smile_id_repository_impl.js.map +1 -1
  84. package/dist/data/security/request_canonicalizer.d.ts.map +1 -1
  85. package/dist/data/security/request_canonicalizer.js +14 -2
  86. package/dist/data/security/request_canonicalizer.js.map +1 -1
  87. package/dist/data/security/security_policy.d.ts +43 -0
  88. package/dist/data/security/security_policy.d.ts.map +1 -0
  89. package/dist/data/security/security_policy.js +61 -0
  90. package/dist/data/security/security_policy.js.map +1 -0
  91. package/dist/data/util/retry_util.d.ts +1 -1
  92. package/dist/data/util/retry_util.d.ts.map +1 -1
  93. package/dist/data/util/retry_util.js +2 -1
  94. package/dist/data/util/retry_util.js.map +1 -1
  95. package/dist/data/util/use_smile_id_token_decoder.d.ts +22 -0
  96. package/dist/data/util/use_smile_id_token_decoder.d.ts.map +1 -1
  97. package/dist/data/util/use_smile_id_token_decoder.js +58 -24
  98. package/dist/data/util/use_smile_id_token_decoder.js.map +1 -1
  99. package/dist/l10n/strings_en.d.ts +2 -1
  100. package/dist/l10n/strings_en.d.ts.map +1 -1
  101. package/dist/l10n/strings_en.js +2 -1
  102. package/dist/l10n/strings_en.js.map +1 -1
  103. package/dist/l10n/use_smile_id_localizations.d.ts +1 -0
  104. package/dist/l10n/use_smile_id_localizations.d.ts.map +1 -1
  105. package/dist/l10n/use_smile_id_localizations.js +3 -0
  106. package/dist/l10n/use_smile_id_localizations.js.map +1 -1
  107. package/dist/metadata/builder_configuration.d.ts +39 -0
  108. package/dist/metadata/builder_configuration.d.ts.map +1 -0
  109. package/dist/metadata/builder_configuration.js +34 -0
  110. package/dist/metadata/builder_configuration.js.map +1 -0
  111. package/dist/metadata/captured_image_properties.d.ts +11 -0
  112. package/dist/metadata/captured_image_properties.d.ts.map +1 -0
  113. package/dist/metadata/captured_image_properties.js +11 -0
  114. package/dist/metadata/captured_image_properties.js.map +1 -0
  115. package/dist/metadata/device_orientation_collector.d.ts +17 -0
  116. package/dist/metadata/device_orientation_collector.d.ts.map +1 -0
  117. package/dist/metadata/device_orientation_collector.js +66 -0
  118. package/dist/metadata/device_orientation_collector.js.map +1 -0
  119. package/dist/metadata/geolocation.d.ts +20 -0
  120. package/dist/metadata/geolocation.d.ts.map +1 -0
  121. package/dist/metadata/geolocation.js +40 -0
  122. package/dist/metadata/geolocation.js.map +1 -0
  123. package/dist/metadata/metadata_configuration_mappers.d.ts +48 -0
  124. package/dist/metadata/metadata_configuration_mappers.d.ts.map +1 -0
  125. package/dist/metadata/metadata_configuration_mappers.js +171 -0
  126. package/dist/metadata/metadata_configuration_mappers.js.map +1 -0
  127. package/dist/metadata/model_configuration.d.ts +41 -0
  128. package/dist/metadata/model_configuration.d.ts.map +1 -0
  129. package/dist/metadata/model_configuration.js +44 -0
  130. package/dist/metadata/model_configuration.js.map +1 -0
  131. package/dist/metadata/optional_native_modules.d.ts +79 -3
  132. package/dist/metadata/optional_native_modules.d.ts.map +1 -1
  133. package/dist/metadata/optional_native_modules.js +108 -3
  134. package/dist/metadata/optional_native_modules.js.map +1 -1
  135. package/dist/metadata/use_smile_id_metadata.d.ts +45 -7
  136. package/dist/metadata/use_smile_id_metadata.d.ts.map +1 -1
  137. package/dist/metadata/use_smile_id_metadata.js +85 -13
  138. package/dist/metadata/use_smile_id_metadata.js.map +1 -1
  139. package/dist/metadata/use_smile_id_metadata_factory.d.ts +37 -0
  140. package/dist/metadata/use_smile_id_metadata_factory.d.ts.map +1 -1
  141. package/dist/metadata/use_smile_id_metadata_factory.js +184 -12
  142. package/dist/metadata/use_smile_id_metadata_factory.js.map +1 -1
  143. package/dist/presentation/assets/svg/document_shimmer_strings.d.ts +14 -0
  144. package/dist/presentation/assets/svg/document_shimmer_strings.d.ts.map +1 -0
  145. package/dist/presentation/assets/svg/document_shimmer_strings.js +14 -0
  146. package/dist/presentation/assets/svg/document_shimmer_strings.js.map +1 -0
  147. package/dist/presentation/assets/svg/instruction_svg_strings.d.ts +12 -4
  148. package/dist/presentation/assets/svg/instruction_svg_strings.d.ts.map +1 -1
  149. package/dist/presentation/assets/svg/instruction_svg_strings.js +19 -8
  150. package/dist/presentation/assets/svg/instruction_svg_strings.js.map +1 -1
  151. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts +0 -5
  152. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts.map +1 -1
  153. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js +0 -5
  154. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js.map +1 -1
  155. package/dist/presentation/components/icons/index.d.ts +24 -8
  156. package/dist/presentation/components/icons/index.d.ts.map +1 -1
  157. package/dist/presentation/components/icons/index.js +31 -11
  158. package/dist/presentation/components/icons/index.js.map +1 -1
  159. package/dist/presentation/components/use_smile_id_attribution.d.ts +1 -1
  160. package/dist/presentation/components/use_smile_id_button.d.ts +2 -2
  161. package/dist/presentation/components/use_smile_id_button.js +4 -4
  162. package/dist/presentation/components/use_smile_id_button.js.map +1 -1
  163. package/dist/presentation/components/use_smile_id_capture_content.d.ts +13 -0
  164. package/dist/presentation/components/use_smile_id_capture_content.d.ts.map +1 -1
  165. package/dist/presentation/components/use_smile_id_capture_content.js +15 -9
  166. package/dist/presentation/components/use_smile_id_capture_content.js.map +1 -1
  167. package/dist/presentation/components/use_smile_id_captured_document_image.d.ts +2 -3
  168. package/dist/presentation/components/use_smile_id_captured_document_image.d.ts.map +1 -1
  169. package/dist/presentation/components/use_smile_id_captured_document_image.js +1 -3
  170. package/dist/presentation/components/use_smile_id_captured_document_image.js.map +1 -1
  171. package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts +12 -6
  172. package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts.map +1 -1
  173. package/dist/presentation/components/use_smile_id_document_capture_controls.js +59 -16
  174. package/dist/presentation/components/use_smile_id_document_capture_controls.js.map +1 -1
  175. package/dist/presentation/components/use_smile_id_document_overlay.d.ts +22 -5
  176. package/dist/presentation/components/use_smile_id_document_overlay.d.ts.map +1 -1
  177. package/dist/presentation/components/use_smile_id_document_overlay.js +80 -40
  178. package/dist/presentation/components/use_smile_id_document_overlay.js.map +1 -1
  179. package/dist/presentation/components/use_smile_id_document_shimmer.d.ts +15 -0
  180. package/dist/presentation/components/use_smile_id_document_shimmer.d.ts.map +1 -0
  181. package/dist/presentation/components/use_smile_id_document_shimmer.js +23 -0
  182. package/dist/presentation/components/use_smile_id_document_shimmer.js.map +1 -0
  183. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts.map +1 -1
  184. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js +1 -3
  185. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js.map +1 -1
  186. package/dist/presentation/components/use_smile_id_guideline_thumbnail.d.ts.map +1 -1
  187. package/dist/presentation/components/use_smile_id_guideline_thumbnail.js +84 -1
  188. package/dist/presentation/components/use_smile_id_guideline_thumbnail.js.map +1 -1
  189. package/dist/presentation/components/use_smile_id_instructions_hero.d.ts +3 -1
  190. package/dist/presentation/components/use_smile_id_instructions_hero.d.ts.map +1 -1
  191. package/dist/presentation/components/use_smile_id_instructions_hero.js +18 -3
  192. package/dist/presentation/components/use_smile_id_instructions_hero.js.map +1 -1
  193. package/dist/presentation/components/use_smile_id_oval_border_palette.d.ts.map +1 -1
  194. package/dist/presentation/components/use_smile_id_oval_border_palette.js +7 -3
  195. package/dist/presentation/components/use_smile_id_oval_border_palette.js.map +1 -1
  196. package/dist/presentation/flow/dsl/builder/config_builder.d.ts +12 -0
  197. package/dist/presentation/flow/dsl/builder/config_builder.d.ts.map +1 -1
  198. package/dist/presentation/flow/dsl/builder/config_builder.js +12 -0
  199. package/dist/presentation/flow/dsl/builder/config_builder.js.map +1 -1
  200. package/dist/presentation/flow/dsl/builder/ml_builder.d.ts +13 -4
  201. package/dist/presentation/flow/dsl/builder/ml_builder.d.ts.map +1 -1
  202. package/dist/presentation/flow/dsl/builder/ml_builder.js +3 -2
  203. package/dist/presentation/flow/dsl/builder/ml_builder.js.map +1 -1
  204. package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +111 -10
  205. package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
  206. package/dist/presentation/flow/dsl/builder/screens_builder.js +111 -10
  207. package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
  208. package/dist/presentation/flow/dsl/builder/theme_builder.d.ts +15 -2
  209. package/dist/presentation/flow/dsl/builder/theme_builder.d.ts.map +1 -1
  210. package/dist/presentation/flow/dsl/builder/theme_builder.js +15 -2
  211. package/dist/presentation/flow/dsl/builder/theme_builder.js.map +1 -1
  212. package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts +6 -4
  213. package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts.map +1 -1
  214. package/dist/presentation/flow/dsl/use_smile_id_builder.js.map +1 -1
  215. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts +62 -36
  216. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts.map +1 -1
  217. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +62 -36
  218. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js.map +1 -1
  219. package/dist/presentation/flow/flow_navigation_manager.d.ts +39 -4
  220. package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
  221. package/dist/presentation/flow/flow_navigation_manager.js +141 -10
  222. package/dist/presentation/flow/flow_navigation_manager.js.map +1 -1
  223. package/dist/presentation/flow/model/instruction_guideline.d.ts +9 -0
  224. package/dist/presentation/flow/model/instruction_guideline.d.ts.map +1 -1
  225. package/dist/presentation/flow/model/instructions_defaults.d.ts +11 -2
  226. package/dist/presentation/flow/model/instructions_defaults.d.ts.map +1 -1
  227. package/dist/presentation/flow/model/instructions_defaults.js +73 -25
  228. package/dist/presentation/flow/model/instructions_defaults.js.map +1 -1
  229. package/dist/presentation/flow/screen/orchestrated_capture_screen.d.ts.map +1 -1
  230. package/dist/presentation/flow/screen/orchestrated_capture_screen.js +36 -12
  231. package/dist/presentation/flow/screen/orchestrated_capture_screen.js.map +1 -1
  232. package/dist/presentation/flow/screen/orchestrated_instructions_screen.js +1 -1
  233. package/dist/presentation/flow/screen/orchestrated_instructions_screen.js.map +1 -1
  234. package/dist/presentation/flow/screen/orchestrated_preview_screen.d.ts.map +1 -1
  235. package/dist/presentation/flow/screen/orchestrated_preview_screen.js +3 -1
  236. package/dist/presentation/flow/screen/orchestrated_preview_screen.js.map +1 -1
  237. package/dist/presentation/flow/screen/orchestrated_processing_screen.js +3 -3
  238. package/dist/presentation/flow/screen/orchestrated_processing_screen.js.map +1 -1
  239. package/dist/presentation/flow/validation/job_type_validator.d.ts.map +1 -1
  240. package/dist/presentation/flow/validation/job_type_validator.js +14 -0
  241. package/dist/presentation/flow/validation/job_type_validator.js.map +1 -1
  242. package/dist/presentation/screen/helpers/capture_screen_helpers.d.ts.map +1 -1
  243. package/dist/presentation/screen/helpers/capture_screen_helpers.js +1 -0
  244. package/dist/presentation/screen/helpers/capture_screen_helpers.js.map +1 -1
  245. package/dist/presentation/screen/helpers/instructions_screen_helpers.d.ts +1 -0
  246. package/dist/presentation/screen/helpers/instructions_screen_helpers.d.ts.map +1 -1
  247. package/dist/presentation/screen/helpers/instructions_screen_helpers.js +6 -2
  248. package/dist/presentation/screen/helpers/instructions_screen_helpers.js.map +1 -1
  249. package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js +3 -0
  250. package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js.map +1 -1
  251. package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +17 -1
  252. package/dist/presentation/screen/use_smile_id_capture_screen.d.ts.map +1 -1
  253. package/dist/presentation/screen/use_smile_id_capture_screen.js +153 -18
  254. package/dist/presentation/screen/use_smile_id_capture_screen.js.map +1 -1
  255. package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts +2 -3
  256. package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts.map +1 -1
  257. package/dist/presentation/screen/use_smile_id_document_preview_screen.js +16 -11
  258. package/dist/presentation/screen/use_smile_id_document_preview_screen.js.map +1 -1
  259. package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts +2 -0
  260. package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts.map +1 -1
  261. package/dist/presentation/screen/use_smile_id_instructions_screen.js +2 -1
  262. package/dist/presentation/screen/use_smile_id_instructions_screen.js.map +1 -1
  263. package/dist/presentation/screen/use_smile_id_preview_screen.d.ts +7 -6
  264. package/dist/presentation/screen/use_smile_id_preview_screen.d.ts.map +1 -1
  265. package/dist/presentation/screen/use_smile_id_preview_screen.js +9 -8
  266. package/dist/presentation/screen/use_smile_id_preview_screen.js.map +1 -1
  267. package/dist/presentation/screen/use_smile_id_processing_screen.d.ts +2 -3
  268. package/dist/presentation/screen/use_smile_id_processing_screen.d.ts.map +1 -1
  269. package/dist/presentation/screen/use_smile_id_processing_screen.js +3 -2
  270. package/dist/presentation/screen/use_smile_id_processing_screen.js.map +1 -1
  271. package/dist/presentation/theme/theme.d.ts +1 -1
  272. package/dist/presentation/theme/theme.d.ts.map +1 -1
  273. package/dist/presentation/theme/theme.js +20 -18
  274. package/dist/presentation/theme/theme.js.map +1 -1
  275. package/dist/presentation/utils/force_max_brightness.d.ts +4 -4
  276. package/package.json +26 -6
  277. package/src/__tests__/react_native_mock.tsx +8 -0
  278. package/src/camera/camera_defaults.ts +11 -9
  279. package/src/camera/orientation_degrees.ts +5 -6
  280. package/src/core/models/__tests__/document_type.test.ts +6 -4
  281. package/src/core/models/document_capture_mode.ts +27 -0
  282. package/src/core/models/document_type.ts +6 -4
  283. package/src/core/models/result.ts +9 -8
  284. package/src/data/api/interceptors/__tests__/smile_integrity_interceptor.test.ts +37 -1
  285. package/src/data/api/interceptors/__tests__/smile_request_mac_interceptor.test.ts +59 -1
  286. package/src/data/api/interceptors/smile_auth_interceptor.ts +1 -1
  287. package/src/data/api/interceptors/smile_integrity_interceptor.ts +20 -0
  288. package/src/data/api/interceptors/smile_request_mac_interceptor.ts +13 -0
  289. package/src/data/compression/__tests__/payload_compressor.test.ts +200 -0
  290. package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +222 -0
  291. package/src/data/compression/compressible_asset.ts +62 -0
  292. package/src/data/compression/payload_compression_config.ts +53 -0
  293. package/src/data/compression/payload_compression_runner.ts +102 -0
  294. package/src/data/compression/payload_compressor.ts +164 -0
  295. package/src/data/compression/uri_compressible_asset.ts +85 -0
  296. package/src/data/dsl/builder/cache_config_builder.ts +3 -1
  297. package/src/data/dsl/builder/config_builder.ts +45 -14
  298. package/src/data/dsl/builder/interceptor_config_builder.ts +9 -7
  299. package/src/data/dsl/builder/retry_config_builder.ts +22 -1
  300. package/src/data/dsl/builder/timeout_config_builder.ts +7 -0
  301. package/src/data/dsl/use_smile_id_network_builder.ts +17 -0
  302. package/src/data/factory/networking_factory.ts +14 -1
  303. package/src/data/repository/__tests__/network_retries.test.ts +117 -0
  304. package/src/data/repository/use_smile_id_repository_impl.ts +96 -9
  305. package/src/data/security/__tests__/security_policy.test.ts +96 -0
  306. package/src/data/security/__tests__/smile_id_crypto_manager.test.ts +18 -0
  307. package/src/data/security/request_canonicalizer.ts +15 -2
  308. package/src/data/security/security_policy.ts +70 -0
  309. package/src/data/util/__tests__/use_smile_id_token_decoder.test.ts +57 -1
  310. package/src/data/util/retry_util.ts +3 -2
  311. package/src/data/util/use_smile_id_token_decoder.ts +76 -28
  312. package/src/l10n/strings_en.ts +2 -1
  313. package/src/l10n/use_smile_id_localizations.ts +3 -0
  314. package/src/metadata/__tests__/device_orientation_collector.test.ts +15 -0
  315. package/src/metadata/__tests__/metadata_configuration_mappers.test.ts +215 -0
  316. package/src/metadata/__tests__/metadata_configuration_objects.test.ts +85 -0
  317. package/src/metadata/__tests__/metadata_device_context.test.ts +147 -0
  318. package/src/metadata/__tests__/metadata_golden_fixture.json +13 -0
  319. package/src/metadata/__tests__/metadata_payload_golden.test.ts +193 -0
  320. package/src/metadata/__tests__/use_smile_id_metadata.test.ts +18 -24
  321. package/src/metadata/builder_configuration.ts +63 -0
  322. package/src/metadata/captured_image_properties.ts +10 -0
  323. package/src/metadata/device_orientation_collector.ts +75 -0
  324. package/src/metadata/geolocation.ts +46 -0
  325. package/src/metadata/metadata_configuration_mappers.ts +234 -0
  326. package/src/metadata/model_configuration.ts +68 -0
  327. package/src/metadata/optional_native_modules.ts +157 -3
  328. package/src/metadata/use_smile_id_metadata.ts +140 -17
  329. package/src/metadata/use_smile_id_metadata_factory.ts +195 -11
  330. package/src/presentation/assets/si_ess_animation_all_directions.json +1300 -286
  331. package/src/presentation/assets/svg/document_shimmer_strings.ts +17 -0
  332. package/src/presentation/assets/svg/instruction_svg_strings.ts +34 -12
  333. package/src/presentation/components/__tests__/enhanced_smart_selfie_animation_frames.test.ts +1 -3
  334. package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +3 -4
  335. package/src/presentation/components/__tests__/use_smile_id_guideline_thumbnail.test.tsx +34 -1
  336. package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +27 -0
  337. package/src/presentation/components/__tests__/use_smile_id_oval_border_palette.test.ts +7 -5
  338. package/src/presentation/components/helpers/enhanced_smart_selfie_animation_frames.ts +0 -6
  339. package/src/presentation/components/icons/index.tsx +65 -18
  340. package/src/presentation/components/use_smile_id_attribution.tsx +1 -1
  341. package/src/presentation/components/use_smile_id_button.tsx +4 -4
  342. package/src/presentation/components/use_smile_id_capture_content.tsx +36 -12
  343. package/src/presentation/components/use_smile_id_captured_document_image.tsx +3 -8
  344. package/src/presentation/components/use_smile_id_document_capture_controls.tsx +103 -39
  345. package/src/presentation/components/use_smile_id_document_overlay.tsx +134 -44
  346. package/src/presentation/components/use_smile_id_document_shimmer.tsx +51 -0
  347. package/src/presentation/components/use_smile_id_enhanced_smart_selfie_clip.tsx +0 -3
  348. package/src/presentation/components/use_smile_id_guideline_thumbnail.tsx +131 -2
  349. package/src/presentation/components/use_smile_id_instructions_hero.tsx +100 -59
  350. package/src/presentation/components/use_smile_id_oval_border_palette.ts +7 -3
  351. package/src/presentation/flow/__tests__/document_flow_navigation.test.ts +200 -1
  352. package/src/presentation/flow/dsl/builder/config_builder.ts +14 -0
  353. package/src/presentation/flow/dsl/builder/ml_builder.ts +13 -4
  354. package/src/presentation/flow/dsl/builder/screens_builder.ts +111 -10
  355. package/src/presentation/flow/dsl/builder/theme_builder.ts +19 -2
  356. package/src/presentation/flow/dsl/use_smile_id_builder.tsx +6 -4
  357. package/src/presentation/flow/dsl/use_smile_id_flow_builder.ts +62 -36
  358. package/src/presentation/flow/flow_navigation_manager.ts +179 -13
  359. package/src/presentation/flow/model/instruction_guideline.ts +6 -0
  360. package/src/presentation/flow/model/instructions_defaults.ts +103 -25
  361. package/src/presentation/flow/screen/orchestrated_capture_screen.tsx +43 -10
  362. package/src/presentation/flow/screen/orchestrated_instructions_screen.tsx +1 -0
  363. package/src/presentation/flow/screen/orchestrated_preview_screen.tsx +4 -2
  364. package/src/presentation/flow/screen/orchestrated_processing_screen.tsx +3 -3
  365. package/src/presentation/flow/validation/__tests__/job_type_validator.test.ts +64 -0
  366. package/src/presentation/flow/validation/job_type_validator.ts +24 -0
  367. package/src/presentation/screen/__tests__/instructions_screen_helpers.test.ts +15 -3
  368. package/src/presentation/screen/__tests__/use_smile_id_capture_screen.test.tsx +6 -4
  369. package/src/presentation/screen/helpers/capture_screen_helpers.ts +1 -0
  370. package/src/presentation/screen/helpers/instructions_screen_helpers.ts +7 -2
  371. package/src/presentation/screen/helpers/scan_state_to_overlay_state.ts +3 -0
  372. package/src/presentation/screen/use_smile_id_capture_screen.tsx +234 -36
  373. package/src/presentation/screen/use_smile_id_document_preview_screen.tsx +32 -22
  374. package/src/presentation/screen/use_smile_id_instructions_screen.tsx +4 -0
  375. package/src/presentation/screen/use_smile_id_preview_screen.tsx +9 -9
  376. package/src/presentation/screen/use_smile_id_processing_screen.tsx +7 -7
  377. package/src/presentation/theme/theme.ts +21 -19
  378. package/src/presentation/utils/force_max_brightness.tsx +4 -4
  379. package/dist/camera/frame_processor_plugin.d.ts +0 -28
  380. package/dist/camera/frame_processor_plugin.d.ts.map +0 -1
  381. package/dist/camera/frame_processor_plugin.js +0 -21
  382. package/dist/camera/frame_processor_plugin.js.map +0 -1
  383. package/dist/camera/use_smile_id_frame_processor.d.ts +0 -38
  384. package/dist/camera/use_smile_id_frame_processor.d.ts.map +0 -1
  385. package/dist/camera/use_smile_id_frame_processor.js +0 -2
  386. package/dist/camera/use_smile_id_frame_processor.js.map +0 -1
  387. package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts +0 -17
  388. package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts.map +0 -1
  389. package/dist/presentation/components/use_smile_id_document_frame_glyph.js +0 -17
  390. package/dist/presentation/components/use_smile_id_document_frame_glyph.js.map +0 -1
  391. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts +0 -24
  392. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts.map +0 -1
  393. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js +0 -91
  394. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js.map +0 -1
  395. package/dist/presentation/components/use_smile_id_instruction_card.d.ts +0 -31
  396. package/dist/presentation/components/use_smile_id_instruction_card.d.ts.map +0 -1
  397. package/dist/presentation/components/use_smile_id_instruction_card.js +0 -43
  398. package/dist/presentation/components/use_smile_id_instruction_card.js.map +0 -1
  399. package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts +0 -24
  400. package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts.map +0 -1
  401. package/dist/presentation/screen/helpers/use_document_orientation_lock.js +0 -47
  402. package/dist/presentation/screen/helpers/use_document_orientation_lock.js.map +0 -1
  403. package/src/presentation/components/use_smile_id_document_frame_glyph.tsx +0 -162
@@ -15,7 +15,10 @@ import type {
15
15
  } from "../../core/models/params";
16
16
  import { JobType } from "../../core/models/job_type";
17
17
  import { CaptureType } from "../../core/models/ml_config";
18
- import type { DocumentType } from "../../core/models/document_type";
18
+ import {
19
+ defaultFrameAspectRatio,
20
+ type DocumentType,
21
+ } from "../../core/models/document_type";
19
22
  import type { JobSubmissionResponse } from "../../data/model/job_submission_response";
20
23
  import { MissingRequiredFieldException } from "../../core/exception/job_validation_exceptions";
21
24
  import {
@@ -37,9 +40,18 @@ import {
37
40
  DOCUMENT_FRONT_IMAGE_ORIGIN_KEY,
38
41
  type DocumentImageOrigin,
39
42
  } from "../../metadata/document_image_origin";
43
+ import { configurationMetadataEntries } from "../../metadata/metadata_configuration_mappers";
44
+ import {
45
+ CAPTURE_IMAGE_COLOR_DEPTH,
46
+ CAPTURE_IMAGE_PIXEL_CONFIG,
47
+ } from "../../metadata/captured_image_properties";
48
+ import type { CaptureTelemetry } from "../screen/use_smile_id_capture_screen";
40
49
  import type { SdkConfig } from "../../data/model/sdk_config";
41
50
  import { numSamplesOverride } from "../../data/model/sdk_config";
42
- import { decodeSmileIDToken } from "../../data/util/use_smile_id_token_decoder";
51
+ import {
52
+ decodeSmileIDToken,
53
+ type DecodedToken,
54
+ } from "../../data/util/use_smile_id_token_decoder";
43
55
  import {
44
56
  DocumentSide,
45
57
  EnhancedSmartSelfieConfig,
@@ -123,6 +135,17 @@ export class FlowNavigationManager {
123
135
  DocumentSide,
124
136
  DocumentImageOrigin
125
137
  >();
138
+ // Capture telemetry recorded at capture completion (selfie + per document side).
139
+ private _selfieCaptureTelemetry: CaptureTelemetry | undefined;
140
+ private readonly _documentCaptureTelemetry = new Map<
141
+ DocumentSide,
142
+ CaptureTelemetry
143
+ >();
144
+ // Identifier of the camera used for the most recent capture.
145
+ private _cameraName: string | undefined;
146
+ // Accelerometer telemetry from the most recent capture (device_positions / movement).
147
+ private _devicePositions: readonly string[] = [];
148
+ private _deviceMovementDetected: number | null = null;
126
149
  private _jobSubmissionState: JobSubmissionState = { kind: "notAttempted" };
127
150
  private readonly _listeners = new Set<Listener>();
128
151
  private readonly _steps: readonly ScreenSpec[];
@@ -140,6 +163,23 @@ export class FlowNavigationManager {
140
163
  */
141
164
  readonly resolvedSdkConfig: SdkConfig | undefined;
142
165
 
166
+ /** Canonical `partner_id` decoded from the JWT (raw); resolved via the [partnerId] getter. */
167
+ private readonly _resolvedPartnerId: string | undefined;
168
+
169
+ /**
170
+ * Partner identifier the capture screen stamps into the Smile EXIF tag — the tag's HMAC/AES
171
+ * keys derive from it and the backend validates the tag against the request's partner_id.
172
+ *
173
+ * Sourced from the JWT `partner_id` claim (server-canonical form, e.g. `"002"`) so the stamped
174
+ * value matches what the backend keys on; falls back to the partner-supplied config value when
175
+ * the claim is absent/blank. Empty = skip tagging.
176
+ */
177
+ get partnerId(): string {
178
+ const jwtPartnerId = this._resolvedPartnerId;
179
+ if (jwtPartnerId && jwtPartnerId.length > 0) return jwtPartnerId;
180
+ return this._configuration.network?.config?.partnerConfig?.partnerId ?? "";
181
+ }
182
+
143
183
  /** Stable per-flow session id, stamped into every analytics event's `session_id`. */
144
184
  private readonly _sessionId: string;
145
185
 
@@ -157,9 +197,11 @@ export class FlowNavigationManager {
157
197
  this._metadataProvider =
158
198
  options.metadataProvider ?? new UseSmileIDMetadataFactory();
159
199
  this._sessionId = this._metadataProvider.sessionId;
160
- this.resolvedSdkConfig = FlowNavigationManager._decodeSdkConfig(
200
+ const decodedToken = FlowNavigationManager._decodeToken(
161
201
  options.configuration,
162
202
  );
203
+ this.resolvedSdkConfig = decodedToken?.sdkConfig;
204
+ this._resolvedPartnerId = decodedToken?.partnerId;
163
205
  // Seed the path with the first screen so currentScreen/renderer have a
164
206
  // deterministic start. Empty path → host renders the "no screens"
165
207
  // sentinel (validation rejects empty screens at build time anyway).
@@ -204,6 +246,29 @@ export class FlowNavigationManager {
204
246
  return undefined;
205
247
  }
206
248
 
249
+ /**
250
+ * Resolved document capture-frame aspect ratio (width / height), shared by
251
+ * capture, preview, and processing. Precedence: type `knownAspectRatio` →
252
+ * partner `knownIdAspectRatio` → orientation default.
253
+ */
254
+ get documentFrameAspectRatio(): number | undefined {
255
+ for (const step of this._steps) {
256
+ if (
257
+ step.kind === "capture" &&
258
+ step.config.captureType === CaptureType.document
259
+ ) {
260
+ const documentConfig = step.config.documentConfig;
261
+ return (
262
+ documentConfig?.resolvedAspectRatio ??
263
+ defaultFrameAspectRatio(
264
+ documentConfig?.documentType?.orientation ?? "Landscape",
265
+ )
266
+ );
267
+ }
268
+ }
269
+ return undefined;
270
+ }
271
+
207
272
  // --- navigation path --------------------------------------------------
208
273
 
209
274
  /** Read-only navigation stack; top is the active screen. */
@@ -265,6 +330,23 @@ export class FlowNavigationManager {
265
330
  if (next?.kind === "preview") return this._steps[currentIdx + 2];
266
331
  }
267
332
 
333
+ // At the document capture step with the front captured, the back still
334
+ // pending, and no document preview to drive the per-side loop, re-enter the
335
+ // capture step for the back side so captureBothSides is honoured even when
336
+ // the flow omits the document preview { } step. When a preview does follow,
337
+ // the per-side loop above handles the back instead.
338
+ if (
339
+ current.kind === "capture" &&
340
+ current.config.captureType === CaptureType.document &&
341
+ this.documentCapturesBack() &&
342
+ this._captured.frontDocumentPath !== undefined &&
343
+ this._captured.backDocumentPath === undefined &&
344
+ !this._documentBackSkipped &&
345
+ !this.documentPreviewFollowsCapture()
346
+ ) {
347
+ return current;
348
+ }
349
+
268
350
  return this._steps[currentIdx + 1];
269
351
  }
270
352
 
@@ -485,6 +567,31 @@ export class FlowNavigationManager {
485
567
  this._documentImageOrigins.set(side, origin);
486
568
  }
487
569
 
570
+ /** Records selfie capture telemetry (duration + retries) at capture completion. */
571
+ recordSelfieCaptureTelemetry(telemetry: CaptureTelemetry): void {
572
+ if (this._disposed) return;
573
+ this._selfieCaptureTelemetry = telemetry;
574
+ this._captureCameraName(telemetry);
575
+ }
576
+
577
+ /** Records per-side document capture telemetry at each side's completion. */
578
+ recordDocumentCaptureTelemetry(
579
+ side: DocumentSide,
580
+ telemetry: CaptureTelemetry,
581
+ ): void {
582
+ if (this._disposed) return;
583
+ this._documentCaptureTelemetry.set(side, telemetry);
584
+ this._captureCameraName(telemetry);
585
+ }
586
+
587
+ private _captureCameraName(telemetry: CaptureTelemetry): void {
588
+ if (telemetry.cameraName) this._cameraName = telemetry.cameraName;
589
+ if (telemetry.devicePositions.length > 0) {
590
+ this._devicePositions = telemetry.devicePositions;
591
+ this._deviceMovementDetected = telemetry.deviceMovementDetected;
592
+ }
593
+ }
594
+
488
595
  /** Per-side document origin wire entries (front then back; omitted when unset). */
489
596
  private _documentImageOriginEntries(): MetadataEntry[] {
490
597
  const entries: MetadataEntry[] = [];
@@ -499,6 +606,60 @@ export class FlowNavigationManager {
499
606
  return entries;
500
607
  }
501
608
 
609
+ /**
610
+ * Capture telemetry + image-property wire entries. Durations and retries keep
611
+ * a meaningful 0 (capture ran) and are omitted only when that capture type
612
+ * never ran. Color depth / pixel config are emitted for each present capture;
613
+ * document sizes when measured.
614
+ */
615
+ private _captureTelemetryEntries(): MetadataEntry[] {
616
+ const entries: MetadataEntry[] = [];
617
+ const push = (name: string, value: string) => entries.push({ name, value });
618
+
619
+ const selfie = this._selfieCaptureTelemetry;
620
+ if (selfie) {
621
+ // Duration + retries keep a meaningful 0 (capture ran); telemetry is absent only when the
622
+ // capture type never ran.
623
+ push("selfie_capture_duration_ms", String(selfie.durationMs));
624
+ push("selfie_capture_retries", String(selfie.retries));
625
+ }
626
+ if (this._captured.selfiePath !== undefined) {
627
+ push("selfie_image_color_depth", String(CAPTURE_IMAGE_COLOR_DEPTH));
628
+ push("selfie_image_pixel_config", CAPTURE_IMAGE_PIXEL_CONFIG);
629
+ }
630
+ if (this._cameraName) {
631
+ push("camera_name", this._cameraName);
632
+ }
633
+ if (this._devicePositions.length > 0) {
634
+ push("device_positions", JSON.stringify(this._devicePositions));
635
+ if (this._deviceMovementDetected !== null) {
636
+ push("device_movement_detected", String(this._deviceMovementDetected));
637
+ }
638
+ }
639
+
640
+ const sideKey = (side: DocumentSide) =>
641
+ side === DocumentSide.Back ? "back" : "front";
642
+ for (const side of [DocumentSide.Front, DocumentSide.Back]) {
643
+ const key = sideKey(side);
644
+ const telemetry = this._documentCaptureTelemetry.get(side);
645
+ if (telemetry) {
646
+ push(
647
+ `document_${key}_capture_duration_ms`,
648
+ String(telemetry.durationMs),
649
+ );
650
+ push(`document_${key}_capture_retries`, String(telemetry.retries));
651
+ push(
652
+ `document_${key}_image_color_depth`,
653
+ String(CAPTURE_IMAGE_COLOR_DEPTH),
654
+ );
655
+ push(`document_${key}_image_pixel_config`, CAPTURE_IMAGE_PIXEL_CONFIG);
656
+ }
657
+ }
658
+ // Per-image original + final compressed sizes are stamped in the repository around the
659
+ // compression pass (it owns both the before and after byte counts), not here.
660
+ return entries;
661
+ }
662
+
502
663
  private _precedingStepIsDocumentCapture(index: number): boolean {
503
664
  const preceding = this._steps[index - 1];
504
665
  return (
@@ -619,11 +780,16 @@ export class FlowNavigationManager {
619
780
  // make() so a mid-flow rotation is captured. resolvedSdkConfig drives
620
781
  // sdk_config_source + image_width/height provenance.
621
782
  const baseMetadata = this._metadataProvider.make(this.resolvedSdkConfig);
622
- const originEntries = this._documentImageOriginEntries();
623
- const metadata =
624
- originEntries.length > 0
625
- ? baseMetadata.withAdditionalEntries(originEntries)
626
- : baseMetadata;
783
+ // Append the per-side document origins plus the partner's builder setup and
784
+ // the active detection models, all as flat wire entries.
785
+ // configurationMetadataEntries always contributes the builder + model config objects, so
786
+ // there is always at least one extra entry to append.
787
+ const extraEntries = [
788
+ ...this._documentImageOriginEntries(),
789
+ ...this._captureTelemetryEntries(),
790
+ ...configurationMetadataEntries(config),
791
+ ];
792
+ const metadata = baseMetadata.withAdditionalEntries(extraEntries);
627
793
 
628
794
  switch (jobType) {
629
795
  // enableEnhancedLiveness is a screen-level capture flag, not a
@@ -960,16 +1126,16 @@ export class FlowNavigationManager {
960
1126
  }
961
1127
 
962
1128
  /**
963
- * Decode the `sdk_config` JWT claim. `undefined` for offline mode,
964
- * no token, or no valid claim — SDK defaults apply in those cases.
1129
+ * Decode the partner JWT into its claims (`sdk_config`, `partner_id`). `undefined` for offline
1130
+ * mode, no token, or an unparseable token — SDK defaults apply in those cases.
965
1131
  */
966
- private static _decodeSdkConfig(
1132
+ private static _decodeToken(
967
1133
  configuration: FlowConfigurationSnapshot,
968
- ): SdkConfig | undefined {
1134
+ ): DecodedToken | undefined {
969
1135
  if (configuration.config?.allowOfflineMode) return undefined;
970
1136
  const token = configuration.network?.config?.token;
971
1137
  if (!token || token.length === 0) return undefined;
972
- return decodeSmileIDToken(token)?.sdkConfig;
1138
+ return decodeSmileIDToken(token);
973
1139
  }
974
1140
 
975
1141
  private _notify(): void {
@@ -12,4 +12,10 @@ export type InstructionGuideline = {
12
12
  readonly image: FC<{ readonly width?: number; readonly height?: number }>;
13
13
  readonly label: (localizations: UseSmileIDLocalizations) => string;
14
14
  readonly status: GuidelineStatus;
15
+ /**
16
+ * Visible-card size (device-independent px) for a self-contained document
17
+ * illustration (the SVG paints its own card). Set ⇒ document-card tile;
18
+ * omitted ⇒ selfie tile (framed card + pill).
19
+ */
20
+ readonly card?: { readonly width: number; readonly height: number };
15
21
  };
@@ -1,10 +1,18 @@
1
1
  import type { AnimationObject } from "lottie-react-native";
2
2
  import {
3
3
  SiGuidelineAccessories,
4
- SiGuidelineDocumentGood,
5
- SiGuidelineDocumentNotBlurry,
6
- SiGuidelineDocumentNotCropped,
7
- SiGuidelineDocumentNotReflective,
4
+ SiGuidelineDocumentGenericGood,
5
+ SiGuidelineDocumentGenericNotBlurry,
6
+ SiGuidelineDocumentGenericNotCropped,
7
+ SiGuidelineDocumentGenericNotReflective,
8
+ SiGuidelineDocumentGreenBookGood,
9
+ SiGuidelineDocumentGreenBookNotBlurry,
10
+ SiGuidelineDocumentGreenBookNotCropped,
11
+ SiGuidelineDocumentGreenBookNotReflective,
12
+ SiGuidelineDocumentPassportGood,
13
+ SiGuidelineDocumentPassportNotBlurry,
14
+ SiGuidelineDocumentPassportNotCropped,
15
+ SiGuidelineDocumentPassportNotReflective,
8
16
  SiGuidelineGood,
9
17
  SiGuidelineMultipleFaces,
10
18
  SiGuidelinePoorLighting,
@@ -73,34 +81,104 @@ export const SELFIE_GUIDELINES: readonly InstructionGuideline[] = Object.freeze(
73
81
  SELFIE_GUIDELINE_ENTRIES.map((guideline) => Object.freeze(guideline)),
74
82
  );
75
83
 
76
- const DOCUMENT_GUIDELINE_ENTRIES: InstructionGuideline[] = [
77
- {
78
- image: SiGuidelineDocumentGood,
79
- label: (localizations) => localizations.siDocumentGuidelineGood,
80
- status: "allowed",
81
- },
84
+ // Visible card size (device-independent px) per document guideline tile.
85
+ const DOCUMENT_CARD_LANDSCAPE = Object.freeze({ width: 80, height: 56 });
86
+ const DOCUMENT_CARD_PORTRAIT = Object.freeze({ width: 60, height: 84 });
87
+
88
+ type DocumentGuidelineImages = {
89
+ readonly good: InstructionGuideline["image"];
90
+ readonly notCropped: InstructionGuideline["image"];
91
+ readonly notBlurry: InstructionGuideline["image"];
92
+ readonly notReflective: InstructionGuideline["image"];
93
+ };
94
+
95
+ /**
96
+ * Build the four document-capture guidelines (good + not cropped / blurry /
97
+ * reflective) for one document type. The order and labels are shared; only the
98
+ * per-type artwork and card size differ. Allocated once and deeply frozen.
99
+ */
100
+ function buildDocumentGuidelines(
101
+ images: DocumentGuidelineImages,
102
+ card: { readonly width: number; readonly height: number },
103
+ ): readonly InstructionGuideline[] {
104
+ const entries: InstructionGuideline[] = [
105
+ {
106
+ image: images.good,
107
+ label: (localizations) => localizations.siDocumentGuidelineGood,
108
+ status: "allowed",
109
+ card,
110
+ },
111
+ {
112
+ image: images.notCropped,
113
+ label: (localizations) => localizations.siDocumentGuidelineNotCropped,
114
+ status: "blocked",
115
+ card,
116
+ },
117
+ {
118
+ image: images.notBlurry,
119
+ label: (localizations) => localizations.siDocumentGuidelineNotBlurry,
120
+ status: "blocked",
121
+ card,
122
+ },
123
+ {
124
+ image: images.notReflective,
125
+ label: (localizations) => localizations.siDocumentGuidelineNotReflective,
126
+ status: "blocked",
127
+ card,
128
+ },
129
+ ];
130
+ return Object.freeze(entries.map((guideline) => Object.freeze(guideline)));
131
+ }
132
+
133
+ /** Generic-document capture guidelines (landscape card). */
134
+ export const DOCUMENT_GUIDELINES_GENERIC = buildDocumentGuidelines(
82
135
  {
83
- image: SiGuidelineDocumentNotCropped,
84
- label: (localizations) => localizations.siDocumentGuidelineNotCropped,
85
- status: "blocked",
136
+ good: SiGuidelineDocumentGenericGood,
137
+ notCropped: SiGuidelineDocumentGenericNotCropped,
138
+ notBlurry: SiGuidelineDocumentGenericNotBlurry,
139
+ notReflective: SiGuidelineDocumentGenericNotReflective,
86
140
  },
141
+ DOCUMENT_CARD_LANDSCAPE,
142
+ );
143
+
144
+ /** Passport capture guidelines (landscape card). */
145
+ export const DOCUMENT_GUIDELINES_PASSPORT = buildDocumentGuidelines(
87
146
  {
88
- image: SiGuidelineDocumentNotBlurry,
89
- label: (localizations) => localizations.siDocumentGuidelineNotBlurry,
90
- status: "blocked",
147
+ good: SiGuidelineDocumentPassportGood,
148
+ notCropped: SiGuidelineDocumentPassportNotCropped,
149
+ notBlurry: SiGuidelineDocumentPassportNotBlurry,
150
+ notReflective: SiGuidelineDocumentPassportNotReflective,
91
151
  },
152
+ DOCUMENT_CARD_LANDSCAPE,
153
+ );
154
+
155
+ /** South Africa green book capture guidelines (portrait card). */
156
+ export const DOCUMENT_GUIDELINES_GREEN_BOOK = buildDocumentGuidelines(
92
157
  {
93
- image: SiGuidelineDocumentNotReflective,
94
- label: (localizations) => localizations.siDocumentGuidelineNotReflective,
95
- status: "blocked",
158
+ good: SiGuidelineDocumentGreenBookGood,
159
+ notCropped: SiGuidelineDocumentGreenBookNotCropped,
160
+ notBlurry: SiGuidelineDocumentGreenBookNotBlurry,
161
+ notReflective: SiGuidelineDocumentGreenBookNotReflective,
96
162
  },
97
- ];
163
+ DOCUMENT_CARD_PORTRAIT,
164
+ );
98
165
 
99
- /** Default document-capture guidelines — allocated once and deeply frozen. */
100
- export const DOCUMENT_GUIDELINES: readonly InstructionGuideline[] =
101
- Object.freeze(
102
- DOCUMENT_GUIDELINE_ENTRIES.map((guideline) => Object.freeze(guideline)),
103
- );
166
+ /**
167
+ * Resolve the document-capture guidelines for a document type. Falls back to
168
+ * the generic set when the type is unset or has no dedicated artwork.
169
+ */
170
+ export function documentGuidelines(
171
+ documentType: DocumentType | undefined,
172
+ ): readonly InstructionGuideline[] {
173
+ switch (documentType?.kind) {
174
+ case "southAfricaGreenBook":
175
+ return DOCUMENT_GUIDELINES_GREEN_BOOK;
176
+ case "passport":
177
+ return DOCUMENT_GUIDELINES_PASSPORT;
178
+ default:
179
+ return DOCUMENT_GUIDELINES_GENERIC;
180
+ }
181
+ }
104
182
 
105
183
  /**
106
184
  * Resolve the document hero animation for a document type. Falls back to the
@@ -9,6 +9,7 @@ import type {
9
9
  } from "@smileid/usesmileid_bridge";
10
10
  import {
11
11
  CaptureReadyEventKind,
12
+ DeviceIntegrityProvider,
12
13
  DocumentSide,
13
14
  ImageType,
14
15
  } from "@smileid/usesmileid_bridge";
@@ -21,6 +22,7 @@ import { resolveFaceSessionConfig } from "./helpers/face_session_config";
21
22
  import { useCaptureOrientationLock } from "../../screen/helpers/use_capture_orientation_lock";
22
23
  import { resolveJpegQuality } from "../../../data/model/sdk_config_capture";
23
24
  import { UseSmileIDCaptureScreen } from "../../screen/use_smile_id_capture_screen";
25
+ import { defaultLightTheme } from "../../theme/theme";
24
26
  import { UseSmileIDDocumentBackInstructions } from "../../screen/use_smile_id_document_back_instructions";
25
27
  import { useFlowNavigation } from "../flow_navigation_context";
26
28
  import { UseSmileIDOrchestratedScreenHost } from "./use_smile_id_orchestrated_screen_host";
@@ -166,24 +168,37 @@ export function OrchestratedCaptureScreen({
166
168
  }
167
169
  return (
168
170
  <UseSmileIDCaptureScreen
171
+ // Remount per document side so the camera resets between front and back captures.
172
+ key={
173
+ captureType === CaptureType.document
174
+ ? `document-capture-${currentDocumentSide}`
175
+ : "capture"
176
+ }
169
177
  captureType={captureType}
170
178
  analyzer={analyzer}
179
+ // Capture is always light; pass the partner's resolved light tokens
180
+ // so partner colours still apply (the screen forces light internally).
181
+ theme={
182
+ navigationManager.configuration.theme?.light ?? defaultLightTheme
183
+ }
171
184
  enableEnhancedLiveness={
172
185
  configuration.selfieConfig?.enableEnhancedLiveness ?? false
173
186
  }
174
187
  {...(captureType === CaptureType.document && documentConfig
175
188
  ? {
176
- // Partner override wins, then the document type's own ratio,
177
- // then the orientation default (landscape ID / portrait card).
189
+ // Type ratio → partner override → orientation default; matches
190
+ // the preview/processing frames so all three share one shape.
178
191
  knownIdAspectRatio:
179
- documentConfig.knownIdAspectRatio ??
180
- documentType?.knownAspectRatio ??
192
+ documentConfig.resolvedAspectRatio ??
181
193
  defaultFrameAspectRatio(
182
194
  documentType?.orientation ?? "Landscape",
183
195
  ),
184
196
  captureMode: documentConfig.captureMode,
185
197
  allowGalleryUpload: documentConfig.allowGalleryUpload,
186
198
  documentSide: currentDocumentSide,
199
+ ...(documentType?.kind
200
+ ? { documentTypeKind: documentType.kind }
201
+ : {}),
187
202
  onDocumentOrigin: (origin) =>
188
203
  navigationManager.recordDocumentImageOrigin(
189
204
  currentDocumentSide,
@@ -207,7 +222,7 @@ export function OrchestratedCaptureScreen({
207
222
  }
208
223
  onBack();
209
224
  }}
210
- onCaptureComplete={(events) => {
225
+ onCaptureComplete={(events, telemetry) => {
211
226
  const primary = pickPrimaryCaptureUrl(events, captureType);
212
227
  if (!primary) {
213
228
  // Pipeline finished without the expected artifact — stay so the user can retry.
@@ -218,9 +233,10 @@ export function OrchestratedCaptureScreen({
218
233
  // (blank partnerId → native no-op). Context is rebound per
219
234
  // capture because partnerConfig may change across re-renders
220
235
  // (partner builder closures are not memoised).
221
- const partnerId =
222
- navigationManager.configuration.network?.config?.partnerConfig
223
- ?.partnerId ?? "";
236
+ //
237
+ // `navigationManager.partnerId` resolves the JWT's canonical partner_id (e.g.
238
+ // "002"), falling back to the config value — see FlowNavigationManager.partnerId.
239
+ const partnerId = navigationManager.partnerId;
224
240
  const imageTypeForCapture: ImageTypeId =
225
241
  captureType === CaptureType.selfie
226
242
  ? ImageType.Selfie
@@ -234,16 +250,33 @@ export function OrchestratedCaptureScreen({
234
250
  )
235
251
  .map((event) => event.url);
236
252
 
237
- void SmileExifTagger.setContext({ partnerId })
253
+ // Source the device fingerprint from the same native signal the metadata
254
+ // payload uses so the EXIF tag's `fingerprint` matches it. `signals()` is
255
+ // fail-open (resolves with `""` if unavailable); omit it when blank so a
256
+ // capture never ships an empty fingerprint that shadows a real one.
257
+ void DeviceIntegrityProvider.signals()
258
+ .then(({ fingerprint }) =>
259
+ SmileExifTagger.setContext({
260
+ partnerId,
261
+ ...(fingerprint ? { fingerprint } : {}),
262
+ }),
263
+ )
238
264
  .then(() =>
239
265
  SmileExifTagger.finalize(primary, imageTypeForCapture),
240
266
  )
241
- .finally(() => {
267
+ .finally(async () => {
242
268
  if (captureType === CaptureType.selfie) {
243
269
  navigationManager.setCapturedSelfie(primary, livenessUrls);
270
+ navigationManager.recordSelfieCaptureTelemetry(telemetry);
244
271
  onNavigateNext();
245
272
  return;
246
273
  }
274
+ // Document: record this side's capture telemetry before advancing.
275
+ // Image sizes are measured in the repository around the compression pass.
276
+ navigationManager.recordDocumentCaptureTelemetry(
277
+ currentDocumentSide,
278
+ telemetry,
279
+ );
247
280
  if (
248
281
  capturesBack &&
249
282
  currentDocumentSide === DocumentSide.Front
@@ -87,6 +87,7 @@ function OrchestratedInstructionsContent({
87
87
  showAttribution={resolved.showAttribution}
88
88
  showHeroOval={resolved.showHeroOval}
89
89
  showHeroOvalProgress={resolved.showHeroOvalProgress}
90
+ showCardBackground={resolved.showCardBackground}
90
91
  {...(configuration.continueButton
91
92
  ? {
92
93
  // Adapt the config slot `{ onClick, enabled }` to the screen's
@@ -2,6 +2,7 @@ import type { PreviewConfigBuilder } from "../dsl/builder/screens_builder";
2
2
  import { UseSmileIDPreviewScreen } from "../../screen/use_smile_id_preview_screen";
3
3
  import { UseSmileIDDocumentPreviewScreen } from "../../screen/use_smile_id_document_preview_screen";
4
4
  import { UseSmileIDOrchestratedScreenHost } from "./use_smile_id_orchestrated_screen_host";
5
+ import { defaultFrameAspectRatio } from "../../../core/models/document_type";
5
6
 
6
7
  export type OrchestratedPreviewScreenProps = {
7
8
  readonly configuration: PreviewConfigBuilder;
@@ -23,8 +24,9 @@ export function OrchestratedPreviewScreen({
23
24
  const documentPath = navigationManager.currentDocumentPreviewPath();
24
25
  return (
25
26
  <UseSmileIDDocumentPreviewScreen
26
- documentOrientation={
27
- navigationManager.documentType?.orientation ?? "Landscape"
27
+ documentAspectRatio={
28
+ navigationManager.documentFrameAspectRatio ??
29
+ defaultFrameAspectRatio("Landscape")
28
30
  }
29
31
  showAttribution={configuration.showAttribution}
30
32
  {...(documentPath !== undefined
@@ -66,7 +66,7 @@ function ProcessingScreenBody(props: ProcessingScreenBodyProps) {
66
66
  const documentImageUri = requiresDocument(jobType)
67
67
  ? navigationManager.captured.frontDocumentPath
68
68
  : undefined;
69
- const documentOrientation = navigationManager.documentType?.orientation;
69
+ const documentAspectRatio = navigationManager.documentFrameAspectRatio;
70
70
 
71
71
  return (
72
72
  <UseSmileIDProcessingScreen
@@ -75,8 +75,8 @@ function ProcessingScreenBody(props: ProcessingScreenBodyProps) {
75
75
  showProgressPercentage={props.processingConfig.showProgressPercentage}
76
76
  showAttribution={props.processingConfig.showAttribution}
77
77
  {...(documentImageUri !== undefined ? { documentImageUri } : {})}
78
- {...(documentImageUri !== undefined && documentOrientation !== undefined
79
- ? { documentOrientation }
78
+ {...(documentImageUri !== undefined && documentAspectRatio !== undefined
79
+ ? { documentAspectRatio }
80
80
  : {})}
81
81
  {...(navigationManager.captured.selfiePath !== undefined
82
82
  ? { capturedSelfiePath: navigationManager.captured.selfiePath }
@@ -667,6 +667,70 @@ describe("DocumentJobTypeValidator — Android-parity rules", () => {
667
667
  issues.some((i) => i instanceof InvalidJobTypeScreenConfigException),
668
668
  ).toBe(false);
669
669
  });
670
+
671
+ it("rejects SouthAfricaGreenBook for EnhancedDocumentVerification", () => {
672
+ const greenBookStep = (() => {
673
+ const config = new CaptureConfigBuilder();
674
+ config.captureType = CaptureType.document;
675
+ config.document((d) => {
676
+ d.documentType = DocumentType.SouthAfricaGreenBook;
677
+ });
678
+ return { kind: "capture" as const, config };
679
+ })();
680
+ const issues = run({
681
+ steps: [
682
+ consentStep(),
683
+ captureStep(CaptureType.selfie),
684
+ greenBookStep,
685
+ previewStep(),
686
+ processingStep(),
687
+ ],
688
+ network: validNetwork(JobType.enhancedDocumentVerification),
689
+ ml: { analyzers: { selfie: stubFaceAnalyzer() } },
690
+ userDetails: validUserDetails,
691
+ enhancedDocumentVerificationParams: validEnhancedDocumentParams,
692
+ });
693
+ expect(
694
+ issues.some(
695
+ (i) =>
696
+ i instanceof InvalidJobTypeScreenConfigException &&
697
+ i.message.includes(
698
+ "South Africa Green Book is not supported for Enhanced Document Verification",
699
+ ),
700
+ ),
701
+ ).toBe(true);
702
+ });
703
+
704
+ it("accepts SouthAfricaGreenBook for DocumentVerification", () => {
705
+ const greenBookStep = (() => {
706
+ const config = new CaptureConfigBuilder();
707
+ config.captureType = CaptureType.document;
708
+ config.document((d) => {
709
+ d.documentType = DocumentType.SouthAfricaGreenBook;
710
+ });
711
+ return { kind: "capture" as const, config };
712
+ })();
713
+ const issues = run({
714
+ steps: [
715
+ consentStep(),
716
+ captureStep(CaptureType.selfie),
717
+ greenBookStep,
718
+ previewStep(),
719
+ processingStep(),
720
+ ],
721
+ network: validNetwork(JobType.documentVerification),
722
+ ml: { analyzers: { selfie: stubFaceAnalyzer() } },
723
+ userDetails: validUserDetails,
724
+ documentVerificationParams: validDocumentParams,
725
+ });
726
+ expect(
727
+ issues.some(
728
+ (i) =>
729
+ i instanceof InvalidJobTypeScreenConfigException &&
730
+ i.message.includes("South Africa Green Book is not supported"),
731
+ ),
732
+ ).toBe(false);
733
+ });
670
734
  });
671
735
 
672
736
  describe("NonCaptureJobTypeValidator — Android-parity rules", () => {