@smileid/usesmileid 12.3.1-SNAPSHOT.69 → 12.3.1-SNAPSHOT.71

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 (45) hide show
  1. package/dist/data/api/bridge_submissions.js +1 -1
  2. package/dist/data/compression/payload_compression_runner.d.ts +3 -1
  3. package/dist/data/compression/payload_compression_runner.js +1 -1
  4. package/dist/data/compression/uri_compressible_asset.d.ts +30 -4
  5. package/dist/data/compression/uri_compressible_asset.js +1 -1
  6. package/dist/data/factory/networking_factory.d.ts +23 -11
  7. package/dist/data/factory/networking_factory.js +1 -1
  8. package/dist/data/repository/use_smile_id_repository_impl.js +1 -1
  9. package/dist/data/util/scratch_directory.d.ts +12 -0
  10. package/dist/data/util/scratch_directory.js +1 -0
  11. package/dist/metadata/use_smile_id_metadata.d.ts +2 -0
  12. package/dist/metadata/use_smile_id_metadata.js +1 -1
  13. package/dist/metadata/use_smile_id_metadata_factory.d.ts +15 -4
  14. package/dist/metadata/use_smile_id_metadata_factory.js +1 -1
  15. package/dist/presentation/flow/config/flow_configuration_camera.d.ts +0 -2
  16. package/dist/presentation/flow/config/flow_configuration_camera.js +1 -1
  17. package/dist/presentation/flow/config/flow_configuration_screens.d.ts +10 -0
  18. package/dist/presentation/flow/config/flow_configuration_screens.js +1 -0
  19. package/dist/presentation/flow/dsl/use_smile_id_builder.js +1 -1
  20. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts +18 -36
  21. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +1 -1
  22. package/dist/presentation/flow/flow_navigation_graph.d.ts +4 -4
  23. package/dist/presentation/flow/flow_navigation_graph.js +1 -1
  24. package/dist/presentation/flow/flow_navigation_manager.js +1 -1
  25. package/dist/presentation/flow/flow_navigation_manager_routing.js +1 -1
  26. package/dist/presentation/flow/screen/orchestrated_capture_screen.js +1 -1
  27. package/dist/presentation/flow/screen/orchestrated_consent_screen.js +1 -1
  28. package/dist/presentation/flow/screen/orchestrated_partner_screen.js +1 -1
  29. package/dist/presentation/flow/screen/orchestrated_preview_screen.js +1 -1
  30. package/dist/presentation/flow/screen/orchestrated_processing_screen.js +1 -1
  31. package/dist/presentation/flow/screen/use_smile_id_error_code_failure_message.d.ts +8 -0
  32. package/dist/presentation/flow/screen/use_smile_id_error_code_failure_message.js +1 -0
  33. package/dist/presentation/flow/screen/use_smile_id_orchestrated_screen_host.d.ts +14 -1
  34. package/dist/presentation/flow/screen/use_smile_id_orchestrated_screen_host.js +1 -1
  35. package/dist/presentation/flow/validation/flow_validator.d.ts +14 -16
  36. package/dist/presentation/flow/validation/flow_validator.js +1 -1
  37. package/dist/presentation/flow/validation/job_type_validator.d.ts +15 -15
  38. package/dist/presentation/flow/validation/job_type_validator.js +1 -1
  39. package/package.json +6 -6
  40. package/dist/presentation/flow/screen/helpers/failure_message.d.ts +0 -3
  41. package/dist/presentation/flow/screen/helpers/failure_message.js +0 -1
  42. package/dist/presentation/screen/helpers/processing_screen_helpers.d.ts +0 -12
  43. package/dist/presentation/screen/helpers/processing_screen_helpers.js +0 -1
  44. package/dist/presentation/screen/use_smile_id_permission_screen.d.ts +0 -15
  45. package/dist/presentation/screen/use_smile_id_permission_screen.js +0 -1
