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