@velion-la/onboarding-sdk-react-native 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (557) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/LICENSE +12 -0
  3. package/README.md +803 -0
  4. package/lib/commonjs/camera/AddressSearchBar.js +304 -0
  5. package/lib/commonjs/camera/AddressSearchBar.js.map +1 -0
  6. package/lib/commonjs/camera/DocumentCapture.js +505 -0
  7. package/lib/commonjs/camera/DocumentCapture.js.map +1 -0
  8. package/lib/commonjs/camera/LivenessCamera.js +534 -0
  9. package/lib/commonjs/camera/LivenessCamera.js.map +1 -0
  10. package/lib/commonjs/camera/MapAddressPicker.js +341 -0
  11. package/lib/commonjs/camera/MapAddressPicker.js.map +1 -0
  12. package/lib/commonjs/core/VelionOnboarding.js +815 -0
  13. package/lib/commonjs/core/VelionOnboarding.js.map +1 -0
  14. package/lib/commonjs/core/sessionDeclinedCopy.js +56 -0
  15. package/lib/commonjs/core/sessionDeclinedCopy.js.map +1 -0
  16. package/lib/commonjs/core/sessionStateMapper.js +137 -0
  17. package/lib/commonjs/core/sessionStateMapper.js.map +1 -0
  18. package/lib/commonjs/core/sseReasonMessages.js +450 -0
  19. package/lib/commonjs/core/sseReasonMessages.js.map +1 -0
  20. package/lib/commonjs/data/iso3166Alpha2Codes.json +1 -0
  21. package/lib/commonjs/data/iso3166CountryNames.json +251 -0
  22. package/lib/commonjs/i18n/index.js +30 -0
  23. package/lib/commonjs/i18n/index.js.map +1 -0
  24. package/lib/commonjs/i18n/strings/en.js +261 -0
  25. package/lib/commonjs/i18n/strings/en.js.map +1 -0
  26. package/lib/commonjs/i18n/strings/es.js +266 -0
  27. package/lib/commonjs/i18n/strings/es.js.map +1 -0
  28. package/lib/commonjs/index.js +213 -0
  29. package/lib/commonjs/index.js.map +1 -0
  30. package/lib/commonjs/package.json +1 -0
  31. package/lib/commonjs/steps/AddressInfoStep.js +650 -0
  32. package/lib/commonjs/steps/AddressInfoStep.js.map +1 -0
  33. package/lib/commonjs/steps/DocumentsOcrStep.js +397 -0
  34. package/lib/commonjs/steps/DocumentsOcrStep.js.map +1 -0
  35. package/lib/commonjs/steps/EmailContactStep.js +145 -0
  36. package/lib/commonjs/steps/EmailContactStep.js.map +1 -0
  37. package/lib/commonjs/steps/EmailOtpStep.js +220 -0
  38. package/lib/commonjs/steps/EmailOtpStep.js.map +1 -0
  39. package/lib/commonjs/steps/FaceMatchStep.js +166 -0
  40. package/lib/commonjs/steps/FaceMatchStep.js.map +1 -0
  41. package/lib/commonjs/steps/FingerprintStep.js +92 -0
  42. package/lib/commonjs/steps/FingerprintStep.js.map +1 -0
  43. package/lib/commonjs/steps/HumanBasicInfoStep.js +243 -0
  44. package/lib/commonjs/steps/HumanBasicInfoStep.js.map +1 -0
  45. package/lib/commonjs/steps/HumanExtendedInfoStep.js +268 -0
  46. package/lib/commonjs/steps/HumanExtendedInfoStep.js.map +1 -0
  47. package/lib/commonjs/steps/LegalBasicInfoStep.js +188 -0
  48. package/lib/commonjs/steps/LegalBasicInfoStep.js.map +1 -0
  49. package/lib/commonjs/steps/LegalExtendedInfoStep.js +166 -0
  50. package/lib/commonjs/steps/LegalExtendedInfoStep.js.map +1 -0
  51. package/lib/commonjs/steps/LivenessMatchStep.js +707 -0
  52. package/lib/commonjs/steps/LivenessMatchStep.js.map +1 -0
  53. package/lib/commonjs/steps/PhoneContactStep.js +146 -0
  54. package/lib/commonjs/steps/PhoneContactStep.js.map +1 -0
  55. package/lib/commonjs/steps/PhoneOtpStep.js +219 -0
  56. package/lib/commonjs/steps/PhoneOtpStep.js.map +1 -0
  57. package/lib/commonjs/steps/SwornDeclarationStep.js +196 -0
  58. package/lib/commonjs/steps/SwornDeclarationStep.js.map +1 -0
  59. package/lib/commonjs/steps/TaxInfoStep.js +244 -0
  60. package/lib/commonjs/steps/TaxInfoStep.js.map +1 -0
  61. package/lib/commonjs/steps/TermsAndConditionsStep.js +238 -0
  62. package/lib/commonjs/steps/TermsAndConditionsStep.js.map +1 -0
  63. package/lib/commonjs/steps/_shared.js +40 -0
  64. package/lib/commonjs/steps/_shared.js.map +1 -0
  65. package/lib/commonjs/steps/types.js +6 -0
  66. package/lib/commonjs/steps/types.js.map +1 -0
  67. package/lib/commonjs/transport/api.js +176 -0
  68. package/lib/commonjs/transport/api.js.map +1 -0
  69. package/lib/commonjs/transport/irisWebSocket.js +121 -0
  70. package/lib/commonjs/transport/irisWebSocket.js.map +1 -0
  71. package/lib/commonjs/transport/secureUrl.js +50 -0
  72. package/lib/commonjs/transport/secureUrl.js.map +1 -0
  73. package/lib/commonjs/transport/sse.js +248 -0
  74. package/lib/commonjs/transport/sse.js.map +1 -0
  75. package/lib/commonjs/types/index.js +391 -0
  76. package/lib/commonjs/types/index.js.map +1 -0
  77. package/lib/commonjs/ui/MapFallbackBoundary.js +42 -0
  78. package/lib/commonjs/ui/MapFallbackBoundary.js.map +1 -0
  79. package/lib/commonjs/ui/StepShell.js +118 -0
  80. package/lib/commonjs/ui/StepShell.js.map +1 -0
  81. package/lib/commonjs/ui/VelionOnboardingScreen.js +217 -0
  82. package/lib/commonjs/ui/VelionOnboardingScreen.js.map +1 -0
  83. package/lib/commonjs/ui/forms/index.js +38 -0
  84. package/lib/commonjs/ui/forms/index.js.map +1 -0
  85. package/lib/commonjs/ui/forms/useInlineValidation.js +88 -0
  86. package/lib/commonjs/ui/forms/useInlineValidation.js.map +1 -0
  87. package/lib/commonjs/ui/forms/validators.js +34 -0
  88. package/lib/commonjs/ui/forms/validators.js.map +1 -0
  89. package/lib/commonjs/ui/icons/HomeHeartIcon.js +38 -0
  90. package/lib/commonjs/ui/icons/HomeHeartIcon.js.map +1 -0
  91. package/lib/commonjs/ui/icons/StepIcon.js +59 -0
  92. package/lib/commonjs/ui/icons/StepIcon.js.map +1 -0
  93. package/lib/commonjs/ui/overlays/AnalyzingOverlay.js +284 -0
  94. package/lib/commonjs/ui/overlays/AnalyzingOverlay.js.map +1 -0
  95. package/lib/commonjs/ui/overlays/LoadingOverlay.js +108 -0
  96. package/lib/commonjs/ui/overlays/LoadingOverlay.js.map +1 -0
  97. package/lib/commonjs/ui/overlays/ProgressBar.js +95 -0
  98. package/lib/commonjs/ui/overlays/ProgressBar.js.map +1 -0
  99. package/lib/commonjs/ui/overlays/RetryDialog.js +125 -0
  100. package/lib/commonjs/ui/overlays/RetryDialog.js.map +1 -0
  101. package/lib/commonjs/ui/overlays/index.js +33 -0
  102. package/lib/commonjs/ui/overlays/index.js.map +1 -0
  103. package/lib/commonjs/ui/primitives/Banner.js +81 -0
  104. package/lib/commonjs/ui/primitives/Banner.js.map +1 -0
  105. package/lib/commonjs/ui/primitives/Button.js +142 -0
  106. package/lib/commonjs/ui/primitives/Button.js.map +1 -0
  107. package/lib/commonjs/ui/primitives/Card.js +50 -0
  108. package/lib/commonjs/ui/primitives/Card.js.map +1 -0
  109. package/lib/commonjs/ui/primitives/Checkbox.js +139 -0
  110. package/lib/commonjs/ui/primitives/Checkbox.js.map +1 -0
  111. package/lib/commonjs/ui/primitives/CountrySelect.js +288 -0
  112. package/lib/commonjs/ui/primitives/CountrySelect.js.map +1 -0
  113. package/lib/commonjs/ui/primitives/DatePicker.js +245 -0
  114. package/lib/commonjs/ui/primitives/DatePicker.js.map +1 -0
  115. package/lib/commonjs/ui/primitives/Input.js +101 -0
  116. package/lib/commonjs/ui/primitives/Input.js.map +1 -0
  117. package/lib/commonjs/ui/primitives/Select.js +209 -0
  118. package/lib/commonjs/ui/primitives/Select.js.map +1 -0
  119. package/lib/commonjs/ui/primitives/Spinner.js +25 -0
  120. package/lib/commonjs/ui/primitives/Spinner.js.map +1 -0
  121. package/lib/commonjs/ui/primitives/index.js +69 -0
  122. package/lib/commonjs/ui/primitives/index.js.map +1 -0
  123. package/lib/commonjs/ui/theme/ThemeProvider.js +74 -0
  124. package/lib/commonjs/ui/theme/ThemeProvider.js.map +1 -0
  125. package/lib/commonjs/ui/theme/index.js +68 -0
  126. package/lib/commonjs/ui/theme/index.js.map +1 -0
  127. package/lib/commonjs/ui/theme/tokens.js +154 -0
  128. package/lib/commonjs/ui/theme/tokens.js.map +1 -0
  129. package/lib/commonjs/utils/EventEmitter.js +144 -0
  130. package/lib/commonjs/utils/EventEmitter.js.map +1 -0
  131. package/lib/commonjs/utils/base64.js +53 -0
  132. package/lib/commonjs/utils/base64.js.map +1 -0
  133. package/lib/commonjs/utils/deviceFingerprint.js +132 -0
  134. package/lib/commonjs/utils/deviceFingerprint.js.map +1 -0
  135. package/lib/commonjs/utils/documentTypeOptions.js +35 -0
  136. package/lib/commonjs/utils/documentTypeOptions.js.map +1 -0
  137. package/lib/commonjs/utils/googleMapsPreflight.js +77 -0
  138. package/lib/commonjs/utils/googleMapsPreflight.js.map +1 -0
  139. package/lib/commonjs/utils/hmac.js +58 -0
  140. package/lib/commonjs/utils/hmac.js.map +1 -0
  141. package/lib/commonjs/utils/iso3166Countries.js +98 -0
  142. package/lib/commonjs/utils/iso3166Countries.js.map +1 -0
  143. package/lib/commonjs/utils/jpegFromUri.js +44 -0
  144. package/lib/commonjs/utils/jpegFromUri.js.map +1 -0
  145. package/lib/commonjs/utils/keepAwake.js +58 -0
  146. package/lib/commonjs/utils/keepAwake.js.map +1 -0
  147. package/lib/commonjs/utils/log.js +42 -0
  148. package/lib/commonjs/utils/log.js.map +1 -0
  149. package/lib/commonjs/utils/osGeocoder.js +70 -0
  150. package/lib/commonjs/utils/osGeocoder.js.map +1 -0
  151. package/lib/commonjs/utils/parseGoogleAddressComponents.js +74 -0
  152. package/lib/commonjs/utils/parseGoogleAddressComponents.js.map +1 -0
  153. package/lib/commonjs/utils/personNameNormalize.js +24 -0
  154. package/lib/commonjs/utils/personNameNormalize.js.map +1 -0
  155. package/lib/commonjs/utils/sdkError.js +34 -0
  156. package/lib/commonjs/utils/sdkError.js.map +1 -0
  157. package/lib/commonjs/utils/sdkVersion.js +13 -0
  158. package/lib/commonjs/utils/sdkVersion.js.map +1 -0
  159. package/lib/commonjs/utils/stepConfig.js +65 -0
  160. package/lib/commonjs/utils/stepConfig.js.map +1 -0
  161. package/lib/commonjs/utils/taxInfoConfig.js +19 -0
  162. package/lib/commonjs/utils/taxInfoConfig.js.map +1 -0
  163. package/lib/module/camera/AddressSearchBar.js +299 -0
  164. package/lib/module/camera/AddressSearchBar.js.map +1 -0
  165. package/lib/module/camera/DocumentCapture.js +500 -0
  166. package/lib/module/camera/DocumentCapture.js.map +1 -0
  167. package/lib/module/camera/LivenessCamera.js +529 -0
  168. package/lib/module/camera/LivenessCamera.js.map +1 -0
  169. package/lib/module/camera/MapAddressPicker.js +337 -0
  170. package/lib/module/camera/MapAddressPicker.js.map +1 -0
  171. package/lib/module/core/VelionOnboarding.js +811 -0
  172. package/lib/module/core/VelionOnboarding.js.map +1 -0
  173. package/lib/module/core/sessionDeclinedCopy.js +52 -0
  174. package/lib/module/core/sessionDeclinedCopy.js.map +1 -0
  175. package/lib/module/core/sessionStateMapper.js +128 -0
  176. package/lib/module/core/sessionStateMapper.js.map +1 -0
  177. package/lib/module/core/sseReasonMessages.js +446 -0
  178. package/lib/module/core/sseReasonMessages.js.map +1 -0
  179. package/lib/module/data/iso3166Alpha2Codes.json +1 -0
  180. package/lib/module/data/iso3166CountryNames.json +251 -0
  181. package/lib/module/i18n/index.js +25 -0
  182. package/lib/module/i18n/index.js.map +1 -0
  183. package/lib/module/i18n/strings/en.js +257 -0
  184. package/lib/module/i18n/strings/en.js.map +1 -0
  185. package/lib/module/i18n/strings/es.js +262 -0
  186. package/lib/module/i18n/strings/es.js.map +1 -0
  187. package/lib/module/index.js +36 -0
  188. package/lib/module/index.js.map +1 -0
  189. package/lib/module/steps/AddressInfoStep.js +646 -0
  190. package/lib/module/steps/AddressInfoStep.js.map +1 -0
  191. package/lib/module/steps/DocumentsOcrStep.js +391 -0
  192. package/lib/module/steps/DocumentsOcrStep.js.map +1 -0
  193. package/lib/module/steps/EmailContactStep.js +140 -0
  194. package/lib/module/steps/EmailContactStep.js.map +1 -0
  195. package/lib/module/steps/EmailOtpStep.js +215 -0
  196. package/lib/module/steps/EmailOtpStep.js.map +1 -0
  197. package/lib/module/steps/FaceMatchStep.js +161 -0
  198. package/lib/module/steps/FaceMatchStep.js.map +1 -0
  199. package/lib/module/steps/FingerprintStep.js +87 -0
  200. package/lib/module/steps/FingerprintStep.js.map +1 -0
  201. package/lib/module/steps/HumanBasicInfoStep.js +238 -0
  202. package/lib/module/steps/HumanBasicInfoStep.js.map +1 -0
  203. package/lib/module/steps/HumanExtendedInfoStep.js +263 -0
  204. package/lib/module/steps/HumanExtendedInfoStep.js.map +1 -0
  205. package/lib/module/steps/LegalBasicInfoStep.js +183 -0
  206. package/lib/module/steps/LegalBasicInfoStep.js.map +1 -0
  207. package/lib/module/steps/LegalExtendedInfoStep.js +161 -0
  208. package/lib/module/steps/LegalExtendedInfoStep.js.map +1 -0
  209. package/lib/module/steps/LivenessMatchStep.js +701 -0
  210. package/lib/module/steps/LivenessMatchStep.js.map +1 -0
  211. package/lib/module/steps/PhoneContactStep.js +141 -0
  212. package/lib/module/steps/PhoneContactStep.js.map +1 -0
  213. package/lib/module/steps/PhoneOtpStep.js +214 -0
  214. package/lib/module/steps/PhoneOtpStep.js.map +1 -0
  215. package/lib/module/steps/SwornDeclarationStep.js +191 -0
  216. package/lib/module/steps/SwornDeclarationStep.js.map +1 -0
  217. package/lib/module/steps/TaxInfoStep.js +239 -0
  218. package/lib/module/steps/TaxInfoStep.js.map +1 -0
  219. package/lib/module/steps/TermsAndConditionsStep.js +233 -0
  220. package/lib/module/steps/TermsAndConditionsStep.js.map +1 -0
  221. package/lib/module/steps/_shared.js +33 -0
  222. package/lib/module/steps/_shared.js.map +1 -0
  223. package/lib/module/steps/types.js +4 -0
  224. package/lib/module/steps/types.js.map +1 -0
  225. package/lib/module/transport/api.js +173 -0
  226. package/lib/module/transport/api.js.map +1 -0
  227. package/lib/module/transport/irisWebSocket.js +115 -0
  228. package/lib/module/transport/irisWebSocket.js.map +1 -0
  229. package/lib/module/transport/secureUrl.js +45 -0
  230. package/lib/module/transport/secureUrl.js.map +1 -0
  231. package/lib/module/transport/sse.js +242 -0
  232. package/lib/module/transport/sse.js.map +1 -0
  233. package/lib/module/types/index.js +457 -0
  234. package/lib/module/types/index.js.map +1 -0
  235. package/lib/module/ui/MapFallbackBoundary.js +37 -0
  236. package/lib/module/ui/MapFallbackBoundary.js.map +1 -0
  237. package/lib/module/ui/StepShell.js +114 -0
  238. package/lib/module/ui/StepShell.js.map +1 -0
  239. package/lib/module/ui/VelionOnboardingScreen.js +212 -0
  240. package/lib/module/ui/VelionOnboardingScreen.js.map +1 -0
  241. package/lib/module/ui/forms/index.js +5 -0
  242. package/lib/module/ui/forms/index.js.map +1 -0
  243. package/lib/module/ui/forms/useInlineValidation.js +84 -0
  244. package/lib/module/ui/forms/useInlineValidation.js.map +1 -0
  245. package/lib/module/ui/forms/validators.js +27 -0
  246. package/lib/module/ui/forms/validators.js.map +1 -0
  247. package/lib/module/ui/icons/HomeHeartIcon.js +33 -0
  248. package/lib/module/ui/icons/HomeHeartIcon.js.map +1 -0
  249. package/lib/module/ui/icons/StepIcon.js +55 -0
  250. package/lib/module/ui/icons/StepIcon.js.map +1 -0
  251. package/lib/module/ui/overlays/AnalyzingOverlay.js +279 -0
  252. package/lib/module/ui/overlays/AnalyzingOverlay.js.map +1 -0
  253. package/lib/module/ui/overlays/LoadingOverlay.js +104 -0
  254. package/lib/module/ui/overlays/LoadingOverlay.js.map +1 -0
  255. package/lib/module/ui/overlays/ProgressBar.js +90 -0
  256. package/lib/module/ui/overlays/ProgressBar.js.map +1 -0
  257. package/lib/module/ui/overlays/RetryDialog.js +121 -0
  258. package/lib/module/ui/overlays/RetryDialog.js.map +1 -0
  259. package/lib/module/ui/overlays/index.js +6 -0
  260. package/lib/module/ui/overlays/index.js.map +1 -0
  261. package/lib/module/ui/primitives/Banner.js +77 -0
  262. package/lib/module/ui/primitives/Banner.js.map +1 -0
  263. package/lib/module/ui/primitives/Button.js +138 -0
  264. package/lib/module/ui/primitives/Button.js.map +1 -0
  265. package/lib/module/ui/primitives/Card.js +46 -0
  266. package/lib/module/ui/primitives/Card.js.map +1 -0
  267. package/lib/module/ui/primitives/Checkbox.js +136 -0
  268. package/lib/module/ui/primitives/Checkbox.js.map +1 -0
  269. package/lib/module/ui/primitives/CountrySelect.js +284 -0
  270. package/lib/module/ui/primitives/CountrySelect.js.map +1 -0
  271. package/lib/module/ui/primitives/DatePicker.js +241 -0
  272. package/lib/module/ui/primitives/DatePicker.js.map +1 -0
  273. package/lib/module/ui/primitives/Input.js +97 -0
  274. package/lib/module/ui/primitives/Input.js.map +1 -0
  275. package/lib/module/ui/primitives/Select.js +205 -0
  276. package/lib/module/ui/primitives/Select.js.map +1 -0
  277. package/lib/module/ui/primitives/Spinner.js +21 -0
  278. package/lib/module/ui/primitives/Spinner.js.map +1 -0
  279. package/lib/module/ui/primitives/index.js +12 -0
  280. package/lib/module/ui/primitives/index.js.map +1 -0
  281. package/lib/module/ui/theme/ThemeProvider.js +67 -0
  282. package/lib/module/ui/theme/ThemeProvider.js.map +1 -0
  283. package/lib/module/ui/theme/index.js +5 -0
  284. package/lib/module/ui/theme/index.js.map +1 -0
  285. package/lib/module/ui/theme/tokens.js +145 -0
  286. package/lib/module/ui/theme/tokens.js.map +1 -0
  287. package/lib/module/utils/EventEmitter.js +139 -0
  288. package/lib/module/utils/EventEmitter.js.map +1 -0
  289. package/lib/module/utils/base64.js +47 -0
  290. package/lib/module/utils/base64.js.map +1 -0
  291. package/lib/module/utils/deviceFingerprint.js +129 -0
  292. package/lib/module/utils/deviceFingerprint.js.map +1 -0
  293. package/lib/module/utils/documentTypeOptions.js +31 -0
  294. package/lib/module/utils/documentTypeOptions.js.map +1 -0
  295. package/lib/module/utils/googleMapsPreflight.js +73 -0
  296. package/lib/module/utils/googleMapsPreflight.js.map +1 -0
  297. package/lib/module/utils/hmac.js +53 -0
  298. package/lib/module/utils/hmac.js.map +1 -0
  299. package/lib/module/utils/iso3166Countries.js +92 -0
  300. package/lib/module/utils/iso3166Countries.js.map +1 -0
  301. package/lib/module/utils/jpegFromUri.js +40 -0
  302. package/lib/module/utils/jpegFromUri.js.map +1 -0
  303. package/lib/module/utils/keepAwake.js +53 -0
  304. package/lib/module/utils/keepAwake.js.map +1 -0
  305. package/lib/module/utils/log.js +37 -0
  306. package/lib/module/utils/log.js.map +1 -0
  307. package/lib/module/utils/osGeocoder.js +65 -0
  308. package/lib/module/utils/osGeocoder.js.map +1 -0
  309. package/lib/module/utils/parseGoogleAddressComponents.js +69 -0
  310. package/lib/module/utils/parseGoogleAddressComponents.js.map +1 -0
  311. package/lib/module/utils/personNameNormalize.js +20 -0
  312. package/lib/module/utils/personNameNormalize.js.map +1 -0
  313. package/lib/module/utils/sdkError.js +29 -0
  314. package/lib/module/utils/sdkError.js.map +1 -0
  315. package/lib/module/utils/sdkVersion.js +9 -0
  316. package/lib/module/utils/sdkVersion.js.map +1 -0
  317. package/lib/module/utils/stepConfig.js +59 -0
  318. package/lib/module/utils/stepConfig.js.map +1 -0
  319. package/lib/module/utils/taxInfoConfig.js +15 -0
  320. package/lib/module/utils/taxInfoConfig.js.map +1 -0
  321. package/lib/typescript/camera/AddressSearchBar.d.ts +37 -0
  322. package/lib/typescript/camera/AddressSearchBar.d.ts.map +1 -0
  323. package/lib/typescript/camera/DocumentCapture.d.ts +34 -0
  324. package/lib/typescript/camera/DocumentCapture.d.ts.map +1 -0
  325. package/lib/typescript/camera/LivenessCamera.d.ts +50 -0
  326. package/lib/typescript/camera/LivenessCamera.d.ts.map +1 -0
  327. package/lib/typescript/camera/MapAddressPicker.d.ts +57 -0
  328. package/lib/typescript/camera/MapAddressPicker.d.ts.map +1 -0
  329. package/lib/typescript/core/VelionOnboarding.d.ts +115 -0
  330. package/lib/typescript/core/VelionOnboarding.d.ts.map +1 -0
  331. package/lib/typescript/core/sessionDeclinedCopy.d.ts +16 -0
  332. package/lib/typescript/core/sessionDeclinedCopy.d.ts.map +1 -0
  333. package/lib/typescript/core/sessionStateMapper.d.ts +33 -0
  334. package/lib/typescript/core/sessionStateMapper.d.ts.map +1 -0
  335. package/lib/typescript/core/sseReasonMessages.d.ts +20 -0
  336. package/lib/typescript/core/sseReasonMessages.d.ts.map +1 -0
  337. package/lib/typescript/i18n/index.d.ts +13 -0
  338. package/lib/typescript/i18n/index.d.ts.map +1 -0
  339. package/lib/typescript/i18n/strings/en.d.ts +3 -0
  340. package/lib/typescript/i18n/strings/en.d.ts.map +1 -0
  341. package/lib/typescript/i18n/strings/es.d.ts +260 -0
  342. package/lib/typescript/i18n/strings/es.d.ts.map +1 -0
  343. package/lib/typescript/index.d.ts +26 -0
  344. package/lib/typescript/index.d.ts.map +1 -0
  345. package/lib/typescript/steps/AddressInfoStep.d.ts +26 -0
  346. package/lib/typescript/steps/AddressInfoStep.d.ts.map +1 -0
  347. package/lib/typescript/steps/DocumentsOcrStep.d.ts +26 -0
  348. package/lib/typescript/steps/DocumentsOcrStep.d.ts.map +1 -0
  349. package/lib/typescript/steps/EmailContactStep.d.ts +15 -0
  350. package/lib/typescript/steps/EmailContactStep.d.ts.map +1 -0
  351. package/lib/typescript/steps/EmailOtpStep.d.ts +21 -0
  352. package/lib/typescript/steps/EmailOtpStep.d.ts.map +1 -0
  353. package/lib/typescript/steps/FaceMatchStep.d.ts +27 -0
  354. package/lib/typescript/steps/FaceMatchStep.d.ts.map +1 -0
  355. package/lib/typescript/steps/FingerprintStep.d.ts +25 -0
  356. package/lib/typescript/steps/FingerprintStep.d.ts.map +1 -0
  357. package/lib/typescript/steps/HumanBasicInfoStep.d.ts +25 -0
  358. package/lib/typescript/steps/HumanBasicInfoStep.d.ts.map +1 -0
  359. package/lib/typescript/steps/HumanExtendedInfoStep.d.ts +23 -0
  360. package/lib/typescript/steps/HumanExtendedInfoStep.d.ts.map +1 -0
  361. package/lib/typescript/steps/LegalBasicInfoStep.d.ts +17 -0
  362. package/lib/typescript/steps/LegalBasicInfoStep.d.ts.map +1 -0
  363. package/lib/typescript/steps/LegalExtendedInfoStep.d.ts +17 -0
  364. package/lib/typescript/steps/LegalExtendedInfoStep.d.ts.map +1 -0
  365. package/lib/typescript/steps/LivenessMatchStep.d.ts +26 -0
  366. package/lib/typescript/steps/LivenessMatchStep.d.ts.map +1 -0
  367. package/lib/typescript/steps/PhoneContactStep.d.ts +15 -0
  368. package/lib/typescript/steps/PhoneContactStep.d.ts.map +1 -0
  369. package/lib/typescript/steps/PhoneOtpStep.d.ts +19 -0
  370. package/lib/typescript/steps/PhoneOtpStep.d.ts.map +1 -0
  371. package/lib/typescript/steps/SwornDeclarationStep.d.ts +20 -0
  372. package/lib/typescript/steps/SwornDeclarationStep.d.ts.map +1 -0
  373. package/lib/typescript/steps/TaxInfoStep.d.ts +19 -0
  374. package/lib/typescript/steps/TaxInfoStep.d.ts.map +1 -0
  375. package/lib/typescript/steps/TermsAndConditionsStep.d.ts +21 -0
  376. package/lib/typescript/steps/TermsAndConditionsStep.d.ts.map +1 -0
  377. package/lib/typescript/steps/_shared.d.ts +11 -0
  378. package/lib/typescript/steps/_shared.d.ts.map +1 -0
  379. package/lib/typescript/steps/types.d.ts +68 -0
  380. package/lib/typescript/steps/types.d.ts.map +1 -0
  381. package/lib/typescript/transport/api.d.ts +35 -0
  382. package/lib/typescript/transport/api.d.ts.map +1 -0
  383. package/lib/typescript/transport/irisWebSocket.d.ts +72 -0
  384. package/lib/typescript/transport/irisWebSocket.d.ts.map +1 -0
  385. package/lib/typescript/transport/secureUrl.d.ts +14 -0
  386. package/lib/typescript/transport/secureUrl.d.ts.map +1 -0
  387. package/lib/typescript/transport/sse.d.ts +54 -0
  388. package/lib/typescript/transport/sse.d.ts.map +1 -0
  389. package/lib/typescript/types/index.d.ts +1010 -0
  390. package/lib/typescript/types/index.d.ts.map +1 -0
  391. package/lib/typescript/ui/MapFallbackBoundary.d.ts +28 -0
  392. package/lib/typescript/ui/MapFallbackBoundary.d.ts.map +1 -0
  393. package/lib/typescript/ui/StepShell.d.ts +19 -0
  394. package/lib/typescript/ui/StepShell.d.ts.map +1 -0
  395. package/lib/typescript/ui/VelionOnboardingScreen.d.ts +19 -0
  396. package/lib/typescript/ui/VelionOnboardingScreen.d.ts.map +1 -0
  397. package/lib/typescript/ui/forms/index.d.ts +3 -0
  398. package/lib/typescript/ui/forms/index.d.ts.map +1 -0
  399. package/lib/typescript/ui/forms/useInlineValidation.d.ts +30 -0
  400. package/lib/typescript/ui/forms/useInlineValidation.d.ts.map +1 -0
  401. package/lib/typescript/ui/forms/validators.d.ts +11 -0
  402. package/lib/typescript/ui/forms/validators.d.ts.map +1 -0
  403. package/lib/typescript/ui/icons/HomeHeartIcon.d.ts +14 -0
  404. package/lib/typescript/ui/icons/HomeHeartIcon.d.ts.map +1 -0
  405. package/lib/typescript/ui/icons/StepIcon.d.ts +26 -0
  406. package/lib/typescript/ui/icons/StepIcon.d.ts.map +1 -0
  407. package/lib/typescript/ui/overlays/AnalyzingOverlay.d.ts +24 -0
  408. package/lib/typescript/ui/overlays/AnalyzingOverlay.d.ts.map +1 -0
  409. package/lib/typescript/ui/overlays/LoadingOverlay.d.ts +19 -0
  410. package/lib/typescript/ui/overlays/LoadingOverlay.d.ts.map +1 -0
  411. package/lib/typescript/ui/overlays/ProgressBar.d.ts +26 -0
  412. package/lib/typescript/ui/overlays/ProgressBar.d.ts.map +1 -0
  413. package/lib/typescript/ui/overlays/RetryDialog.d.ts +17 -0
  414. package/lib/typescript/ui/overlays/RetryDialog.d.ts.map +1 -0
  415. package/lib/typescript/ui/overlays/index.d.ts +4 -0
  416. package/lib/typescript/ui/overlays/index.d.ts.map +1 -0
  417. package/lib/typescript/ui/primitives/Banner.d.ts +11 -0
  418. package/lib/typescript/ui/primitives/Banner.d.ts.map +1 -0
  419. package/lib/typescript/ui/primitives/Button.d.ts +27 -0
  420. package/lib/typescript/ui/primitives/Button.d.ts.map +1 -0
  421. package/lib/typescript/ui/primitives/Card.d.ts +10 -0
  422. package/lib/typescript/ui/primitives/Card.d.ts.map +1 -0
  423. package/lib/typescript/ui/primitives/Checkbox.d.ts +25 -0
  424. package/lib/typescript/ui/primitives/Checkbox.d.ts.map +1 -0
  425. package/lib/typescript/ui/primitives/CountrySelect.d.ts +31 -0
  426. package/lib/typescript/ui/primitives/CountrySelect.d.ts.map +1 -0
  427. package/lib/typescript/ui/primitives/DatePicker.d.ts +42 -0
  428. package/lib/typescript/ui/primitives/DatePicker.d.ts.map +1 -0
  429. package/lib/typescript/ui/primitives/Input.d.ts +17 -0
  430. package/lib/typescript/ui/primitives/Input.d.ts.map +1 -0
  431. package/lib/typescript/ui/primitives/Select.d.ts +26 -0
  432. package/lib/typescript/ui/primitives/Select.d.ts.map +1 -0
  433. package/lib/typescript/ui/primitives/Spinner.d.ts +10 -0
  434. package/lib/typescript/ui/primitives/Spinner.d.ts.map +1 -0
  435. package/lib/typescript/ui/primitives/index.d.ts +10 -0
  436. package/lib/typescript/ui/primitives/index.d.ts.map +1 -0
  437. package/lib/typescript/ui/theme/ThemeProvider.d.ts +23 -0
  438. package/lib/typescript/ui/theme/ThemeProvider.d.ts.map +1 -0
  439. package/lib/typescript/ui/theme/index.d.ts +3 -0
  440. package/lib/typescript/ui/theme/index.d.ts.map +1 -0
  441. package/lib/typescript/ui/theme/tokens.d.ts +42 -0
  442. package/lib/typescript/ui/theme/tokens.d.ts.map +1 -0
  443. package/lib/typescript/utils/EventEmitter.d.ts +98 -0
  444. package/lib/typescript/utils/EventEmitter.d.ts.map +1 -0
  445. package/lib/typescript/utils/base64.d.ts +19 -0
  446. package/lib/typescript/utils/base64.d.ts.map +1 -0
  447. package/lib/typescript/utils/deviceFingerprint.d.ts +42 -0
  448. package/lib/typescript/utils/deviceFingerprint.d.ts.map +1 -0
  449. package/lib/typescript/utils/documentTypeOptions.d.ts +13 -0
  450. package/lib/typescript/utils/documentTypeOptions.d.ts.map +1 -0
  451. package/lib/typescript/utils/googleMapsPreflight.d.ts +44 -0
  452. package/lib/typescript/utils/googleMapsPreflight.d.ts.map +1 -0
  453. package/lib/typescript/utils/hmac.d.ts +39 -0
  454. package/lib/typescript/utils/hmac.d.ts.map +1 -0
  455. package/lib/typescript/utils/iso3166Countries.d.ts +27 -0
  456. package/lib/typescript/utils/iso3166Countries.d.ts.map +1 -0
  457. package/lib/typescript/utils/jpegFromUri.d.ts +29 -0
  458. package/lib/typescript/utils/jpegFromUri.d.ts.map +1 -0
  459. package/lib/typescript/utils/keepAwake.d.ts +16 -0
  460. package/lib/typescript/utils/keepAwake.d.ts.map +1 -0
  461. package/lib/typescript/utils/log.d.ts +18 -0
  462. package/lib/typescript/utils/log.d.ts.map +1 -0
  463. package/lib/typescript/utils/osGeocoder.d.ts +38 -0
  464. package/lib/typescript/utils/osGeocoder.d.ts.map +1 -0
  465. package/lib/typescript/utils/parseGoogleAddressComponents.d.ts +43 -0
  466. package/lib/typescript/utils/parseGoogleAddressComponents.d.ts.map +1 -0
  467. package/lib/typescript/utils/personNameNormalize.d.ts +10 -0
  468. package/lib/typescript/utils/personNameNormalize.d.ts.map +1 -0
  469. package/lib/typescript/utils/sdkError.d.ts +14 -0
  470. package/lib/typescript/utils/sdkError.d.ts.map +1 -0
  471. package/lib/typescript/utils/sdkVersion.d.ts +7 -0
  472. package/lib/typescript/utils/sdkVersion.d.ts.map +1 -0
  473. package/lib/typescript/utils/stepConfig.d.ts +8 -0
  474. package/lib/typescript/utils/stepConfig.d.ts.map +1 -0
  475. package/lib/typescript/utils/taxInfoConfig.d.ts +7 -0
  476. package/lib/typescript/utils/taxInfoConfig.d.ts.map +1 -0
  477. package/package.json +99 -0
  478. package/src/camera/AddressSearchBar.tsx +363 -0
  479. package/src/camera/DocumentCapture.tsx +505 -0
  480. package/src/camera/LivenessCamera.tsx +602 -0
  481. package/src/camera/MapAddressPicker.tsx +397 -0
  482. package/src/core/VelionOnboarding.ts +974 -0
  483. package/src/core/sessionDeclinedCopy.ts +76 -0
  484. package/src/core/sessionStateMapper.ts +167 -0
  485. package/src/core/sseReasonMessages.ts +531 -0
  486. package/src/data/iso3166Alpha2Codes.json +1 -0
  487. package/src/data/iso3166CountryNames.json +251 -0
  488. package/src/i18n/index.ts +26 -0
  489. package/src/i18n/strings/en.ts +289 -0
  490. package/src/i18n/strings/es.ts +291 -0
  491. package/src/index.ts +137 -0
  492. package/src/steps/AddressInfoStep.tsx +726 -0
  493. package/src/steps/DocumentsOcrStep.tsx +472 -0
  494. package/src/steps/EmailContactStep.tsx +159 -0
  495. package/src/steps/EmailOtpStep.tsx +250 -0
  496. package/src/steps/FaceMatchStep.tsx +177 -0
  497. package/src/steps/FingerprintStep.tsx +99 -0
  498. package/src/steps/HumanBasicInfoStep.tsx +274 -0
  499. package/src/steps/HumanExtendedInfoStep.tsx +353 -0
  500. package/src/steps/LegalBasicInfoStep.tsx +205 -0
  501. package/src/steps/LegalExtendedInfoStep.tsx +171 -0
  502. package/src/steps/LivenessMatchStep.tsx +846 -0
  503. package/src/steps/PhoneContactStep.tsx +160 -0
  504. package/src/steps/PhoneOtpStep.tsx +249 -0
  505. package/src/steps/SwornDeclarationStep.tsx +220 -0
  506. package/src/steps/TaxInfoStep.tsx +277 -0
  507. package/src/steps/TermsAndConditionsStep.tsx +261 -0
  508. package/src/steps/_shared.ts +44 -0
  509. package/src/steps/types.ts +72 -0
  510. package/src/transport/api.ts +257 -0
  511. package/src/transport/irisWebSocket.ts +186 -0
  512. package/src/transport/secureUrl.ts +47 -0
  513. package/src/transport/sse.ts +310 -0
  514. package/src/types/index.ts +1198 -0
  515. package/src/ui/MapFallbackBoundary.tsx +46 -0
  516. package/src/ui/StepShell.tsx +137 -0
  517. package/src/ui/VelionOnboardingScreen.tsx +223 -0
  518. package/src/ui/forms/index.ts +12 -0
  519. package/src/ui/forms/useInlineValidation.ts +115 -0
  520. package/src/ui/forms/validators.ts +29 -0
  521. package/src/ui/icons/HomeHeartIcon.tsx +34 -0
  522. package/src/ui/icons/StepIcon.tsx +77 -0
  523. package/src/ui/overlays/AnalyzingOverlay.tsx +323 -0
  524. package/src/ui/overlays/LoadingOverlay.tsx +115 -0
  525. package/src/ui/overlays/ProgressBar.tsx +99 -0
  526. package/src/ui/overlays/RetryDialog.tsx +128 -0
  527. package/src/ui/overlays/index.ts +3 -0
  528. package/src/ui/primitives/Banner.tsx +81 -0
  529. package/src/ui/primitives/Button.tsx +164 -0
  530. package/src/ui/primitives/Card.tsx +55 -0
  531. package/src/ui/primitives/Checkbox.tsx +153 -0
  532. package/src/ui/primitives/CountrySelect.tsx +356 -0
  533. package/src/ui/primitives/DatePicker.tsx +266 -0
  534. package/src/ui/primitives/Input.tsx +110 -0
  535. package/src/ui/primitives/Select.tsx +259 -0
  536. package/src/ui/primitives/Spinner.tsx +17 -0
  537. package/src/ui/primitives/index.ts +9 -0
  538. package/src/ui/theme/ThemeProvider.tsx +102 -0
  539. package/src/ui/theme/index.ts +17 -0
  540. package/src/ui/theme/tokens.ts +159 -0
  541. package/src/utils/EventEmitter.ts +155 -0
  542. package/src/utils/base64.ts +44 -0
  543. package/src/utils/deviceFingerprint.ts +184 -0
  544. package/src/utils/documentTypeOptions.ts +31 -0
  545. package/src/utils/googleMapsPreflight.ts +72 -0
  546. package/src/utils/hmac.ts +61 -0
  547. package/src/utils/iso3166Countries.ts +111 -0
  548. package/src/utils/jpegFromUri.ts +42 -0
  549. package/src/utils/keepAwake.ts +62 -0
  550. package/src/utils/log.ts +37 -0
  551. package/src/utils/osGeocoder.ts +75 -0
  552. package/src/utils/parseGoogleAddressComponents.ts +123 -0
  553. package/src/utils/personNameNormalize.ts +17 -0
  554. package/src/utils/sdkError.ts +40 -0
  555. package/src/utils/sdkVersion.ts +6 -0
  556. package/src/utils/stepConfig.ts +75 -0
  557. package/src/utils/taxInfoConfig.ts +14 -0