@@ -1 +1 @@
1
- "use strict";import{Directory as S,File as w,Paths as x}from"expo-file-system";import{filePath as k}from"../util/file_path";import{sourceSdkIdentifier as b}from"@smileid/usesmileid_bridge";import{NativeNetworkClient as y,NativeNetworkError as E,toNativeNetworkError as D}from"@smileid/usesmileid_bridge/internal";import{usesSandbox as C}from"./environment";import{testRoutePort as M}from"./test_route";import{LogLevel as d,RetryStrategy as m}from"../../core/models/network_config";import{decodeSecurityPolicyBitCode as _}from"../util/use_smile_id_token_decoder";import{NetworkServerException as T,NetworkTimeoutException as v,NetworkTransportException as I}from"../../core/exception/use_smile_id_network_exception";import{UseSmileIDErrorCode as c}from"../../core/exception/use_smile_id_error_code";const O="12.3.0";export class BridgeSubmissions{_client;_routed;constructor(t,n){this._client=t,this._routed=n}static configure(t,n=y.shared(),i=M(t)??null){const a=t.config?.logging,o=t.config?.onTokenExpired,{onRequest:s,onResponse:l}=t,h={...BridgeSubmissions.wireConfig(t),...i===null?{}:{testRoute:{port:i}}},N={onRequest:s?r=>s({method:String(r.method??""),url:String(r.url??""),headers:p(r.headers)}):void 0,onResponse:l?r=>l({method:String(r.method??""),url:String(r.url??""),status:Number(r.status??0),durationMillis:Number(r.durationMillis??0),headers:p(r.headers)}):void 0,onTokenExpired:o,onLog:a?.enabled&&a.level!==d.none?r=>console.log(`[UseSmileID] ${r}`):void 0};try{n.configure(h,N)}catch(r){throw D(r)}return new BridgeSubmissions(n,i!==null)}static wireConfig(t){const n=t.config,i=n?.token??"",a=t.timeouts,o=n?.logging;return{partnerId:n?.partnerConfig?.partnerId??"",environment:C(n?.partnerConfig)?"sandbox":"production",token:i,sourceSdk:b(),sourceSdkVersion:O,policy:_(i)??null,timeouts:{connectSeconds:a?.connect??60,readSeconds:a?.read??60,writeSeconds:a?.write??60,callSeconds:a?.call??120},retry:j(t.retry),cache:{enabled:t.cache?.enabled??!0,maxSizeBytes:t.cache?.maxSize??50*1024*1024},logging:{enabled:o?.enabled??!0,level:(o?.level??d.basic).toUpperCase(),redactHeaders:o?.redactHeaders??[]}}}warm(){this._routed||this._client.warm()}async submit(t,n){try{return await this._client.submit({path:t,parts:n.toWire()})}catch(i){throw g(i)}}async seal(t,n){const i=new S(x.cache,`si_sealed_${Date.now()}_${Math.random().toString(36).slice(2)}`);i.create({intermediates:!0});try{const a=new w(i,"package.json");try{await this._client.seal({path:t,parts:n.toWire()},k(a.uri))}catch(s){throw g(s)}const o=JSON.parse(await a.text());return{headers:Object.fromEntries(Object.entries(o.headers??{}).map(([s,l])=>[s,String(l)])),encryptedPackage:o.encryptedPackage,packageNonce:o.packageNonce,packageTag:o.packageTag}}finally{i.exists&&i.delete()}}}function g(e){if(!(e instanceof E))return e;const t=R.find(n=>n===e.code);return e.status!==void 0?new T({statusCode:e.status,message:e.message,cause:e,...t===c.Network.CallbackUrlRequired?{errorCode:t}:{}}):t===c.Network.Timeout?new v({message:e.message,cause:e}):new I({message:e.message,cause:e,errorCode:t??(e.retryable===!0?c.Network.ConnectionFailed:c.Network.RequestFailed)})}const R=Object.values(c.Network);export class BridgeSealed extends Error{sealed;constructor(t){super("Sealed by the native client"),this.sealed=t,this.name="BridgeSealed"}}function p(e){const t={};if(e===null||typeof e!="object")return t;for(const[n,i]of Object.entries(e))t[n]=Array.isArray(i)?i.map(String).join(", "):String(i);return t}function j(e){if(e===void 0||e.strategy===m.none)return{strategy:"none"};const t=Number.isNaN(e.maxAttempts)?1:Math.min(A,Math.max(1,Math.ceil(e.maxAttempts)));return e.strategy===m.fixed?{strategy:"fixed",maxAttempts:t,fixedDelaySeconds:u(e.fixedDelay)}:{strategy:"exponential",maxAttempts:t,initialDelaySeconds:u(e.initialDelay),multiplier:P(e),maxDelaySeconds:f(e),jitter:Number.isNaN(e.jitter)?0:Math.min(1,Math.max(0,e.jitter))}}const A=2**31-1,F=86400;function f(e){return e.maxDelay===Number.POSITIVE_INFINITY?F:u(e.maxDelay)}function u(e){return Number.isFinite(e)?Math.max(0,e):0}function P(e){const t=u(e.initialDelay);return t===0||Number.isNaN(e.multiplier)?1:Number.isFinite(e.multiplier)?Math.max(0,e.multiplier):e.multiplier>0?Math.max(1,f(e)/t):0}
1
+ "use strict";import{File as S}from"expo-file-system";import{filePath as w}from"../util/file_path";import{withScratchDirectory as x}from"../util/scratch_directory";import{sourceSdkIdentifier as k}from"@smileid/usesmileid_bridge";import{NativeNetworkClient as b,NativeNetworkError as y,toNativeNetworkError as E}from"@smileid/usesmileid_bridge/internal";import{usesSandbox as C}from"./environment";import{testRoutePort as D}from"./test_route";import{LogLevel as d,RetryStrategy as m}from"../../core/models/network_config";import{decodeSecurityPolicyBitCode as M}from"../util/use_smile_id_token_decoder";import{NetworkServerException as T,NetworkTimeoutException as _,NetworkTransportException as v}from"../../core/exception/use_smile_id_network_exception";import{UseSmileIDErrorCode as c}from"../../core/exception/use_smile_id_error_code";const I="12.3.0";export class BridgeSubmissions{_client;_routed;constructor(t,n){this._client=t,this._routed=n}static configure(t,n=b.shared(),i=D(t)??null){const a=t.config?.logging,o=t.config?.onTokenExpired,{onRequest:s,onResponse:l}=t,h={...BridgeSubmissions.wireConfig(t),...i===null?{}:{testRoute:{port:i}}},N={onRequest:s?r=>s({method:String(r.method??""),url:String(r.url??""),headers:g(r.headers)}):void 0,onResponse:l?r=>l({method:String(r.method??""),url:String(r.url??""),status:Number(r.status??0),durationMillis:Number(r.durationMillis??0),headers:g(r.headers)}):void 0,onTokenExpired:o,onLog:a?.enabled&&a.level!==d.none?r=>console.log(`[UseSmileID] ${r}`):void 0};try{n.configure(h,N)}catch(r){throw E(r)}return new BridgeSubmissions(n,i!==null)}static wireConfig(t){const n=t.config,i=n?.token??"",a=t.timeouts,o=n?.logging;return{partnerId:n?.partnerConfig?.partnerId??"",environment:C(n?.partnerConfig)?"sandbox":"production",token:i,sourceSdk:k(),sourceSdkVersion:I,policy:M(i)??null,timeouts:{connectSeconds:a?.connect??60,readSeconds:a?.read??60,writeSeconds:a?.write??60,callSeconds:a?.call??120},retry:R(t.retry),cache:{enabled:t.cache?.enabled??!0,maxSizeBytes:t.cache?.maxSize??50*1024*1024},logging:{enabled:o?.enabled??!0,level:(o?.level??d.basic).toUpperCase(),redactHeaders:o?.redactHeaders??[]}}}warm(){this._routed||this._client.warm()}async submit(t,n){try{return await this._client.submit({path:t,parts:n.toWire()})}catch(i){throw p(i)}}async seal(t,n){return x("si_sealed",async i=>{const a=new S(i,"package.json");try{await this._client.seal({path:t,parts:n.toWire()},w(a.uri))}catch(s){throw p(s)}const o=JSON.parse(await a.text());return{headers:Object.fromEntries(Object.entries(o.headers??{}).map(([s,l])=>[s,String(l)])),encryptedPackage:o.encryptedPackage,packageNonce:o.packageNonce,packageTag:o.packageTag}})}}function p(e){if(!(e instanceof y))return e;const t=O.find(n=>n===e.code);return e.status!==void 0?new T({statusCode:e.status,message:e.message,cause:e,...t===c.Network.CallbackUrlRequired?{errorCode:t}:{}}):t===c.Network.Timeout?new _({message:e.message,cause:e}):new v({message:e.message,cause:e,errorCode:t??(e.retryable===!0?c.Network.ConnectionFailed:c.Network.RequestFailed)})}const O=Object.values(c.Network);export class BridgeSealed extends Error{sealed;constructor(t){super("Sealed by the native client"),this.sealed=t,this.name="BridgeSealed"}}function g(e){const t={};if(e===null||typeof e!="object")return t;for(const[n,i]of Object.entries(e))t[n]=Array.isArray(i)?i.map(String).join(", "):String(i);return t}function R(e){if(e===void 0||e.strategy===m.none)return{strategy:"none"};const t=Number.isNaN(e.maxAttempts)?1:Math.min(j,Math.max(1,Math.ceil(e.maxAttempts)));return e.strategy===m.fixed?{strategy:"fixed",maxAttempts:t,fixedDelaySeconds:u(e.fixedDelay)}:{strategy:"exponential",maxAttempts:t,initialDelaySeconds:u(e.initialDelay),multiplier:F(e),maxDelaySeconds:f(e),jitter:Number.isNaN(e.jitter)?0:Math.min(1,Math.max(0,e.jitter))}}const j=2**31-1,A=86400;function f(e){return e.maxDelay===Number.POSITIVE_INFINITY?A:u(e.maxDelay)}function u(e){return Number.isFinite(e)?Math.max(0,e):0}function F(e){const t=u(e.initialDelay);return t===0||Number.isNaN(e.multiplier)?1:Number.isFinite(e.multiplier)?Math.max(0,e.multiplier):e.multiplier>0?Math.max(1,f(e)/t):0}
@@ -18,7 +18,9 @@ export interface PayloadCompressionSizes {
18
18
  * Builds `CompressibleAssets` from a submission's captured JPEG URIs and runs `PayloadCompressor`
19
19
  * to bring the bundle under the transmission cap, re-stamping the Smile EXIF `image_digest` (and
20
20
  * re-encoding natively) per step. Best-effort: it compresses each image down to its quality floor
21
- * and resolves — it never throws on size, so submission is never blocked.
21
+ * and resolves — it never throws on size, so submission is never blocked. Each pass keeps the
22
+ * sources it re-encodes from in a scratch folder of its own under the cache directory
23
+ * (`withScratchDirectory`), which goes when the pass ends, whether the pass succeeded or threw.
22
24
  */
23
25
  export declare const PayloadCompressionRunner: {
24
26
  compress(args: {
@@ -1 +1 @@
1
- "use strict";import{File as a}from"expo-file-system";import{ImageType as n}from"@smileid/usesmileid_bridge";import{resolveCaptureQuality as i}from"../model/sdk_config_capture";import{CompressibleAssets as d}from"./compressible_asset";import{PayloadCompressor as r}from"./payload_compressor";import{UriCompressibleAsset as t}from"./uri_compressible_asset";const b=1024*1024;function o(e){if(e===void 0)return;const m=new a(e).size??0;return m>0?m/b:void 0}export const PayloadCompressionRunner={async compress(e){const m=o(e.selfieImage),s=o(e.frontDocument),c=o(e.backDocument),f=o(e.visaDocument),u=new d({selfie:e.selfieImage?new t(n.Selfie,e.selfieImage,i(e.sdkConfig,n.Selfie)):void 0,liveness:(e.livenessImages??[]).map(l=>new t(n.Liveness,l,i(e.sdkConfig,n.Liveness))),documentFront:e.frontDocument?new t(n.DocumentFront,e.frontDocument,i(e.sdkConfig,n.DocumentFront)):void 0,documentBack:e.backDocument?new t(n.DocumentBack,e.backDocument,i(e.sdkConfig,n.DocumentBack)):void 0,documentVisa:e.visaDocument?new t(n.DocumentVisa,e.visaDocument,i(e.sdkConfig,n.DocumentVisa)):void 0});return await r.prepareBundleForTransmission(u,e.metadataBytes),{selfieOriginalMb:m,selfieFinalMb:o(e.selfieImage),frontOriginalMb:s,frontFinalMb:o(e.frontDocument),backOriginalMb:c,backFinalMb:o(e.backDocument),visaOriginalMb:f,visaFinalMb:o(e.visaDocument)}}};
1
+ "use strict";import{File as l}from"expo-file-system";import{ImageType as t}from"@smileid/usesmileid_bridge";import{resolveCaptureQuality as d}from"../model/sdk_config_capture";import{withScratchDirectory as b}from"../util/scratch_directory";import{CompressibleAssets as p}from"./compressible_asset";import{PayloadCompressor as D}from"./payload_compressor";import{UriCompressibleAsset as v}from"./uri_compressible_asset";const M=1024*1024;function n(e){if(e===void 0)return;const i=new l(e).size??0;return i>0?i/M:void 0}export const PayloadCompressionRunner={async compress(e){const i=n(e.selfieImage),s=n(e.frontDocument),c=n(e.backDocument),r=n(e.visaDocument);return await b("si_compress",u=>{const o=(m,a)=>new v(m,a,d(e.sdkConfig,m),u),f=new p({selfie:e.selfieImage?o(t.Selfie,e.selfieImage):void 0,liveness:(e.livenessImages??[]).map(m=>o(t.Liveness,m)),documentFront:e.frontDocument?o(t.DocumentFront,e.frontDocument):void 0,documentBack:e.backDocument?o(t.DocumentBack,e.backDocument):void 0,documentVisa:e.visaDocument?o(t.DocumentVisa,e.visaDocument):void 0});return D.prepareBundleForTransmission(f,e.metadataBytes)}),{selfieOriginalMb:i,selfieFinalMb:n(e.selfieImage),frontOriginalMb:s,frontFinalMb:n(e.frontDocument),backOriginalMb:c,backFinalMb:n(e.backDocument),visaOriginalMb:r,visaFinalMb:n(e.visaDocument)}}};
@@ -1,3 +1,4 @@
1
+ import { type Directory } from "expo-file-system";
1
2
  import type { ImageTypeId } from "@smileid/usesmileid_bridge";
2
3
  import type { CompressibleAsset } from "./compressible_asset";
3
4
  /**
@@ -5,18 +6,43 @@ import type { CompressibleAsset } from "./compressible_asset";
5
6
  *
6
7
  * The re-encode is **native** (`expo-image-manipulator`, per the spec's "do not reimplement
7
8
  * compression in JS" rule), and the Smile EXIF `image_digest` re-stamp is **native**
8
- * (`SmileExifTagger.finalize`). The original bytes are preserved once on the first `recompress`
9
- * so every step re-encodes from source (no generational stacking; deterministic retries).
9
+ * (`SmileExifTagger.finalize`). The first `recompress` copies the capture into `scratch`, the
10
+ * pass's own folder that `PayloadCompressionRunner` deletes when the pass ends, and every step
11
+ * re-encodes from that copy (no generational stacking; deterministic retries). Nothing is ever
12
+ * written beside the capture.
13
+ *
14
+ * The capture is replaced only by a re-encoded file that exists. When the replacement or the
15
+ * re-stamp fails, the source copy is put back at the capture's path, so the request always points
16
+ * at a readable image; those bytes keep their capture-time stamp. A step whose source copy fails
17
+ * leaves the capture as it was rather than re-encode it without a backup. Every step records the
18
+ * requested quality, whatever happened, so the compressor's loops always advance; an encoder or
19
+ * re-stamp failure still reaches the caller.
10
20
  */
11
21
  export declare class UriCompressibleAsset implements CompressibleAsset {
12
22
  readonly imageType: ImageTypeId;
13
23
  private readonly uri;
24
+ private readonly scratch;
25
+ private static _nextSourceId;
14
26
  private _quality;
15
27
  private _size;
16
- private _sourceUri;
17
- constructor(imageType: ImageTypeId, uri: string, captureQuality: number);
28
+ private _source;
29
+ constructor(imageType: ImageTypeId, uri: string, captureQuality: number, scratch: Directory);
18
30
  encodedSize(): number;
19
31
  quality(): number;
20
32
  recompress(quality: number): Promise<void>;
33
+ /**
34
+ * The copy of the capture every step re-encodes from, made in `scratch` on the first step that
35
+ * finds the capture. `undefined` when there is no capture, or when the copy failed: the step
36
+ * then leaves the capture alone.
37
+ */
38
+ private _retainedSource;
39
+ /**
40
+ * Moves `result` over the capture and answers true. On failure, puts the captured bytes back
41
+ * from `source`, deletes `result`, and answers false.
42
+ */
43
+ private _replaceCapture;
44
+ /** Puts the captured bytes kept in `source` back at the capture's path. */
45
+ private _restoreCapture;
46
+ private static _deleteQuietly;
21
47
  private static _fileSize;
22
48
  }
@@ -1 +1 @@
1
- "use strict";import{File as e}from"expo-file-system";import{ImageManipulator as n,SaveFormat as c}from"expo-image-manipulator";import{SmileExifTagger as o}from"@smileid/usesmileid_bridge/exif/smile_exif_tagger";export class UriCompressibleAsset{imageType;uri;_quality;_size;_sourceUri;constructor(t,i,r){this.imageType=t,this.uri=i,this._quality=Math.min(Math.max(r,0),1),this._size=UriCompressibleAsset._fileSize(i)}encodedSize(){return this._size}quality(){return this._quality}async recompress(t){const i=new e(this.uri);if(!i.exists)return;if(this._sourceUri===void 0){const s=`${this.uri}.orig`;try{i.copy(new e(s)),this._sourceUri=s}catch{this._sourceUri=this.uri}}const r=Math.min(Math.max(t,0),1),a=await(await n.manipulate(this._sourceUri).renderAsync()).saveAsync({compress:r,format:c.JPEG});try{i.exists&&i.delete(),new e(a.uri).move(i)}catch{}await o.finalize(this.uri,this.imageType),this._quality=t,this._size=UriCompressibleAsset._fileSize(this.uri)}static _fileSize(t){try{return new e(t).size??0}catch{return 0}}}
1
+ "use strict";import{File as i}from"expo-file-system";import{ImageManipulator as n,SaveFormat as u}from"expo-image-manipulator";import{SmileExifTagger as o}from"@smileid/usesmileid_bridge/exif/smile_exif_tagger";export class UriCompressibleAsset{imageType;uri;scratch;static _nextSourceId=0;_quality;_size;_source;constructor(t,e,r,a){this.imageType=t,this.uri=e,this.scratch=a,this._quality=Math.min(Math.max(r,0),1),this._size=UriCompressibleAsset._fileSize(e)}encodedSize(){return this._size}quality(){return this._quality}async recompress(t){try{const e=await this._retainedSource();if(e===void 0)return;const c=await(await n.manipulate(e.uri).renderAsync()).saveAsync({compress:Math.min(Math.max(t,0),1),format:u.JPEG});if(!await this._replaceCapture(new i(c.uri),e))return;try{await o.finalize(this.uri,this.imageType)}catch(s){throw await this._restoreCapture(e),s}}finally{this._quality=t,this._size=UriCompressibleAsset._fileSize(this.uri)}}async _retainedSource(){const t=new i(this.uri);if(!t.exists)return;if(this._source!==void 0)return this._source;const e=new i(this.scratch,`source_${UriCompressibleAsset._nextSourceId++}.jpg`);try{await t.copy(e)}catch{UriCompressibleAsset._deleteQuietly(e);return}return this._source=e,e}async _replaceCapture(t,e){try{if(!t.exists)return!1;const r=new i(this.uri);return r.exists&&r.delete(),await t.move(r),!0}catch{return await this._restoreCapture(e),UriCompressibleAsset._deleteQuietly(t),!1}}async _restoreCapture(t){try{const e=new i(this.uri);e.exists&&e.delete(),await t.copy(e)}catch{}}static _deleteQuietly(t){try{t.exists&&t.delete()}catch{}}static _fileSize(t){try{return new i(t).size??0}catch{return 0}}}
@@ -3,15 +3,7 @@ import { SmileIDAPI } from "../api/smile_id_api";
3
3
  import type { NativeNetworkClient } from "@smileid/usesmileid_bridge/internal";
4
4
  import { BridgeSubmissions } from "../api/bridge_submissions";
5
5
  import type { MetadataProvider } from "../../metadata/use_smile_id_metadata_factory";
6
- /**
7
- * Validates `config` and returns a `SmileIDAPI` on the native network client, which signs,
8
- * attests, retries and sends each job.
9
- *
10
- * With `capturing`, the client is the one a skipped submission seals its request through: the
11
- * native client signs and seals each job instead of sending it.
12
- */
13
- export declare function makeNetworkingFactory(config: NetworkConfig, options?: {
14
- readonly capturing?: boolean;
6
+ type NetworkingFactoryOptions = {
15
7
  /** The native client, the shared one unless a test hands over a fake. */
16
8
  readonly nativeClient?: NativeNetworkClient;
17
9
  /**
@@ -19,11 +11,31 @@ export declare function makeNetworkingFactory(config: NetworkConfig, options?: {
19
11
  * seals through the same one rather than configure the shared client again.
20
12
  */
21
13
  readonly bridge?: BridgeSubmissions;
22
- }): {
14
+ };
15
+ /** A capture client: the API that seals each job, and the native client it seals through. */
16
+ type CapturingNetworking = {
23
17
  readonly api: SmileIDAPI;
24
- readonly metadata: MetadataProvider;
25
18
  /** The native client this flow's requests go through. */
26
19
  readonly bridge: BridgeSubmissions;
27
20
  };
21
+ /** A submission client, with the flow's one metadata provider. */
22
+ type SubmittingNetworking = CapturingNetworking & {
23
+ readonly metadata: MetadataProvider;
24
+ };
25
+ /**
26
+ * Validates `config` and returns a `SmileIDAPI` on the native network client, which signs,
27
+ * attests, retries and sends each job, with the flow's metadata provider.
28
+ *
29
+ * With `capturing`, the client is the one a skipped submission seals its request through: the
30
+ * native client signs and seals each job instead of sending it. It builds no metadata provider,
31
+ * since the flow's submission client already owns the one whose warm-up runs once per flow.
32
+ */
33
+ export declare function makeNetworkingFactory(config: NetworkConfig, options?: NetworkingFactoryOptions & {
34
+ readonly capturing?: false;
35
+ }): SubmittingNetworking;
36
+ export declare function makeNetworkingFactory(config: NetworkConfig, options: NetworkingFactoryOptions & {
37
+ readonly capturing: true;
38
+ }): CapturingNetworking;
28
39
  /** Mirrors the server's resolver: blank, a callback ID, or an absolute http(s) URL with a host. */
29
40
  export declare function isResolvableCallbackUrl(value: string): boolean;
41
+ export {};
@@ -1 +1 @@
1
- "use strict";import{SmileIDAPI as l}from"../api/smile_id_api";import{Attestation as m}from"@smileid/usesmileid_bridge";import{BridgeSubmissions as f}from"../api/bridge_submissions";import{testRoutePort as p}from"../api/test_route";import{MissingPartnerConfigException as n}from"../exception/missing_partner_config_exception";import{UseSmileIDMetadataFactory as h}from"../../metadata/use_smile_id_metadata_factory";export function makeNetworkingFactory(t,o={}){const r=t.config?.partnerConfig;if(!r||r.partnerId.trim()==="")throw n.missingPartnerId();if(!t.config?.token||t.config.token.trim()==="")throw n.missingAuthToken();const i=/[\u0000-\u001F\u007F-\u009F]/;if(i.test(r.partnerId))throw n.controlCharacterPartnerId();if(i.test(t.config.token))throw n.controlCharacterAuthToken();if(!isResolvableCallbackUrl(r.callbackUrl??""))throw n.unresolvableCallbackUrl();const e=o.capturing===!0,a=new h,c=p(t)??null,s=o.bridge??f.configure(t,o.nativeClient,c),u=new l(r,s,e);return e||m.warmUp().catch(()=>{}),{api:u,metadata:a,bridge:s}}const d=/^callback_[0-9a-hjkmnp-tv-z]{26}$/;export function isResolvableCallbackUrl(t){if(t===""||d.test(t))return!0;const o=t.indexOf("://");if(o<=0)return!1;const r=t.slice(0,o).toLowerCase();if(r!=="http"&&r!=="https")return!1;const e=((t.slice(o+3).split(/[/?#]/)[0]??"").split("@").pop()??"").split(":")[0]??"";return e!==""&&!/[\s\u0000-\u001F\u007F-\u009F]/.test(e)}
1
+ "use strict";import{SmileIDAPI as u}from"../api/smile_id_api";import{Attestation as l}from"@smileid/usesmileid_bridge";import{BridgeSubmissions as m}from"../api/bridge_submissions";import{testRoutePort as f}from"../api/test_route";import{MissingPartnerConfigException as n}from"../exception/missing_partner_config_exception";import{UseSmileIDMetadataFactory as p}from"../../metadata/use_smile_id_metadata_factory";export function makeNetworkingFactory(t,e={}){const r=t.config?.partnerConfig;if(!r||r.partnerId.trim()==="")throw n.missingPartnerId();if(!t.config?.token||t.config.token.trim()==="")throw n.missingAuthToken();const i=/[\u0000-\u001F\u007F-\u009F]/;if(i.test(r.partnerId))throw n.controlCharacterPartnerId();if(i.test(t.config.token))throw n.controlCharacterAuthToken();if(!isResolvableCallbackUrl(r.callbackUrl??""))throw n.unresolvableCallbackUrl();const o=e.capturing===!0,c=f(t)??null,s=e.bridge??m.configure(t,e.nativeClient,c),a=new u(r,s,o);return o?{api:a,bridge:s}:(l.warmUp().catch(()=>{}),{api:a,metadata:new p,bridge:s})}const h=/^callback_[0-9a-hjkmnp-tv-z]{26}$/;export function isResolvableCallbackUrl(t){if(t===""||h.test(t))return!0;const e=t.indexOf("://");if(e<=0)return!1;const r=t.slice(0,e).toLowerCase();if(r!=="http"&&r!=="https")return!1;const o=((t.slice(e+3).split(/[/?#]/)[0]??"").split("@").pop()??"").split(":")[0]??"";return o!==""&&!/[\s\u0000-\u001F\u007F-\u009F]/.test(o)}
@@ -1 +1 @@
1
- "use strict";import{failure as s,success as m}from"../../core/models/result";import{JobType as t}from"../../core/models/job_type";import{InvalidFieldValueException as l}from"../../core/exception/job_validation_exceptions";import{UseSmileIDException as u}from"../../core/exception/use_smile_id_exception";import{NetworkUnknownException as d}from"../../core/exception/use_smile_id_network_exception";import{PayloadCompressionRunner as o}from"../compression/payload_compression_runner";import{BridgeSealed as _}from"../api/bridge_submissions";function p(i){const e=[],n=(r,a)=>{a!==void 0&&a>0&&e.push({name:r,value:String(a)})};return n("selfie_original_size",i.selfieOriginalMb),n("selfie_final_compressed_size",i.selfieFinalMb),n("document_front_original_size",i.frontOriginalMb),n("document_front_final_compressed_size",i.frontFinalMb),n("document_back_original_size",i.backOriginalMb),n("document_back_final_compressed_size",i.backFinalMb),n("document_visa_original_size",i.visaOriginalMb),n("document_visa_final_compressed_size",i.visaFinalMb),e}export class UseSmileIDRepositoryImpl{_api;_captureApi;constructor(e,n){this._api=e,this._captureApi=n}async seal(e,n){if(e.jobType===t.bvn)return s(new l({fieldName:"jobType",reason:"BVN submission is not yet supported"}));const r=this._captureApi;if(!r)return s(new Error("No capture client to seal the request through"));const a=await this._compressed(e,n);try{return await UseSmileIDRepositoryImpl._send(r,a),s(new Error("The capture client sent the request instead of sealing it"))}catch(c){return c instanceof _?m(c.sealed):s(f(c))}}async submit(e,n){if(e.jobType===t.bvn)return s(new l({fieldName:"jobType",reason:"BVN submission is not yet supported"}));const r=await this._compressed(e,n);try{return m(await UseSmileIDRepositoryImpl._send(this._api,r))}catch(a){return s(f(a))}}async _compressed(e,n){try{const r=await this._compressPayload(e,n),a=r?p(r):[];if(a.length>0)return{...e,metadata:e.metadata.withAdditionalEntries(a)}}catch{}return e}async _compressPayload(e,n){const r=JSON.stringify(e.metadata.toEntries()).length;switch(e.jobType){case t.smartSelfieEnrollment:case t.smartSelfieAuthentication:case t.biometricKyc:return o.compress({selfieImage:e.selfieImage,livenessImages:e.livenessImages,metadataBytes:r,sdkConfig:n});case t.documentVerification:case t.enhancedDocumentVerification:return o.compress({selfieImage:e.selfieImage,livenessImages:e.livenessImages,frontDocument:e.frontDocument,backDocument:e.backDocument,metadataBytes:r,sdkConfig:n});case t.residencyDocumentVerification:return o.compress({selfieImage:e.selfieImage,livenessImages:e.livenessImages,frontDocument:e.frontDocument,visaDocument:e.visaDocument,metadataBytes:r,sdkConfig:n});default:return}}static _send(e,n){switch(n.jobType){case t.smartSelfieEnrollment:return e.smartSelfieEnrollment(n);case t.smartSelfieAuthentication:return e.smartSelfieAuthentication(n);case t.enhancedKyc:return e.enhancedKyc(n);case t.biometricKyc:return e.biometricKyc(n);case t.documentVerification:return e.documentVerification(n);case t.enhancedDocumentVerification:return e.enhancedDocumentVerification(n);case t.residencyDocumentVerification:return e.residencyDocumentVerification(n)}}}function f(i){return i instanceof u?i:new d({message:i instanceof Error?i.message:String(i),cause:i})}
1
+ "use strict";import{failure as c,success as l}from"../../core/models/result";import{JobType as t}from"../../core/models/job_type";import{InvalidFieldValueException as f}from"../../core/exception/job_validation_exceptions";import{UseSmileIDException as d}from"../../core/exception/use_smile_id_exception";import{NetworkUnknownException as o}from"../../core/exception/use_smile_id_network_exception";import{PayloadCompressionRunner as m}from"../compression/payload_compression_runner";import{BridgeSealed as _}from"../api/bridge_submissions";function p(i){const e=[],n=(a,s)=>{s!==void 0&&s>0&&e.push({name:a,value:String(s)})};return n("selfie_original_size",i.selfieOriginalMb),n("selfie_final_compressed_size",i.selfieFinalMb),n("document_front_original_size",i.frontOriginalMb),n("document_front_final_compressed_size",i.frontFinalMb),n("document_back_original_size",i.backOriginalMb),n("document_back_final_compressed_size",i.backFinalMb),n("document_visa_original_size",i.visaOriginalMb),n("document_visa_final_compressed_size",i.visaFinalMb),e}export class UseSmileIDRepositoryImpl{_api;_captureApi;constructor(e,n){this._api=e,this._captureApi=n}async seal(e,n){if(e.jobType===t.bvn)return c(new f({fieldName:"jobType",reason:"BVN submission is not yet supported"}));const a=this._captureApi;if(!a)return c(new o({message:"No capture client to seal the request through"}));const s=await this._compressed(e,n);try{return await UseSmileIDRepositoryImpl._send(a,s),c(new o({message:"The capture client sent the request instead of sealing it"}))}catch(r){return r instanceof _?l(r.sealed):c(u(r))}}async submit(e,n){if(e.jobType===t.bvn)return c(new f({fieldName:"jobType",reason:"BVN submission is not yet supported"}));const a=await this._compressed(e,n);try{return l(await UseSmileIDRepositoryImpl._send(this._api,a))}catch(s){return c(u(s))}}async _compressed(e,n){try{const a=await this._compressPayload(e,n),s=a?p(a):[];if(s.length>0)return{...e,metadata:e.metadata.withAdditionalEntries(s)}}catch{}return e}async _compressPayload(e,n){const a=JSON.stringify(e.metadata.toEntries()).length;switch(e.jobType){case t.smartSelfieEnrollment:case t.smartSelfieAuthentication:case t.biometricKyc:return m.compress({selfieImage:e.selfieImage,livenessImages:e.livenessImages,metadataBytes:a,sdkConfig:n});case t.documentVerification:case t.enhancedDocumentVerification:return m.compress({selfieImage:e.selfieImage,livenessImages:e.livenessImages,frontDocument:e.frontDocument,backDocument:e.backDocument,metadataBytes:a,sdkConfig:n});case t.residencyDocumentVerification:return m.compress({selfieImage:e.selfieImage,livenessImages:e.livenessImages,frontDocument:e.frontDocument,visaDocument:e.visaDocument,metadataBytes:a,sdkConfig:n});default:return}}static _send(e,n){switch(n.jobType){case t.smartSelfieEnrollment:return e.smartSelfieEnrollment(n);case t.smartSelfieAuthentication:return e.smartSelfieAuthentication(n);case t.enhancedKyc:return e.enhancedKyc(n);case t.biometricKyc:return e.biometricKyc(n);case t.documentVerification:return e.documentVerification(n);case t.enhancedDocumentVerification:return e.enhancedDocumentVerification(n);case t.residencyDocumentVerification:return e.residencyDocumentVerification(n)}}}function u(i){return i instanceof d?i:new o({message:i instanceof Error?i.message:String(i),cause:i})}
@@ -0,0 +1,12 @@
1
+ import { Directory } from "expo-file-system";
2
+ /**
3
+ * Runs `body` with a new folder of its own under the cache directory, named
4
+ * `<prefix>_<time>_<random>`, and deletes the folder once `body` settles, whether it resolved or
5
+ * threw. A failed delete does not replace `body`'s result or error: the OS purges the cache
6
+ * directory.
7
+ *
8
+ * A process killed while `body` runs never reaches that delete. So the first folder a JS runtime
9
+ * makes for `prefix` first deletes every `<prefix>_` folder in the cache directory: none of them can
10
+ * belong to this runtime yet, so only an earlier one's leftovers go.
11
+ */
12
+ export declare function withScratchDirectory<T>(prefix: string, body: (directory: Directory) => Promise<T>): Promise<T>;
@@ -0,0 +1 @@
1
+ "use strict";import{Directory as c,Paths as r}from"expo-file-system";const a=new Set;export async function withScratchDirectory(t,e){o(t);const n=new c(r.cache,`${t}_${Date.now()}_${Math.random().toString(36).slice(2)}`);n.create({intermediates:!0});try{return await e(n)}finally{i(n)}}function o(t){if(!a.has(t)){a.add(t);try{for(const e of r.cache.list())e instanceof c&&e.name.startsWith(`${t}_`)&&i(e)}catch{}}}function i(t){try{t.exists&&t.delete()}catch{}}
@@ -84,6 +84,8 @@ export type UseSmileIDMetadataFields = {
84
84
  readonly geolocation?: Geolocation;
85
85
  /** Obfuscated device security-state signal (computed natively) → `privileges`. Omitted when undefined/blank. */
86
86
  readonly privileges?: string;
87
+ /** Sealed runtime report (computed natively) → `runtime_integrity`, verbatim. Omitted when undefined/blank. */
88
+ readonly runtimeIntegrity?: string;
87
89
  /** kamera's device tier (`entry`, `standard` or `high`, design 61) → `device_tier`. Omitted when undefined/blank. */
88
90
  readonly deviceTier?: string;
89
91
  /**
@@ -1 +1 @@
1
- "use strict";export class UseSmileIDMetadata{_fields;_extraEntries;constructor(e,i=[]){this._fields=e,this._extraEntries=i}toFields(){return this._fields}withAdditionalEntries(e){return new UseSmileIDMetadata(this._fields,[...this._extraEntries,...e])}toEntries(){const e=this._fields,i=[];if(i.push({name:"sdk_version",value:e.sdkVersion}),i.push({name:"sdk",value:e.sdk}),i.push({name:"device_os",value:e.deviceOs}),i.push({name:"device_model",value:e.deviceModel}),i.push({name:"app_name",value:e.appName}),i.push({name:"session_id",value:e.sessionId}),e.proxy!==void 0&&i.push({name:"proxy",value:String(e.proxy)}),e.proximitySensor!==void 0&&i.push({name:"proximity_sensor",value:String(e.proximitySensor)}),n(i,"client_ip",e.clientIp),n(i,"network_connection",e.networkConnection),n(i,"carrier_info",e.carrierInfo),n(i,"timezone",e.timezone),n(i,"locale",e.locale),n(i,"screen_resolution",e.screenResolution),n(i,"device_orientation",e.deviceOrientation),n(i,"system_architecture",e.systemArchitecture),n(i,"host_application",e.hostApplication),a(i,"memory_info",e.memoryInfoMb),a(i,"number_of_cameras",e.numberOfCameras),n(i,"device_tier",e.deviceTier??""),n(i,"device_profile",e.deviceProfile??""),i.push({name:"security_policy_version",value:e.securityPolicyVersion}),e.hardwareAttestationSecurityLevel!==void 0){i.push({name:"supports_hardware_attestation",value:String(e.hardwareAttestationSecurityLevel)});const s=e.attestationCertificateChain;s&&s.length>0&&i.push({name:"attestation_certificate_chain",value:JSON.stringify(s)})}return e.supportsAppAttest!==void 0&&i.push({name:"supports_app_attest",value:String(e.supportsAppAttest)}),i.push({name:"sdk_config_source",value:e.sdkConfigSource}),e.imageWidth>0&&e.imageHeight>0&&i.push({name:"selfie_image_dimensions",value:`${e.imageWidth}x${e.imageHeight}`}),e.livenessImageWidth>0&&e.livenessImageHeight>0&&i.push({name:"liveness_image_dimensions",value:`${e.livenessImageWidth}x${e.livenessImageHeight}`}),e.timezoneOffsetMinutes!==void 0&&i.push({name:"timezone_offset",value:String(e.timezoneOffsetMinutes)}),n(i,"build_brand",e.buildBrand??""),n(i,"build_device",e.buildDevice??""),n(i,"build_fingerprint",e.buildFingerprint??""),n(i,"build_product",e.buildProduct??""),n(i,"build_hardware",e.buildHardware??""),n(i,"build_source",e.buildSource??""),n(i,"package_name",e.packageName??""),n(i,"fingerprint",e.fingerprint??""),n(i,"local_time_of_enrolment",e.localTimeOfEnrolment??""),e.batteryStatus!==void 0&&i.push({name:"battery_status",value:String(e.batteryStatus)}),e.vpn!==void 0&&i.push({name:"vpn",value:String(e.vpn)}),e.certificateDigest!==void 0&&e.certificateDigest.length>0&&i.push({name:"certificate_digest",value:JSON.stringify(e.certificateDigest)}),n(i,"wrapper_name",e.wrapperName??""),n(i,"wrapper_version",e.wrapperVersion??""),e.sdkLaunchCount!==void 0&&e.sdkLaunchCount>0&&i.push({name:"sdk_launch_count",value:String(e.sdkLaunchCount)}),e.geolocation!==void 0&&i.push({name:"geolocation",value:JSON.stringify(e.geolocation)}),e.privileges!==void 0&&e.privileges.length>0&&i.push({name:"privileges",value:e.privileges}),i.push(...this._extraEntries),Object.freeze(i)}}function n(t,e,i){i&&i.length>0&&t.push({name:e,value:i})}function a(t,e,i){i!==0&&t.push({name:e,value:String(i)})}
1
+ "use strict";export class UseSmileIDMetadata{_fields;_extraEntries;constructor(e,i=[]){this._fields=e,this._extraEntries=i}toFields(){return this._fields}withAdditionalEntries(e){return new UseSmileIDMetadata(this._fields,[...this._extraEntries,...e])}toEntries(){const e=this._fields,i=[];if(i.push({name:"sdk_version",value:e.sdkVersion}),i.push({name:"sdk",value:e.sdk}),i.push({name:"device_os",value:e.deviceOs}),i.push({name:"device_model",value:e.deviceModel}),i.push({name:"app_name",value:e.appName}),i.push({name:"session_id",value:e.sessionId}),e.proxy!==void 0&&i.push({name:"proxy",value:String(e.proxy)}),e.proximitySensor!==void 0&&i.push({name:"proximity_sensor",value:String(e.proximitySensor)}),t(i,"client_ip",e.clientIp),t(i,"network_connection",e.networkConnection),t(i,"carrier_info",e.carrierInfo),t(i,"timezone",e.timezone),t(i,"locale",e.locale),t(i,"screen_resolution",e.screenResolution),t(i,"device_orientation",e.deviceOrientation),t(i,"system_architecture",e.systemArchitecture),t(i,"host_application",e.hostApplication),r(i,"memory_info",e.memoryInfoMb),r(i,"number_of_cameras",e.numberOfCameras),t(i,"device_tier",e.deviceTier??""),t(i,"device_profile",e.deviceProfile??""),i.push({name:"security_policy_version",value:e.securityPolicyVersion}),e.hardwareAttestationSecurityLevel!==void 0){i.push({name:"supports_hardware_attestation",value:String(e.hardwareAttestationSecurityLevel)});const s=e.attestationCertificateChain;s&&s.length>0&&i.push({name:"attestation_certificate_chain",value:JSON.stringify(s)})}return e.supportsAppAttest!==void 0&&i.push({name:"supports_app_attest",value:String(e.supportsAppAttest)}),i.push({name:"sdk_config_source",value:e.sdkConfigSource}),e.imageWidth>0&&e.imageHeight>0&&i.push({name:"selfie_image_dimensions",value:`${e.imageWidth}x${e.imageHeight}`}),e.livenessImageWidth>0&&e.livenessImageHeight>0&&i.push({name:"liveness_image_dimensions",value:`${e.livenessImageWidth}x${e.livenessImageHeight}`}),e.timezoneOffsetMinutes!==void 0&&i.push({name:"timezone_offset",value:String(e.timezoneOffsetMinutes)}),t(i,"build_brand",e.buildBrand??""),t(i,"build_device",e.buildDevice??""),t(i,"build_fingerprint",e.buildFingerprint??""),t(i,"build_product",e.buildProduct??""),t(i,"build_hardware",e.buildHardware??""),t(i,"build_source",e.buildSource??""),t(i,"package_name",e.packageName??""),t(i,"fingerprint",e.fingerprint??""),t(i,"local_time_of_enrolment",e.localTimeOfEnrolment??""),e.batteryStatus!==void 0&&i.push({name:"battery_status",value:String(e.batteryStatus)}),e.vpn!==void 0&&i.push({name:"vpn",value:String(e.vpn)}),e.certificateDigest!==void 0&&e.certificateDigest.length>0&&i.push({name:"certificate_digest",value:JSON.stringify(e.certificateDigest)}),t(i,"wrapper_name",e.wrapperName??""),t(i,"wrapper_version",e.wrapperVersion??""),e.sdkLaunchCount!==void 0&&e.sdkLaunchCount>0&&i.push({name:"sdk_launch_count",value:String(e.sdkLaunchCount)}),e.geolocation!==void 0&&i.push({name:"geolocation",value:JSON.stringify(e.geolocation)}),e.privileges!==void 0&&e.privileges.length>0&&i.push({name:"privileges",value:e.privileges}),e.runtimeIntegrity!==void 0&&e.runtimeIntegrity.length>0&&i.push({name:"runtime_integrity",value:e.runtimeIntegrity}),i.push(...this._extraEntries),Object.freeze(i)}}function t(n,e,i){i&&i.length>0&&n.push({name:e,value:i})}function r(n,e,i){i!==0&&n.push({name:e,value:String(i)})}
@@ -53,11 +53,13 @@ export declare class UseSmileIDMetadataFactory implements MetadataProvider {
53
53
  private _sdkLaunchCount?;
54
54
  private _geolocation?;
55
55
  private _privileges?;
56
+ private _runtimeIntegrity?;
56
57
  private _deviceIntegrity?;
57
58
  private _clientIp;
58
59
  private _networkConnection;
59
60
  private _hardwareAttestation?;
60
61
  private _deviceProfile?;
62
+ private readonly _warmup;
61
63
  constructor(options?: MetadataFactoryOptions);
62
64
  /**
63
65
  * Resolve kamera's device profile into the cache. kamera says it never rejects (a device it
@@ -73,13 +75,16 @@ export declare class UseSmileIDMetadataFactory implements MetadataProvider {
73
75
  */
74
76
  get sessionId(): string;
75
77
  /**
76
- * Resolve the async `expo-network` fields into the cache. Called
77
- * from the constructor as fire-and-forget; partners can also
78
- * `await` it explicitly when they want to guarantee populated
79
- * network fields on the first submission.
78
+ * Settles once the warm-up the constructor started has resolved the async fields. It never
79
+ * starts another, so awaiting it neither reruns the native probes nor counts another launch.
80
80
  */
81
81
  warmup(): Promise<void>;
82
82
  private _warmupAsync;
83
+ /**
84
+ * Resolve the async `expo-network` fields (`network_connection`, `client_ip`) into the cache.
85
+ * Fail-open: leaves the cached empty strings when the module is absent or a call rejects.
86
+ */
87
+ private _warmUpNetwork;
83
88
  /**
84
89
  * Resolve the last-known location (expo-location) into the cache — only when a permission
85
90
  * is already granted (never prompts). Fail-open: leaves `_geolocation` unset otherwise.
@@ -90,6 +95,12 @@ export declare class UseSmileIDMetadataFactory implements MetadataProvider {
90
95
  * Fail-open: `PrivilegesProvider` returns `"{}"` when the native module is unavailable.
91
96
  */
92
97
  private _warmUpPrivileges;
98
+ /**
99
+ * Resolve the sealed runtime report from the native bridge into the cache. Fail-open:
100
+ * `RuntimeIntegrityProvider` returns undefined when the device can't seal it or the native
101
+ * module is absent.
102
+ */
103
+ private _warmUpRuntimeIntegrity;
93
104
  /**
94
105
  * Resolve the native device-integrity signals (fingerprint, package name, vpn, build
95
106
  * hardware, install source, cert digests) from the bridge into the cache. Fail-open:
@@ -1 +1 @@
1
- "use strict";import{KameraKit as I}from"@smileid/kamera";import{Dimensions as d,Platform as r}from"react-native";import{Attestation as b,DeviceIntegrityProvider as S,PrivilegesProvider as A}from"@smileid/usesmileid_bridge";import{UseSmileIDMetadata as D}from"./use_smile_id_metadata";import{loadAsyncStorage as O,loadExpoBattery as C,loadExpoCellular as P,loadExpoDevice as l,loadExpoNetwork as M}from"./optional_native_modules";import{resolveGeolocation as U}from"./geolocation";import{resolveDimensions as u}from"../data/model/sdk_config_capture";import{SdkConfigSource as h}from"../data/model/sdk_config_source";import{CameraDefaults as o}from"../camera/core/camera_defaults";const m="12.3.0",k="12.0.0",N="react-native-expo",p="com.usesmileid.metadata.sdk_launch_count";export class UseSmileIDMetadataFactory{_sessionId;_deviceOs;_deviceModel;_appName;_hostApplication;_systemArchitecture;_memoryInfoMb;_buildBrand;_buildDevice;_buildFingerprint;_buildProduct;_carrierInfo;_batteryStatus;_sdkLaunchCount;_geolocation;_privileges;_deviceIntegrity;_clientIp="";_networkConnection="";_hardwareAttestation;_deviceProfile;constructor(e={}){this._sessionId=generateSessionId(),this._deviceOs=x(),this._appName=e.appName??"",this._hostApplication=e.hostApplication??"";const t=l();t?(this._deviceModel=resolveDeviceModel(t),this._systemArchitecture=t.supportedCpuArchitectures?.[0]?.trim()??"",this._memoryInfoMb=typeof t.totalMemory=="number"&&t.totalMemory>0?Math.round(t.totalMemory/(1024*1024)):0,this._buildBrand=t.brand?.trim()??"",this._buildDevice=(r.OS==="ios"?t.modelId:t.designName)?.trim()??"",this._buildFingerprint=t.osBuildFingerprint?.trim()??"",this._buildProduct=t.productName?.trim()??""):(this._deviceModel="",this._systemArchitecture="",this._memoryInfoMb=0,this._buildBrand="",this._buildDevice="",this._buildFingerprint="",this._buildProduct=""),this._carrierInfo=P()?.carrier?.trim()??"",this._warmupAsync(),this._warmUpHardwareAttestation(),this._warmUpDeviceProfile()}async _warmUpDeviceProfile(){try{this._deviceProfile=await I.deviceProfile()}catch{}}get sessionId(){return this._sessionId}async warmup(){return this._warmupAsync()}async _warmupAsync(){const e=M();if(!e)return;const t=e.getNetworkStateAsync().then(s=>{this._networkConnection=(s.type??"").toString()}).catch(()=>{}),n=e.getIpAddressAsync?e.getIpAddressAsync().then(s=>{this._clientIp=s??""}).catch(()=>{}):Promise.resolve();await Promise.all([t,n,this._warmUpBatteryStatus(),this._warmUpLaunchCount(),this._warmUpGeolocation(),this._warmUpPrivileges(),this._warmUpDeviceIntegrity()])}async _warmUpGeolocation(){const e=await U();e&&(this._geolocation=e)}async _warmUpPrivileges(){const e=await A.privileges();e.length>0&&(this._privileges=e)}async _warmUpDeviceIntegrity(){this._deviceIntegrity=await S.signals()}async _warmUpLaunchCount(){const e=O();if(e)try{const n=(Number(await e.getItem(p))||0)+1;await e.setItem(p,String(n)),this._sdkLaunchCount=n}catch{}}async _warmUpBatteryStatus(){const e=C();if(e)try{switch(await e.getBatteryStateAsync()){case 1:this._batteryStatus=0;break;case 2:case 3:this._batteryStatus=1;break;default:this._batteryStatus=-1}}catch{}}async _warmUpHardwareAttestation(){try{this._hardwareAttestation=await b.generateHardwareAttestation(this._sessionId)}catch{}}make(e){const t=this._hardwareAttestation,n=r.OS==="android"&&t?{hardwareAttestationSecurityLevel:t.securityLevel,...t.certificateChain&&t.certificateChain.length>0?{attestationCertificateChain:t.certificateChain}:{}}:{},s=r.OS==="ios"&&t?{supportsAppAttest:t.supportsAppAttest}:{},a=u(e?.selfie),_=e!==void 0?h.sdkConfig:h.defaultSource,f=a?.width??o.selfieJpegTargetWidth,g=a?.height??o.selfieJpegTargetHeight,c=u(e?.liveness),v=c?.width??o.selfieJpegTargetWidth,y=c?.height??o.selfieJpegTargetHeight,w={sdkVersion:m,sdk:N,deviceOs:this._deviceOs,deviceModel:this._deviceModel,appName:this._appName,sessionId:this._sessionId,clientIp:this._clientIp,networkConnection:this._networkConnection,carrierInfo:this._carrierInfo,timezone:L(),timezoneOffsetMinutes:B(),locale:E(),screenResolution:H(),memoryInfoMb:this._memoryInfoMb,deviceOrientation:F(),systemArchitecture:this._systemArchitecture,numberOfCameras:0,hostApplication:this._hostApplication,securityPolicyVersion:k,...n,...s,sdkConfigSource:_,imageWidth:f,imageHeight:g,livenessImageWidth:v,livenessImageHeight:y,buildBrand:this._buildBrand,buildDevice:this._buildDevice,buildFingerprint:this._buildFingerprint,buildProduct:this._buildProduct,buildHardware:this._deviceIntegrity?.buildHardware??"",buildSource:this._deviceIntegrity?.buildSource??"",packageName:this._deviceIntegrity?.packageName??"",fingerprint:this._deviceIntegrity?.fingerprint??"",localTimeOfEnrolment:R(),wrapperName:"react_native_expo",wrapperVersion:m,...this._deviceIntegrity?.vpn!==void 0?{vpn:this._deviceIntegrity.vpn}:{},...this._deviceIntegrity?.certificateDigest!==void 0?{certificateDigest:this._deviceIntegrity.certificateDigest}:{},...this._batteryStatus!==void 0?{batteryStatus:this._batteryStatus}:{},...this._sdkLaunchCount!==void 0?{sdkLaunchCount:this._sdkLaunchCount}:{},...this._geolocation!==void 0?{geolocation:this._geolocation}:{},...this._privileges!==void 0?{privileges:this._privileges}:{},...this._deviceProfile!==void 0?{deviceTier:this._deviceProfile.tier,deviceProfile:deviceProfileMetadataJson(this._deviceProfile)}:{}};return new D(w)}}export function deviceProfileMetadataJson(i){const e={lowRamDevice:i.lowRamDevice,maxCpuFreqKHz:i.maxCpuFreqKHz,mediaPerformanceClass:i.mediaPerformanceClass,modelIdentifier:i.modelIdentifier,possibleCores:i.possibleCores,socModel:i.socModel,tier:i.tier,totalRamBytes:i.totalRamBytes};return JSON.stringify(Object.fromEntries(Object.entries(e).filter(([,t])=>t!==null)))}export function resolveDeviceModel(i=l()){if(!i)return"";const e=i.brand?.trim()??"",t=i.modelName?.trim()??"";return[e,t].filter(Boolean).join(" ")}function x(){const i=r.OS==="ios"?"iOS":r.OS==="android"?"Android":r.OS,e=T();return e?`${i} ${e}`:i}function T(){if(r.OS==="android"){const i=r.constants?.Release;if(i!=null&&`${i}`!="")return`${i}`}return typeof r.Version<"u"?String(r.Version):""}function R(){try{return new Date().toISOString()}catch{return""}}function L(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone??""}catch{return""}}function B(){return-new Date().getTimezoneOffset()}function E(){try{return Intl.DateTimeFormat().resolvedOptions().locale??""}catch{return""}}function H(){try{const{width:i,height:e,scale:t}=d.get("screen");if(!i||!e)return"";const n=Math.round(i*(t||1)),s=Math.round(e*(t||1));return`${n} \xD7 ${s}`}catch{return""}}function F(){try{const{width:i,height:e}=d.get("window");return!i||!e?"":e>=i?"Portrait":"Landscape"}catch{return""}}export function generateSessionId(){const i=globalThis.crypto;if(i&&typeof i.randomUUID=="function")return i.randomUUID();const e=()=>typeof i?.getRandomValues=="function"?i.getRandomValues(new Uint16Array(1))[0]??0:Math.floor(Math.random()*65536),t=()=>e().toString(16).padStart(4,"0");return[t()+t(),t(),"4"+t().slice(1),(parseInt(t(),16)&16383|32768).toString(16),t()+t()+t()].join("-")}
1
+ "use strict";import{KameraKit as I}from"@smileid/kamera";import{Dimensions as d,Platform as r}from"react-native";import{Attestation as b,DeviceIntegrityProvider as S,PrivilegesProvider as A}from"@smileid/usesmileid_bridge";import{RuntimeIntegrityProvider as D}from"@smileid/usesmileid_bridge/internal";import{UseSmileIDMetadata as O}from"./use_smile_id_metadata";import{loadAsyncStorage as C,loadExpoBattery as P,loadExpoCellular as U,loadExpoDevice as l,loadExpoNetwork as M}from"./optional_native_modules";import{resolveGeolocation as k}from"./geolocation";import{resolveDimensions as u}from"../data/model/sdk_config_capture";import{SdkConfigSource as h}from"../data/model/sdk_config_source";import{CameraDefaults as o}from"../camera/core/camera_defaults";const m="12.3.0",N="12.0.0",x="react-native-expo",p="com.usesmileid.metadata.sdk_launch_count";export class UseSmileIDMetadataFactory{_sessionId;_deviceOs;_deviceModel;_appName;_hostApplication;_systemArchitecture;_memoryInfoMb;_buildBrand;_buildDevice;_buildFingerprint;_buildProduct;_carrierInfo;_batteryStatus;_sdkLaunchCount;_geolocation;_privileges;_runtimeIntegrity;_deviceIntegrity;_clientIp="";_networkConnection="";_hardwareAttestation;_deviceProfile;_warmup;constructor(t={}){this._sessionId=generateSessionId(),this._deviceOs=R(),this._appName=t.appName??"",this._hostApplication=t.hostApplication??"";const e=l();e?(this._deviceModel=resolveDeviceModel(e),this._systemArchitecture=e.supportedCpuArchitectures?.[0]?.trim()??"",this._memoryInfoMb=typeof e.totalMemory=="number"&&e.totalMemory>0?Math.round(e.totalMemory/(1024*1024)):0,this._buildBrand=e.brand?.trim()??"",this._buildDevice=(r.OS==="ios"?e.modelId:e.designName)?.trim()??"",this._buildFingerprint=e.osBuildFingerprint?.trim()??"",this._buildProduct=e.productName?.trim()??""):(this._deviceModel="",this._systemArchitecture="",this._memoryInfoMb=0,this._buildBrand="",this._buildDevice="",this._buildFingerprint="",this._buildProduct=""),this._carrierInfo=U()?.carrier?.trim()??"",this._warmup=this._warmupAsync(),this._warmUpHardwareAttestation(),this._warmUpDeviceProfile()}async _warmUpDeviceProfile(){try{this._deviceProfile=await I.deviceProfile()}catch{}}get sessionId(){return this._sessionId}warmup(){return this._warmup}async _warmupAsync(){await Promise.allSettled([this._warmUpNetwork(),this._warmUpBatteryStatus(),this._warmUpLaunchCount(),this._warmUpGeolocation(),this._warmUpPrivileges(),this._warmUpDeviceIntegrity()]),await this._warmUpRuntimeIntegrity()}async _warmUpNetwork(){const t=M();if(!t)return;const e=t.getNetworkStateAsync().then(s=>{this._networkConnection=(s.type??"").toString()}).catch(()=>{}),n=t.getIpAddressAsync?t.getIpAddressAsync().then(s=>{this._clientIp=s??""}).catch(()=>{}):Promise.resolve();await Promise.all([e,n])}async _warmUpGeolocation(){const t=await k();t&&(this._geolocation=t)}async _warmUpPrivileges(){const t=await A.privileges();t.length>0&&(this._privileges=t)}async _warmUpRuntimeIntegrity(){const t=await D.runtimeIntegrity();t!==void 0&&(this._runtimeIntegrity=t)}async _warmUpDeviceIntegrity(){this._deviceIntegrity=await S.signals()}async _warmUpLaunchCount(){const t=C();if(t)try{const n=(Number(await t.getItem(p))||0)+1;await t.setItem(p,String(n)),this._sdkLaunchCount=n}catch{}}async _warmUpBatteryStatus(){const t=P();if(t)try{switch(await t.getBatteryStateAsync()){case 1:this._batteryStatus=0;break;case 2:case 3:this._batteryStatus=1;break;default:this._batteryStatus=-1}}catch{}}async _warmUpHardwareAttestation(){try{this._hardwareAttestation=await b.generateHardwareAttestation(this._sessionId)}catch{}}make(t){const e=this._hardwareAttestation,n=r.OS==="android"&&e?{hardwareAttestationSecurityLevel:e.securityLevel,...e.certificateChain&&e.certificateChain.length>0?{attestationCertificateChain:e.certificateChain}:{}}:{},s=r.OS==="ios"&&e?{supportsAppAttest:e.supportsAppAttest}:{},a=u(t?.selfie),_=t!==void 0?h.sdkConfig:h.defaultSource,f=a?.width??o.selfieJpegTargetWidth,g=a?.height??o.selfieJpegTargetHeight,c=u(t?.liveness),y=c?.width??o.selfieJpegTargetWidth,v=c?.height??o.selfieJpegTargetHeight,w={sdkVersion:m,sdk:x,deviceOs:this._deviceOs,deviceModel:this._deviceModel,appName:this._appName,sessionId:this._sessionId,clientIp:this._clientIp,networkConnection:this._networkConnection,carrierInfo:this._carrierInfo,timezone:B(),timezoneOffsetMinutes:E(),locale:H(),screenResolution:F(),memoryInfoMb:this._memoryInfoMb,deviceOrientation:V(),systemArchitecture:this._systemArchitecture,numberOfCameras:0,hostApplication:this._hostApplication,securityPolicyVersion:N,...n,...s,sdkConfigSource:_,imageWidth:f,imageHeight:g,livenessImageWidth:y,livenessImageHeight:v,buildBrand:this._buildBrand,buildDevice:this._buildDevice,buildFingerprint:this._buildFingerprint,buildProduct:this._buildProduct,buildHardware:this._deviceIntegrity?.buildHardware??"",buildSource:this._deviceIntegrity?.buildSource??"",packageName:this._deviceIntegrity?.packageName??"",fingerprint:this._deviceIntegrity?.fingerprint??"",localTimeOfEnrolment:L(),wrapperName:"react_native_expo",wrapperVersion:m,...this._deviceIntegrity?.vpn!==void 0?{vpn:this._deviceIntegrity.vpn}:{},...this._deviceIntegrity?.certificateDigest!==void 0?{certificateDigest:this._deviceIntegrity.certificateDigest}:{},...this._batteryStatus!==void 0?{batteryStatus:this._batteryStatus}:{},...this._sdkLaunchCount!==void 0?{sdkLaunchCount:this._sdkLaunchCount}:{},...this._geolocation!==void 0?{geolocation:this._geolocation}:{},...this._privileges!==void 0?{privileges:this._privileges}:{},...this._runtimeIntegrity!==void 0?{runtimeIntegrity:this._runtimeIntegrity}:{},...this._deviceProfile!==void 0?{deviceTier:this._deviceProfile.tier,deviceProfile:deviceProfileMetadataJson(this._deviceProfile)}:{}};return new O(w)}}export function deviceProfileMetadataJson(i){const t={lowRamDevice:i.lowRamDevice,maxCpuFreqKHz:i.maxCpuFreqKHz,mediaPerformanceClass:i.mediaPerformanceClass,modelIdentifier:i.modelIdentifier,possibleCores:i.possibleCores,socModel:i.socModel,tier:i.tier,totalRamBytes:i.totalRamBytes};return JSON.stringify(Object.fromEntries(Object.entries(t).filter(([,e])=>e!==null)))}export function resolveDeviceModel(i=l()){if(!i)return"";const t=i.brand?.trim()??"",e=i.modelName?.trim()??"";return[t,e].filter(Boolean).join(" ")}function R(){const i=r.OS==="ios"?"iOS":r.OS==="android"?"Android":r.OS,t=T();return t?`${i} ${t}`:i}function T(){if(r.OS==="android"){const i=r.constants?.Release;if(i!=null&&`${i}`!="")return`${i}`}return typeof r.Version<"u"?String(r.Version):""}function L(){try{return new Date().toISOString()}catch{return""}}function B(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone??""}catch{return""}}function E(){return-new Date().getTimezoneOffset()}function H(){try{return Intl.DateTimeFormat().resolvedOptions().locale??""}catch{return""}}function F(){try{const{width:i,height:t,scale:e}=d.get("screen");if(!i||!t)return"";const n=Math.round(i*(e||1)),s=Math.round(t*(e||1));return`${n} \xD7 ${s}`}catch{return""}}function V(){try{const{width:i,height:t}=d.get("window");return!i||!t?"":t>=i?"Portrait":"Landscape"}catch{return""}}export function generateSessionId(){const i=globalThis.crypto;if(i&&typeof i.randomUUID=="function")return i.randomUUID();const t=()=>typeof i?.getRandomValues=="function"?i.getRandomValues(new Uint16Array(1))[0]??0:Math.floor(Math.random()*65536),e=()=>t().toString(16).padStart(4,"0");return[e()+e(),e(),"4"+e().slice(1),(parseInt(e(),16)&16383|32768).toString(16),e()+e()+e()].join("-")}
@@ -1,6 +1,4 @@
1
1
  import type { FlowConfiguration } from "./flow_configuration";
2
- /** Whether a step of `configuration` captures with the camera, selfie or document. */
3
- export declare function opensCamera(configuration: FlowConfiguration): boolean;
4
2
  /**
5
3
  * Starts the camera stack's one-off set-up now when a step of `configuration` captures, so the
6
4
  * capture screen's camera doesn't wait for it. Opens no camera, needs no permission, and kamera's
@@ -1 +1 @@
1
- "use strict";import{KameraSession as n}from"@smileid/kamera";export function opensCamera(e){return e.screens.steps.some(r=>r.kind==="capture")}export function prewarmCameraIfNeeded(e,r=()=>n.prewarm()){opensCamera(e)&&r()}
1
+ "use strict";import{KameraSession as a}from"@smileid/kamera";import{hasCaptureScreen as m}from"./flow_configuration_screens";export function prewarmCameraIfNeeded(e,r=()=>a.prewarm()){m(e.screens.steps)&&r()}
@@ -0,0 +1,10 @@
1
+ import type { CaptureConfigBuilder, ScreenSpec } from "../dsl/screen_builders";
2
+ export declare function hasConsentScreen(steps: readonly ScreenSpec[]): boolean;
3
+ export declare function hasProcessingScreen(steps: readonly ScreenSpec[]): boolean;
4
+ /** Whether a step of the flow captures with the camera, selfie or document. */
5
+ export declare function hasCaptureScreen(steps: readonly ScreenSpec[]): boolean;
6
+ export declare function hasDocumentCaptureScreen(steps: readonly ScreenSpec[]): boolean;
7
+ export declare function resolveSelfieCaptures(steps: readonly ScreenSpec[]): readonly CaptureConfigBuilder[];
8
+ export declare function resolveDocumentCaptures(steps: readonly ScreenSpec[]): readonly CaptureConfigBuilder[];
9
+ /** The SDK's own screens, without the partner's, in the order the flow declares them. */
10
+ export declare function resolveSdkScreens(steps: readonly ScreenSpec[]): readonly ScreenSpec[];
@@ -0,0 +1 @@
1
+ "use strict";import{CaptureType as t}from"../../../core/models/ml_config";export function hasConsentScreen(e){return e.some(n=>n.kind==="consent")}export function hasProcessingScreen(e){return e.some(n=>n.kind==="processing")}export function hasCaptureScreen(e){return e.some(n=>n.kind==="capture")}export function hasDocumentCaptureScreen(e){return resolveDocumentCaptures(e).length>0}export function resolveSelfieCaptures(e){return o(e,t.selfie)}export function resolveDocumentCaptures(e){return o(e,t.document)}export function resolveSdkScreens(e){return e.filter(n=>n.kind!=="partner")}function o(e,n){return e.flatMap(r=>r.kind==="capture"&&r.config.captureType===n?[r.config]:[])}
@@ -1 +1 @@
1
- "use strict";import{jsx as r}from"react/jsx-runtime";import{useMemo as n}from"react";import{FlowInvalidDispatcher as t,FlowSuccessRenderer as s}from"../use_smile_id_flow";import{UseSmileIDFlowBuilder as u}from"./use_smile_id_flow_builder";export function UseSmileIDBuilder({builder:i}){const{result:e,invalidMeta:l}=n(()=>{const o=new u;return i(o),{result:o.build(),invalidMeta:{onResult:o.onResult,enableDebugMode:o._config?.build().enableDebugMode===!0}}},[]);return e.kind==="invalid"?r(t,{result:e,onResult:l.onResult,enableDebugMode:l.enableDebugMode}):r(s,{configuration:e.configuration})}export function useSmileIDBuilder(i){const e=new u;return i(e),e.build()}export{UseSmileIDFlowBuilder}from"./use_smile_id_flow_builder";
1
+ "use strict";import{jsx as r}from"react/jsx-runtime";import{useMemo as u}from"react";import{FlowInvalidDispatcher as t,FlowSuccessRenderer as s}from"../use_smile_id_flow";import{UseSmileIDFlowBuilder as n}from"./use_smile_id_flow_builder";export function UseSmileIDBuilder({builder:i}){const{result:e,invalidMeta:l}=u(()=>{const o=new n;return i(o),{result:o.build(),invalidMeta:{onResult:o.onResult,enableDebugMode:o.isDebugModeEnabled}}},[]);return e.kind==="invalid"?r(t,{result:e,onResult:l.onResult,enableDebugMode:l.enableDebugMode}):r(s,{configuration:e.configuration})}export function useSmileIDBuilder(i){const e=new n;return i(e),e.build()}export{UseSmileIDFlowBuilder}from"./use_smile_id_flow_builder";
@@ -145,13 +145,16 @@ export declare class UseSmileIDFlowBuilder {
145
145
  * flow list in declaration order.
146
146
  */
147
147
  screens(block: (s: ScreensBuilder) => void): void;
148
+ /** Returns the `ValidationState` `build()` would, without building. */
149
+ validate(): ValidationState;
148
150
  /**
149
- * Runs a pre-flight check of the current builder configuration and
150
- * returns a `ValidationState` describing any blocking issues, without
151
- * throwing. Checks the screens and their own settings; job-level rules
152
- * run only in `build()`.
151
+ * Whether `enableDebugMode` is on in the current config block; `false`
152
+ * until a config block sets it. `<UseSmileIDBuilder>` reads it to decide
153
+ * whether an invalid flow also renders the debug screen.
154
+ *
155
+ * @internal
153
156
  */
154
- validate(): ValidationState;
157
+ get isDebugModeEnabled(): boolean;
155
158
  /**
156
159
  * Validates a `ConsentInformation` payload in isolation and returns a
157
160
  * `ValidationState`, without throwing. Useful when the payload comes
@@ -194,45 +197,24 @@ export declare class UseSmileIDFlowBuilder {
194
197
  /**
195
198
  * Snapshot the current builder state and report the validation
196
199
  * outcome as a [FlowBuildResult]. Returns `{kind: 'success', ...}`
197
- * when every rule passed, or `{kind: 'invalid', ...}` carrying the
198
- * issues, the partner's `onResult` callback, and the resolved
199
- * `enableDebugMode` flag so the wrapper can route the failure
200
- * through `onResult.failure` and decide whether to render the
201
- * debug screen.
200
+ * when no issue is an error, logging each warning, or
201
+ * `{kind: 'invalid', ...}` carrying every issue, warnings included.
202
202
  *
203
203
  * Internal — partners use `<UseSmileIDBuilder>`, which calls this
204
204
  * method and dispatches on `kind` (success → render flow, invalid →
205
205
  * fire `onResult.failure(BuilderValidationException)` and optionally
206
- * render the debug screen).
207
- *
208
- * Validation rules (see `validate()` for non-throwing access from
209
- * inside a builder closure):
210
- * 1. The screens list must not be empty.
211
- * 2. Screen ordering: consent must be first if present; processing
212
- * must be last if present; instructions must come before any
213
- * capture; every preview must be preceded by a capture.
214
- * 3. Duplicate screen types are rejected (capture is exempt — a
215
- * flow may have both selfie and document capture).
216
- * 4. ML configuration is required when any capture screen is
217
- * present.
218
- * 5. Network configuration is required when a processing screen
219
- * is present.
220
- * 6. The configured `jobType` may not be `unknown` once a
221
- * processing screen is wired.
222
- * 7. Pre-supplied `consentInformation` and an in-flow consent
223
- * screen are mutually exclusive — exactly one source.
224
- * 8. When set, `consentInformation` must have `granted: true`,
225
- * non-blank `grantedAt`, `noticeLanguage`, and
226
- * `noticePrivacyPolicyUrl`, and `grantedAt` must not parse to
227
- * a future timestamp.
228
- * 9. When set, `EnhancedKYCParams` and `BiometricKYCParams` must
229
- * have non-blank `idType`, `idNumber`, `country`, and a
230
- * `userDetails` whose `givenNames` and `lastName` are non-blank
231
- * and whose `email` or `phoneNumber` (at least one) is set.
206
+ * render the debug screen). `validate()` reports the same issues
207
+ * without building.
232
208
  *
233
209
  * @internal
234
210
  */
235
211
  build(): FlowBuildResult;
212
+ /**
213
+ * The snapshot this builder describes, with every issue it has, in one
214
+ * pass and before the severity gate. The snapshot is `undefined` until a
215
+ * `screens` block runs.
216
+ */
217
+ private verdict;
236
218
  }
237
219
  /**
238
220
  * Frozen snapshot produced by `UseSmileIDFlowBuilder.build()`.
@@ -1 +1 @@
1
- "use strict";import{RESIDENCY_ID_TYPE as d}from"../../../core/models/params";import{UseSmileIDConfigBuilder as l}from"../config/use_smile_id_config_builder";import{ThemeConfigBuilder as u}from"./theme_config_builder";import{UseSmileIDNetworkBuilder as h}from"../../../data/dsl/use_smile_id_network_builder";import{UseSmileIDMLBuilder as f}from"../../../bridge/dsl/use_smile_id_ml_builder";import{ScreensBuilder as P}from"./screen_builders";import{IssueSeverity as D}from"../../../core/exception/issue_severity";import{runBiometricKYCParamsValidation as V,runBuilderValidation as v,runConsentValidation as _,runDocumentVerificationParamsValidation as I,runEnhancedDocumentVerificationParamsValidation as g,runEnhancedKYCParamsValidation as w,runFlowValidation as p,runResidencyDocumentVerificationParamsValidation as y}from"../validation/flow_validator";import{ValidationState as n}from"../validation/validation_state";import{residencyIdTypeIssue as C}from"../validation/job_type_validator";import{decodeSmileIDToken as Y}from"../../../data/util/use_smile_id_token_decoder";export class UseSmileIDFlowBuilder{consentInformation;enhancedKYCParams;biometricKYCParams;documentVerificationParams;enhancedDocumentVerificationParams;residencyDocumentVerificationParams;userDetails;userId;localizations;onResult=()=>{};onAnalyticsEvent;_config;_theme;_network;_ml;_screens;config(i){this._config||(this._config=new l),i(this._config)}theme(i){this._theme=new u,i(this._theme)}network(i){this._network=new h,i(this._network)}ml(i){this._ml||(this._ml=new f),i(this._ml)}screens(i){this._screens||(this._screens=new P),i(this._screens)}validate(){return n.invalid(v(this._screens?.build().steps??[]))}validateConsent(i){return n.invalid(_(i))}validateEnhancedKYCParams(i){return n.invalid(w(i))}validateBiometricKYCParams(i){return n.invalid(V(i))}validateDocumentVerificationParams(i){return n.invalid(I(i))}validateEnhancedDocumentVerificationParams(i){return n.invalid(g(i))}validateResidencyDocumentVerificationParams(i){const e=i.idType.trim()!==""&&i.idType!==d?[C()]:[];return n.invalid([...y(i),...e])}build(){const i=this._screens?.build(),e=this._network?.build(),a=this._ml?.build(),t=this._config?.build(),m=k(t?.allowOfflineMode,e),o=p({steps:i?.steps??[],network:e,ml:a,consentInformation:this.consentInformation,enhancedKYCParams:this.enhancedKYCParams,biometricKYCParams:this.biometricKYCParams,documentVerificationParams:this.documentVerificationParams,enhancedDocumentVerificationParams:this.enhancedDocumentVerificationParams,residencyDocumentVerificationParams:this.residencyDocumentVerificationParams,userDetails:this.userDetails,userId:this.userId,tokenPayload:m,skipApiSubmission:t?.skipApiSubmission}),c=n.invalid(o);if(!c.valid)return{kind:"invalid",validation:c};for(const s of o)s.severity===D.warning&&(console.warn(`[UseSmileIDFlowBuilder] ${s.message}`),s.suggestedFix&&console.warn(`[UseSmileIDFlowBuilder] Suggested fix: ${s.suggestedFix}`));if(!i)throw new Error("UseSmileIDFlowBuilder: internal invariant violated \u2014 screens missing after validation passed.");return{kind:"success",configuration:Object.freeze({...this.consentInformation?{consentInformation:this.consentInformation}:{},...this.enhancedKYCParams?{enhancedKYCParams:this.enhancedKYCParams}:{},...this.biometricKYCParams?{biometricKYCParams:this.biometricKYCParams}:{},...this.documentVerificationParams?{documentVerificationParams:this.documentVerificationParams}:{},...this.enhancedDocumentVerificationParams?{enhancedDocumentVerificationParams:this.enhancedDocumentVerificationParams}:{},...this.residencyDocumentVerificationParams?{residencyDocumentVerificationParams:this.residencyDocumentVerificationParams}:{},...this.userDetails?{userDetails:this.userDetails}:{},...this.userId?{userId:this.userId}:{},...t?{config:t}:{},...this._theme?{theme:this._theme.build()}:{},...e?{network:e}:{},...a?{ml:a}:{},screens:i,...this.localizations?{localizations:this.localizations}:{},onResult:this.onResult,...this.onAnalyticsEvent?{onAnalyticsEvent:this.onAnalyticsEvent}:{}})}}}function k(r,i){if(r)return;const e=i?.config?.token;if(!(!e||e.length===0))return Y(e)?.tokenPayload}
1
+ "use strict";import{UseSmileIDConfigBuilder as c}from"../config/use_smile_id_config_builder";import{ThemeConfigBuilder as m}from"./theme_config_builder";import{UseSmileIDNetworkBuilder as d}from"../../../data/dsl/use_smile_id_network_builder";import{UseSmileIDMLBuilder as l}from"../../../bridge/dsl/use_smile_id_ml_builder";import{ScreensBuilder as u}from"./screen_builders";import{IssueSeverity as h}from"../../../core/exception/issue_severity";import{runBiometricKYCParamsValidation as f,runConsentValidation as P,runDocumentVerificationParamsValidation as D,runEnhancedDocumentVerificationParamsValidation as V,runEnhancedKYCParamsValidation as v,runFlowValidation as g,runResidencyDocumentVerificationParamsValidation as _}from"../validation/flow_validator";import{ValidationState as t}from"../validation/validation_state";import{decodeSmileIDToken as w}from"../../../data/util/use_smile_id_token_decoder";export class UseSmileIDFlowBuilder{consentInformation;enhancedKYCParams;biometricKYCParams;documentVerificationParams;enhancedDocumentVerificationParams;residencyDocumentVerificationParams;userDetails;userId;localizations;onResult=()=>{};onAnalyticsEvent;_config;_theme;_network;_ml;_screens;config(i){this._config||(this._config=new c),i(this._config)}theme(i){this._theme=new m,i(this._theme)}network(i){this._network=new d,i(this._network)}ml(i){this._ml||(this._ml=new l),i(this._ml)}screens(i){this._screens||(this._screens=new u),i(this._screens)}validate(){return t.invalid(this.verdict().issues)}get isDebugModeEnabled(){return this._config?.build().enableDebugMode===!0}validateConsent(i){return t.invalid(P(i))}validateEnhancedKYCParams(i){return t.invalid(v(i))}validateBiometricKYCParams(i){return t.invalid(f(i))}validateDocumentVerificationParams(i){return t.invalid(D(i))}validateEnhancedDocumentVerificationParams(i){return t.invalid(V(i))}validateResidencyDocumentVerificationParams(i){return t.invalid(_(i))}build(){const{configuration:i,issues:e}=this.verdict(),s=t.invalid(e);if(!s.valid)return{kind:"invalid",validation:s};for(const n of e)n.severity===h.warning&&(console.warn(`[UseSmileIDFlowBuilder] ${n.message}`),n.suggestedFix&&console.warn(`[UseSmileIDFlowBuilder] Suggested fix: ${n.suggestedFix}`));if(!i)throw new Error("UseSmileIDFlowBuilder: internal invariant violated \u2014 screens missing after validation passed.");return{kind:"success",configuration:i}}verdict(){const i=this._screens?.build(),e=this._network?.build(),s=this._ml?.build(),n=this._config?.build(),o=C(n?.allowOfflineMode,e),r=g({steps:i?.steps??[],network:e,ml:s,consentInformation:this.consentInformation,enhancedKYCParams:this.enhancedKYCParams,biometricKYCParams:this.biometricKYCParams,documentVerificationParams:this.documentVerificationParams,enhancedDocumentVerificationParams:this.enhancedDocumentVerificationParams,residencyDocumentVerificationParams:this.residencyDocumentVerificationParams,userDetails:this.userDetails,userId:this.userId,tokenPayload:o,skipApiSubmission:n?.skipApiSubmission});return i?{configuration:Object.freeze({...this.consentInformation?{consentInformation:this.consentInformation}:{},...this.enhancedKYCParams?{enhancedKYCParams:this.enhancedKYCParams}:{},...this.biometricKYCParams?{biometricKYCParams:this.biometricKYCParams}:{},...this.documentVerificationParams?{documentVerificationParams:this.documentVerificationParams}:{},...this.enhancedDocumentVerificationParams?{enhancedDocumentVerificationParams:this.enhancedDocumentVerificationParams}:{},...this.residencyDocumentVerificationParams?{residencyDocumentVerificationParams:this.residencyDocumentVerificationParams}:{},...this.userDetails?{userDetails:this.userDetails}:{},...this.userId?{userId:this.userId}:{},...n?{config:n}:{},...this._theme?{theme:this._theme.build()}:{},...e?{network:e}:{},...s?{ml:s}:{},screens:i,...this.localizations?{localizations:this.localizations}:{},onResult:this.onResult,...this.onAnalyticsEvent?{onAnalyticsEvent:this.onAnalyticsEvent}:{}}),issues:r}:{configuration:void 0,issues:r}}}function C(a,i){if(a)return;const e=i?.config?.token;if(!(!e||e.length===0))return w(e)?.tokenPayload}
@@ -9,8 +9,8 @@ export declare const FlowFact: {
9
9
  };
10
10
  /** A fact the flow's routing reads. */
11
11
  export type FlowFact = (typeof FlowFact)[keyof typeof FlowFact];
12
- /** The busy reason while a skip-submission hand-over is under way. */
13
- export declare const HANDING_OVER = "handingOver";
12
+ /** The busy reason while a job is being submitted, or sealed for a skip-submission hand-over. */
13
+ export declare const SUBMITTING = "submitting";
14
14
  /** How the flow's step kinds and facts are named on the wire. */
15
15
  export declare const flowCodec: NjiaCodec<string, FlowFact>;
16
16
  /** The flow's screens as a njia graph, with each step resolving back to the screen it came from. */
@@ -23,8 +23,8 @@ export type FlowGraph = {
23
23
  * The screens as a graph. Steps are named `kind#ordinal`, so two equal screens, such as a document
24
24
  * and a selfie `preview {}`, are two steps. A document capture, with the preview that follows it, is a
25
25
  * segment that repeats while {@link FlowFact.supportingSidePending} holds, which captures and previews
26
- * the back or visa; skipping the back leaves the segment. Back is refused while a hand-over is under
27
- * way ({@link HANDING_OVER}) and once the job is the partner's ({@link FlowFact.jobHandedOver}).
26
+ * the back or visa; skipping the back leaves the segment. Back is refused while a job is being
27
+ * submitted ({@link SUBMITTING}) and once the job is the partner's ({@link FlowFact.jobHandedOver}).
28
28
  */
29
29
  export declare function toFlowGraph(screens: readonly ScreenSpec[]): FlowGraph;
30
30
  /** The graph's step for the partner screen added with `id`: `partner.<id>`, outside the SDK's own steps. */
@@ -1 +1 @@
1
- "use strict";import{allOf as c,guard as u,njiaCodec as w,njiaGraph as m,njiaSegment as v,njiaStep as f,stringWire as O,wireOfStrings as j}from"@smileid/njia";import{CaptureType as k}from"../../core/models/ml_config";export const FlowFact={supportingSidePending:"supportingSidePending",jobHandedOver:"jobHandedOver"},HANDING_OVER="handingOver",flowCodec=w(O,j(Object.values(FlowFact)));export function toFlowGraph(n){const a=new Map,i=new Map,p=e=>{if(e.kind==="partner"){const s=f(partnerStepId(e.config.id),"partner",{partner:!0});return i.set(s.id,e),s}const t=S(e),r=a.get(t)??0;a.set(t,r+1);const o=f(`${t}#${r}`,t);return i.set(o.id,e),o},d=[];let l=0;for(let e=0;e<n.length;){const t=n[e];if(g(t)){const r=n[e+1]?.kind==="preview"?n[e+1]:void 0,o=[p(t),...r?[p(r)]:[]];d.push(v(`document#${l++}`,o,{repeatWhile:c(FlowFact.supportingSidePending)})),e+=o.length}else d.push(p(t)),e+=1}const h=[u("back","hand-over under way",{whenBusy:[HANDING_OVER]}),u("back","the files are the partner's",{condition:c(FlowFact.jobHandedOver)})];return{graph:m(d,{guards:h}),screenOf:e=>{const t=i.get(e);if(t===void 0)throw new Error(`no screen for step ${e}`);return t}}}const g=n=>n.kind==="capture"&&n.config.captureType===k.document;function S(n){return n.kind==="capture"?g(n)?"capture.document":"capture.selfie":n.kind}export const partnerStepId=n=>`partner.${n}`;
1
+ "use strict";import{allOf as u,guard as c,njiaCodec as m,njiaGraph as w,njiaSegment as S,njiaStep as f,stringWire as b,wireOfStrings as j}from"@smileid/njia";import{CaptureType as k}from"../../core/models/ml_config";export const FlowFact={supportingSidePending:"supportingSidePending",jobHandedOver:"jobHandedOver"},SUBMITTING="submitting",flowCodec=m(b,j(Object.values(FlowFact)));export function toFlowGraph(e){const d=new Map,i=new Map,p=t=>{if(t.kind==="partner"){const a=f(partnerStepId(t.config.id),"partner",{partner:!0});return i.set(a.id,t),a}const n=v(t),r=d.get(n)??0;d.set(n,r+1);const o=f(`${n}#${r}`,n);return i.set(o.id,t),o},s=[];let l=0;for(let t=0;t<e.length;){const n=e[t];if(g(n)){const r=e[t+1]?.kind==="preview"?e[t+1]:void 0,o=[p(n),...r?[p(r)]:[]];s.push(S(`document#${l++}`,o,{repeatWhile:u(FlowFact.supportingSidePending)})),t+=o.length}else s.push(p(n)),t+=1}const h=[c("back","submission under way",{whenBusy:[SUBMITTING]}),c("back","the files are the partner's",{condition:u(FlowFact.jobHandedOver)})];return{graph:w(s,{guards:h}),screenOf:t=>{const n=i.get(t);if(n===void 0)throw new Error(`no screen for step ${t}`);return n}}}const g=e=>e.kind==="capture"&&e.config.captureType===k.document;function v(e){return e.kind==="capture"?g(e)?"capture.document":"capture.selfie":e.kind}export const partnerStepId=e=>`partner.${e}`;
@@ -1 +1 @@
1
- "use strict";import{File as g}from"expo-file-system";import{deleteImportedDocument as f}from"../../camera/core/imported_document_folder";import{JobType as k}from"../../core/models/job_type";import{CaptureType as d}from"../../core/models/ml_config";import{defaultFrameAspectRatio as v}from"./config/document_type";import{UseSmileIDMetadataFactory as C}from"../../metadata/use_smile_id_metadata_factory";import{decodeSmileIDToken as S}from"../../data/util/use_smile_id_token_decoder";import{isTokenConsentComplete as y}from"../../data/model/token_payload";import{UseSmileIDCrashReporting as w}from"@smileid/usesmileid_bridge";import{answerOf as b,NjiaException as P,NjiaIntents as h,NjiaKit as T,top as c}from"@smileid/njia";import{getNextScreen as D,nextIntent as F,sendFromTop as p,supportingDocumentSide as I,documentPreviewFollowsCapture as j}from"./flow_navigation_manager_routing";import{flowCodec as E,partnerStepId as x,toFlowGraph as N}from"./flow_navigation_graph";import{NavigationFailedException as O}from"../../core/exception/navigation_failed_exception";import{flowNavigationModule as R}from"./flow_navigation_engine";import{currentDocumentCaptureSide as B,currentDocumentPreviewBorderFraction as G,currentDocumentPreviewPath as M,currentPreviewIsDocument as A,documentBorderFraction as W,documentCapturesBack as J,recordDocumentImageOrigin as L,retakeCurrentDocumentSide as Q,setCapturedBackDocument as V,setCapturedFrontDocument as U,setCapturedVisaDocument as K,skipDocumentBack as q}from"./flow_navigation_manager_documents";import{logAnalyticsEvent as z,logKind as a,recordDocumentCaptureTelemetry as H,recordDocumentQualityWaiver as X,recordSelfieCaptureTelemetry as Y,screenViewedEvent as l}from"./flow_navigation_manager_analytics";import{beginSubmissionIfNeeded as Z,retrySubmission as $,submit as ee}from"./flow_navigation_manager_submission";import{markCapturedTake as te}from"../components/helpers/captured_image_uri";function _(u){return[u.frontDocumentPath,u.backDocumentPath,u.visaDocumentPath].filter(e=>e!==void 0)}export class FlowNavigationManager{_navigationPath=[];_flowGraph;_engine;_navigationStartFailure;_captured={livenessPaths:[]};_documentBackSkipped=!1;_documentBorderFractions=new Map;_documentImageOrigins=new Map;_selfieCaptureTelemetry;_documentCaptureTelemetry=new Map;_documentQualityWaivers=new Map;_cameraName;_devicePositions=[];_deviceMovementDetected=null;_selfieCaptureTakes=1;_selfieRetakeCounted=!1;_selfieCaptureStarted=!1;_jobSubmissionState={kind:"notAttempted"};_listeners=new Set;_steps;_configuration;_repository;_metadataProvider;_onExit;_disposed=!1;_submissionResponse;_capturedJob;_flowEnded=!1;resolvedSdkConfig;_resolvedPartnerId;_resolvedTokenPayload;get partnerId(){const e=this._resolvedPartnerId;return e&&e.length>0?e:this._configuration.network?.config?.partnerConfig?.partnerId??""}_sessionId;_submissionAttemptCount=0;constructor(e){this._configuration=e.configuration,this._onExit=e.onExit,this._repository=e.repository,this._metadataProvider=e.metadataProvider??new C,this._sessionId=this._metadataProvider.sessionId;const t=FlowNavigationManager._decodeToken(e.configuration);this.resolvedSdkConfig=t?.sdkConfig,this._resolvedPartnerId=t?.partnerId,this._resolvedTokenPayload=t?.tokenPayload;const i=e.configuration.screens.steps;this._steps=y(t?.tokenPayload?.consent)?i.filter(s=>s.kind!=="consent"):i,this._flowGraph=N(this._steps),this._engine=this._startEngine();const o=this._navigationPath[0];a(this,{kind:"flowStarted",jobType:this._jobType()}),o&&a(this,l(this,o))}get configuration(){return this._configuration}get enhancedLivenessEnabled(){return this._steps.some(e=>e.kind==="capture"&&e.config.selfieConfig?.enableEnhancedLiveness===!0)}get documentType(){for(const e of this._steps)if(e.kind==="capture"&&e.config.captureType===d.document)return e.config.documentConfig?.documentType}get instructionsDocumentType(){const e=this.currentScreen,t=e?this._steps.indexOf(e)+1:0,i=this._steps.slice(t).find(o=>o.kind==="capture");return i?.kind==="capture"&&i.config.captureType===d.document?i.config.documentConfig?.documentType:void 0}get documentFrameAspectRatio(){for(const e of this._steps)if(e.kind==="capture"&&e.config.captureType===d.document){const t=e.config.documentConfig;return t?.resolvedAspectRatio??v(t?.documentType?.orientation??"Landscape")}}get navigationPath(){return this._navigationPath}get currentScreen(){return this._navigationPath[this._navigationPath.length-1]}get currentDepth(){return this._navigationPath.length-1}get isFirstScreen(){return this._navigationPath.length<=1}get isLastScreen(){return this.getNextScreen()===void 0}getNextScreen(){return D(this)}navigateToNext(){this._moveOn(e=>F(this,e))}navigateToNextWith(e){this._moveOn(t=>h.answer(t.id,e))}partnerValue(e){const t=this._engine;return t?b(t.state,x(e)):void 0}_moveOn(e){if(this._disposed)return;const t=this._engine,i=t&&c(t.state)?p(this,e):void 0;if(t&&c(t.state)&&i===void 0)return;const o=i===void 0||i.effects.some(r=>r.kind==="pastEnd"),s=i?.effects.filter(r=>r.kind==="entered").at(-1);if(!o&&(s===void 0||!("entry"in s)))return;const n=s&&"entry"in s?this._flowGraph.screenOf(s.entry.step):void 0;if(!n){const r=this._jobSubmissionState;if(this._submissionResponse){this._finishFlow({kind:"completed",job:this._submissionResponse});return}if(r.kind==="failure"){this._finishFlow({kind:"failed",error:r.error});return}const m=r.kind==="success"?r.response:{userId:"",jobId:"",status:"",message:""};this._finishFlow({kind:"completed",job:m});return}a(this,l(this,n)),n.kind==="processing"&&this._jobSubmissionState.kind==="notAttempted"&&this._repository!==void 0&&(this._jobSubmissionState={kind:"loading"}),this._notify(),n.kind==="processing"&&this._jobSubmissionState.kind==="loading"&&this._repository!==void 0&&setTimeout(()=>{this._disposed||ee(this)},0)}navigateBack(){if(this._disposed)return;const e=this._engine;if(!e||!c(e.state)){this._finishFlow({kind:"cancelled"});return}const t=this.currentScreen,i=t?.kind,o=t?.kind==="capture"&&t.config.captureType===d.selfie&&this._selfieCaptureStarted,s=p(this,n=>h.back(n.id));if(s!==void 0){if(s.effects.some(n=>n.kind==="finished")){this._finishFlow({kind:"cancelled"});return}if(s.effects.some(n=>n.kind==="left")){(i==="capture"||i==="preview")&&a(this,{kind:"retakeRequested"});const n=this.currentScreen,r=n?.kind==="capture"&&n.config.captureType===d.selfie&&this._captured.selfiePath!==void 0;(o||r)&&(this._selfieCaptureTakes+=1),r&&(this._selfieRetakeCounted=!0),i==="capture"&&(this._selfieCaptureStarted=!1),this._notify()}}}navigateToStart(){if(this._disposed)return;const e=this._navigationPath;this._engine?.dispose(),this._engine=this._startEngine();const t=this._navigationPath;if(e.length!==t.length||e.some((i,o)=>i!==t[o])){const i=this._captured.selfiePath!==void 0;(this._selfieCaptureStarted||i&&!this._selfieRetakeCounted)&&(this._selfieCaptureTakes+=1),this._selfieRetakeCounted=i,this._selfieCaptureStarted=!1}this.deliverNavigationStartFailure(),this._notify()}_startEngine(){if(this._navigationStartFailure=void 0,this._navigationPath=[],this._flowGraph.graph.nodes.length===0)return;const e=R();let t;try{t=T.start(E,this._flowGraph.graph,e?{module:e}:{})}catch(i){if(!(i instanceof P))throw i;this._navigationStartFailure=i;return}return this._navigationPath=this._pathOf(t.state),t.addListener(i=>{this._navigationPath=this._pathOf(i.state)}),t}deliverNavigationStartFailure(){this._navigationStartFailure!==void 0&&this.failNavigation(this._navigationStartFailure)}failNavigation(e){if(!this._disposed){if(this._flowEnded){w.captureException(e);return}this._finishFlow({kind:"failed",error:new O({cause:e})})}}_pathOf(e){return e.entries.map(t=>this._flowGraph.screenOf(t.step))}exit(e={kind:"cancelled"}){this._disposed||e.kind!=="captured"&&this._finishFlow(e)}get captured(){return this._captured}get capturedJob(){return this._capturedJob}setCapturedSelfie(e,t){this._disposed||(te(e),this._captured={...this._captured,selfiePath:e,livenessPaths:Object.freeze([...t])},this._selfieRetakeCounted=!1,a(this,{kind:"selfieCaptured",livenessImageCount:t.length}),this._notify())}get selfieCaptureGeometry(){return this._selfieCaptureGeometry}_selfieCaptureGeometry;recordSelfieCaptureGeometry(e){e&&(this._selfieCaptureGeometry=e)}setCapturedFrontDocument(e,t=0){U(this,e,t)}setCapturedBackDocument(e,t=0){V(this,e,t)}supportingDocumentSide(){return I(this)}documentCapturesBack(){return J(this)}currentDocumentCaptureSide(){return B(this)}setCapturedVisaDocument(e,t=0){K(this,e,t)}documentPreviewFollowsCapture(){return j(this)}currentPreviewIsDocument(){return A(this)}currentDocumentPreviewPath(){return M(this)}documentBorderFraction(e){return W(this,e)}currentDocumentPreviewBorderFraction(){return G(this)}retakeCurrentDocumentSide(){Q(this)}skipDocumentBack(){q(this)}recordDocumentImageOrigin(e,t){L(this,e,t)}recordSelfieCaptureTelemetry(e){Y(this,e)}recordSelfieCaptureStarted(){this._disposed||(this._selfieCaptureStarted=!0)}recordSelfieUploadCheckRestart(){const e=this.currentScreen;this._disposed||e?.kind!=="capture"||e.config.captureType!==d.selfie||(this._selfieCaptureTakes+=1,this._selfieCaptureStarted=!1)}get selfieCaptureTakes(){return this._selfieCaptureTakes}recordDocumentCaptureTelemetry(e,t){H(this,e,t)}recordDocumentQualityWaiver(e,t){X(this,e,t)}documentQualityWaived(e){return this._documentQualityWaivers.get(e)}setConsent(e){this._disposed||(this._captured={...this._captured,consentInformation:e},a(this,{kind:"consentCaptured"}),this._notify())}get jobSubmissionState(){return this._jobSubmissionState}beginSubmissionIfNeeded(){Z(this)}retrySubmission(){$(this)}_setCaptured(e){const t=new Set(_(e));for(const i of _(this._captured))t.has(i)||f(i);this._captured=e}_deleteCapturedFiles(){if(this._configuration.config?.allowOfflineMode)return;const{selfiePath:e,livenessPaths:t,frontDocumentPath:i,backDocumentPath:o,visaDocumentPath:s}=this._captured;for(const n of[e,...t,i,o,s])if(n){try{const r=new g(n);r.exists&&r.delete()}catch{}f(n)}}_finishFlow(e){this._capturedJob!==void 0&&e.kind!=="captured"||(this._flowEnded=!0,e.kind!=="captured"&&this._deleteCapturedFiles(),e.kind==="completed"?a(this,e.job.jobId?{kind:"flowCompletedSuccess",jobId:e.job.jobId}:{kind:"flowCompletedSuccess"}):e.kind==="failed"&&a(this,{kind:"flowCompletedFailure",errorMessage:e.error instanceof Error?e.error.message:String(e.error)}),e.kind==="captured"&&a(this,{kind:"flowCompletedCaptured"}),this._onExit(e))}logAnalyticsEvent(e){z(this,e)}_jobType(){return this._configuration.network?.config?.jobType??k.unknown}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}dispose(){this._disposed||(this._disposed=!0,this._listeners.clear(),this._engine?.dispose(),this._engine=void 0)}static _decodeToken(e){if(e.config?.allowOfflineMode)return;const t=e.network?.config?.token;if(!(!t||t.length===0))return S(t)}_notify(){for(const e of this._listeners)try{e()}catch{}}}
1
+ "use strict";import{File as k}from"expo-file-system";import{deleteImportedDocument as h}from"../../camera/core/imported_document_folder";import{JobType as v}from"../../core/models/job_type";import{CaptureType as u}from"../../core/models/ml_config";import{defaultFrameAspectRatio as C}from"./config/document_type";import{UseSmileIDMetadataFactory as S}from"../../metadata/use_smile_id_metadata_factory";import{decodeSmileIDToken as y}from"../../data/util/use_smile_id_token_decoder";import{isTokenConsentComplete as w}from"../../data/model/token_payload";import{UseSmileIDCrashReporting as b}from"@smileid/usesmileid_bridge";import{answerOf as P,NjiaException as T,NjiaIntents as p,NjiaKit as D,top as f}from"@smileid/njia";import{getNextScreen as F,nextIntent as I,sendFromTop as l,supportingDocumentSide as j,documentPreviewFollowsCapture as E}from"./flow_navigation_manager_routing";import{flowCodec as x,partnerStepId as N,toFlowGraph as O}from"./flow_navigation_graph";import{NavigationFailedException as R}from"../../core/exception/navigation_failed_exception";import{flowNavigationModule as B}from"./flow_navigation_engine";import{currentDocumentCaptureSide as G,currentDocumentPreviewBorderFraction as M,currentDocumentPreviewPath as A,currentPreviewIsDocument as W,documentBorderFraction as J,documentCapturesBack as L,recordDocumentImageOrigin as Q,retakeCurrentDocumentSide as V,setCapturedBackDocument as K,setCapturedFrontDocument as U,setCapturedVisaDocument as q,skipDocumentBack as z}from"./flow_navigation_manager_documents";import{logAnalyticsEvent as H,logKind as o,recordDocumentCaptureTelemetry as X,recordDocumentQualityWaiver as Y,recordSelfieCaptureTelemetry as Z,screenViewedEvent as m}from"./flow_navigation_manager_analytics";import{beginSubmissionIfNeeded as $,retrySubmission as ee,submit as te}from"./flow_navigation_manager_submission";import{markCapturedTake as ie}from"../components/helpers/captured_image_uri";function _(c){return[c.frontDocumentPath,c.backDocumentPath,c.visaDocumentPath].filter(e=>e!==void 0)}export class FlowNavigationManager{_navigationPath=[];_flowGraph;_engine;_navigationStartFailure;_captured={livenessPaths:[]};_documentBackSkipped=!1;_documentBorderFractions=new Map;_documentImageOrigins=new Map;_selfieCaptureTelemetry;_documentCaptureTelemetry=new Map;_documentQualityWaivers=new Map;_cameraName;_devicePositions=[];_deviceMovementDetected=null;_selfieCaptureTakes=1;_selfieRetakeCounted=!1;_selfieCaptureStarted=!1;_jobSubmissionState={kind:"notAttempted"};_listeners=new Set;_steps;_configuration;_repository;_metadataProvider;_onExit;_disposed=!1;_submissionResponse;_capturedJob;_flowEnded=!1;resolvedSdkConfig;_resolvedPartnerId;_resolvedTokenPayload;get partnerId(){const e=this._resolvedPartnerId;return e&&e.length>0?e:this._configuration.network?.config?.partnerConfig?.partnerId??""}_sessionId;_submissionAttemptCount=0;constructor(e){this._configuration=e.configuration,this._onExit=e.onExit,this._repository=e.repository,this._metadataProvider=e.metadataProvider??new S,this._sessionId=this._metadataProvider.sessionId;const t=FlowNavigationManager._decodeToken(e.configuration);this.resolvedSdkConfig=t?.sdkConfig,this._resolvedPartnerId=t?.partnerId,this._resolvedTokenPayload=t?.tokenPayload;const i=e.configuration.screens.steps;this._steps=w(t?.tokenPayload?.consent)?i.filter(r=>r.kind!=="consent"):i,this._flowGraph=O(this._steps),this._engine=this._startEngine();const s=this._navigationPath[0];o(this,{kind:"flowStarted",jobType:this._jobType()}),s&&o(this,m(this,s))}get configuration(){return this._configuration}get enhancedLivenessEnabled(){return this._steps.some(e=>e.kind==="capture"&&e.config.selfieConfig?.enableEnhancedLiveness===!0)}get documentType(){for(const e of this._steps)if(e.kind==="capture"&&e.config.captureType===u.document)return e.config.documentConfig?.documentType}get instructionsDocumentType(){const e=this.currentScreen,t=e?this._steps.indexOf(e)+1:0,i=this._steps.slice(t).find(s=>s.kind==="capture");return i?.kind==="capture"&&i.config.captureType===u.document?i.config.documentConfig?.documentType:void 0}get documentFrameAspectRatio(){for(const e of this._steps)if(e.kind==="capture"&&e.config.captureType===u.document){const t=e.config.documentConfig;return t?.resolvedAspectRatio??C(t?.documentType?.orientation??"Landscape")}}get navigationPath(){return this._navigationPath}get currentScreen(){return this._navigationPath[this._navigationPath.length-1]}get currentDepth(){return this._navigationPath.length-1}get isFirstScreen(){return this._navigationPath.length<=1}get isLastScreen(){return this.getNextScreen()===void 0}getNextScreen(){return F(this)}navigateToNext(){this._moveOn(e=>I(this,e))}navigateToNextWith(e){this._moveOn(t=>p.answer(t.id,e))}partnerValue(e){const t=this._engine;return t?P(t.state,N(e)):void 0}_moveOn(e){if(this._disposed)return;const t=this._engine,i=t&&f(t.state)?l(this,e):void 0;if(t&&f(t.state)&&i===void 0)return;const s=i===void 0||i.effects.some(d=>d.kind==="pastEnd"),r=i?.effects.filter(d=>d.kind==="entered").at(-1);if(!s&&(r===void 0||!("entry"in r)))return;const n=r&&"entry"in r?this._flowGraph.screenOf(r.entry.step):void 0;if(!n){const d=this._jobSubmissionState;if(this._submissionResponse){this._finishFlow({kind:"completed",job:this._submissionResponse});return}if(d.kind==="failure"){this._finishFlow({kind:"failed",error:d.error});return}const g=d.kind==="success"?d.response:{userId:"",jobId:"",status:"",message:""};this._finishFlow({kind:"completed",job:g});return}o(this,m(this,n));const a=this._jobSubmissionState.kind;n.kind==="processing"&&(a==="notAttempted"||a==="failure")&&this._repository!==void 0&&(this._jobSubmissionState={kind:"loading"}),this._notify(),n.kind==="processing"&&this._jobSubmissionState.kind==="loading"&&this._repository!==void 0&&setTimeout(()=>{this._disposed||te(this)},0)}navigateBack(){if(this._disposed)return;const e=this._engine;if(!e||!f(e.state)){this._finishFlow({kind:"cancelled"});return}const t=this.currentScreen,i=t?.kind,s=t?.kind==="capture"&&t.config.captureType===u.selfie&&this._selfieCaptureStarted,r=l(this,n=>p.back(n.id));if(r!==void 0){if(r.effects.some(n=>n.kind==="finished")){this._finishFlow({kind:"cancelled"});return}if(r.effects.some(n=>n.kind==="left")){(i==="capture"||i==="preview")&&o(this,{kind:"retakeRequested"});const n=this.currentScreen,a=n?.kind==="capture"&&n.config.captureType===u.selfie&&this._captured.selfiePath!==void 0;(s||a)&&(this._selfieCaptureTakes+=1),a&&(this._selfieRetakeCounted=!0),i==="capture"&&(this._selfieCaptureStarted=!1),this._notify()}}}navigateToStart(){if(this._disposed)return;const e=this._navigationPath;this._engine?.dispose(),this._engine=this._startEngine();const t=this._navigationPath;if(e.length!==t.length||e.some((i,s)=>i!==t[s])){const i=this._captured.selfiePath!==void 0;(this._selfieCaptureStarted||i&&!this._selfieRetakeCounted)&&(this._selfieCaptureTakes+=1),this._selfieRetakeCounted=i,this._selfieCaptureStarted=!1}this.deliverNavigationStartFailure(),this._notify()}_startEngine(){if(this._navigationStartFailure=void 0,this._navigationPath=[],this._flowGraph.graph.nodes.length===0)return;const e=B();let t;try{t=D.start(x,this._flowGraph.graph,e?{module:e}:{})}catch(i){if(!(i instanceof T))throw i;this._navigationStartFailure=i;return}return this._navigationPath=this._pathOf(t.state),t.addListener(i=>{this._navigationPath=this._pathOf(i.state)}),t}deliverNavigationStartFailure(){this._navigationStartFailure!==void 0&&this.failNavigation(this._navigationStartFailure)}failNavigation(e){if(!this._disposed){if(this._flowEnded){b.captureException(e);return}this._finishFlow({kind:"failed",error:new R({cause:e})})}}_pathOf(e){return e.entries.map(t=>this._flowGraph.screenOf(t.step))}exit(e={kind:"cancelled"}){this._disposed||e.kind!=="captured"&&this._finishFlow(e)}get captured(){return this._captured}get capturedJob(){return this._capturedJob}setCapturedSelfie(e,t){this._disposed||(ie(e),this._captured={...this._captured,selfiePath:e,livenessPaths:Object.freeze([...t])},this._selfieRetakeCounted=!1,o(this,{kind:"selfieCaptured",livenessImageCount:t.length}),this._notify())}get selfieCaptureGeometry(){return this._selfieCaptureGeometry}_selfieCaptureGeometry;recordSelfieCaptureGeometry(e){e&&(this._selfieCaptureGeometry=e)}setCapturedFrontDocument(e,t=0){U(this,e,t)}setCapturedBackDocument(e,t=0){K(this,e,t)}supportingDocumentSide(){return j(this)}documentCapturesBack(){return L(this)}currentDocumentCaptureSide(){return G(this)}setCapturedVisaDocument(e,t=0){q(this,e,t)}documentPreviewFollowsCapture(){return E(this)}currentPreviewIsDocument(){return W(this)}currentDocumentPreviewPath(){return A(this)}documentBorderFraction(e){return J(this,e)}currentDocumentPreviewBorderFraction(){return M(this)}retakeCurrentDocumentSide(){V(this)}skipDocumentBack(){z(this)}recordDocumentImageOrigin(e,t){Q(this,e,t)}recordSelfieCaptureTelemetry(e){Z(this,e)}recordSelfieCaptureStarted(){this._disposed||(this._selfieCaptureStarted=!0)}recordSelfieUploadCheckRestart(){const e=this.currentScreen;this._disposed||e?.kind!=="capture"||e.config.captureType!==u.selfie||(this._selfieCaptureTakes+=1,this._selfieCaptureStarted=!1)}get selfieCaptureTakes(){return this._selfieCaptureTakes}recordDocumentCaptureTelemetry(e,t){X(this,e,t)}recordDocumentQualityWaiver(e,t){Y(this,e,t)}documentQualityWaived(e){return this._documentQualityWaivers.get(e)}setConsent(e){this._disposed||(this._captured={...this._captured,consentInformation:e},o(this,{kind:"consentCaptured"}),this._notify())}get jobSubmissionState(){return this._jobSubmissionState}beginSubmissionIfNeeded(){$(this)}retrySubmission(){ee(this)}_setCaptured(e){const t=new Set(_(e));for(const i of _(this._captured))t.has(i)||h(i);this._captured=e}_deleteCapturedFiles(){if(this._configuration.config?.allowOfflineMode)return;const{selfiePath:e,livenessPaths:t,frontDocumentPath:i,backDocumentPath:s,visaDocumentPath:r}=this._captured;for(const n of[e,...t,i,s,r])if(n){try{const a=new k(n);a.exists&&a.delete()}catch{}h(n)}}_finishFlow(e){this._capturedJob!==void 0&&e.kind!=="captured"||(this._flowEnded=!0,e.kind!=="captured"&&this._deleteCapturedFiles(),e.kind==="completed"?o(this,e.job.jobId?{kind:"flowCompletedSuccess",jobId:e.job.jobId}:{kind:"flowCompletedSuccess"}):e.kind==="failed"&&o(this,{kind:"flowCompletedFailure",errorMessage:e.error instanceof Error?e.error.message:String(e.error)}),e.kind==="captured"&&o(this,{kind:"flowCompletedCaptured"}),this._onExit(e))}logAnalyticsEvent(e){H(this,e)}_jobType(){return this._configuration.network?.config?.jobType??v.unknown}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}dispose(){this._disposed||(this._disposed=!0,this._listeners.clear(),this._engine?.dispose(),this._engine=void 0)}static _decodeToken(e){if(e.config?.allowOfflineMode)return;const t=e.network?.config?.token;if(!(!t||t.length===0))return y(t)}_notify(){for(const e of this._listeners)try{e()}catch{}}}
@@ -1 +1 @@
1
- "use strict";import{isBusy as a,NjiaException as l,NjiaIntents as c,top as s}from"@smileid/njia";import{FlowFact as k,HANDING_OVER as _}from"./flow_navigation_graph";import{JobType as m}from"../../core/models/job_type";import{CaptureType as r}from"../../core/models/ml_config";import{DocumentSide as u}from"@smileid/usesmileid_bridge";export function getNextScreen(e){const t=e._engine,n=t?s(t.state):void 0;if(!t||!n)return;syncNavigationState(e);const i=t.preview(nextIntent(e,n)).effects.filter(o=>o.kind==="entered").at(-1);return i&&"entry"in i?e._flowGraph.screenOf(i.entry.step):void 0}export function sendFromTop(e,t){const n=e._engine,i=n?s(n.state):void 0;if(!(!n||!i))try{syncNavigationState(e);const o=s(n.state);return o?n.send(t(o)):void 0}catch(o){if(!(o instanceof l))throw o;e.failNavigation(o);return}}export function syncNavigationState(e){const t=e._engine;if(!t)return;const n=flowFacts(e),i=t.state.facts,o=[...n].filter(d=>!i.has(d)),f=[...i].filter(d=>!n.has(d));(o.length>0||f.length>0)&&t.send(c.facts(o,f));const p=e._configuration.config?.skipApiSubmission===!0&&e._jobSubmissionState.kind==="loading";p&&!a(t.state)&&t.send(c.busy(_)),!p&&a(t.state)&&t.send(c.idle())}export function nextIntent(e,t){const n=e._flowGraph.screenOf(t.step),i=n.kind==="capture"&&n.config.captureType===r.document;return e._documentBackSkipped&&i?c.skip(t.id):c.next(t.id)}export function flowFacts(e){const t=new Set;return e.supportingDocumentSide()!==void 0&&e._captured.frontDocumentPath!==void 0&&capturedSupportingDocument(e)===void 0&&!e._documentBackSkipped&&t.add(k.supportingSidePending),e._capturedJob!==void 0&&t.add(k.jobHandedOver),t}export function supportingDocumentSide(e){if(e._configuration.network?.config?.jobType===m.residencyDocumentVerification)return u.Visa;for(const t of e._steps)if(t.kind==="capture"&&t.config.captureType===r.document){const n=t.config.documentConfig;return n?.documentType?.hasBackSide===!0&&(n?.captureBothSides??!1)?u.Back:void 0}}export function capturedSupportingDocument(e){switch(e.supportingDocumentSide()){case u.Visa:return e._captured.visaDocumentPath;case u.Back:return e._captured.backDocumentPath;default:return}}export function documentPreviewFollowsCapture(e){const t=e._steps.findIndex(n=>n.kind==="capture"&&n.config.captureType===r.document);return t<0?!1:e._steps[t+1]?.kind==="preview"}export function precedingStepIsDocumentCapture(e,t){const n=e._steps[t-1];return n?.kind==="capture"&&n.config.captureType===r.document}
1
+ "use strict";import{isBusy as a,NjiaException as l,NjiaIntents as c,top as s}from"@smileid/njia";import{FlowFact as k,SUBMITTING as m}from"./flow_navigation_graph";import{JobType as S}from"../../core/models/job_type";import{CaptureType as r}from"../../core/models/ml_config";import{DocumentSide as u}from"@smileid/usesmileid_bridge";export function getNextScreen(e){const t=e._engine,n=t?s(t.state):void 0;if(!t||!n)return;syncNavigationState(e);const i=t.preview(nextIntent(e,n)).effects.filter(o=>o.kind==="entered").at(-1);return i&&"entry"in i?e._flowGraph.screenOf(i.entry.step):void 0}export function sendFromTop(e,t){const n=e._engine,i=n?s(n.state):void 0;if(!(!n||!i))try{syncNavigationState(e);const o=s(n.state);return o?n.send(t(o)):void 0}catch(o){if(!(o instanceof l))throw o;e.failNavigation(o);return}}export function syncNavigationState(e){const t=e._engine;if(!t)return;const n=flowFacts(e),i=t.state.facts,o=[...n].filter(d=>!i.has(d)),f=[...i].filter(d=>!n.has(d));(o.length>0||f.length>0)&&t.send(c.facts(o,f));const p=e._jobSubmissionState.kind==="loading";p&&!a(t.state)&&t.send(c.busy(m)),!p&&a(t.state)&&t.send(c.idle())}export function nextIntent(e,t){const n=e._flowGraph.screenOf(t.step),i=n.kind==="capture"&&n.config.captureType===r.document;return e._documentBackSkipped&&i?c.skip(t.id):c.next(t.id)}export function flowFacts(e){const t=new Set;return e.supportingDocumentSide()!==void 0&&e._captured.frontDocumentPath!==void 0&&capturedSupportingDocument(e)===void 0&&!e._documentBackSkipped&&t.add(k.supportingSidePending),e._capturedJob!==void 0&&t.add(k.jobHandedOver),t}export function supportingDocumentSide(e){if(e._configuration.network?.config?.jobType===S.residencyDocumentVerification)return u.Visa;for(const t of e._steps)if(t.kind==="capture"&&t.config.captureType===r.document){const n=t.config.documentConfig;return n?.documentType?.hasBackSide===!0&&(n?.captureBothSides??!1)?u.Back:void 0}}export function capturedSupportingDocument(e){switch(e.supportingDocumentSide()){case u.Visa:return e._captured.visaDocumentPath;case u.Back:return e._captured.backDocumentPath;default:return}}export function documentPreviewFollowsCapture(e){const t=e._steps.findIndex(n=>n.kind==="capture"&&n.config.captureType===r.document);return t<0?!1:e._steps[t+1]?.kind==="preview"}export function precedingStepIsDocumentCapture(e,t){const n=e._steps[t-1];return n?.kind==="capture"&&n.config.captureType===r.document}
@@ -1 +1 @@
1
- "use strict";import{jsx as A}from"react/jsx-runtime";import{useEffect as W,useState as P}from"react";import{StyleSheet as Q,View as j}from"react-native";import{AnalyzerNotFoundException as J,CaptureReadyEventKind as B,DeviceIntegrityProvider as $,DocumentSide as d,ImageType as F}from"@smileid/usesmileid_bridge";import{CameraLens as q}from"../../../camera/core/camera_lens";import{KameraConfigFactory as X}from"../../../camera/core/kamera_config_factory";import{CaptureType as i}from"../../../core/models/ml_config";import{defaultFrameAspectRatio as Y,documentFrameOrientation as Z}from"../config/document_type";import{SmileExifTagger as z}from"@smileid/usesmileid_bridge/exif/smile_exif_tagger";import{resolveDeviceModel as N}from"../../../metadata/use_smile_id_metadata_factory";import{claimAnalyzer as V,isMissingAnalyzerError as M,releaseAnalyzer as ee}from"./helpers/analyzer_lifecycle";import{resolveFaceSessionConfig as te}from"./helpers/face_session_config";import{useCaptureOrientationLock as oe}from"../../screen/helpers/use_capture_orientation_lock";import{localizedDocumentName as re}from"../../screen/helpers/instructions_screen_helpers";import{resolveJpegQuality as ne}from"../../../data/model/sdk_config_capture";import{AttributionResolver as ie,flowShowAttribution as E}from"../config/attribution_resolver";import{UseSmileIDCaptureScreen as se}from"../../screen/use_smile_id_capture_screen";import{cameraExceptionFromKameraError as ce}from"../../../camera/core/kamera_error_mapping";import{defaultLightTheme as ue}from"../../theme/theme";import{UseSmileIDDocumentBackInstructions as le}from"../../screen/use_smile_id_document_back_instructions";import{UseSmileIDInstructionsScreen as de}from"../../screen/use_smile_id_instructions_screen";import{DOCUMENT_HERO_VISA_ANIMATION as ae,documentGuidelines as me}from"../model/instructions_defaults";import{useUseSmileIDLocalizations as fe}from"../../../l10n/use_smile_id_localizations_provider";import{useFlowNavigation as pe}from"../flow_navigation_context";import{UseSmileIDOrchestratedScreenHost as ye}from"./use_smile_id_orchestrated_screen_host";export function OrchestratedCaptureScreen({configuration:s}){const n=pe(),C=fe(),t=s.captureType,f=s.documentConfig,p=f?.documentType,h=n.supportingDocumentSide(),k=h!==void 0,g=f?.allowSkipBack??!1,b=n.documentPreviewFollowsCapture(),O=n.captured.frontDocumentPath!==void 0,[o,L]=P(k&&O&&h!==void 0?h:d.Front),[U,w]=P(k&&O),R=n.configuration.config?.exitOrientations,K=t===i.document&&!U?Z(p,f?.resolvedAspectRatio):"Portrait",_=oe(K,{...R!==void 0?{exitLock:R}:{}}),c=t===i.selfie?n.configuration.ml?.analyzers.selfie:n.configuration.ml?.analyzers.document;return W(()=>{if(!c)return;let e=!1;const D=u=>{e||n.exit({kind:"failed",error:M(u)?new J({captureType:c.kind,cause:u,suggestedFix:"This build leaves that analyzer out. Pick with UseSmileIDMobileServices.analyzerProvider(), or keep the analyzer in this store's flavor."}):u})};let l=0;if(t===i.selfie&&c.kind==="face"){const u=n.configuration.ml?.analyzers.selfieConfig??{analyzerFactoryKey:c.key};l=V(()=>c.configure(te(u,s.selfieConfig?.enableEnhancedLiveness??!1,n.resolvedSdkConfig)),D)}else if(t===i.document&&c.kind==="document"){const u=ne(n.resolvedSdkConfig?.document),r=X.create(i.document,q.back).analysis,a=s.documentConfig?.documentType?.kind,S=s.documentConfig?.resolvedAspectRatio,I=S!==void 0&&Number.isFinite(S)&&S>0?S:void 0;l=V(()=>c.configure({documentSide:o,...u!==void 0?{documentJpegQuality:u}:{},...a!==void 0?{documentKind:a}:{},...I!==void 0?{knownAspectRatio:I}:{},sessionFrameWidth:r.targetWidth,sessionFrameHeight:r.targetHeight}),D)}return()=>{e=!0,ee(l,c)}},[c,t,n,s,o]),A(ye,{content:({navigationManager:e,onBack:D,onNavigateNext:l})=>{if(!c)throw new Error(`OrchestratedCaptureScreen: no ${t} analyzer registered in the ML DSL`);if(t===i.document&&k&&U){const r=()=>{if(b){D();return}w(!1),L(d.Front)};return o===d.Visa?A(de,{titlePrefix:C.siInstructionsTitlePrefix,titleEmphasis:C.siInstructionsEmphasisVisa,heroSource:ae,guidelinesSectionTitle:C.siInstructionsCaptureGuidelines,guidelines:me(p),showAttribution:E(e.configuration),showHeroOval:!1,showHeroOvalProgress:!1,showCardBackground:!0,onContinue:()=>w(!1),onBack:r}):A(le,{documentTypeDisplayName:p?re(p,C):"",allowSkip:g,showAttribution:E(e.configuration),onCaptureBack:()=>w(!1),onSkip:()=>{e.skipDocumentBack(),l()},onBack:r})}const u=e.configuration.theme?.light??ue;return _?A(se,{captureType:t,analyzer:c,onAnalyticsEvent:r=>e.logAnalyticsEvent(r),...t===i.selfie?{onStartCapture:()=>e.recordSelfieCaptureStarted(),onUploadCheckRetake:()=>e.recordSelfieUploadCheckRestart()}:{},theme:u,enableEnhancedLiveness:s.selfieConfig?.enableEnhancedLiveness??!1,allowAgentMode:s.selfieConfig?.allowAgentMode??!1,showAttribution:ie.resolveForCapture({captureType:t,showAttribution:E(e.configuration)}),...t===i.document&&f?{knownIdAspectRatio:f.resolvedAspectRatio??Y(p?.orientation??"Landscape"),captureMode:f.captureMode,allowGalleryUpload:f.allowGalleryUpload,documentSide:o,...p?.kind?{documentTypeKind:p.kind}:{},onDocumentOrigin:r=>e.recordDocumentImageOrigin(o,r),onClose:()=>e.exit()}:{},...s.startButton!==void 0?{startButton:s.startButton}:{},onBack:()=>{if(t===i.document&&k&&o!==d.Front){w(!0);return}D()},onCameraError:(r,a)=>{e.exit({kind:"failed",error:ce(r,a)})},onCaptureComplete:(r,a,S,I)=>{const T=S??0,y=Ce(r,t);if(!y)return;const H=e.partnerId,G=t===i.selfie?F.Selfie:o===d.Visa?F.DocumentVisa:o===d.Back?F.DocumentBack:F.DocumentFront,v=r.filter(m=>m.kind===B.Liveness).map(m=>m.url),x=N();$.signals().then(({fingerprint:m})=>z.setContext({partnerId:H,...x?{deviceModel:x}:{},...m?{fingerprint:m}:{}})).then(async()=>{await z.finalize(y,G),await Promise.all(v.map(m=>z.finalize(m,F.Liveness)))}).catch(()=>{}).finally(async()=>{if(t===i.selfie){e.setCapturedSelfie(y,v),e.recordSelfieCaptureGeometry(I),e.recordSelfieCaptureTelemetry(a),l();return}if(e.recordDocumentCaptureTelemetry(o,a),e.recordDocumentQualityWaiver(o,a.qualityWaived),k&&h!==void 0&&o===d.Front){e.setCapturedFrontDocument(y,T),b?l():(L(h),w(!0));return}if(o===d.Visa){e.setCapturedVisaDocument(y,T),l();return}if(k&&o===d.Back){e.setCapturedBackDocument(y,T),l();return}e.setCapturedFrontDocument(y,T),l()})}},t===i.document?`document-capture-${o}`:"capture"):A(j,{style:[Q.absoluteFill,{backgroundColor:u.colors.offBlack}],testID:"si_capture_orientation_pending"})}})}function Ce(s,n){const C=n===i.selfie?B.Selfie:B.Document;return s.find(t=>t.kind===C)?.url}
1
+ "use strict";import{jsx as T}from"react/jsx-runtime";import{useEffect as G,useState as R}from"react";import{StyleSheet as W,View as Q}from"react-native";import{AnalyzerNotFoundException as j,CaptureReadyEventKind as x,DeviceIntegrityProvider as J,DocumentSide as u,ImageType as A}from"@smileid/usesmileid_bridge";import{CameraLens as $}from"../../../camera/core/camera_lens";import{KameraConfigFactory as q}from"../../../camera/core/kamera_config_factory";import{CaptureType as n}from"../../../core/models/ml_config";import{defaultFrameAspectRatio as X,documentFrameOrientation as Y}from"../config/document_type";import{SmileExifTagger as B}from"@smileid/usesmileid_bridge/exif/smile_exif_tagger";import{resolveDeviceModel as Z}from"../../../metadata/use_smile_id_metadata_factory";import{claimAnalyzer as P,isMissingAnalyzerError as M,releaseAnalyzer as ee}from"./helpers/analyzer_lifecycle";import{resolveFaceSessionConfig as te}from"./helpers/face_session_config";import{useCaptureOrientationLock as oe}from"../../screen/helpers/use_capture_orientation_lock";import{localizedDocumentName as re}from"../../screen/helpers/instructions_screen_helpers";import{resolveJpegQuality as ie}from"../../../data/model/sdk_config_capture";import{AttributionResolver as ne,flowShowAttribution as z}from"../config/attribution_resolver";import{UseSmileIDCaptureScreen as se}from"../../screen/use_smile_id_capture_screen";import{cameraExceptionFromKameraError as ce}from"../../../camera/core/kamera_error_mapping";import{defaultLightTheme as ue}from"../../theme/theme";import{UseSmileIDDocumentBackInstructions as le}from"../../screen/use_smile_id_document_back_instructions";import{UseSmileIDInstructionsScreen as de}from"../../screen/use_smile_id_instructions_screen";import{DOCUMENT_HERO_VISA_ANIMATION as ae,documentGuidelines as me}from"../model/instructions_defaults";import{useUseSmileIDLocalizations as fe}from"../../../l10n/use_smile_id_localizations_provider";import{useFlowNavigation as pe}from"../flow_navigation_context";import{UseSmileIDOrchestratedScreenHost as ye,useWhileOnTop as Ce}from"./use_smile_id_orchestrated_screen_host";export function OrchestratedCaptureScreen({configuration:s}){const r=pe(),F=Ce(r),y=fe(),o=s.captureType,a=s.documentConfig,m=a?.documentType,h=r.supportingDocumentSide(),C=h!==void 0,g=a?.allowSkipBack??!1,E=r.documentPreviewFollowsCapture(),O=r.captured.frontDocumentPath!==void 0,[i,b]=R(C&&O&&h!==void 0?h:u.Front),[v,w]=R(C&&O),L=r.configuration.config?.exitOrientations,V=o===n.document&&!v?Y(m,a?.resolvedAspectRatio):"Portrait",K=oe(V,{...L!==void 0?{exitLock:L}:{}}),c=o===n.selfie?r.configuration.ml?.analyzers.selfie:r.configuration.ml?.analyzers.document;return G(()=>{if(!c)return;let e=!1;const D=t=>{e||r.exit({kind:"failed",error:M(t)?new j({captureType:c.kind,cause:t,suggestedFix:"This build leaves that analyzer out. Pick with UseSmileIDMobileServices.analyzerProvider(), or keep the analyzer in this store's flavor."}):t})};let k=0;if(o===n.selfie&&c.kind==="face"){const t=r.configuration.ml?.analyzers.selfieConfig??{analyzerFactoryKey:c.key};k=P(()=>c.configure(te(t,s.selfieConfig?.enableEnhancedLiveness??!1,r.resolvedSdkConfig)),D)}else if(o===n.document&&c.kind==="document"){const t=ie(r.resolvedSdkConfig?.document),l=q.create(n.document,$.back).analysis,I=s.documentConfig?.documentType?.kind,S=s.documentConfig?.resolvedAspectRatio,f=S!==void 0&&Number.isFinite(S)&&S>0?S:void 0;k=P(()=>c.configure({documentSide:i,...t!==void 0?{documentJpegQuality:t}:{},...I!==void 0?{documentKind:I}:{},...f!==void 0?{knownAspectRatio:f}:{},sessionFrameWidth:l.targetWidth,sessionFrameHeight:l.targetHeight}),D)}return()=>{e=!0,ee(k,c)}},[c,o,r,s,i]),T(ye,{content:({navigationManager:e,onBack:D})=>{if(!c)throw new Error(`OrchestratedCaptureScreen: no ${o} analyzer registered in the ML DSL`);if(o===n.document&&C&&v){const t=()=>{if(E){D();return}w(!1),b(u.Front)};return i===u.Visa?T(de,{titlePrefix:y.siInstructionsTitlePrefix,titleEmphasis:y.siInstructionsEmphasisVisa,heroSource:ae,guidelinesSectionTitle:y.siInstructionsCaptureGuidelines,guidelines:me(m),showAttribution:z(e.configuration),showHeroOval:!1,showHeroOvalProgress:!1,showCardBackground:!0,onContinue:()=>w(!1),onBack:t}):T(le,{documentTypeDisplayName:m?re(m,y):"",allowSkip:g,showAttribution:z(e.configuration),onCaptureBack:()=>w(!1),onSkip:()=>{F(()=>{e.skipDocumentBack(),e.navigateToNext()})},onBack:t})}const k=e.configuration.theme?.light??ue;return K?T(se,{captureType:o,analyzer:c,onAnalyticsEvent:t=>e.logAnalyticsEvent(t),...o===n.selfie?{onStartCapture:()=>e.recordSelfieCaptureStarted(),onUploadCheckRetake:()=>e.recordSelfieUploadCheckRestart()}:{},theme:k,enableEnhancedLiveness:s.selfieConfig?.enableEnhancedLiveness??!1,allowAgentMode:s.selfieConfig?.allowAgentMode??!1,showAttribution:ne.resolveForCapture({captureType:o,showAttribution:z(e.configuration)}),...o===n.document&&a?{knownIdAspectRatio:a.resolvedAspectRatio??X(m?.orientation??"Landscape"),captureMode:a.captureMode,allowGalleryUpload:a.allowGalleryUpload,documentSide:i,...m?.kind?{documentTypeKind:m.kind}:{},onDocumentOrigin:t=>e.recordDocumentImageOrigin(i,t),onClose:()=>e.exit()}:{},...s.startButton!==void 0?{startButton:s.startButton}:{},onBack:()=>{if(o===n.document&&C&&i!==u.Front){w(!0);return}D()},onCameraError:(t,l)=>{e.exit({kind:"failed",error:ce(t,l)})},onCaptureComplete:(t,l,I,S)=>{const f=I??0,p=ke(t,o);if(!p)return;const _=e.partnerId,H=o===n.selfie?A.Selfie:i===u.Visa?A.DocumentVisa:i===u.Back?A.DocumentBack:A.DocumentFront,U=t.filter(d=>d.kind===x.Liveness).map(d=>d.url),N=Z();J.signals().then(({fingerprint:d})=>B.setContext({partnerId:_,...N?{deviceModel:N}:{},...d?{fingerprint:d}:{}})).then(async()=>{await B.finalize(p,H),await Promise.all(U.map(d=>B.finalize(d,A.Liveness)))}).catch(()=>{}).finally(()=>F(()=>{if(o===n.selfie){e.setCapturedSelfie(p,U),e.recordSelfieCaptureGeometry(S),e.recordSelfieCaptureTelemetry(l),e.navigateToNext();return}if(e.recordDocumentCaptureTelemetry(i,l),e.recordDocumentQualityWaiver(i,l.qualityWaived),C&&h!==void 0&&i===u.Front){e.setCapturedFrontDocument(p,f),E?e.navigateToNext():(b(h),w(!0));return}i===u.Visa?e.setCapturedVisaDocument(p,f):C&&i===u.Back?e.setCapturedBackDocument(p,f):e.setCapturedFrontDocument(p,f),e.navigateToNext()}))}},o===n.document?`document-capture-${i}`:"capture"):T(Q,{style:[W.absoluteFill,{backgroundColor:k.colors.offBlack}],testID:"si_capture_orientation_pending"})}})}function ke(s,r){const F=r===n.selfie?x.Selfie:x.Document;return s.find(y=>y.kind===F)?.url}
@@ -1 +1 @@
1
- "use strict";import{jsx as n}from"react/jsx-runtime";import{UseSmileIDCrashReporting as p}from"@smileid/usesmileid_bridge";import{ConsentDeniedException as c}from"../../../core/exception";import{GlobalPrivacyControl as s}from"../config/global_privacy_control";import{flowShowAttribution as i}from"../config/attribution_resolver";import{UseSmileIDConsentScreen as a}from"../../screen/use_smile_id_consent_screen";import{UseSmileIDOrchestratedScreenHost as d}from"./use_smile_id_orchestrated_screen_host";import{alwaysEnabledSlot as y}from"./helpers/always_enabled_slot";export function OrchestratedConsentScreen({configuration:r}){const e=y(r.denyButton);return n(d,{content:({navigationManager:t,onNavigateNext:l})=>n(a,{partnerName:r.partnerName,globalPrivacyControl:t.configuration.config?.globalPrivacyControl??s.OptOut,...r.partnerIcon!==void 0?{partnerIcon:r.partnerIcon}:{},...r.partnerPrivacyPolicyUrl!==void 0?{partnerPrivacyPolicyUrl:r.partnerPrivacyPolicyUrl}:{},showAttribution:i(t.configuration),...r.allowButton?{allowButton:r.allowButton}:{},...e!==void 0?{denyButton:e}:{},onAllow:o=>{t.setConsent(o);try{r.onConsentGranted?.(o)}catch(m){p.captureException(m)}l()},onDeny:()=>{t.exit({kind:"failed",error:new c({timestamp:Date.now()})})}})})}
1
+ "use strict";import{jsx as n}from"react/jsx-runtime";import{UseSmileIDCrashReporting as m}from"@smileid/usesmileid_bridge";import{ConsentDeniedException as s}from"../../../core/exception";import{GlobalPrivacyControl as i}from"../config/global_privacy_control";import{flowShowAttribution as c}from"../config/attribution_resolver";import{UseSmileIDConsentScreen as a}from"../../screen/use_smile_id_consent_screen";import{useFlowNavigation as d}from"../flow_navigation_context";import{UseSmileIDOrchestratedScreenHost as y,useWhileOnTop as w}from"./use_smile_id_orchestrated_screen_host";import{alwaysEnabledSlot as u}from"./helpers/always_enabled_slot";export function OrchestratedConsentScreen({configuration:e}){const r=u(e.denyButton),l=w(d());return n(y,{content:({navigationManager:t})=>n(a,{partnerName:e.partnerName,globalPrivacyControl:t.configuration.config?.globalPrivacyControl??i.OptOut,...e.partnerIcon!==void 0?{partnerIcon:e.partnerIcon}:{},...e.partnerPrivacyPolicyUrl!==void 0?{partnerPrivacyPolicyUrl:e.partnerPrivacyPolicyUrl}:{},showAttribution:c(t.configuration),...e.allowButton?{allowButton:e.allowButton}:{},...r!==void 0?{denyButton:r}:{},onAllow:o=>l(()=>{t.setConsent(o);try{e.onConsentGranted?.(o)}catch(p){m.captureException(p)}t.navigateToNext()}),onDeny:()=>{t.exit({kind:"failed",error:new s({timestamp:Date.now()})})}})})}
@@ -1 +1 @@
1
- "use strict";import{Fragment as s,jsx as u}from"react/jsx-runtime";import{useMemo as f,useRef as p}from"react";import{useFlowNavigation as x}from"../flow_navigation_context";export function OrchestratedPartnerScreen({configuration:r}){const e=x(),i=p(e.currentDepth).current,o=f(()=>{const a=()=>e.currentDepth===i;function c(t,n){if(t!==void 0&&n===void 0)throw new TypeError("next takes a value and its format together");a()&&(n===void 0?e.navigateToNext():e.navigateToNextWith(n.encode(t)))}return Object.freeze({stepId:r.id,next:c,value:(t,n)=>{const d=e.partnerValue(t);return d===void 0?void 0:n.decode(d)},back:()=>{a()&&e.navigateBack()},cancel:()=>{a()&&e.exit({kind:"cancelled"})}})},[r.id,i,e]);return u(s,{children:r.render(o)})}
1
+ "use strict";import{Fragment as c,jsx as s}from"react/jsx-runtime";import{useMemo as u}from"react";import{useFlowNavigation as f}from"../flow_navigation_context";import{useWhileOnTop as p}from"./use_smile_id_orchestrated_screen_host";export function OrchestratedPartnerScreen({configuration:a}){const e=f(),t=p(e),o=u(()=>{function d(r,n){if(r!==void 0&&n===void 0)throw new TypeError("next takes a value and its format together");t(()=>{n===void 0?e.navigateToNext():e.navigateToNextWith(n.encode(r))})}return Object.freeze({stepId:a.id,next:d,value:(r,n)=>{const i=e.partnerValue(r);return i===void 0?void 0:n.decode(i)},back:()=>t(()=>e.navigateBack()),cancel:()=>t(()=>e.exit({kind:"cancelled"}))})},[a.id,e,t]);return s(c,{children:a.render(o)})}
@@ -1 +1 @@
1
- "use strict";import{jsx as r}from"react/jsx-runtime";import{flowShowAttribution as s}from"../config/attribution_resolver";import{UseSmileIDPreviewScreen as p}from"../../screen/use_smile_id_preview_screen";import{UseSmileIDDocumentPreviewScreen as l}from"../../screen/use_smile_id_document_preview_screen";import{UseSmileIDOrchestratedScreenHost as d}from"./use_smile_id_orchestrated_screen_host";import{defaultFrameAspectRatio as f}from"../config/document_type";export function OrchestratedPreviewScreen({configuration:t}){return r(d,{content:({navigationManager:e,onBack:o,onNavigateNext:c})=>{const u=s(e.configuration);if(e.currentPreviewIsDocument()){const m=e.currentDocumentPreviewPath();return r(l,{documentAspectRatio:e.documentFrameAspectRatio??f("Landscape"),showAttribution:u,...m!==void 0?{capturedDocumentPath:m,capturedDocumentBorderFraction:e.currentDocumentPreviewBorderFraction()}:{},onAccept:c,onReject:()=>{t.allowRetake&&(e.retakeCurrentDocumentSide(),o())},onClose:()=>e.exit()})}return r(p,{allowRetake:t.allowRetake,showAttribution:u,...e.selfieCaptureGeometry?{selfieCaptureGeometry:e.selfieCaptureGeometry}:{},...e.captured.selfiePath!==void 0?{capturedSelfiePath:e.captured.selfiePath}:{},onAccept:c,onReject:()=>{t.allowRetake&&o()}})}})}
1
+ "use strict";import{jsx as r}from"react/jsx-runtime";import{flowShowAttribution as p}from"../config/attribution_resolver";import{UseSmileIDPreviewScreen as i}from"../../screen/use_smile_id_preview_screen";import{UseSmileIDDocumentPreviewScreen as l}from"../../screen/use_smile_id_document_preview_screen";import{useFlowNavigation as f}from"../flow_navigation_context";import{UseSmileIDOrchestratedScreenHost as d,useWhileOnTop as w}from"./use_smile_id_orchestrated_screen_host";import{defaultFrameAspectRatio as h}from"../config/document_type";export function OrchestratedPreviewScreen({configuration:t}){const m=w(f());return r(d,{content:({navigationManager:e,onBack:s,onNavigateNext:o})=>{const c=p(e.configuration);if(e.currentPreviewIsDocument()){const u=e.currentDocumentPreviewPath();return r(l,{documentAspectRatio:e.documentFrameAspectRatio??h("Landscape"),showAttribution:c,...u!==void 0?{capturedDocumentPath:u,capturedDocumentBorderFraction:e.currentDocumentPreviewBorderFraction()}:{},onAccept:o,onReject:()=>{t.allowRetake&&m(()=>{e.retakeCurrentDocumentSide(),e.navigateBack()})},onClose:()=>e.exit()})}return r(i,{allowRetake:t.allowRetake,showAttribution:c,...e.selfieCaptureGeometry?{selfieCaptureGeometry:e.selfieCaptureGeometry}:{},...e.captured.selfiePath!==void 0?{capturedSelfiePath:e.captured.selfiePath}:{},onAccept:o,onReject:()=>{t.allowRetake&&s()}})}})}
@@ -1 +1 @@
1
- "use strict";import{jsx as r}from"react/jsx-runtime";import{useEffect as a}from"react";import{DocumentSide as d}from"@smileid/usesmileid_bridge";import{UseSmileIDProcessingScreen as m}from"../../screen/use_smile_id_processing_screen";import{flowShowAttribution as f}from"../config/attribution_resolver";import{UseSmileIDOrchestratedScreenHost as g}from"./use_smile_id_orchestrated_screen_host";import{ProcessingCancelledException as p}from"../../../core/exception";import{alwaysEnabledSlot as i}from"./helpers/always_enabled_slot";import{resolveFailureMessage as l}from"./helpers/failure_message";import{useUseSmileIDLocalizations as S}from"../../../l10n/use_smile_id_localizations_provider";import{JobType as b,requiresDocument as c,requiresSelfie as P}from"../../../core/models/job_type";export function OrchestratedProcessingScreen({configuration:n}){return r(g,{content:({navigationManager:e,onNavigateNext:o})=>r(h,{processingConfig:n,navigationManager:e,onContinue:o})})}function h(n){const{navigationManager:e}=n;a(()=>{e.beginSubmissionIfNeeded()},[e]);const o=e.configuration.network?.config?.jobType??b.unknown,t=c(o)?e.captured.frontDocumentPath:void 0,s=e.documentFrameAspectRatio,u=S();return r(m,{state:B(e.jobSubmissionState,u),showFaceOval:P(o)||c(o),...e.selfieCaptureGeometry?{selfieCaptureGeometry:e.selfieCaptureGeometry}:{},showProgressPercentage:n.processingConfig.showProgressPercentage,showAttribution:f(e.configuration),...t!==void 0?{documentImageUri:t,documentBorderFraction:e.documentBorderFraction(d.Front)}:{},...t!==void 0&&s!==void 0?{documentAspectRatio:s}:{},...e.captured.selfiePath!==void 0?{capturedSelfiePath:e.captured.selfiePath}:{},...y(n.processingConfig),onContinue:n.onContinue,onRetry:()=>e.retrySubmission(),onExit:()=>e.exit({kind:"failed",error:w(e.jobSubmissionState)})})}function y(n){const e=i(n.continueButton),o=i(n.retryButton),t=i(n.exitButton);return{...e!==void 0?{continueButton:e}:{},...o!==void 0?{retryButton:o}:{},...t!==void 0?{exitButton:t}:{}}}function w(n){return n.kind==="failure"?n.error:new p}function B(n,e){switch(n.kind){case"notAttempted":case"loading":case"skipped":return{kind:"loading"};case"success":return{kind:"success",message:n.response.message};case"failure":return{kind:"failed",errorMessage:l(n.error,e)}}}
1
+ "use strict";import{jsx as t}from"react/jsx-runtime";import{useEffect as a}from"react";import{DocumentSide as d}from"@smileid/usesmileid_bridge";import{UseSmileIDProcessingScreen as m}from"../../screen/use_smile_id_processing_screen";import{flowShowAttribution as f}from"../config/attribution_resolver";import{UseSmileIDOrchestratedScreenHost as p}from"./use_smile_id_orchestrated_screen_host";import{ProcessingCancelledException as g,UseSmileIDException as l}from"../../../core/exception";import{alwaysEnabledSlot as i}from"./helpers/always_enabled_slot";import{resolveFailureMessage as S}from"./use_smile_id_error_code_failure_message";import{useUseSmileIDLocalizations as b}from"../../../l10n/use_smile_id_localizations_provider";import{JobType as P,requiresDocument as c,requiresSelfie as h}from"../../../core/models/job_type";export function OrchestratedProcessingScreen({configuration:n}){return t(p,{content:({navigationManager:e,onNavigateNext:o})=>t(y,{processingConfig:n,navigationManager:e,onContinue:o})})}function y(n){const{navigationManager:e}=n;a(()=>{e.beginSubmissionIfNeeded()},[e]);const o=e.configuration.network?.config?.jobType??P.unknown,r=c(o)?e.captured.frontDocumentPath:void 0,s=e.documentFrameAspectRatio,u=b();return t(m,{state:x(e.jobSubmissionState,u),showFaceOval:h(o)||c(o),...e.selfieCaptureGeometry?{selfieCaptureGeometry:e.selfieCaptureGeometry}:{},showProgressPercentage:n.processingConfig.showProgressPercentage,showAttribution:f(e.configuration),...r!==void 0?{documentImageUri:r,documentBorderFraction:e.documentBorderFraction(d.Front)}:{},...r!==void 0&&s!==void 0?{documentAspectRatio:s}:{},...e.captured.selfiePath!==void 0?{capturedSelfiePath:e.captured.selfiePath}:{},...w(n.processingConfig),onContinue:n.onContinue,onRetry:()=>e.retrySubmission(),onExit:()=>e.exit({kind:"failed",error:C(e.jobSubmissionState)})})}function w(n){const e=i(n.continueButton),o=i(n.retryButton),r=i(n.exitButton);return{...e!==void 0?{continueButton:e}:{},...o!==void 0?{retryButton:o}:{},...r!==void 0?{exitButton:r}:{}}}function C(n){return n.kind==="failure"?n.error:new g}function x(n,e){switch(n.kind){case"notAttempted":case"loading":case"skipped":return{kind:"loading"};case"success":return{kind:"success",message:n.response.message};case"failure":return{kind:"failed",errorMessage:S(n.error instanceof l?n.error.errorCode:void 0,e)}}}
@@ -0,0 +1,8 @@
1
+ import { UseSmileIDErrorCode } from "../../../core/exception";
2
+ import type { UseSmileIDLocalizations } from "../../../l10n/use_smile_id_localizations";
3
+ /**
4
+ * The processing screen's failure copy, keyed off the error code and never off the exception's
5
+ * message, which also feeds `onResult` and analytics. Only an unreachable server or a timeout
6
+ * reads as a lost connection; a code the table doesn't name gets the generic copy.
7
+ */
8
+ export declare function resolveFailureMessage(code: UseSmileIDErrorCode | undefined, localizations: UseSmileIDLocalizations): string;
@@ -0,0 +1 @@
1
+ "use strict";import{UseSmileIDErrorCode as i,isNetworkErrorCode as s,isRetryableErrorCode as n}from"../../../core/exception";export function resolveFailureMessage(r,e){return r===i.Network.RequestFailed?e.siProcessingErrorGeneric:r===i.Camera.PermissionDenied?e.siProcessingErrorCameraPermission:r===i.Network.RateLimit||r===i.Network.ServerError?e.siProcessingErrorRetryLater:r!==void 0&&s(r)&&!n(r)?e.siProcessingErrorUnavailable:r===i.Network.ConnectionFailed||r===i.Network.Timeout?e.siProcessingErrorNoConnection:e.siProcessingErrorGeneric}
@@ -1,4 +1,4 @@
1
- import type { ReactNode } from "react";
1
+ import { type ReactNode } from "react";
2
2
  import type { FlowNavigationManager } from "../flow_navigation_manager";
3
3
  export type OrchestratedScreenHostContent = (args: {
4
4
  readonly navigationManager: FlowNavigationManager;
@@ -18,5 +18,18 @@ export type UseSmileIDOrchestratedScreenHostProps = {
18
18
  * `useFlowNavigation()` call throws a loud "called outside
19
19
  * `<UseSmileIDBuilder>`" error rather than silently no-op-ing on
20
20
  * `navigateToNext()` / `navigateBack()`.
21
+ *
22
+ * Each move acts only while this screen is the one on top
23
+ * ({@link useWhileOnTop}).
21
24
  */
22
25
  export declare function UseSmileIDOrchestratedScreenHost({ content, }: UseSmileIDOrchestratedScreenHostProps): import("react").JSX.Element;
26
+ /**
27
+ * Runs the calling screen's work only while it is the one on top. A tap that
28
+ * lands after the flow moved on (a double tap, a tap during the transition, a
29
+ * Continue whose camera permission prompt resolved late) would move it again
30
+ * from the next screen and skip it, so the screen's depth is pinned when it
31
+ * mounts and checked when the work runs. A screen that records something as
32
+ * it moves (a consent, a side cleared to retake, a capture) does both inside
33
+ * it, so a dropped move records nothing either.
34
+ */
35
+ export declare function useWhileOnTop(navigationManager: FlowNavigationManager): (work: () => void) => void;
@@ -1 +1 @@
1
- "use strict";import{Fragment as t,jsx as n}from"react/jsx-runtime";import{useFlowNavigation as o}from"../flow_navigation_context";export function UseSmileIDOrchestratedScreenHost({content:e}){const a=o();return n(t,{children:e({navigationManager:a,onBack:()=>a.navigateBack(),onNavigateNext:()=>a.navigateToNext()})})}
1
+ "use strict";import{Fragment as n,jsx as o}from"react/jsx-runtime";import{useCallback as c,useRef as s}from"react";import{useFlowNavigation as a}from"../flow_navigation_context";export function UseSmileIDOrchestratedScreenHost({content:t}){const e=a(),r=useWhileOnTop(e);return o(n,{children:t({navigationManager:e,onBack:()=>r(()=>e.navigateBack()),onNavigateNext:()=>r(()=>e.navigateToNext())})})}export function useWhileOnTop(t){const e=s(t.currentDepth).current;return c(r=>{t.currentDepth===e&&r()},[t,e])}
@@ -3,23 +3,22 @@ import type { NetworkConfig } from "../../../core/models/network_config";
3
3
  import type { BiometricKYCParams, ConsentInformation, DocumentVerificationParams, EnhancedDocumentVerificationParams, EnhancedKYCParams, ResidencyDocumentVerificationParams, UserDetails } from "../../../core/models/params";
4
4
  import type { ScreenSpec } from "../dsl/screen_builders";
5
5
  import { type TokenPayload } from "../../../data/model/token_payload";
6
- import { type ValidationIssue } from "./validation_state";
6
+ import type { ValidationIssue } from "./validation_state";
7
7
  /**
8
8
  * Pure flow validator — returns typed `UseSmileIDValidationException`
9
- * instances. The same instances are exposed via `b.validate()` and
10
- * thrown by `b.build()` (after picking the first `error`-severity
11
- * issue), so partner regex-matchers and `instanceof` checks see the
12
- * same object whether they're inspecting validate-state or catching
13
- * a thrown error.
9
+ * instances. `b.build()` and `b.validate()` both read
10
+ * `runFlowValidation`, so partner regex-matchers and `instanceof` checks
11
+ * see the same objects whether they're inspecting validate-state or the
12
+ * `BuilderValidationException` delivered through `onResult`.
14
13
  *
15
14
  * `runFlowValidation` owns only the builder / job-agnostic concerns:
16
- * empty screens, per-screen capture / consent config, ML / Network
17
- * block presence, missing job type, the standalone param validators,
18
- * and the consent-mutex check. Every flow-composition rule — screen
19
- * ordering, duplicate screen types, preview placement, analyzer
20
- * dependencies, and per-job field requirements — is owned by the
21
- * per-`JobType` validators in `job_type_validator.ts`, dispatched via
22
- * `collectJobTypeIssues`.
15
+ * empty screens, per-screen capture / consent config, partner screens and
16
+ * the consent mutex before the dispatch, then the preset consent and the
17
+ * standalone param validators. Every flow-composition rule — screen
18
+ * ordering, duplicate screen types, preview placement, ML / Network
19
+ * dependencies, a missing job type, and per-job field requirements — is
20
+ * owned by the per-`JobType` validators in `job_type_validator.ts`,
21
+ * dispatched via `collectJobTypeIssues`.
23
22
  *
24
23
  * Rule order, message wording, severity, and `errorCode` values are
25
24
  * the contract surface partners see. Don't reword existing rules
@@ -46,8 +45,6 @@ type FlowValidatorInput = {
46
45
  readonly tokenPayload?: TokenPayload | undefined;
47
46
  readonly skipApiSubmission?: boolean | undefined;
48
47
  };
49
- /** `b.validate()`'s pre-flight: screens and their own settings, not job-level rules. */
50
- export declare function runBuilderValidation(steps: readonly ScreenSpec[]): ValidationIssue[];
51
48
  /**
52
49
  * Run every flow-level validation rule and return the collected
53
50
  * issues. Empty array means valid.
@@ -81,7 +78,8 @@ export declare function runDocumentVerificationParamsValidation(params: Document
81
78
  export declare function runEnhancedDocumentVerificationParamsValidation(params: EnhancedDocumentVerificationParams, tokenPayload?: TokenPayload): ValidationIssue[];
82
79
  /**
83
80
  * Validate a `ResidencyDocumentVerificationParams` payload in isolation.
84
- * Both `country` and `idType` are required and must be non-blank.
81
+ * Both `country` and `idType` are required, and `idType` must be
82
+ * `"PASSPORT"`, the one value the backend accepts, unless the token binds it.
85
83
  */
86
84
  export declare function runResidencyDocumentVerificationParamsValidation(params: ResidencyDocumentVerificationParams, tokenPayload?: TokenPayload): ValidationIssue[];
87
85
  /**
@@ -1 +1 @@
1
- "use strict";import{partnerScreenIssues as g}from"./partner_screen_validation";import{CaptureType as d}from"../../../core/models/ml_config";import{JobType as w,jobTypeFromValue as P}from"../../../core/models/job_type";import{InvalidConsentConfigException as c,InvalidConsentInformationException as m}from"../../../core/exception/consent_validation_exceptions";import{InvalidFieldValueException as s,MissingJobTypeException as k,MissingMLConfigurationBlockException as b,MissingNetworkConfigurationBlockException as C}from"../../../core/exception/job_validation_exceptions";import{AgentModeWithEnhancedLivenessException as I,InvalidDocumentCaptureConfigException as u,InvalidMissingCaptureTypeException as T}from"../../../core/exception/capture_validation_exceptions";import{EmptyScreensBlockException as p}from"../../../core/exception/screen_config_validation_exceptions";import{isIdFieldBoundByToken as a}from"../../../data/model/token_payload";import{collectJobTypeIssues as V}from"./job_type_validator";function x(e){return e?.allowAgentMode&&e.enableEnhancedLiveness?[new I]:[]}function v(e){return e===void 0?[new u({reason:"document is required when mode is Document"})]:e.documentType===void 0?[new u({reason:"documentType is required for document capture"})]:e.knownIdAspectRatio!==void 0&&e.knownIdAspectRatio<=0?[new u({reason:"knownIdAspectRatio must be > 0 if provided"})]:[]}export function runBuilderValidation(e){return e.length===0?[new p]:[...l(e),...h(e)]}function l(e){const n=[];for(const o of e)o.kind==="capture"&&(o.config.captureType===void 0&&n.push(new T),o.config.captureType===d.selfie&&n.push(...x(o.config.selfieConfig)),o.config.captureType===d.document&&n.push(...v(o.config.documentConfig)));return n}function h(e){const n=[],o=e.find(i=>i.kind==="consent");return o&&(!o.config.partnerName||!o.config.partnerName.trim())&&n.push(new c({reason:"partnerName cannot be empty"})),o&&o.config.partnerIcon===void 0&&n.push(new c({reason:"partnerIcon is required for the consent screen"})),o&&(o.config.partnerPrivacyPolicyUrl===void 0||!o.config.partnerPrivacyPolicyUrl.trim())&&n.push(new c({reason:"partnerPrivacyPolicyUrl is required for the consent screen"})),n}export function runFlowValidation(e){const n=[];if(e.steps.length===0)return n.push(new p),n;n.push(...l(e.steps)),n.push(...g(e.steps));const o=e.steps.some(t=>t.kind==="capture"),i=e.steps.some(t=>t.kind==="processing"),r=e.network?.config?.jobType,f=r===void 0||P(r)===w.unknown;return o&&!e.ml&&f&&n.push(new b),i&&!e.network&&n.push(new C),i&&f&&n.push(new k),n.push(...h(e.steps)),e.steps.some(t=>t.kind==="consent")&&e.consentInformation!==void 0&&n.push(new c({reason:"Exactly one form of consent is required \u2014 remove the consent { } screen if using consentInformation, or clear consentInformation if using the consent screen"})),e.consentInformation&&e.tokenPayload?.consent===void 0&&n.push(...runConsentValidation(e.consentInformation)),e.enhancedKYCParams&&n.push(...runEnhancedKYCParamsValidation(e.enhancedKYCParams,e.tokenPayload)),e.biometricKYCParams&&n.push(...runBiometricKYCParamsValidation(e.biometricKYCParams,e.tokenPayload)),e.documentVerificationParams&&n.push(...runDocumentVerificationParamsValidation(e.documentVerificationParams,e.tokenPayload)),e.enhancedDocumentVerificationParams&&n.push(...runEnhancedDocumentVerificationParamsValidation(e.enhancedDocumentVerificationParams,e.tokenPayload)),e.residencyDocumentVerificationParams&&n.push(...runResidencyDocumentVerificationParamsValidation(e.residencyDocumentVerificationParams,e.tokenPayload)),V(e,n),n}export function runEnhancedKYCParamsValidation(e,n){return y(e,n)}export function runBiometricKYCParamsValidation(e,n){return y(e,n)}export function runDocumentVerificationParamsValidation(e,n){const o=[];return!a(n,"country")&&!e.country?.trim()&&o.push(new s({fieldName:"country",reason:"must not be blank"})),!a(n,"idType")&&e.idType!==void 0&&!e.idType.trim()&&o.push(new s({fieldName:"idType",reason:"must not be blank"})),o}export function runEnhancedDocumentVerificationParamsValidation(e,n){const o=[];for(const i of["country","idType"]){const r=e[i];!a(n,i)&&!r?.trim()&&o.push(new s({fieldName:i,reason:"must not be blank"}))}return o}export function runResidencyDocumentVerificationParamsValidation(e,n){const o=[];for(const i of["country","idType"]){const r=e[i];!a(n,i)&&!r?.trim()&&o.push(new s({fieldName:i,reason:"must not be blank"}))}return o}export function runConsentValidation(e){const n=[];e.granted||n.push(new m({detail:"granted must be true"}));for(const o of["grantedAt","noticeLanguage","noticePrivacyPolicyUrl"])(!e[o]||!e[o].trim())&&n.push(new m({detail:`${o} must not be blank`}));return n}function y(e,n){const o=[];for(const i of["idType","idNumber","country"]){const r=e[i];!a(n,i)&&!r?.trim()&&o.push(new s({fieldName:i,reason:"must not be blank"}))}return o}
1
+ "use strict";import{partnerScreenIssues as p}from"./partner_screen_validation";import{CaptureType as f}from"../../../core/models/ml_config";import{InvalidConsentConfigException as t,InvalidConsentInformationException as d}from"../../../core/exception/consent_validation_exceptions";import{InvalidFieldValueException as s}from"../../../core/exception/job_validation_exceptions";import{AgentModeWithEnhancedLivenessException as l,InvalidDocumentCaptureConfigException as a,InvalidMissingCaptureTypeException as y}from"../../../core/exception/capture_validation_exceptions";import{EmptyScreensBlockException as h}from"../../../core/exception/screen_config_validation_exceptions";import{isIdFieldBoundByToken as r}from"../../../data/model/token_payload";import{collectJobTypeIssues as P,hasNonPassportIdType as I,residencyIdTypeIssue as w}from"./job_type_validator";import{hasConsentScreen as g}from"../config/flow_configuration_screens";function C(e){return e?.allowAgentMode&&e.enableEnhancedLiveness?[new l]:[]}function T(e){if(e===void 0)return[new a({reason:"document is required when mode is Document"})];if(e.documentType===void 0)return[new a({reason:"documentType is required for document capture"})];const n=e.documentType.knownAspectRatio;return n!==void 0&&n<=0?[new a({reason:"documentType.knownAspectRatio must be > 0 if provided"})]:e.knownIdAspectRatio!==void 0&&e.knownIdAspectRatio<=0?[new a({reason:"knownIdAspectRatio must be > 0 if provided"})]:[]}function b(e){const n=[];for(const o of e)o.kind==="capture"&&(o.config.captureType===void 0&&n.push(new y),o.config.captureType===f.selfie&&n.push(...C(o.config.selfieConfig)),o.config.captureType===f.document&&n.push(...T(o.config.documentConfig))),o.kind==="consent"&&n.push(...k(o));return n}function k(e){const n=[];return(!e.config.partnerName||!e.config.partnerName.trim())&&n.push(new t({reason:"partnerName cannot be empty"})),e.config.partnerIcon===void 0&&n.push(new t({reason:"partnerIcon is required for the consent screen"})),(e.config.partnerPrivacyPolicyUrl===void 0||!e.config.partnerPrivacyPolicyUrl.trim())&&n.push(new t({reason:"partnerPrivacyPolicyUrl is required for the consent screen"})),n}export function runFlowValidation(e){const n=[];return e.steps.length===0?(n.push(new h),n):(n.push(...b(e.steps)),n.push(...p(e.steps)),g(e.steps)&&e.consentInformation!==void 0&&n.push(new t({reason:"Exactly one form of consent is required \u2014 remove the consent { } screen if using consentInformation, or clear consentInformation if using the consent screen"})),P(e,n),e.consentInformation&&e.tokenPayload?.consent===void 0&&n.push(...runConsentValidation(e.consentInformation)),e.enhancedKYCParams&&n.push(...runEnhancedKYCParamsValidation(e.enhancedKYCParams,e.tokenPayload)),e.biometricKYCParams&&n.push(...runBiometricKYCParamsValidation(e.biometricKYCParams,e.tokenPayload)),e.documentVerificationParams&&n.push(...runDocumentVerificationParamsValidation(e.documentVerificationParams,e.tokenPayload)),e.enhancedDocumentVerificationParams&&n.push(...runEnhancedDocumentVerificationParamsValidation(e.enhancedDocumentVerificationParams,e.tokenPayload)),e.residencyDocumentVerificationParams&&n.push(...u(e.residencyDocumentVerificationParams,e.tokenPayload)),n)}export function runEnhancedKYCParamsValidation(e,n){return m(e,n)}export function runBiometricKYCParamsValidation(e,n){return m(e,n)}export function runDocumentVerificationParamsValidation(e,n){const o=[];return!r(n,"country")&&!e.country?.trim()&&o.push(new s({fieldName:"country",reason:"must not be blank"})),!r(n,"idType")&&e.idType!==void 0&&!e.idType.trim()&&o.push(new s({fieldName:"idType",reason:"must not be blank"})),o}export function runEnhancedDocumentVerificationParamsValidation(e,n){return u(e,n)}export function runResidencyDocumentVerificationParamsValidation(e,n){const o=u(e,n);return!r(n,"idType")&&I(e)&&o.push(w()),o}function u(e,n){const o=[];for(const i of["country","idType"]){const c=e[i];!r(n,i)&&!c?.trim()&&o.push(new s({fieldName:i,reason:"must not be blank"}))}return o}export function runConsentValidation(e){const n=[];e.granted||n.push(new d({detail:"granted must be true"}));for(const o of["grantedAt","noticeLanguage","noticePrivacyPolicyUrl"])(!e[o]||!e[o].trim())&&n.push(new d({detail:`${o} must not be blank`}));return n}function m(e,n){const o=[];for(const i of["idType","idNumber","country"]){const c=e[i];!r(n,i)&&!c?.trim()&&o.push(new s({fieldName:i,reason:"must not be blank"}))}return o}
@@ -14,8 +14,8 @@ import type { ValidationIssue } from "./validation_state";
14
14
  * screen ordering, preview placement, ML analyzer dependencies, consent
15
15
  * presence, capture counts, processing, and per-job field requirements.
16
16
  * `FlowValidator` only owns the builder / job-agnostic concerns (empty
17
- * screens, per-screen config, ML / Network block presence, missing job
18
- * type) before dispatching to the matching validator.
17
+ * screens, per-screen config, the consent mutex, the preset consent and
18
+ * the params payloads) around its dispatch to the matching validator.
19
19
  *
20
20
  * Adding a new job type requires only a new entry in
21
21
  * `FlowValidator`'s `jobTypeValidators` registry — `FlowValidator`
@@ -106,13 +106,12 @@ export declare class NonCaptureJobTypeValidator implements JobTypeValidator {
106
106
  validate(input: JobTypeValidatorInput, issues: ValidationIssue[]): void;
107
107
  }
108
108
  /**
109
- * Generic structural validator used when no concrete `JobType` is
110
- * resolved yet (e.g. a UI-only flow without a `network { }` block). It
111
- * applies only the job-agnostic structural rules so partners still get
112
- * screen-order / duplicate / preview feedback while prototyping. A
113
- * single Preview following a Capture is permitted by default.
109
+ * Validates a flow whose `JobType` doesn't resolve. It is always invalid,
110
+ * and still gets the structural rules and the missing-block warnings, so a
111
+ * partner sees every problem at once. The preview cap is the document bound
112
+ * of two, since the per-job caps apply only once the job type resolves.
114
113
  */
115
- export declare class DefaultStructuralValidator implements JobTypeValidator {
114
+ export declare class UnknownJobTypeValidator implements JobTypeValidator {
116
115
  validate(input: JobTypeValidatorInput, issues: ValidationIssue[]): void;
117
116
  }
118
117
  /**
@@ -122,17 +121,13 @@ export declare class DefaultStructuralValidator implements JobTypeValidator {
122
121
  */
123
122
  export declare const jobTypeValidators: ReadonlyMap<JobType, JobTypeValidator>;
124
123
  /**
125
- * Resolve the validator for the configured job type, falling back to the
126
- * generic structural validator when the job type is unknown or
127
- * unregistered. Always returns a validator so the generic structural
128
- * rules run regardless of dispatch.
124
+ * Resolve the validator for the configured job type, falling back to
125
+ * `UnknownJobTypeValidator` when the job type is unknown or unregistered.
129
126
  */
130
127
  export declare function resolveJobTypeValidator(jobType: JobType | undefined): JobTypeValidator;
131
128
  /**
132
129
  * Run the job-type-specific rules against the flow and append any issues
133
- * found. Called by `FlowValidator` after its generic builder pass. The
134
- * matching validator is resolved from the configured `jobType`, with the
135
- * generic structural validator as the fallback for unknown job types.
130
+ * found. Called by `FlowValidator` after its per-screen pass.
136
131
  */
137
132
  export declare function collectJobTypeIssues(input: JobTypeValidatorInput, issues: ValidationIssue[]): void;
138
133
  /**
@@ -141,3 +136,8 @@ export declare function collectJobTypeIssues(input: JobTypeValidatorInput, issue
141
136
  * standalone params pre-check report it identically.
142
137
  */
143
138
  export declare function residencyIdTypeIssue(): InvalidJobTypeScreenConfigException;
139
+ /**
140
+ * A set `idType` other than {@link RESIDENCY_ID_TYPE}; a blank one is the
141
+ * presence rule's to report.
142
+ */
143
+ export declare function hasNonPassportIdType(params: ResidencyDocumentVerificationParams): boolean;
@@ -1 +1 @@
1
- "use strict";import{RESIDENCY_ID_TYPE as h}from"../../../core/models/params";import{JobType as i}from"../../../core/models/job_type";import{CaptureType as y}from"../dsl/screen_builders";import{InvalidJobTypeScreenConfigException as a}from"../../../core/exception/job_validation_exceptions";import{JOB_PARAMS_OWNERS as C,UnusedJobParamsException as x}from"../../../core/exception/unused_job_params_exception";import{DuplicateScreenTypeException as V,InvalidScreenOrderException as p,MissingCaptureForPreviewException as D}from"../../../core/exception/screen_config_validation_exceptions";import{IssueSeverity as u}from"../../../core/exception/issue_severity";import{tokenConsentMissingSubfields as P}from"../../../data/model/token_payload";const E=new Map([[i.biometricKyc,"BiometricKyc"],[i.smartSelfieAuthentication,"SmartSelfieAuthentication"],[i.smartSelfieEnrollment,"SmartSelfieEnrollment"],[i.enhancedKyc,"EnhancedKyc"],[i.documentVerification,"DocumentVerification"],[i.bvn,"BVN"],[i.enhancedDocumentVerification,"EnhancedDocumentVerification"],[i.residencyDocumentVerification,"ResidencyDocumentVerification"],[i.unknown,"Unknown"]]);function j(o){return E.get(o)??"Unknown"}function b(o,e,n){const r=e.steps.some(s=>s.kind==="consent"),t=e.consentInformation!==void 0,c=e.tokenPayload?.consent;if(c!==void 0){const s=P(c);s.length>0&&n.push(a.forJob({jobType:o,reason:`the token's consent binding is incomplete \u2014 missing: ${s.join(", ")}`,suggestedFix:"Bind all four consent fields when minting the token at /v3/token, or bind none and collect consent in the app"}));return}e.skipApiSubmission!==!0&&!r&&!t&&n.push(a.forJob({jobType:o,reason:"must include either a Consent screen or a pre-supplied consentInformation",suggestedFix:"Add a consent { } screen to your flow, or supply consentInformation via the builder"}))}export const JOB_PARAMS_SUPPLIERS={enhancedKYCParams:o=>o.enhancedKYCParams,biometricKYCParams:o=>o.biometricKYCParams,documentVerificationParams:o=>o.documentVerificationParams,enhancedDocumentVerificationParams:o=>o.enhancedDocumentVerificationParams,residencyDocumentVerificationParams:o=>o.residencyDocumentVerificationParams};function T(o,e,n){for(const{fieldName:r,owner:t}of C)t!==o&&JOB_PARAMS_SUPPLIERS[r]?.(e)!==void 0&&n.push(new x({jobType:o,fieldName:r}))}function v(o){return o.filter(e=>e.kind!=="partner")}function f(o,e){const n=new Map;let r=0;o.forEach((t,c)=>{if(t.kind==="capture"){r++;return}if(t.kind==="preview"||t.kind==="partner")return;const s=t.kind==="instructions"?`${t.kind}:${r}`:t.kind,d=n.get(s)??{kind:t.kind,indices:[]};d.indices.push(c),n.set(s,d)});for(const{kind:t,indices:c}of n.values())c.length>1&&e.push(new V({screenType:t,indices:c}))}function m(o,e){v(o).findIndex(c=>c.kind==="consent")>0&&e.push(new p({description:"Consent screen must be the first screen in the flow",severity:u.error}));const r=o.findIndex(c=>c.kind==="processing");r!==-1&&r!==o.length-1&&e.push(new p({description:"Processing screen must be the last screen in the flow",severity:u.error}));const t=o.some(c=>c.kind==="capture");o.forEach((c,s)=>{const d=o[s+1]?.kind;c.kind==="instructions"&&t&&d!=="capture"&&d!=="instructions"&&e.push(new p({description:`Instructions screen at index ${s} must be followed by a Capture screen`,severity:u.error}))})}function l(o,e,n){let r=!1,t=0;o.forEach((c,s)=>{c.kind==="capture"?r=!0:c.kind==="preview"&&(t+=1,r?t>e&&n.push(new p({description:`Preview screen at index ${s} exceeds the maximum of ${e} preview screen(s) allowed for this flow`,severity:u.error})):n.push(new D({previewIndex:s})))})}function g(o,e,n){e.steps.some(t=>t.kind==="processing")||n.push(a.forJob({jobType:o,reason:"must include a Processing screen",suggestedFix:"Add a processing { } screen as the last screen in the flow"}))}function k(o,e,n){const r=e.steps.filter(t=>t.kind==="capture"&&t.config.captureType===y.selfie);r.length===0?n.push(a.forJob({jobType:o,reason:"must include exactly one Capture screen with captureType = SELFIE",suggestedFix:"Add a capture { captureType = CaptureType.SELFIE } screen to your flow"})):r.length>1&&n.push(a.forJob({jobType:o,reason:`must include exactly one Capture screen with captureType = SELFIE, but found ${r.length}`,suggestedFix:"Remove the extra selfie capture screens \u2014 only one is allowed"}))}function w(o,e,n,r){e.ml?e.ml.analyzers.selfie||r.push(a.forJob({jobType:o,reason:"ml { } block must register analyzers for CaptureType.SELFIE",suggestedFix:"Add forCaptureType(CaptureType.SELFIE) { } inside the ml { } block"})):r.push(a.forJob({jobType:o,reason:"ml { } block is required and must register analyzers for CaptureType.SELFIE",suggestedFix:n}))}export class SelfieJobTypeValidator{jobType;constructor(e){this.jobType=e}validate(e,n){f(e.steps,n),m(e.steps,n),l(e.steps,1,n),b(this.jobType,e,n),T(this.jobType,e,n),k(this.jobType,e,n),e.steps.some(t=>t.kind==="capture"&&t.config.captureType===y.document)&&n.push(a.forJob({jobType:this.jobType,reason:"must not include a Document capture screen",suggestedFix:`Remove the Document capture screen \u2014 ${j(this.jobType)} requires selfie capture only`})),g(this.jobType,e,n),w(this.jobType,e,"Add the ml { } block with forCaptureType(CaptureType.SELFIE) { } inside",n),e.ml?.analyzers.document&&n.push(a.forJob({jobType:this.jobType,reason:"ml { } block must not register analyzers for CaptureType.DOCUMENT",suggestedFix:`Remove forCaptureType(CaptureType.DOCUMENT) { } from the ml { } block \u2014 ${j(this.jobType)} does not use document capture`})),this.jobType===i.biometricKyc&&e.biometricKYCParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"biometricKYCParams is required for BiometricKyc jobs",suggestedFix:"Set builder.biometricKYCParams with the identity fields before building"})),this.jobType===i.smartSelfieAuthentication&&(e.userId===void 0||e.userId.trim()==="")&&n.push(a.forJob({jobType:this.jobType,reason:"userId is required for SmartSelfieAuthentication jobs",suggestedFix:"Set builder.userId with the identifier returned by a prior Smart Selfie Enrollment before building"}))}}export class DocumentJobTypeValidator{jobType;constructor(e){this.jobType=e}validate(e,n){f(e.steps,n),m(e.steps,n),l(e.steps,2,n),b(this.jobType,e,n),T(this.jobType,e,n),k(this.jobType,e,n);const r=e.steps.filter(t=>t.kind==="capture"&&t.config.captureType===y.document);if(r.length===0?n.push(a.forJob({jobType:this.jobType,reason:"must include exactly one Capture screen with captureType = DOCUMENT",suggestedFix:"Add a capture { captureType = CaptureType.DOCUMENT } screen to your flow"})):r.length>1&&n.push(a.forJob({jobType:this.jobType,reason:`must include exactly one Capture screen with captureType = DOCUMENT, but found ${r.length}`,suggestedFix:"Remove the extra document capture screens \u2014 only one is allowed"})),g(this.jobType,e,n),w(this.jobType,e,"Add the ml { } block with forCaptureType(CaptureType.SELFIE) { } inside \u2014 document capture uses NoopDocumentDetectorAnalyzer by default",n),this.appendParamsRule(e,n),this.jobType===i.enhancedDocumentVerification&&r.some(t=>t.kind==="capture"&&t.config.documentConfig?.documentType?.kind==="southAfricaGreenBook")&&n.push(a.forJob({jobType:this.jobType,reason:"South Africa Green Book is not supported for Enhanced Document Verification",suggestedFix:"Use JobType.documentVerification for the Green Book, or choose a supported document type for Enhanced Document Verification"})),this.jobType===i.residencyDocumentVerification)for(const t of r){if(t.kind!=="capture")continue;const c=t.config.documentConfig,s=c?.documentType;s?.kind!=="passport"&&n.push(a.forJob({jobType:this.jobType,reason:`documentType must be passport \u2014 ${s?.kind??"no document type"} is not a residency primary document`,suggestedFix:"Set documentType to the passport preset on the document capture screen"})),c&&c.allowSkipBack===!0&&n.push(a.forJob({jobType:this.jobType,reason:"allowSkipBack must be false \u2014 the visa capture is mandatory",suggestedFix:"Remove allowSkipBack from the document capture screen"}))}}appendParamsRule(e,n){this.jobType===i.documentVerification&&e.documentVerificationParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"documentVerificationParams is required for DocumentVerification jobs",suggestedFix:"Set builder.documentVerificationParams with the country (and optional idType) before building"})),this.jobType===i.enhancedDocumentVerification&&e.enhancedDocumentVerificationParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"enhancedDocumentVerificationParams is required for EnhancedDocumentVerification jobs",suggestedFix:"Set builder.enhancedDocumentVerificationParams with the country and idType before building"})),this.jobType===i.residencyDocumentVerification&&e.tokenPayload?.hasIdType!==!0&&e.residencyDocumentVerificationParams!==void 0&&e.residencyDocumentVerificationParams.idType!==h&&n.push(residencyIdTypeIssue()),this.jobType===i.residencyDocumentVerification&&e.residencyDocumentVerificationParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"residencyDocumentVerificationParams is required for ResidencyDocumentVerification jobs",suggestedFix:"Set builder.residencyDocumentVerificationParams with the country and idType before building"}))}}export class NonCaptureJobTypeValidator{jobType;constructor(e){this.jobType=e}validate(e,n){f(e.steps,n),m(e.steps,n),l(e.steps,0,n),b(this.jobType,e,n),T(this.jobType,e,n),g(this.jobType,e,n);const r=e.steps.filter(t=>t.kind!=="consent"&&t.kind!=="processing"&&t.kind!=="partner");if(r.length>0){const t=[...new Set(r.map(c=>c.kind))].join(", ");n.push(a.forJob({jobType:this.jobType,reason:`must only contain consent and processing screens, but found: ${t}`,suggestedFix:"Remove all screens except consent { } and processing { } from your flow"}))}this.jobType===i.enhancedKyc&&e.enhancedKYCParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"enhancedKYCParams is required for EnhancedKyc jobs",suggestedFix:"Set builder.enhancedKYCParams with the identity fields before building"}))}}export class DefaultStructuralValidator{validate(e,n){f(e.steps,n),m(e.steps,n),l(e.steps,1,n)}}export const jobTypeValidators=new Map([[i.biometricKyc,new SelfieJobTypeValidator(i.biometricKyc)],[i.smartSelfieAuthentication,new SelfieJobTypeValidator(i.smartSelfieAuthentication)],[i.smartSelfieEnrollment,new SelfieJobTypeValidator(i.smartSelfieEnrollment)],[i.documentVerification,new DocumentJobTypeValidator(i.documentVerification)],[i.enhancedDocumentVerification,new DocumentJobTypeValidator(i.enhancedDocumentVerification)],[i.residencyDocumentVerification,new DocumentJobTypeValidator(i.residencyDocumentVerification)],[i.enhancedKyc,new NonCaptureJobTypeValidator(i.enhancedKyc)],[i.bvn,new NonCaptureJobTypeValidator(i.bvn)]]);const S=new DefaultStructuralValidator;export function resolveJobTypeValidator(o){return o===void 0||o===i.unknown?S:jobTypeValidators.get(o)??S}export function collectJobTypeIssues(o,e){const n=o.network?.config?.jobType;resolveJobTypeValidator(n).validate(o,e)}export function residencyIdTypeIssue(){return a.forJob({jobType:i.residencyDocumentVerification,reason:`idType must be "${h}" \u2014 the backend rejects any other value for this job type`,suggestedFix:`Set builder.residencyDocumentVerificationParams with idType: "${h}"`})}
1
+ "use strict";import{RESIDENCY_ID_TYPE as y}from"../../../core/models/params";import{JobType as t}from"../../../core/models/job_type";import{InvalidJobTypeScreenConfigException as a,MissingJobTypeException as V,MissingMLConfigurationBlockException as E,MissingNetworkConfigurationBlockException as D}from"../../../core/exception/job_validation_exceptions";import{JOB_PARAMS_OWNERS as P,UnusedJobParamsException as v}from"../../../core/exception/unused_job_params_exception";import{DuplicateScreenTypeException as J,InvalidScreenOrderException as p,MissingCaptureForPreviewException as I}from"../../../core/exception/screen_config_validation_exceptions";import{IssueSeverity as u}from"../../../core/exception/issue_severity";import{isIdFieldBoundByToken as F,tokenConsentMissingSubfields as K}from"../../../data/model/token_payload";import{hasCaptureScreen as g,hasConsentScreen as R,hasDocumentCaptureScreen as A,hasProcessingScreen as w,resolveDocumentCaptures as B,resolveSdkScreens as j,resolveSelfieCaptures as M}from"../config/flow_configuration_screens";const N=new Map([[t.biometricKyc,"BiometricKyc"],[t.smartSelfieAuthentication,"SmartSelfieAuthentication"],[t.smartSelfieEnrollment,"SmartSelfieEnrollment"],[t.enhancedKyc,"EnhancedKyc"],[t.documentVerification,"DocumentVerification"],[t.bvn,"BVN"],[t.enhancedDocumentVerification,"EnhancedDocumentVerification"],[t.residencyDocumentVerification,"ResidencyDocumentVerification"],[t.unknown,"Unknown"]]);function S(o){return N.get(o)??"Unknown"}function h(o,e,n){const i=e.consentInformation!==void 0,r=e.tokenPayload?.consent;if(r!==void 0){const c=K(r);c.length>0&&n.push(a.forJob({jobType:o,reason:`the token's consent binding is incomplete \u2014 missing: ${c.join(", ")}`,suggestedFix:"Bind all four consent fields when minting the token at /v3/token, or bind none and collect consent in the app"}));return}e.skipApiSubmission!==!0&&!R(e.steps)&&!i&&n.push(a.forJob({jobType:o,reason:"must include either a Consent screen or a pre-supplied consentInformation",suggestedFix:"Add a consent { } screen to your flow, or supply consentInformation via the builder"}))}export const JOB_PARAMS_SUPPLIERS={enhancedKYCParams:o=>o.enhancedKYCParams,biometricKYCParams:o=>o.biometricKYCParams,documentVerificationParams:o=>o.documentVerificationParams,enhancedDocumentVerificationParams:o=>o.enhancedDocumentVerificationParams,residencyDocumentVerificationParams:o=>o.residencyDocumentVerificationParams};function b(o,e,n){for(const{fieldName:i,owner:r}of P)r!==o&&JOB_PARAMS_SUPPLIERS[i]?.(e)!==void 0&&n.push(new v({jobType:o,fieldName:i}))}function f(o,e){const n=new Map;let i=0;o.forEach((r,c)=>{if(r.kind==="capture"){i++;return}if(r.kind==="preview"||r.kind==="partner")return;const s=r.kind==="instructions"?`${r.kind}:${i}`:r.kind,d=n.get(s)??{kind:r.kind,indices:[]};d.indices.push(c),n.set(s,d)});for(const{kind:r,indices:c}of n.values())c.length>1&&e.push(new J({screenType:r,indices:c}))}function m(o,e){j(o).findIndex(c=>c.kind==="consent")>0&&e.push(new p({description:"Consent screen must be the first screen in the flow",severity:u.error}));const i=o.findIndex(c=>c.kind==="processing");i!==-1&&i!==o.length-1&&e.push(new p({description:"Processing screen must be the last screen in the flow",severity:u.error}));const r=g(o);o.forEach((c,s)=>{const d=o[s+1]?.kind;c.kind==="instructions"&&r&&d!=="capture"&&d!=="instructions"&&e.push(new p({description:`Instructions screen at index ${s} must be followed by a Capture screen`,severity:u.error}))})}function l(o,e,n){let i=!1,r=0;o.forEach((c,s)=>{c.kind==="capture"?i=!0:c.kind==="preview"&&(r+=1,i?r>e&&n.push(new p({description:`Preview screen at index ${s} exceeds the maximum of ${e} preview screen(s) allowed for this flow`,severity:u.error})):n.push(new I({previewIndex:s})))})}function T(o,e,n){w(e.steps)||n.push(a.forJob({jobType:o,reason:"must include a Processing screen",suggestedFix:"Add a processing { } screen as the last screen in the flow"}))}function k(o,e,n){const i=M(e.steps);i.length===0?n.push(a.forJob({jobType:o,reason:"must include exactly one Capture screen with captureType = SELFIE",suggestedFix:"Add a capture { captureType = CaptureType.SELFIE } screen to your flow"})):i.length>1&&n.push(a.forJob({jobType:o,reason:`must include exactly one Capture screen with captureType = SELFIE, but found ${i.length}`,suggestedFix:"Remove the extra selfie capture screens \u2014 only one is allowed"}))}function C(o,e,n,i){e.ml?e.ml.analyzers.selfie||i.push(a.forJob({jobType:o,reason:"ml { } block must register analyzers for CaptureType.SELFIE",suggestedFix:"Add forCaptureType(CaptureType.SELFIE) { } inside the ml { } block"})):i.push(a.forJob({jobType:o,reason:"ml { } block is required and must register analyzers for CaptureType.SELFIE",suggestedFix:n}))}export class SelfieJobTypeValidator{jobType;constructor(e){this.jobType=e}validate(e,n){f(e.steps,n),m(e.steps,n),l(e.steps,1,n),h(this.jobType,e,n),b(this.jobType,e,n),k(this.jobType,e,n),A(e.steps)&&n.push(a.forJob({jobType:this.jobType,reason:"must not include a Document capture screen",suggestedFix:`Remove the Document capture screen \u2014 ${S(this.jobType)} requires selfie capture only`})),T(this.jobType,e,n),C(this.jobType,e,"Add the ml { } block with forCaptureType(CaptureType.SELFIE) { } inside",n),e.ml?.analyzers.document&&n.push(a.forJob({jobType:this.jobType,reason:"ml { } block must not register analyzers for CaptureType.DOCUMENT",suggestedFix:`Remove forCaptureType(CaptureType.DOCUMENT) { } from the ml { } block \u2014 ${S(this.jobType)} does not use document capture`})),this.jobType===t.biometricKyc&&e.biometricKYCParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"biometricKYCParams is required for BiometricKyc jobs",suggestedFix:"Set builder.biometricKYCParams with the identity fields before building"})),this.jobType===t.smartSelfieAuthentication&&(e.userId===void 0||e.userId.trim()==="")&&n.push(a.forJob({jobType:this.jobType,reason:"userId is required for SmartSelfieAuthentication jobs",suggestedFix:"Set builder.userId with the identifier returned by a prior Smart Selfie Enrollment before building"}))}}export class DocumentJobTypeValidator{jobType;constructor(e){this.jobType=e}validate(e,n){f(e.steps,n),m(e.steps,n),l(e.steps,2,n),h(this.jobType,e,n),b(this.jobType,e,n),k(this.jobType,e,n);const i=B(e.steps);if(i.length===0?n.push(a.forJob({jobType:this.jobType,reason:"must include exactly one Capture screen with captureType = DOCUMENT",suggestedFix:"Add a capture { captureType = CaptureType.DOCUMENT } screen to your flow"})):i.length>1&&n.push(a.forJob({jobType:this.jobType,reason:`must include exactly one Capture screen with captureType = DOCUMENT, but found ${i.length}`,suggestedFix:"Remove the extra document capture screens \u2014 only one is allowed"})),T(this.jobType,e,n),C(this.jobType,e,"Add the ml { } block with forCaptureType(CaptureType.SELFIE) { } inside \u2014 document capture uses NoopDocumentDetectorAnalyzer by default",n),this.appendParamsRule(e,n),this.jobType===t.enhancedDocumentVerification&&i.some(r=>r.documentConfig?.documentType?.kind==="southAfricaGreenBook")&&n.push(a.forJob({jobType:this.jobType,reason:"South Africa Green Book is not supported for Enhanced Document Verification",suggestedFix:"Use JobType.documentVerification for the Green Book, or choose a supported document type for Enhanced Document Verification"})),this.jobType===t.residencyDocumentVerification)for(const r of i){const c=r.documentConfig,s=c?.documentType;s?.kind!=="passport"&&n.push(a.forJob({jobType:this.jobType,reason:`documentType must be passport \u2014 ${s?.kind??"no document type"} is not a residency primary document`,suggestedFix:"Set documentType to the passport preset on the document capture screen"})),c&&c.allowSkipBack===!0&&n.push(a.forJob({jobType:this.jobType,reason:"allowSkipBack must be false \u2014 the visa capture is mandatory",suggestedFix:"Remove allowSkipBack from the document capture screen"}))}}appendParamsRule(e,n){this.jobType===t.documentVerification&&e.documentVerificationParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"documentVerificationParams is required for DocumentVerification jobs",suggestedFix:"Set builder.documentVerificationParams with the country (and optional idType) before building"})),this.jobType===t.enhancedDocumentVerification&&e.enhancedDocumentVerificationParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"enhancedDocumentVerificationParams is required for EnhancedDocumentVerification jobs",suggestedFix:"Set builder.enhancedDocumentVerificationParams with the country and idType before building"})),this.jobType===t.residencyDocumentVerification&&!F(e.tokenPayload,"idType")&&e.residencyDocumentVerificationParams!==void 0&&hasNonPassportIdType(e.residencyDocumentVerificationParams)&&n.push(residencyIdTypeIssue()),this.jobType===t.residencyDocumentVerification&&e.residencyDocumentVerificationParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"residencyDocumentVerificationParams is required for ResidencyDocumentVerification jobs",suggestedFix:"Set builder.residencyDocumentVerificationParams with the country and idType before building"}))}}export class NonCaptureJobTypeValidator{jobType;constructor(e){this.jobType=e}validate(e,n){f(e.steps,n),m(e.steps,n),l(e.steps,0,n),h(this.jobType,e,n),b(this.jobType,e,n),T(this.jobType,e,n);const i=j(e.steps).filter(r=>r.kind!=="consent"&&r.kind!=="processing");if(i.length>0){const r=[...new Set(i.map(c=>c.kind))].join(", ");n.push(a.forJob({jobType:this.jobType,reason:`must only contain consent and processing screens, but found: ${r}`,suggestedFix:"Remove all screens except consent { } and processing { } from your flow"}))}this.jobType===t.enhancedKyc&&e.enhancedKYCParams===void 0&&n.push(a.forJob({jobType:this.jobType,reason:"enhancedKYCParams is required for EnhancedKyc jobs",suggestedFix:"Set builder.enhancedKYCParams with the identity fields before building"}))}}export class UnknownJobTypeValidator{validate(e,n){f(e.steps,n),m(e.steps,n),l(e.steps,2,n),g(e.steps)&&!e.ml&&n.push(new E),w(e.steps)&&!e.network&&n.push(new D),n.push(new V)}}export const jobTypeValidators=new Map([[t.biometricKyc,new SelfieJobTypeValidator(t.biometricKyc)],[t.smartSelfieAuthentication,new SelfieJobTypeValidator(t.smartSelfieAuthentication)],[t.smartSelfieEnrollment,new SelfieJobTypeValidator(t.smartSelfieEnrollment)],[t.documentVerification,new DocumentJobTypeValidator(t.documentVerification)],[t.enhancedDocumentVerification,new DocumentJobTypeValidator(t.enhancedDocumentVerification)],[t.residencyDocumentVerification,new DocumentJobTypeValidator(t.residencyDocumentVerification)],[t.enhancedKyc,new NonCaptureJobTypeValidator(t.enhancedKyc)],[t.bvn,new NonCaptureJobTypeValidator(t.bvn)]]);const x=new UnknownJobTypeValidator;export function resolveJobTypeValidator(o){return o===void 0?x:jobTypeValidators.get(o)??x}export function collectJobTypeIssues(o,e){const n=o.network?.config?.jobType;resolveJobTypeValidator(n).validate(o,e)}export function residencyIdTypeIssue(){return a.forJob({jobType:t.residencyDocumentVerification,reason:`idType must be "${y}" \u2014 the backend rejects any other value for this job type`,suggestedFix:`Set builder.residencyDocumentVerificationParams with idType: "${y}"`})}export function hasNonPassportIdType(o){return(o.idType?.trim()??"")!==""&&o.idType!==y}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smileid/usesmileid",
3
- "version": "12.3.1-SNAPSHOT.69",
3
+ "version": "12.3.1-SNAPSHOT.71",
4
4
  "description": "Official Smile ID React Native (Expo) SDK for identity verification: selfie capture, liveness checks, and document verification powered by on-device ML.",