@@ -0,0 +1,974 @@
1
+ /**
2
+ * @fileoverview VelionOnboarding — orchestrator for the React Native SDK.
3
+ *
4
+ * Platform-agnostic dynamic state machine: deals with HTTP, SSE, dedupe and
5
+ * step-module orchestration. UI mounting is delegated to a React component
6
+ * (`VelionOnboardingScreen`) instead of direct DOM manipulation.
7
+ *
8
+ * Invariants:
9
+ * - SSE dedupe by `event_id` (monotonic)
10
+ * - Suppress duplicate `NEXT_STEP` for the just-completed step
11
+ * - 45 s watchdog for terminal SSE event after final step → fallback GET
12
+ * - SESSION_DECLINED handling races with module.run()
13
+ */
14
+
15
+ import { TypedEventEmitter } from '../utils/EventEmitter';
16
+ import { createApiCaller, type ApiCaller } from '../transport/api';
17
+ import { setDebugEnabled, log } from '../utils/log';
18
+ import {
19
+ mapOnboardingDtoToSessionState,
20
+ mapOnboardingDtoToResult,
21
+ mapOnboardingDtoToResultWithStatus,
22
+ isTerminalSessionStatusFromDto,
23
+ requiresCurrentStepForSessionStatus,
24
+ } from './sessionStateMapper';
25
+ import { createSessionEventSource } from '../transport/sse';
26
+ import { resolveSessionDeclinedCopy } from './sessionDeclinedCopy';
27
+ import { FingerprintStep } from '../steps/FingerprintStep';
28
+ import { HumanBasicInfoStep } from '../steps/HumanBasicInfoStep';
29
+ import { EmailContactStep } from '../steps/EmailContactStep';
30
+ import { PhoneContactStep } from '../steps/PhoneContactStep';
31
+ import { EmailOtpStep } from '../steps/EmailOtpStep';
32
+ import { PhoneOtpStep } from '../steps/PhoneOtpStep';
33
+ import { TaxInfoStep } from '../steps/TaxInfoStep';
34
+ import { SwornDeclarationStep } from '../steps/SwornDeclarationStep';
35
+ import { TermsAndConditionsStep } from '../steps/TermsAndConditionsStep';
36
+ import { LegalBasicInfoStep } from '../steps/LegalBasicInfoStep';
37
+ import { HumanExtendedInfoStep } from '../steps/HumanExtendedInfoStep';
38
+ import { LegalExtendedInfoStep } from '../steps/LegalExtendedInfoStep';
39
+ import { AddressInfoStep } from '../steps/AddressInfoStep';
40
+ import { DocumentsOcrStep } from '../steps/DocumentsOcrStep';
41
+ import { LivenessMatchStep } from '../steps/LivenessMatchStep';
42
+ import { FaceMatchStep } from '../steps/FaceMatchStep';
43
+ import {
44
+ SdkErrorCode,
45
+ type VelionConfig as WebVelionConfig,
46
+ type SdkStatus,
47
+ type SdkEventMap,
48
+ type SdkError,
49
+ type OnboardingStep,
50
+ type OnboardingResult,
51
+ type OnboardingDtoResponse,
52
+ type OnboardingSessionEvent,
53
+ type SessionState,
54
+ } from '../types';
55
+ import type { StepModule, StepUiHandle } from '../steps/types';
56
+ import type { ReactNode } from 'react';
57
+
58
+ // ─────────────────────────────────────────────────────────────────────────────
59
+ // PUBLIC CONFIG (RN flavor)
60
+ // ─────────────────────────────────────────────────────────────────────────────
61
+
62
+ /**
63
+ * RN-specific config. Drops web-only fields (`containerId`, `allowEmbedded`,
64
+ * `iframeParentOrigin`) and keeps everything else identical to
65
+ * `WebVelionConfig`, including `fingerprintEndpoint` and `fingerprintApiKey`
66
+ * — both are honoured by the native Fingerprint Pro SDK on mobile too.
67
+ */
68
+ export type VelionConfig = Omit<
69
+ WebVelionConfig,
70
+ 'containerId' | 'allowEmbedded' | 'iframeParentOrigin'
71
+ >;
72
+
73
+ // ─────────────────────────────────────────────────────────────────────────────
74
+ // INTERNAL CONTRACTS
75
+ // ─────────────────────────────────────────────────────────────────────────────
76
+
77
+ interface NextStepCommand {
78
+ step: OnboardingStep;
79
+ stepConfig?: Record<string, unknown>;
80
+ /** `NEXT_STEP` advances; `RETRY_STEP` re-runs the same step intentionally. */
81
+ action: 'NEXT_STEP' | 'RETRY_STEP';
82
+ }
83
+
84
+ const BACKEND_ONLY_ORCHESTRATED_STEPS = new Set<string>(['FACE_MATCH', 'AML_SCREENING']);
85
+
86
+ const DEFAULT_API_URL = 'https://sdk.velion.la/onboarding';
87
+
88
+ function isBackendOnlyOrchestratedStep(step: string | undefined): boolean {
89
+ if (typeof step !== 'string' || step.trim() === '') return false;
90
+ return BACKEND_ONLY_ORCHESTRATED_STEPS.has(step.trim().toUpperCase());
91
+ }
92
+
93
+ function isTerminalSessionEvent(event: OnboardingSessionEvent): boolean {
94
+ const t = event.event_type;
95
+ return (
96
+ t === 'SESSION_APPROVED' ||
97
+ t === 'SESSION_MANUAL_REVIEW' ||
98
+ t === 'SESSION_DECLINED' ||
99
+ t === 'SESSION_TERMINATED'
100
+ );
101
+ }
102
+
103
+ function terminalEventTypeToStatus(
104
+ eventType: string | undefined,
105
+ ): OnboardingResult['status'] | undefined {
106
+ switch (eventType) {
107
+ case 'SESSION_APPROVED':
108
+ return 'APPROVED';
109
+ case 'SESSION_MANUAL_REVIEW':
110
+ return 'MANUAL_REVIEW';
111
+ case 'SESSION_DECLINED':
112
+ return 'DECLINED';
113
+ case 'SESSION_TERMINATED':
114
+ return 'REJECTED';
115
+ default:
116
+ return undefined;
117
+ }
118
+ }
119
+
120
+ function isSessionTokenAuthSdkError(err: unknown): err is SdkError {
121
+ return (
122
+ err != null &&
123
+ typeof err === 'object' &&
124
+ (err as SdkError).code === SdkErrorCode.SESSION_EXPIRED
125
+ );
126
+ }
127
+
128
+ // ─────────────────────────────────────────────────────────────────────────────
129
+ // PUBLIC: ORCHESTRATOR
130
+ // ─────────────────────────────────────────────────────────────────────────────
131
+
132
+ /**
133
+ * Optional view bridge given to the orchestrator by `VelionOnboardingScreen`.
134
+ *
135
+ * The orchestrator never reads from this — it only writes:
136
+ * - `setLoading(text)` to display a status message between steps
137
+ * - `setStepNode(node)` to mount the active step's UI
138
+ * - `setError(err)` to surface a fatal error
139
+ * - `setResult(result)` on flow completion (host may show their own result)
140
+ */
141
+ export interface OrchestratorView {
142
+ setLoading?: (text: string | null) => void;
143
+ setStepNode?: (node: ReactNode | null) => void;
144
+ setError?: (err: SdkError) => void;
145
+ setResult?: (result: OnboardingResult) => void;
146
+ }
147
+
148
+ /**
149
+ * Top-level entry point. Instantiate once per session, call `start()`, and
150
+ * `destroy()` from the host's unmount path.
151
+ */
152
+ export class VelionOnboarding {
153
+ private readonly config: Readonly<VelionConfig & { apiUrl: string }>;
154
+ private readonly emitter = new TypedEventEmitter<SdkEventMap>();
155
+ private readonly api: ApiCaller;
156
+ private readonly constructionError: SdkError | null;
157
+
158
+ private status: SdkStatus = 'IDLE';
159
+ private activeModule: StepModule | null = null;
160
+ private view: OrchestratorView = {};
161
+ private readonly uiHandle: StepUiHandle = {
162
+ setNode: (node) => this.view.setStepNode?.(node),
163
+ };
164
+
165
+ private initAbortController = new AbortController();
166
+ private sseAbortController = new AbortController();
167
+ private sseCleanup: (() => void) | null = null;
168
+
169
+ private sseTerminalResolve: ((event: OnboardingSessionEvent) => void) | null = null;
170
+ private sseNextStepResolve: ((cmd: NextStepCommand | null) => void) | null = null;
171
+ private queuedNextStepCommand: NextStepCommand | null = null;
172
+ private lastSseEventId = '0';
173
+
174
+ private sessionDeclineHandler: ((event: OnboardingSessionEvent) => void) | null = null;
175
+ private pendingSessionDeclined: OnboardingSessionEvent | null = null;
176
+ private pendingTerminalEvent: OnboardingSessionEvent | null = null;
177
+ private sessionEnded = false;
178
+
179
+ constructor(config: VelionConfig) {
180
+ const apiUrl = config.apiUrl ?? DEFAULT_API_URL;
181
+ this.config = Object.freeze({ ...config, apiUrl });
182
+ if (this.config.debug === true) setDebugEnabled(true);
183
+ let api: ApiCaller;
184
+ let constructionError: SdkError | null = null;
185
+ try {
186
+ api = createApiCaller(
187
+ apiUrl,
188
+ config.sessionToken,
189
+ config.expiresAt,
190
+ );
191
+ } catch (err) {
192
+ constructionError = err as SdkError;
193
+ // Provide a safe-but-unused caller so typed code paths don't crash.
194
+ api = createApiCaller(
195
+ 'https://invalid.velion.invalid',
196
+ config.sessionToken,
197
+ config.expiresAt,
198
+ );
199
+ }
200
+ this.api = api;
201
+ this.constructionError = constructionError;
202
+ this.wireExternalCallbacks();
203
+ }
204
+
205
+ /** Connects an `OrchestratorView` (typically `VelionOnboardingScreen`). */
206
+ attachView(view: OrchestratorView): void {
207
+ this.view = view;
208
+ }
209
+
210
+ /** Detaches the active view (called from screen unmount). */
211
+ detachView(): void {
212
+ this.view = {};
213
+ }
214
+
215
+ on<K extends keyof SdkEventMap>(
216
+ event: K,
217
+ listener: (payload: SdkEventMap[K]) => void,
218
+ ): () => void {
219
+ return this.emitter.on(event, listener);
220
+ }
221
+
222
+ getStatus(): SdkStatus {
223
+ return this.status;
224
+ }
225
+
226
+ /**
227
+ * Hot-rotate the bearer token used by every subsequent backend call. The SSE
228
+ * stream is also reopened so the new token reaches the server-side authenticator.
229
+ */
230
+ refreshSessionToken(token: string, expiresAt?: string): void {
231
+ if (this.status === 'DESTROYED') return;
232
+ this.api.setSessionToken(token, expiresAt);
233
+ if (this.sseCleanup) {
234
+ log.info('[Flow] Reopening SSE after session token rotation');
235
+ this.sseCleanup();
236
+ this.sseAbortController.abort();
237
+ this.sseAbortController = new AbortController();
238
+ this.openSseStream(token);
239
+ }
240
+ }
241
+
242
+ async start(): Promise<void> {
243
+ if (this.status === 'DESTROYED') {
244
+ this.emitError({
245
+ code: SdkErrorCode.INSTANCE_DESTROYED,
246
+ message:
247
+ 'This VelionOnboarding instance has been destroyed. Create a new instance to retry.',
248
+ });
249
+ return;
250
+ }
251
+
252
+ if (this.status !== 'IDLE') {
253
+ this.emitError({
254
+ code: SdkErrorCode.ALREADY_STARTED,
255
+ message:
256
+ 'start() was called on an already-running SDK instance. Call destroy() before re-starting.',
257
+ });
258
+ return;
259
+ }
260
+
261
+ if (this.constructionError) {
262
+ this.emitError(this.constructionError);
263
+ return;
264
+ }
265
+
266
+ try {
267
+ await this.initialize();
268
+ } catch (err) {
269
+ this.emitError(err as SdkError);
270
+ }
271
+ }
272
+
273
+ destroy(): void {
274
+ if (this.status === 'DESTROYED') return;
275
+ this.setStatus('DESTROYED');
276
+ this.initAbortController.abort();
277
+ this.sseCleanup?.();
278
+ this.sseAbortController.abort();
279
+ this.activeModule?.destroy();
280
+ this.activeModule = null;
281
+ this.view.setStepNode?.(null);
282
+ this.view.setLoading?.(null);
283
+ this.emitter.removeAllListeners();
284
+ this.sessionDeclineHandler = null;
285
+ this.pendingSessionDeclined = null;
286
+ }
287
+
288
+ // ── Initialization ────────────────────────────────────────────────────────
289
+
290
+ private async initialize(): Promise<void> {
291
+ this.setStatus('INITIALIZING');
292
+ this.showLoading(this.localizedLoadingMsg());
293
+
294
+ let dto: OnboardingDtoResponse;
295
+ try {
296
+ dto = await this.api.get<OnboardingDtoResponse>(
297
+ `/sessions/${this.config.sessionId}`,
298
+ {
299
+ signal: this.initAbortController.signal,
300
+ extraHeaders: {
301
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
302
+ Pragma: 'no-cache',
303
+ },
304
+ },
305
+ );
306
+ } catch (err) {
307
+ this.showLoading(null);
308
+ if (isSessionTokenAuthSdkError(err)) {
309
+ throw err;
310
+ }
311
+ throw {
312
+ code: SdkErrorCode.SESSION_FETCH_FAILED,
313
+ message:
314
+ `Failed to fetch session for sessionId="${this.config.sessionId}". Verify the apiUrl and sessionToken are correct.`,
315
+ cause: err,
316
+ } satisfies SdkError;
317
+ }
318
+
319
+ const sessionState = mapOnboardingDtoToSessionState(dto);
320
+ this.emitter.emit('session:loaded', sessionState);
321
+
322
+ if (isTerminalSessionStatusFromDto(dto.status)) {
323
+ const result = mapOnboardingDtoToResult(dto, this.config.sessionId);
324
+ this.completeFlow(result);
325
+ return;
326
+ }
327
+
328
+ this.validateSessionState(dto, sessionState);
329
+
330
+ this.sseAbortController = new AbortController();
331
+ this.openSseStream(this.config.sessionToken);
332
+
333
+ this.setStatus('RUNNING');
334
+ await this.runStepMachine(sessionState);
335
+ }
336
+
337
+ private validateSessionState(
338
+ dto: OnboardingDtoResponse,
339
+ state: SessionState,
340
+ ): void {
341
+ if (
342
+ requiresCurrentStepForSessionStatus(dto.status) &&
343
+ !state.currentStep
344
+ ) {
345
+ throw {
346
+ code: SdkErrorCode.SESSION_FETCH_FAILED,
347
+ message:
348
+ `Session ${this.config.sessionId} reports status="${dto.status}" but no current_step. Backend payload is incomplete.`,
349
+ } satisfies SdkError;
350
+ }
351
+ }
352
+
353
+ // ── Step Machine ──────────────────────────────────────────────────────────
354
+
355
+ private async runStepMachine(sessionState: SessionState): Promise<void> {
356
+ if (await this.consumePendingTerminalEvent()) return;
357
+ if (this.pendingSessionDeclined) {
358
+ const ev = this.pendingSessionDeclined;
359
+ this.pendingSessionDeclined = null;
360
+ this.endFlowWithSessionDeclined(ev);
361
+ return;
362
+ }
363
+
364
+ let index = 0;
365
+ let currentStep = sessionState.currentStep;
366
+ let currentStepConfig = sessionState.currentStepConfig;
367
+ const knownStepConfigs = { ...(sessionState.stepConfigs ?? {}) };
368
+
369
+ if (currentStep && isBackendOnlyOrchestratedStep(currentStep)) {
370
+ this.showLoading(this.localizedProcessingMsg());
371
+ try {
372
+ const outcome = await this.withSessionDeclineRace(
373
+ this.waitForRoutingAfterBackendOnlyStep(),
374
+ );
375
+ if (await this.consumePendingTerminalEvent()) return;
376
+ if (outcome.declined) {
377
+ this.endFlowWithSessionDeclined(outcome.event);
378
+ return;
379
+ }
380
+ const routed = outcome.value;
381
+ if (!routed?.step) {
382
+ throw {
383
+ code: SdkErrorCode.SESSION_FETCH_FAILED,
384
+ message:
385
+ `Timed out waiting for ROUTING_COMMAND while the session was on a backend-only step (${String(currentStep)}).`,
386
+ } satisfies SdkError;
387
+ }
388
+ currentStep = routed.step;
389
+ currentStepConfig = routed.stepConfig;
390
+ } finally {
391
+ this.showLoading(null);
392
+ }
393
+ }
394
+
395
+ while (currentStep) {
396
+ if (await this.consumePendingTerminalEvent()) return;
397
+ if (this.pendingSessionDeclined) {
398
+ const ev = this.pendingSessionDeclined;
399
+ this.pendingSessionDeclined = null;
400
+ this.endFlowWithSessionDeclined(ev);
401
+ return;
402
+ }
403
+ this.setStatus('STEP_PROCESSING');
404
+ this.emitter.emit('step:change', { step: currentStep, index });
405
+
406
+ if (currentStepConfig) {
407
+ knownStepConfigs[currentStep] = currentStepConfig;
408
+ }
409
+
410
+ const module = this.createModule(currentStep, currentStepConfig);
411
+ this.activeModule = module;
412
+
413
+ try {
414
+ const runOutcome = await this.withSessionDeclineRace(module.run());
415
+ if (await this.consumePendingTerminalEvent()) {
416
+ module.destroy();
417
+ this.activeModule = null;
418
+ return;
419
+ }
420
+ if (runOutcome.declined) {
421
+ module.destroy();
422
+ this.activeModule = null;
423
+ this.endFlowWithSessionDeclined(runOutcome.event);
424
+ return;
425
+ }
426
+ } catch (err) {
427
+ module.destroy();
428
+ this.activeModule = null;
429
+ throw err;
430
+ }
431
+
432
+ module.destroy();
433
+ this.activeModule = null;
434
+ this.view.setStepNode?.(null);
435
+ this.emitter.emit('step:complete', { step: currentStep });
436
+ this.setStatus('RUNNING');
437
+ index += 1;
438
+
439
+ this.showLoading('');
440
+ let next: NextStepCommand | null;
441
+ try {
442
+ const nextOutcome = await this.withSessionDeclineRace(
443
+ this.resolveNextStepAfterCompletion(),
444
+ );
445
+ if (await this.consumePendingTerminalEvent()) {
446
+ this.showLoading(null);
447
+ return;
448
+ }
449
+ if (nextOutcome.declined) {
450
+ this.endFlowWithSessionDeclined(nextOutcome.event);
451
+ return;
452
+ }
453
+ next = nextOutcome.value;
454
+ } catch (err) {
455
+ this.showLoading(null);
456
+ throw err;
457
+ }
458
+
459
+ while (
460
+ next?.step &&
461
+ next.action === 'NEXT_STEP' &&
462
+ next.step === currentStep
463
+ ) {
464
+ log.warn('[Flow] Dropping duplicate NEXT_STEP for just-completed step', {
465
+ step: currentStep,
466
+ });
467
+ const retryOutcome = await this.withSessionDeclineRace(
468
+ this.resolveNextStepAfterCompletion(),
469
+ );
470
+ if (await this.consumePendingTerminalEvent()) {
471
+ this.showLoading(null);
472
+ return;
473
+ }
474
+ if (retryOutcome.declined) {
475
+ this.endFlowWithSessionDeclined(retryOutcome.event);
476
+ return;
477
+ }
478
+ next = retryOutcome.value;
479
+ }
480
+
481
+ if (next?.step) {
482
+ this.showLoading(null);
483
+ }
484
+ if (!next?.step) break;
485
+ currentStep = next.step;
486
+ currentStepConfig = next.stepConfig;
487
+ }
488
+
489
+ this.showLoading(this.localizedFinalizingMsg());
490
+ try {
491
+ if (this.pendingSessionDeclined) {
492
+ const ev = this.pendingSessionDeclined;
493
+ this.pendingSessionDeclined = null;
494
+ this.endFlowWithSessionDeclined(ev);
495
+ return;
496
+ }
497
+ if (await this.consumePendingTerminalEvent()) return;
498
+ const terminalOutcome = await this.withSessionDeclineRace(
499
+ this.waitForTerminalSseEvent(45_000),
500
+ );
501
+ if (terminalOutcome.declined) {
502
+ this.endFlowWithSessionDeclined(terminalOutcome.event);
503
+ return;
504
+ }
505
+ const terminalEvent = terminalOutcome.value;
506
+ if (terminalEvent) {
507
+ await this.finalizeSessionWithTerminalEvent(terminalEvent);
508
+ return;
509
+ }
510
+ await this.finalizeSessionSingleGet();
511
+ } finally {
512
+ this.showLoading(null);
513
+ }
514
+ }
515
+
516
+ private createModule(
517
+ step: OnboardingStep,
518
+ stepConfig: Record<string, unknown> | undefined,
519
+ ): StepModule {
520
+ const deps = {
521
+ api: this.api,
522
+ sessionId: this.config.sessionId,
523
+ locale: this.config.locale ?? 'es',
524
+ colorMode: (this.config.colorMode ?? 'light') as 'light' | 'dark',
525
+ ui: this.uiHandle,
526
+ step,
527
+ ...(stepConfig !== undefined && { stepConfig }),
528
+ ...(this.config.googleMapsApiKey !== undefined && {
529
+ googleMapsApiKey: this.config.googleMapsApiKey,
530
+ }),
531
+ ...(this.config.fingerprintEndpoint !== undefined && {
532
+ fingerprintEndpoint: this.config.fingerprintEndpoint,
533
+ }),
534
+ ...(this.config.fingerprintApiKey !== undefined && {
535
+ fingerprintApiKey: this.config.fingerprintApiKey,
536
+ }),
537
+ ...(this.config.fingerprintTimeoutMs !== undefined && {
538
+ fingerprintTimeoutMs: this.config.fingerprintTimeoutMs,
539
+ }),
540
+ ...(this.config.livenessCalibrationLabel !== undefined && {
541
+ livenessCalibrationLabel: this.config.livenessCalibrationLabel,
542
+ }),
543
+ } as const;
544
+
545
+ switch (step) {
546
+ case 'DEVICE_FINGERPRINT':
547
+ return new FingerprintStep(deps);
548
+ case 'HUMAN_BASIC_INFO':
549
+ return new HumanBasicInfoStep(deps);
550
+ case 'EMAIL_CONTACT':
551
+ return new EmailContactStep(deps);
552
+ case 'PHONE_CONTACT':
553
+ return new PhoneContactStep(deps);
554
+ case 'EMAIL_OTP':
555
+ return new EmailOtpStep(deps);
556
+ case 'PHONE_OTP':
557
+ return new PhoneOtpStep(deps);
558
+ case 'TAX_INFO':
559
+ return new TaxInfoStep(deps);
560
+ case 'SWORN_DECLARATION':
561
+ return new SwornDeclarationStep(deps);
562
+ case 'TERMS_AND_CONDITIONS':
563
+ return new TermsAndConditionsStep(deps);
564
+ case 'LEGAL_BASIC_INFO':
565
+ return new LegalBasicInfoStep(deps);
566
+ case 'HUMAN_EXTENDED_INFO':
567
+ return new HumanExtendedInfoStep(deps);
568
+ case 'LEGAL_EXTENDED_INFO':
569
+ return new LegalExtendedInfoStep(deps);
570
+ case 'ADDRESS_INFO':
571
+ return new AddressInfoStep(deps);
572
+ case 'DOCUMENTS_OCR':
573
+ return new DocumentsOcrStep(deps);
574
+ case 'LIVENESS_MATCH':
575
+ return new LivenessMatchStep(deps);
576
+ case 'FACE_MATCH':
577
+ return new FaceMatchStep(deps);
578
+ default:
579
+ throw {
580
+ code: SdkErrorCode.UNKNOWN,
581
+ message:
582
+ `Step "${String(step)}" is not implemented yet in the React Native SDK. ` +
583
+ 'See the port roadmap in the repo README.',
584
+ } satisfies SdkError;
585
+ }
586
+ }
587
+
588
+ // ── Finalization ──────────────────────────────────────────────────────────
589
+
590
+ private async finalizeSessionWithTerminalEvent(
591
+ event: OnboardingSessionEvent,
592
+ ): Promise<void> {
593
+ const status = terminalEventTypeToStatus(event.event_type);
594
+ if (!status) {
595
+ await this.finalizeSessionSingleGet();
596
+ return;
597
+ }
598
+ let dto: OnboardingDtoResponse;
599
+ try {
600
+ dto = await this.api.get<OnboardingDtoResponse>(
601
+ `/sessions/${this.config.sessionId}`,
602
+ );
603
+ } catch (err) {
604
+ throw {
605
+ code: SdkErrorCode.API_ERROR,
606
+ message: 'All steps completed but failed to retrieve the final session result.',
607
+ cause: err,
608
+ } satisfies SdkError;
609
+ }
610
+ const result = mapOnboardingDtoToResultWithStatus(
611
+ dto,
612
+ this.config.sessionId,
613
+ status,
614
+ event.reason,
615
+ );
616
+ this.completeFlow(result);
617
+ }
618
+
619
+ private async finalizeSessionSingleGet(): Promise<void> {
620
+ let dto: OnboardingDtoResponse;
621
+ try {
622
+ dto = await this.api.get<OnboardingDtoResponse>(
623
+ `/sessions/${this.config.sessionId}`,
624
+ );
625
+ } catch (err) {
626
+ throw {
627
+ code: SdkErrorCode.API_ERROR,
628
+ message:
629
+ 'All steps completed but no terminal SSE event was received within the timeout, and the session fetch failed.',
630
+ cause: err,
631
+ } satisfies SdkError;
632
+ }
633
+ const result = mapOnboardingDtoToResult(dto, this.config.sessionId);
634
+ this.completeFlow(result);
635
+ }
636
+
637
+ private completeFlow(result: OnboardingResult): void {
638
+ this.sessionEnded = true;
639
+ this.setStatus('COMPLETED');
640
+ log.info('[Flow] Session finalized', {
641
+ sessionId: result.sessionId,
642
+ status: result.status,
643
+ terminalReason: result.terminalReason,
644
+ referenceId: result.referenceId,
645
+ completedAt: result.completedAt,
646
+ });
647
+ this.view.setResult?.(result);
648
+ this.emitter.emit('flow:complete', result);
649
+ }
650
+
651
+ private endFlowWithSessionDeclined(event: OnboardingSessionEvent): void {
652
+ if (this.sessionEnded) return;
653
+ this.sessionEnded = true;
654
+ log.info('[Flow] Session finalized', {
655
+ sessionId: this.config.sessionId,
656
+ status: 'DECLINED',
657
+ terminalReason: event.reason,
658
+ stepCode: event.step_code,
659
+ });
660
+ const copy = resolveSessionDeclinedCopy(
661
+ this.config.locale,
662
+ this.config.sessionDeclinedReasonTexts,
663
+ event.reason,
664
+ this.config.finalResultScreenTexts?.dismissLabel,
665
+ );
666
+ const err: SdkError = {
667
+ code: SdkErrorCode.SESSION_DECLINED,
668
+ message: copy.message,
669
+ ...(event.reason !== undefined && { declineReason: event.reason }),
670
+ ...(event.step_code !== undefined && { stepCode: event.step_code }),
671
+ declineTitle: copy.title,
672
+ declineMessage: copy.message,
673
+ };
674
+ this.emitError(err);
675
+ }
676
+
677
+ // ── SSE plumbing ──────────────────────────────────────────────────────────
678
+
679
+ private openSseStream(sessionToken: string): void {
680
+ this.sseCleanup = createSessionEventSource({
681
+ baseUrl: this.config.apiUrl,
682
+ sessionId: this.config.sessionId,
683
+ sessionToken,
684
+ lastEventId: this.lastSseEventId,
685
+ signal: this.sseAbortController.signal,
686
+ onEvent: (event) => this.handleSseEvent(event),
687
+ onError: (err) => {
688
+ log.warn('[Flow] SSE onError callback invoked', err);
689
+ },
690
+ });
691
+ }
692
+
693
+ private handleSseEvent(event: OnboardingSessionEvent): void {
694
+ if (this.sessionEnded) return;
695
+
696
+ if (event.event_id !== undefined) {
697
+ const incoming = Number(event.event_id);
698
+ const lastSeen = Number(this.lastSseEventId);
699
+ if (
700
+ Number.isFinite(incoming) &&
701
+ Number.isFinite(lastSeen) &&
702
+ incoming <= lastSeen
703
+ ) {
704
+ log.info('[SSE] Skipping replayed event', {
705
+ eventId: event.event_id,
706
+ lastSeen: this.lastSseEventId,
707
+ eventType: event.event_type,
708
+ action: event.action,
709
+ });
710
+ return;
711
+ }
712
+ if (Number.isFinite(incoming)) {
713
+ this.lastSseEventId = String(event.event_id);
714
+ }
715
+ }
716
+
717
+ this.config.onSessionEvent?.(event);
718
+ const isTerminal = isTerminalSessionEvent(event);
719
+
720
+ if (event.event_type === 'SESSION_DECLINED') {
721
+ this.pendingTerminalEvent = event;
722
+ if (this.sessionDeclineHandler) {
723
+ this.sessionDeclineHandler(event);
724
+ } else {
725
+ this.pendingSessionDeclined = event;
726
+ }
727
+ return;
728
+ }
729
+
730
+ if (isTerminal) {
731
+ this.pendingTerminalEvent = event;
732
+ if (this.sseNextStepResolve) {
733
+ log.info('[Flow] Terminal event interrupted ROUTING_COMMAND wait', {
734
+ eventType: event.event_type,
735
+ });
736
+ const resolveNext = this.sseNextStepResolve;
737
+ this.sseNextStepResolve = null;
738
+ resolveNext(null);
739
+ }
740
+ }
741
+
742
+ const maybeNext = this.extractNextStepCommand(event);
743
+ if (maybeNext) {
744
+ log.info('[Flow] ROUTING_COMMAND received from SSE', {
745
+ step: maybeNext.step,
746
+ hasStepConfig: maybeNext.stepConfig !== undefined,
747
+ eventType: event.event_type,
748
+ action: event.action,
749
+ });
750
+ if (this.sseNextStepResolve) {
751
+ const resolve = this.sseNextStepResolve;
752
+ this.sseNextStepResolve = null;
753
+ resolve(maybeNext);
754
+ } else {
755
+ this.queuedNextStepCommand = maybeNext;
756
+ }
757
+ }
758
+
759
+ if (this.sseTerminalResolve && isTerminal) {
760
+ log.info('[Flow] Terminal event received from SSE', {
761
+ eventType: event.event_type,
762
+ });
763
+ const resolve = this.sseTerminalResolve;
764
+ this.sseTerminalResolve = null;
765
+ resolve(event);
766
+ }
767
+ }
768
+
769
+ private extractNextStepCommand(
770
+ event: OnboardingSessionEvent,
771
+ ): NextStepCommand | null {
772
+ if (event.event_type !== 'ROUTING_COMMAND') return null;
773
+ const action = event.action;
774
+ if (action !== 'NEXT_STEP' && action !== 'RETRY_STEP') return null;
775
+ const step = event.step_code as OnboardingStep | undefined;
776
+ if (!step) return null;
777
+ return {
778
+ step,
779
+ action,
780
+ ...(event.step_config !== undefined && { stepConfig: event.step_config }),
781
+ };
782
+ }
783
+
784
+ // ── Wait helpers ──────────────────────────────────────────────────────────
785
+
786
+ /**
787
+ * Wait for the next ROUTING_COMMAND. The orchestrator races this with a 30 s
788
+ * timeout that, on fire, falls back to a fresh GET /sessions/:id to recover
789
+ * if SSE was missed.
790
+ */
791
+ private resolveNextStepAfterCompletion(): Promise<NextStepCommand | null> {
792
+ if (this.queuedNextStepCommand) {
793
+ const next = this.queuedNextStepCommand;
794
+ this.queuedNextStepCommand = null;
795
+ return Promise.resolve(next);
796
+ }
797
+
798
+ return new Promise<NextStepCommand | null>((resolve) => {
799
+ const timeout = setTimeout(async () => {
800
+ if (this.sseNextStepResolve) {
801
+ this.sseNextStepResolve = null;
802
+ }
803
+ log.warn(
804
+ '[Flow] No ROUTING_COMMAND within 30 s — falling back to GET /sessions for next step',
805
+ );
806
+ try {
807
+ const dto = await this.api.get<OnboardingDtoResponse>(
808
+ `/sessions/${this.config.sessionId}`,
809
+ {
810
+ extraHeaders: {
811
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
812
+ },
813
+ },
814
+ );
815
+ if (isTerminalSessionStatusFromDto(dto.status)) {
816
+ resolve(null);
817
+ return;
818
+ }
819
+ const state = mapOnboardingDtoToSessionState(dto);
820
+ if (state.currentStep) {
821
+ resolve({
822
+ step: state.currentStep,
823
+ action: 'NEXT_STEP',
824
+ ...(state.currentStepConfig !== undefined && {
825
+ stepConfig: state.currentStepConfig,
826
+ }),
827
+ });
828
+ return;
829
+ }
830
+ resolve(null);
831
+ } catch (err) {
832
+ log.error('[Flow] Fallback GET /sessions failed', err);
833
+ resolve(null);
834
+ }
835
+ }, 30_000);
836
+
837
+ this.sseNextStepResolve = (cmd) => {
838
+ clearTimeout(timeout);
839
+ resolve(cmd);
840
+ };
841
+ });
842
+ }
843
+
844
+ private waitForRoutingAfterBackendOnlyStep(): Promise<NextStepCommand | null> {
845
+ return this.resolveNextStepAfterCompletion();
846
+ }
847
+
848
+ private waitForTerminalSseEvent(
849
+ timeoutMs: number,
850
+ ): Promise<OnboardingSessionEvent | null> {
851
+ if (this.pendingTerminalEvent) {
852
+ const ev = this.pendingTerminalEvent;
853
+ return Promise.resolve(ev);
854
+ }
855
+ return new Promise<OnboardingSessionEvent | null>((resolve) => {
856
+ const timeout = setTimeout(() => {
857
+ if (this.sseTerminalResolve) {
858
+ this.sseTerminalResolve = null;
859
+ resolve(null);
860
+ }
861
+ }, timeoutMs);
862
+ this.sseTerminalResolve = (event) => {
863
+ clearTimeout(timeout);
864
+ resolve(event);
865
+ };
866
+ });
867
+ }
868
+
869
+ /**
870
+ * Drain a pending terminal event (e.g. SESSION_APPROVED arrived while the
871
+ * orchestrator was busy mid-step). Returns true when the flow has been ended
872
+ * by the consumed event.
873
+ */
874
+ private async consumePendingTerminalEvent(): Promise<boolean> {
875
+ const event = this.pendingTerminalEvent;
876
+ if (!event) return false;
877
+ this.pendingTerminalEvent = null;
878
+ if (event.event_type === 'SESSION_DECLINED') {
879
+ this.endFlowWithSessionDeclined(event);
880
+ return true;
881
+ }
882
+ await this.finalizeSessionWithTerminalEvent(event);
883
+ return true;
884
+ }
885
+
886
+ /**
887
+ * Race a step's promise against SESSION_DECLINED. If decline arrives first,
888
+ * `declined` is true so the caller can short-circuit cleanup.
889
+ */
890
+ private withSessionDeclineRace<T>(
891
+ promise: Promise<T>,
892
+ ): Promise<
893
+ | { declined: false; value: T }
894
+ | { declined: true; event: OnboardingSessionEvent }
895
+ > {
896
+ return new Promise((resolve, reject) => {
897
+ let settled = false;
898
+ const declineHandler = (event: OnboardingSessionEvent): void => {
899
+ if (settled) return;
900
+ settled = true;
901
+ this.sessionDeclineHandler = null;
902
+ resolve({ declined: true, event });
903
+ };
904
+ this.sessionDeclineHandler = declineHandler;
905
+
906
+ promise
907
+ .then((value) => {
908
+ if (settled) return;
909
+ settled = true;
910
+ this.sessionDeclineHandler = null;
911
+ resolve({ declined: false, value });
912
+ })
913
+ .catch((err) => {
914
+ if (settled) return;
915
+ settled = true;
916
+ this.sessionDeclineHandler = null;
917
+ reject(err);
918
+ });
919
+ });
920
+ }
921
+
922
+ // ── Helpers ───────────────────────────────────────────────────────────────
923
+
924
+ private wireExternalCallbacks(): void {
925
+ const cb = this.config;
926
+ if (cb.onError) this.emitter.on('error', cb.onError);
927
+ if (cb.onSuccess) this.emitter.on('flow:complete', cb.onSuccess);
928
+ if (cb.onStepChange) {
929
+ this.emitter.on('step:change', ({ step, index }) =>
930
+ cb.onStepChange?.(step, index),
931
+ );
932
+ }
933
+ if (cb.onStepComplete) {
934
+ this.emitter.on('step:complete', ({ step }) => cb.onStepComplete?.(step));
935
+ }
936
+ // session:loaded has no public callback — internal only.
937
+ }
938
+
939
+ private setStatus(next: SdkStatus): void {
940
+ this.status = next;
941
+ this.emitter.emit('status:change', next);
942
+ }
943
+
944
+ private emitError(err: SdkError): void {
945
+ if (this.status === 'DESTROYED') return;
946
+ this.setStatus('ERROR');
947
+ this.view.setError?.(err);
948
+ this.emitter.emit('error', err);
949
+ }
950
+
951
+ private isEnglish(): boolean {
952
+ return (this.config.locale ?? 'es').toLowerCase().startsWith('en');
953
+ }
954
+
955
+ private localizedLoadingMsg(): string {
956
+ return this.isEnglish() ? 'Loading…' : 'Cargando…';
957
+ }
958
+
959
+ private localizedProcessingMsg(): string {
960
+ return this.isEnglish()
961
+ ? 'Processing your verification…'
962
+ : 'Procesando tu verificación…';
963
+ }
964
+
965
+ private localizedFinalizingMsg(): string {
966
+ return this.isEnglish()
967
+ ? 'Processing your information…'
968
+ : 'Procesando tu información…';
969
+ }
970
+
971
+ private showLoading(text: string | null): void {
972
+ this.view.setLoading?.(text);
973
+ }
974
+ }