5
5
  "homepage": "https://usesmileid.com",
6
6
  "repository": {
@@ -48,11 +48,11 @@
48
48
  "CHANGELOG.md"
49
49
  ],
50
50
  "dependencies": {
51
- "@smileid/kamera": "1.2.1-SNAPSHOT.33",
52
- "@smileid/njia": "0.0.1-SNAPSHOT.10",
51
+ "@smileid/kamera": "1.2.1-SNAPSHOT.34",
52
+ "@smileid/njia": "0.0.1-SNAPSHOT.11",
53
53
  "zod": "^4.6.7",
54
- "@smileid/usesmileid_platform_interface": "12.3.1-SNAPSHOT.69",
55
- "@smileid/usesmileid_bridge": "12.3.1-SNAPSHOT.69"
54
+ "@smileid/usesmileid_bridge": "12.3.1-SNAPSHOT.71",
55
+ "@smileid/usesmileid_platform_interface": "12.3.1-SNAPSHOT.71"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "@react-native-async-storage/async-storage": ">=1.21.0",
@@ -102,7 +102,7 @@
102
102
  }
103
103
  },
104
104
  "devDependencies": {
105
- "@smileid/njia-testing": "0.0.1-SNAPSHOT.10",
105
+ "@smileid/njia-testing": "0.0.1-SNAPSHOT.11",
106
106
  "@types/react": "^19.2.18",
107
107
  "expo": "~57.0.26",
108
108
  "expo-brightness": "~57.0.2",
@@ -1,3 +0,0 @@
1
- import type { UseSmileIDLocalizations } from "../../../../l10n/use_smile_id_localizations";
2
- /** Failure copy resolved from `errorCode`; `.message` and `errorCode` are left untouched — they are the `onResult` payload and the analytics field. */
3
- export declare function resolveFailureMessage(error: unknown, localizations: UseSmileIDLocalizations): string;
@@ -1 +0,0 @@
1
- "use strict";import{UseSmileIDErrorCode as i,UseSmileIDException as o,isNetworkErrorCode as n,isRetryableErrorCode as t}from"../../../../core/exception";export function resolveFailureMessage(s,r){if(!(s instanceof o))return r.siProcessingErrorGeneric;const e=s.errorCode;return e===i.Camera.PermissionDenied?r.siProcessingErrorCameraPermission:n(e)?e===i.Network.RequestFailed?r.siProcessingErrorGeneric:e===i.Network.RateLimit||e===i.Network.ServerError?r.siProcessingErrorRetryLater:t(e)?r.siProcessingErrorNoConnection:r.siProcessingErrorUnavailable:r.siProcessingErrorGeneric}
@@ -1,12 +0,0 @@
1
- import type { UseSmileIDOverlayState as OverlayState } from "../../state/use_smile_id_overlay_state";
2
- /**
3
- * Pure-logic helpers for `UseSmileIDProcessingScreen`. The visual
4
- * branches by `state.kind`; this maps each kind to the matching
5
- * overlay-border state so the face oval colour transitions cleanly:
6
- *
7
- * loading → CAPTURING (blue)
8
- * success → READY (green)
9
- * failure → IDLE (default)
10
- */
11
- export type ProcessingStateKind = "loading" | "success" | "failed";
12
- export declare function resolveOverlayStateForProcessing(kind: ProcessingStateKind): OverlayState;
@@ -1 +0,0 @@
1
- "use strict";import{UseSmileIDOverlayState as e}from"../../state/use_smile_id_overlay_state";export function resolveOverlayStateForProcessing(r){switch(r){case"loading":return e.PROCESSING;case"success":return e.READY;case"failed":return e.IDLE}}
@@ -1,15 +0,0 @@
1
- import type { UseSmileIDTheme } from "../theme/theme";
2
- export type UseSmileIDPermissionScreenProps = {
3
- readonly cameraRationale?: string;
4
- readonly onGranted?: () => void;
5
- readonly onDenied?: () => void;
6
- readonly theme?: UseSmileIDTheme;
7
- };
8
- /**
9
- * Permission screen — requests camera (and optionally microphone)
10
- * at the OS level.
11
- *
12
- * **STUB.** Visual implementation pending — see
13
- * `react-native-expo/docs/Architecture.md § Rollout`.
14
- */
15
- export declare function UseSmileIDPermissionScreen(props: UseSmileIDPermissionScreenProps): import("react").JSX.Element;
@@ -1 +0,0 @@
1
- "use strict";import{jsx as o,jsxs as i}from"react/jsx-runtime";import{Text as t,View as n}from"react-native";import{useUseSmileIDTheme as c}from"../theme/theme_context";export function UseSmileIDPermissionScreen(r){const s=c(),e=r.theme??s;return i(n,{style:{flex:1,alignItems:"center",justifyContent:"center",backgroundColor:e.colors.background,padding:e.spacing.large},children:[o(t,{style:{...e.typography.sectionHeading,color:e.colors.titleText},children:"UseSmileIDPermissionScreen"}),o(t,{style:{...e.typography.cardSubTitle,color:e.colors.cardText},children:r.cameraRationale??"Camera permission required \u2014 stub"})]})}