@smileid/usesmileid 12.3.0 → 12.3.1-SNAPSHOT.49

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 (43) hide show
  1. package/README.md +2 -2
  2. package/dist/core/exception/flow_exceptions.d.ts +12 -0
  3. package/dist/core/exception/flow_exceptions.js +1 -1
  4. package/dist/core/exception/index.d.ts +2 -1
  5. package/dist/core/exception/index.js +1 -1
  6. package/dist/core/exception/invalid_partner_screen_exception.d.ts +10 -0
  7. package/dist/core/exception/invalid_partner_screen_exception.js +1 -0
  8. package/dist/core/exception/use_smile_id_error_code.d.ts +1 -0
  9. package/dist/core/exception/use_smile_id_error_code.js +1 -1
  10. package/dist/data/api/connection_warmer.d.ts +27 -0
  11. package/dist/data/api/connection_warmer.js +1 -0
  12. package/dist/data/api/smile_id_api.d.ts +3 -0
  13. package/dist/data/api/smile_id_api.js +1 -1
  14. package/dist/index.d.ts +3 -2
  15. package/dist/index.js +1 -1
  16. package/dist/metadata/metadata_configuration_mappers.js +1 -1
  17. package/dist/presentation/flow/analytics/use_smile_id_analytics_event.d.ts +3 -0
  18. package/dist/presentation/flow/analytics/use_smile_id_analytics_event.js +1 -1
  19. package/dist/presentation/flow/analytics/use_smile_id_analytics_event_kind.d.ts +5 -0
  20. package/dist/presentation/flow/analytics/use_smile_id_analytics_event_kind.js +1 -1
  21. package/dist/presentation/flow/dsl/builder/partner_value_format.d.ts +22 -0
  22. package/dist/presentation/flow/dsl/builder/partner_value_format.js +1 -0
  23. package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +49 -0
  24. package/dist/presentation/flow/dsl/builder/screens_builder.js +1 -1
  25. package/dist/presentation/flow/flow_navigation_engine.d.ts +12 -0
  26. package/dist/presentation/flow/flow_navigation_engine.js +1 -0
  27. package/dist/presentation/flow/flow_navigation_graph.d.ts +32 -0
  28. package/dist/presentation/flow/flow_navigation_graph.js +1 -0
  29. package/dist/presentation/flow/flow_navigation_manager.d.ts +57 -6
  30. package/dist/presentation/flow/flow_navigation_manager.js +1 -1
  31. package/dist/presentation/flow/flow_navigation_manager_analytics.d.ts +9 -1
  32. package/dist/presentation/flow/flow_navigation_manager_analytics.js +1 -1
  33. package/dist/presentation/flow/flow_navigation_manager_routing.d.ts +26 -1
  34. package/dist/presentation/flow/flow_navigation_manager_routing.js +1 -1
  35. package/dist/presentation/flow/graph/screen_renderer.js +1 -1
  36. package/dist/presentation/flow/screen/orchestrated_partner_screen.d.ts +10 -0
  37. package/dist/presentation/flow/screen/orchestrated_partner_screen.js +1 -0
  38. package/dist/presentation/flow/use_smile_id_flow.js +1 -1
  39. package/dist/presentation/flow/validation/flow_validator.js +1 -1
  40. package/dist/presentation/flow/validation/job_type_validator.js +1 -1
  41. package/dist/presentation/flow/validation/partner_screen_validation.d.ts +10 -0
  42. package/dist/presentation/flow/validation/partner_screen_validation.js +1 -0
  43. package/package.json +5 -3
package/README.md CHANGED
@@ -53,7 +53,7 @@ npx expo install expo-brightness expo-file-system expo-font expo-haptics \
53
53
  expo-image-manipulator expo-image-picker expo-keep-awake expo-screen-orientation
54
54
  ```
55
55
 
56
- (For Android phones without Google Play services, use `@smileid/usesmileid_huawei_{face,document}` instead of the ML Kit packages in the build you ship to those phones, such as your AppGallery build. Your Google Play build keeps ML Kit.)
56
+ (For Android phones without Google Play services, add `@smileid/usesmileid_huawei_{face,document}` and pick per phone, or ship a build per store whose AppGallery flavor uses them instead of the ML Kit packages: see the repository README's Huawei section.)
57
57
 
58
58
  Everything above except the `@smileid/*` packages is a **required peer dependency**, and must be installed in your app directly: React Native autolinking only links native modules declared in the app's own `package.json`, not a library's transitive ones. `expo`, `expo-modules-core`, `react` and `react-native` are omitted because they ship with your app.
59
59
 
@@ -78,7 +78,7 @@ The provider packages each have native code (Android AAR / iOS SPM), and the ML
78
78
  }
79
79
  ```
80
80
 
81
- Autolinking finds the native modules through `expo-module.config.json` on its own, but it cannot change settings the root Gradle project and the Podfile own — without these plugins the build does not compile. The Android plugins pin the Kotlin the AARs were compiled with (2.3.20) and the `androidx.core` version that resolves under Expo's Android Gradle Plugin; Expo's own KSP lookup carries no entry for that Kotlin, so pass `kspVersion` as shown. The Huawei providers ship no config plugin — apply those root Gradle settings yourself on a no-GMS target. For bare React Native, run `npx pod-install` after adding the packages and let Gradle resolve the AARs on the next Android build.
81
+ Autolinking finds the native modules through `expo-module.config.json` on its own, but it cannot change settings the root Gradle project and the Podfile own — without these plugins the build does not compile. The Android plugins pin the Kotlin the AARs were compiled with (2.3.20) and the `androidx.core` version that resolves under Expo's Android Gradle Plugin; Expo's own KSP lookup carries no entry for that Kotlin, so pass `kspVersion` as shown. The Huawei packages' config plugin settles `android:allowBackup` and, with `storeFlavors`, writes a flavor per store. For bare React Native, run `npx pod-install` after adding the packages and let Gradle resolve the AARs on the next Android build.
82
82
 
83
83
  ---
84
84
 
@@ -26,3 +26,15 @@ export declare class ProcessingCancelledException extends UseSmileIDGeneralExcep
26
26
  cause?: unknown;
27
27
  });
28
28
  }
29
+ /**
30
+ * The flow's navigation failed: njia refused to start the flow's engine, or a
31
+ * call to it failed. Surfaced through `onResult.failure` with
32
+ * `GENERAL_INVALID_STATE` and njia's error as its `cause`, as the native SDKs
33
+ * surface it through their general exception.
34
+ */
35
+ export declare class NavigationFailedException extends UseSmileIDGeneralException {
36
+ readonly errorCode: "GENERAL_INVALID_STATE";
37
+ constructor(args: {
38
+ cause: unknown;
39
+ });
40
+ }
@@ -1 +1 @@
1
- "use strict";import{UseSmileIDErrorCode as s}from"./use_smile_id_error_code";import{UseSmileIDGeneralException as r}from"./use_smile_id_general_exception";export class ConsentDeniedException extends r{errorCode=s.General.OperationFailed;constructor(e){super({message:"User denied consent",suggestedFix:"The user declined the consent notice; no further action is required.",errorDetails:{timestamp:e.timestamp}})}}export class ProcessingCancelledException extends r{errorCode=s.General.OperationFailed;constructor(e={}){super({message:"Processing was cancelled",suggestedFix:"The user exited the processing screen before submission completed.",...e.cause!==void 0?{cause:e.cause}:{}})}}
1
+ "use strict";import{UseSmileIDErrorCode as s}from"./use_smile_id_error_code";import{UseSmileIDGeneralException as r}from"./use_smile_id_general_exception";export class ConsentDeniedException extends r{errorCode=s.General.OperationFailed;constructor(e){super({message:"User denied consent",suggestedFix:"The user declined the consent notice; no further action is required.",errorDetails:{timestamp:e.timestamp}})}}export class ProcessingCancelledException extends r{errorCode=s.General.OperationFailed;constructor(e={}){super({message:"Processing was cancelled",suggestedFix:"The user exited the processing screen before submission completed.",...e.cause!==void 0?{cause:e.cause}:{}})}}export class NavigationFailedException extends r{errorCode=s.General.InvalidState;constructor(e){super({message:`The flow's navigation failed: ${e.cause instanceof Error?e.cause.message:String(e.cause)}`,suggestedFix:"Contact Smile ID support if the issue persists.",cause:e.cause})}}
@@ -20,9 +20,10 @@ export { UseSmileIDNetworkException } from "./use_smile_id_network_exception";
20
20
  export { UseSmileIDAttestationException } from "./use_smile_id_attestation_exception";
21
21
  export { UseSmileIDGeneralException } from "./use_smile_id_general_exception";
22
22
  export { BuilderValidationException } from "./builder_validation_exception";
23
- export { ConsentDeniedException, ProcessingCancelledException, } from "./flow_exceptions";
23
+ export { ConsentDeniedException, NavigationFailedException, ProcessingCancelledException, } from "./flow_exceptions";
24
24
  export { EmptyScreensBlockException } from "./empty_screens_block_exception";
25
25
  export { InvalidScreenOrderException } from "./invalid_screen_order_exception";
26
+ export { InvalidPartnerScreenException } from "./invalid_partner_screen_exception";
26
27
  export { MissingCaptureForPreviewException } from "./missing_capture_for_preview_exception";
27
28
  export { DuplicateScreenTypeException } from "./duplicate_screen_type_exception";
28
29
  export { AgentModeWithEnhancedLivenessException } from "./agent_mode_with_enhanced_liveness_exception";
@@ -1 +1 @@
1
- "use strict";export{IssueSeverity}from"./issue_severity";export{UseSmileIDErrorCode,isNetworkErrorCode,isRetryableErrorCode}from"./use_smile_id_error_code";export{UseSmileIDException}from"./use_smile_id_exception";export{UseSmileIDValidationException}from"./use_smile_id_validation_exception";export{UseSmileIDBuilderException}from"./use_smile_id_builder_exception";export{UseSmileIDCameraException}from"./use_smile_id_camera_exception";export{UseSmileIDCameraSurfaceException}from"./use_smile_id_camera_surface_exception";export{UseSmileIDNetworkException}from"./use_smile_id_network_exception";export{UseSmileIDAttestationException}from"./use_smile_id_attestation_exception";export{UseSmileIDGeneralException}from"./use_smile_id_general_exception";export{BuilderValidationException}from"./builder_validation_exception";export{ConsentDeniedException,ProcessingCancelledException}from"./flow_exceptions";export{EmptyScreensBlockException}from"./empty_screens_block_exception";export{InvalidScreenOrderException}from"./invalid_screen_order_exception";export{MissingCaptureForPreviewException}from"./missing_capture_for_preview_exception";export{DuplicateScreenTypeException}from"./duplicate_screen_type_exception";export{AgentModeWithEnhancedLivenessException}from"./agent_mode_with_enhanced_liveness_exception";export{InvalidSelfieCaptureConfigException}from"./invalid_selfie_capture_config_exception";export{InvalidDocumentCaptureConfigException}from"./invalid_document_capture_config_exception";export{InvalidMissingCaptureTypeException}from"./invalid_missing_capture_type_exception";export{InvalidConsentConfigException}from"./invalid_consent_config_exception";export{InvalidConsentInformationException}from"./invalid_consent_information_exception";export{MissingMLConfigurationBlockException}from"./missing_ml_configuration_block_exception";export{MissingNetworkConfigurationBlockException}from"./missing_network_configuration_block_exception";export{MissingPartnerConfigException}from"./missing_partner_config_exception";export{LivenessFrameCountException}from"./liveness_frame_count_exception";export{MissingJobTypeException}from"./missing_job_type_exception";export{MissingRequiredFieldException}from"./missing_required_field_exception";export{InvalidJobTypeScreenConfigException}from"./invalid_job_type_screen_config_exception";export{UnusedJobParamsException}from"./unused_job_params_exception";export{InvalidFieldValueException}from"./invalid_field_value_exception";export{NetworkServerException,NetworkTransportException,NetworkTimeoutException,NetworkResponseParseException,NetworkRequestBuildException,NetworkUnknownException,mapAxiosError}from"./use_smile_id_network_exception";
1
+ "use strict";export{IssueSeverity}from"./issue_severity";export{UseSmileIDErrorCode,isNetworkErrorCode,isRetryableErrorCode}from"./use_smile_id_error_code";export{UseSmileIDException}from"./use_smile_id_exception";export{UseSmileIDValidationException}from"./use_smile_id_validation_exception";export{UseSmileIDBuilderException}from"./use_smile_id_builder_exception";export{UseSmileIDCameraException}from"./use_smile_id_camera_exception";export{UseSmileIDCameraSurfaceException}from"./use_smile_id_camera_surface_exception";export{UseSmileIDNetworkException}from"./use_smile_id_network_exception";export{UseSmileIDAttestationException}from"./use_smile_id_attestation_exception";export{UseSmileIDGeneralException}from"./use_smile_id_general_exception";export{BuilderValidationException}from"./builder_validation_exception";export{ConsentDeniedException,NavigationFailedException,ProcessingCancelledException}from"./flow_exceptions";export{EmptyScreensBlockException}from"./empty_screens_block_exception";export{InvalidScreenOrderException}from"./invalid_screen_order_exception";export{InvalidPartnerScreenException}from"./invalid_partner_screen_exception";export{MissingCaptureForPreviewException}from"./missing_capture_for_preview_exception";export{DuplicateScreenTypeException}from"./duplicate_screen_type_exception";export{AgentModeWithEnhancedLivenessException}from"./agent_mode_with_enhanced_liveness_exception";export{InvalidSelfieCaptureConfigException}from"./invalid_selfie_capture_config_exception";export{InvalidDocumentCaptureConfigException}from"./invalid_document_capture_config_exception";export{InvalidMissingCaptureTypeException}from"./invalid_missing_capture_type_exception";export{InvalidConsentConfigException}from"./invalid_consent_config_exception";export{InvalidConsentInformationException}from"./invalid_consent_information_exception";export{MissingMLConfigurationBlockException}from"./missing_ml_configuration_block_exception";export{MissingNetworkConfigurationBlockException}from"./missing_network_configuration_block_exception";export{MissingPartnerConfigException}from"./missing_partner_config_exception";export{LivenessFrameCountException}from"./liveness_frame_count_exception";export{MissingJobTypeException}from"./missing_job_type_exception";export{MissingRequiredFieldException}from"./missing_required_field_exception";export{InvalidJobTypeScreenConfigException}from"./invalid_job_type_screen_config_exception";export{UnusedJobParamsException}from"./unused_job_params_exception";export{InvalidFieldValueException}from"./invalid_field_value_exception";export{NetworkServerException,NetworkTransportException,NetworkTimeoutException,NetworkResponseParseException,NetworkRequestBuildException,NetworkUnknownException,mapAxiosError}from"./use_smile_id_network_exception";
@@ -0,0 +1,10 @@
1
+ import { UseSmileIDBuilderException } from "./use_smile_id_builder_exception";
2
+ /**
3
+ * A partner screen (`screens.partner(id, render)`) has a blank or repeated
4
+ * id, or sits between a capture and its preview, which the flow keeps
5
+ * together so the preview's Retake reaches the capture.
6
+ */
7
+ export declare class InvalidPartnerScreenException extends UseSmileIDBuilderException {
8
+ readonly errorCode: "BUILDER_INVALID_PARTNER_SCREEN";
9
+ constructor(reason: string);
10
+ }
@@ -0,0 +1 @@
1
+ "use strict";import{IssueSeverity as r}from"./issue_severity";import{UseSmileIDBuilderException as i}from"./use_smile_id_builder_exception";import{UseSmileIDErrorCode as t}from"./use_smile_id_error_code";export class InvalidPartnerScreenException extends i{errorCode=t.Builder.InvalidPartnerScreen;constructor(e){super({message:`Invalid partner screen: ${e}`,severity:r.error,suggestedFix:"Give each partner screen its own non-blank id, and place it before a capture or after its preview.",errorDetails:{reason:e}})}}
@@ -35,6 +35,7 @@ export declare const UseSmileIDErrorCode: {
35
35
  readonly InvalidConsentInformation: "BUILDER_INVALID_CONSENT_INFORMATION";
36
36
  readonly InvalidJobTypeScreenConfig: "BUILDER_INVALID_JOB_TYPE_SCREEN_CONFIG";
37
37
  readonly UnusedJobParams: "BUILDER_UNUSED_JOB_PARAMS";
38
+ readonly InvalidPartnerScreen: "BUILDER_INVALID_PARTNER_SCREEN";
38
39
  };
39
40
  /** Camera / capture surface. */
40
41
  readonly Camera: {
@@ -1 +1 @@
1
- "use strict";export const UseSmileIDErrorCode={Builder:{ValidationError:"BUILDER_VALIDATION_ERROR",InvalidConfiguration:"BUILDER_INVALID_CONFIG",MissingRequiredField:"BUILDER_MISSING_FIELD",InvalidConsentConfig:"BUILDER_INVALID_CONSENT_CONFIG",MissingCaptureType:"BUILDER_MISSING_CAPTURE_TYPE",EmptyScreensBlock:"BUILDER_EMPTY_SCREENS",MissingScreenConfiguration:"BUILDER_MISSING_SCREEN_CONFIG",DuplicateScreenType:"BUILDER_DUPLICATE_SCREEN",InvalidSelfieCaptureConfig:"BUILDER_INVALID_SELFIE_CONFIG",AgentModeWithEnhancedLiveness:"BUILDER_AGENT_MODE_WITH_ENHANCED_LIVENESS",InvalidDocumentCaptureConfig:"BUILDER_INVALID_DOCUMENT_CONFIG",MissingMLConfiguration:"BUILDER_MISSING_ML_CONFIG",MissingNetworkConfiguration:"BUILDER_MISSING_NETWORK_CONFIG",MissingJobType:"BUILDER_MISSING_JOB_TYPE",MissingCaptureForPreview:"BUILDER_MISSING_CAPTURE_FOR_PREVIEW",InvalidScreenOrder:"BUILDER_INVALID_SCREEN_ORDER",ConfigurationBlockFailed:"BUILDER_CONFIG_BLOCK_FAILED",InvalidConsentInformation:"BUILDER_INVALID_CONSENT_INFORMATION",InvalidJobTypeScreenConfig:"BUILDER_INVALID_JOB_TYPE_SCREEN_CONFIG",UnusedJobParams:"BUILDER_UNUSED_JOB_PARAMS"},Camera:{InitializationFailed:"CAMERA_INIT_FAILED",PermissionDenied:"CAMERA_PERMISSION_DENIED",CaptureFailed:"CAMERA_CAPTURE_FAILED",UseCaseNotSupported:"CAMERA_USE_CASE_NOT_SUPPORTED",VideoCaptureDisabled:"CAMERA_VIDEO_DISABLED",Unknown:"CAMERA_UNKNOWN_ERROR"},Network:{ConnectionFailed:"NETWORK_CONNECTION_FAILED",Timeout:"NETWORK_TIMEOUT",RequestFailed:"NETWORK_REQUEST_FAILED",ResponseParseError:"NETWORK_PARSE_ERROR",Unauthorized:"NETWORK_UNAUTHORIZED",Forbidden:"NETWORK_FORBIDDEN",NotFound:"NETWORK_NOT_FOUND",RateLimit:"NETWORK_RATE_LIMIT",ServerError:"NETWORK_SERVER_ERROR",CallbackUrlRequired:"NETWORK_CALLBACK_URL_REQUIRED"},Validation:{InvalidInput:"VALIDATION_INVALID_INPUT",InvalidState:"VALIDATION_INVALID_STATE",ConstraintViolation:"VALIDATION_CONSTRAINT_VIOLATION"},General:{Unknown:"GENERAL_UNKNOWN_ERROR",InvalidState:"GENERAL_INVALID_STATE",OperationFailed:"GENERAL_OPERATION_FAILED"}};const I=new Set([UseSmileIDErrorCode.Camera.CaptureFailed,UseSmileIDErrorCode.Network.ConnectionFailed,UseSmileIDErrorCode.Network.Timeout,UseSmileIDErrorCode.Network.RateLimit,UseSmileIDErrorCode.Network.ServerError]),e=new Set(Object.values(UseSmileIDErrorCode.Network));export function isRetryableErrorCode(E){return I.has(E)}export function isNetworkErrorCode(E){return e.has(E)}
1
+ "use strict";export const UseSmileIDErrorCode={Builder:{ValidationError:"BUILDER_VALIDATION_ERROR",InvalidConfiguration:"BUILDER_INVALID_CONFIG",MissingRequiredField:"BUILDER_MISSING_FIELD",InvalidConsentConfig:"BUILDER_INVALID_CONSENT_CONFIG",MissingCaptureType:"BUILDER_MISSING_CAPTURE_TYPE",EmptyScreensBlock:"BUILDER_EMPTY_SCREENS",MissingScreenConfiguration:"BUILDER_MISSING_SCREEN_CONFIG",DuplicateScreenType:"BUILDER_DUPLICATE_SCREEN",InvalidSelfieCaptureConfig:"BUILDER_INVALID_SELFIE_CONFIG",AgentModeWithEnhancedLiveness:"BUILDER_AGENT_MODE_WITH_ENHANCED_LIVENESS",InvalidDocumentCaptureConfig:"BUILDER_INVALID_DOCUMENT_CONFIG",MissingMLConfiguration:"BUILDER_MISSING_ML_CONFIG",MissingNetworkConfiguration:"BUILDER_MISSING_NETWORK_CONFIG",MissingJobType:"BUILDER_MISSING_JOB_TYPE",MissingCaptureForPreview:"BUILDER_MISSING_CAPTURE_FOR_PREVIEW",InvalidScreenOrder:"BUILDER_INVALID_SCREEN_ORDER",ConfigurationBlockFailed:"BUILDER_CONFIG_BLOCK_FAILED",InvalidConsentInformation:"BUILDER_INVALID_CONSENT_INFORMATION",InvalidJobTypeScreenConfig:"BUILDER_INVALID_JOB_TYPE_SCREEN_CONFIG",UnusedJobParams:"BUILDER_UNUSED_JOB_PARAMS",InvalidPartnerScreen:"BUILDER_INVALID_PARTNER_SCREEN"},Camera:{InitializationFailed:"CAMERA_INIT_FAILED",PermissionDenied:"CAMERA_PERMISSION_DENIED",CaptureFailed:"CAMERA_CAPTURE_FAILED",UseCaseNotSupported:"CAMERA_USE_CASE_NOT_SUPPORTED",VideoCaptureDisabled:"CAMERA_VIDEO_DISABLED",Unknown:"CAMERA_UNKNOWN_ERROR"},Network:{ConnectionFailed:"NETWORK_CONNECTION_FAILED",Timeout:"NETWORK_TIMEOUT",RequestFailed:"NETWORK_REQUEST_FAILED",ResponseParseError:"NETWORK_PARSE_ERROR",Unauthorized:"NETWORK_UNAUTHORIZED",Forbidden:"NETWORK_FORBIDDEN",NotFound:"NETWORK_NOT_FOUND",RateLimit:"NETWORK_RATE_LIMIT",ServerError:"NETWORK_SERVER_ERROR",CallbackUrlRequired:"NETWORK_CALLBACK_URL_REQUIRED"},Validation:{InvalidInput:"VALIDATION_INVALID_INPUT",InvalidState:"VALIDATION_INVALID_STATE",ConstraintViolation:"VALIDATION_CONSTRAINT_VIOLATION"},General:{Unknown:"GENERAL_UNKNOWN_ERROR",InvalidState:"GENERAL_INVALID_STATE",OperationFailed:"GENERAL_OPERATION_FAILED"}};const I=new Set([UseSmileIDErrorCode.Camera.CaptureFailed,UseSmileIDErrorCode.Network.ConnectionFailed,UseSmileIDErrorCode.Network.Timeout,UseSmileIDErrorCode.Network.RateLimit,UseSmileIDErrorCode.Network.ServerError]),e=new Set(Object.values(UseSmileIDErrorCode.Network));export function isRetryableErrorCode(E){return I.has(E)}export function isNetworkErrorCode(E){return e.has(E)}
@@ -0,0 +1,27 @@
1
+ import { type AxiosInstance } from "axios";
2
+ /** A submission path, so the preflight goes to the host and stage the submission does. */
3
+ export declare const PREFLIGHT_PATH = "/v3/registration";
4
+ /**
5
+ * Opens the connection a flow's submission will use while the user is still
6
+ * on the first screens, so the submission doesn't wait on the processing
7
+ * screen for DNS, TCP and TLS as well as the upload.
8
+ *
9
+ * `warmUp` sends one CORS preflight, `OPTIONS /v3/registration`, to the API
10
+ * host. API Gateway answers preflights itself, with no Lambda behind it. The
11
+ * preflight goes through a bare axios instance with the submission client's
12
+ * base URL and adapter, and none of its interceptors: it carries no token,
13
+ * signature, integrity claim or partner header, and the partner's own
14
+ * interceptors never see it. React Native sends every request through one
15
+ * native client (OkHttp on Android, an `NSURLSession` on iOS), so the
16
+ * connection lands in the pool the submission draws from.
17
+ */
18
+ export declare class ConnectionWarmer {
19
+ private readonly _client;
20
+ private _started;
21
+ constructor(submissionClient: AxiosInstance);
22
+ /**
23
+ * Sends the preflight once; later calls do nothing. A failure is ignored:
24
+ * the submission then connects as it would have.
25
+ */
26
+ warmUp(): void;
27
+ }
@@ -0,0 +1 @@
1
+ "use strict";import n from"axios";export const PREFLIGHT_PATH="/v3/registration";export class ConnectionWarmer{_client;_started=!1;constructor(i){const{baseURL:t,timeout:e,adapter:r}=i.defaults;this._client=n.create({...t!==void 0&&{baseURL:t},...e!==void 0&&{timeout:e},...r!==void 0&&{adapter:r}})}warmUp(){this._started||(this._started=!0,this._client.request({url:PREFLIGHT_PATH,method:"options"}).catch(()=>{}))}}
@@ -24,6 +24,9 @@ export declare class SmileIDAPI {
24
24
  private readonly _client;
25
25
  private readonly _partnerConfig;
26
26
  constructor(client: AxiosInstance, partnerConfig: PartnerConfig);
27
+ private _connectionWarmer;
28
+ /** Opens the connection the submission will use, once per client; see `ConnectionWarmer`. */
29
+ warmUpConnection(): void;
27
30
  /**
28
31
  * v3 smart-selfie enrollment.
29
32
  *
@@ -1 +1 @@
1
- "use strict";import u from"axios";import{SmileIDUrls as d}from"../smile_id_urls";import{userDetailsPayloadToWire as g}from"../model/user_details_payload";import{SmileAuthInterceptor as h}from"./interceptors/smile_auth_interceptor";import{attachLoggingInterceptor as y}from"./interceptors/logging_interceptor";import{REQUEST_MAC_OPT_IN_KEY as b}from"./interceptors/smile_request_mac_interceptor";import{ATTESTATION_OPT_IN_KEY as D}from"./interceptors/smile_integrity_interceptor";import{NetworkResponseParseException as m}from"../../core/exception";import{LivenessFrameCountException as S}from"../../core/exception";const l=d.production,_=d.sandbox,C={[b]:!0,[D]:!0};export class SmileIDAPI{_client;_partnerConfig;constructor(t,n){this._client=t,this._partnerConfig=n}async smartSelfieEnrollment(t){const n=this._buildSelfieFormData(t);return r(n,t),this._appendPartnerConfigParts(n),this._appendConsentAndMetadata(n,t.consent,t.metadata),this._postMultipart("/v3/registration",n)}async smartSelfieAuthentication(t){const n=this._buildSelfieFormData(t);return i(n,"user_id",t.userId),r(n,t),this._appendPartnerConfigParts(n),this._appendConsentAndMetadata(n,t.consent,t.metadata),this._postMultipart("/v3/authentication",n)}async enhancedKyc(t){const n=new FormData;return this._appendIdFields(n,t.params),r(n,t),t.params.bankCode&&i(n,"bank_code",t.params.bankCode),t.params.mobileOperator&&i(n,"operator",t.params.mobileOperator),this._appendPartnerConfigParts(n),this._appendConsentAndMetadata(n,t.consent,t.metadata),this._postMultipart("/v3/enhanced_kyc",n)}async biometricKyc(t){const n=t.params.useEnrolledImage,e=this._buildSelfieFormData(t);return this._appendIdFields(e,t.params),r(e,t),n&&i(e,"use_enrolled_image","true"),this._appendPartnerConfigParts(e),this._appendConsentAndMetadata(e,t.consent,t.metadata),this._postMultipart("/v3/biometric_kyc",e)}async documentVerification(t){return this._postDocumentVerification(t,"/v3/document_verification")}async enhancedDocumentVerification(t){return this._postDocumentVerification(t,"/v3/enhanced_document_verification")}async residencyDocumentVerification(t){return this._postDocumentVerification(t,"/v3/residency_document_verification")}async _postDocumentVerification(t,n){const e=this._buildSelfieFormData(t);return s(e,"document",t.frontDocument),"backDocument"in t&&t.backDocument&&s(e,"document_back",t.backDocument),"visaDocument"in t&&s(e,"visa",t.visaDocument),t.country&&i(e,"country",t.country),t.idType&&i(e,"id_type",t.idType),r(e,t),this._appendPartnerConfigParts(e),this._appendConsentAndMetadata(e,t.consent,t.metadata),this._postMultipart(n,e)}_buildSelfieFormData(t){SmileIDAPI._validateLivenessCount(t.livenessImages,t.expectedLivenessImageCount);const n=new FormData;s(n,"selfie_image",t.selfieImage);for(const e of t.livenessImages)s(n,"liveness_images",e);return n}static _validateLivenessCount(t,n){if(t.length!==n)throw new S({expected:n,actual:t.length})}_appendIdFields(t,n){n.idType&&i(t,"id_type",n.idType),n.idNumber&&i(t,"id_number",n.idNumber),n.country&&i(t,"country",n.country)}_appendPartnerConfigParts(t){const n=this._partnerConfig.callbackUrl;n&&i(t,"callback_url",n);const e=this._partnerConfig.partnerParams;e&&Object.keys(e).length>0&&c(t,"partner_params",e)}_appendConsentAndMetadata(t,n,e){n!==void 0&&c(t,"consent",{granted:n.granted,granted_at:n.grantedAt,notice_language:n.noticeLanguage,notice_privacy_policy_url:n.noticePrivacyPolicyUrl}),c(t,"metadata",e.toEntries())}async _postMultipart(t,n){const e=await this._client.post(t,n,{headers:{"Content-Type":"multipart/form-data"},...C});return P(e.data)}}function P(a){if(a==null||typeof a!="object"||Array.isArray(a))throw new m({message:"SmileIDAPI: server returned an empty or non-object response body."});const t=a,n=(p,f)=>{if(typeof p!="string")throw new m({message:`SmileIDAPI: response is missing the required string field '${f}'.`});return p},e={jobId:n(t.job_id??t.jobId,"job_id"),userId:n(t.user_id??t.userId,"user_id"),status:n(t.status,"status"),message:n(t.message,"message")},o=t.created_at??t.createdAt;return typeof o=="string"&&o.length>0?{...e,createdAt:o}:e}function r(a,t){const n=t.userDetails;n!==void 0&&c(a,"user_details",g(n))}function i(a,t,n){a.append(t,n)}function c(a,t,n){const e=JSON.stringify(n);a.append(t,e)}function s(a,t,n){const e=n.split("/").pop()??`${t}.jpg`;a.append(t,{uri:n,name:e,type:"image/jpeg"})}export function buildAxiosClient(a){const e=a.config?.partnerConfig?.useSandbox??!0?_:l,o=a.timeouts?.call??120;return u.create({baseURL:e,timeout:o*1e3})}export{h as SmileAuthInterceptor,y as attachLoggingInterceptor,l as PROD_BASE_URL,_ as SANDBOX_BASE_URL};
1
+ "use strict";import u from"axios";import{SmileIDUrls as d}from"../smile_id_urls";import{userDetailsPayloadToWire as g}from"../model/user_details_payload";import{SmileAuthInterceptor as h}from"./interceptors/smile_auth_interceptor";import{attachLoggingInterceptor as y}from"./interceptors/logging_interceptor";import{REQUEST_MAC_OPT_IN_KEY as b}from"./interceptors/smile_request_mac_interceptor";import{ATTESTATION_OPT_IN_KEY as D}from"./interceptors/smile_integrity_interceptor";import{NetworkResponseParseException as m}from"../../core/exception";import{LivenessFrameCountException as C}from"../../core/exception";import{ConnectionWarmer as S}from"./connection_warmer";const l=d.production,_=d.sandbox,P={[b]:!0,[D]:!0};export class SmileIDAPI{_client;_partnerConfig;constructor(t,n){this._client=t,this._partnerConfig=n}_connectionWarmer;warmUpConnection(){(this._connectionWarmer??=new S(this._client)).warmUp()}async smartSelfieEnrollment(t){const n=this._buildSelfieFormData(t);return r(n,t),this._appendPartnerConfigParts(n),this._appendConsentAndMetadata(n,t.consent,t.metadata),this._postMultipart("/v3/registration",n)}async smartSelfieAuthentication(t){const n=this._buildSelfieFormData(t);return i(n,"user_id",t.userId),r(n,t),this._appendPartnerConfigParts(n),this._appendConsentAndMetadata(n,t.consent,t.metadata),this._postMultipart("/v3/authentication",n)}async enhancedKyc(t){const n=new FormData;return this._appendIdFields(n,t.params),r(n,t),t.params.bankCode&&i(n,"bank_code",t.params.bankCode),t.params.mobileOperator&&i(n,"operator",t.params.mobileOperator),this._appendPartnerConfigParts(n),this._appendConsentAndMetadata(n,t.consent,t.metadata),this._postMultipart("/v3/enhanced_kyc",n)}async biometricKyc(t){const n=t.params.useEnrolledImage,e=this._buildSelfieFormData(t);return this._appendIdFields(e,t.params),r(e,t),n&&i(e,"use_enrolled_image","true"),this._appendPartnerConfigParts(e),this._appendConsentAndMetadata(e,t.consent,t.metadata),this._postMultipart("/v3/biometric_kyc",e)}async documentVerification(t){return this._postDocumentVerification(t,"/v3/document_verification")}async enhancedDocumentVerification(t){return this._postDocumentVerification(t,"/v3/enhanced_document_verification")}async residencyDocumentVerification(t){return this._postDocumentVerification(t,"/v3/residency_document_verification")}async _postDocumentVerification(t,n){const e=this._buildSelfieFormData(t);return s(e,"document",t.frontDocument),"backDocument"in t&&t.backDocument&&s(e,"document_back",t.backDocument),"visaDocument"in t&&s(e,"visa",t.visaDocument),t.country&&i(e,"country",t.country),t.idType&&i(e,"id_type",t.idType),r(e,t),this._appendPartnerConfigParts(e),this._appendConsentAndMetadata(e,t.consent,t.metadata),this._postMultipart(n,e)}_buildSelfieFormData(t){SmileIDAPI._validateLivenessCount(t.livenessImages,t.expectedLivenessImageCount);const n=new FormData;s(n,"selfie_image",t.selfieImage);for(const e of t.livenessImages)s(n,"liveness_images",e);return n}static _validateLivenessCount(t,n){if(t.length!==n)throw new C({expected:n,actual:t.length})}_appendIdFields(t,n){n.idType&&i(t,"id_type",n.idType),n.idNumber&&i(t,"id_number",n.idNumber),n.country&&i(t,"country",n.country)}_appendPartnerConfigParts(t){const n=this._partnerConfig.callbackUrl;n&&i(t,"callback_url",n);const e=this._partnerConfig.partnerParams;e&&Object.keys(e).length>0&&c(t,"partner_params",e)}_appendConsentAndMetadata(t,n,e){n!==void 0&&c(t,"consent",{granted:n.granted,granted_at:n.grantedAt,notice_language:n.noticeLanguage,notice_privacy_policy_url:n.noticePrivacyPolicyUrl}),c(t,"metadata",e.toEntries())}async _postMultipart(t,n){const e=await this._client.post(t,n,{headers:{"Content-Type":"multipart/form-data"},...P});return I(e.data)}}function I(a){if(a==null||typeof a!="object"||Array.isArray(a))throw new m({message:"SmileIDAPI: server returned an empty or non-object response body."});const t=a,n=(p,f)=>{if(typeof p!="string")throw new m({message:`SmileIDAPI: response is missing the required string field '${f}'.`});return p},e={jobId:n(t.job_id??t.jobId,"job_id"),userId:n(t.user_id??t.userId,"user_id"),status:n(t.status,"status"),message:n(t.message,"message")},o=t.created_at??t.createdAt;return typeof o=="string"&&o.length>0?{...e,createdAt:o}:e}function r(a,t){const n=t.userDetails;n!==void 0&&c(a,"user_details",g(n))}function i(a,t,n){a.append(t,n)}function c(a,t,n){const e=JSON.stringify(n);a.append(t,e)}function s(a,t,n){const e=n.split("/").pop()??`${t}.jpg`;a.append(t,{uri:n,name:e,type:"image/jpeg"})}export function buildAxiosClient(a){const e=a.config?.partnerConfig?.useSandbox??!0?_:l,o=a.timeouts?.call??120;return u.create({baseURL:e,timeout:o*1e3})}export{h as SmileAuthInterceptor,y as attachLoggingInterceptor,l as PROD_BASE_URL,_ as SANDBOX_BASE_URL};
package/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export { UseSmileIDBuilder } from "./presentation/flow/dsl/use_smile_id_builder"
10
10
  export { UseSmileIDFlowBuilder } from "./presentation/flow/dsl/use_smile_id_flow_builder";
11
11
  export type { FlowBuildResult, FlowBuildResultInvalid, FlowBuildResultSuccess, } from "./presentation/flow/dsl/flow_build_result";
12
12
  export { ValidationState, type ValidationIssue, type ValidationStateInvalid, } from "./presentation/flow/validation/validation_state";
13
- export { AgentModeWithEnhancedLivenessException, BuilderValidationException, isNetworkErrorCode, isRetryableErrorCode, ConsentDeniedException, DuplicateScreenTypeException, EmptyScreensBlockException, InvalidConsentConfigException, InvalidConsentInformationException, InvalidDocumentCaptureConfigException, InvalidFieldValueException, InvalidJobTypeScreenConfigException, InvalidMissingCaptureTypeException, InvalidScreenOrderException, InvalidSelfieCaptureConfigException, LivenessFrameCountException, IssueSeverity, MissingCaptureForPreviewException, MissingJobTypeException, MissingMLConfigurationBlockException, MissingNetworkConfigurationBlockException, MissingPartnerConfigException, MissingRequiredFieldException, ProcessingCancelledException, UseSmileIDAttestationException, UseSmileIDBuilderException, UseSmileIDCameraException, UseSmileIDCameraSurfaceException, UseSmileIDErrorCode, UseSmileIDException, UseSmileIDGeneralException, UnusedJobParamsException, UseSmileIDNetworkException, type UseSmileIDNetworkErrorCode, UseSmileIDValidationException, } from "./core/exception";
13
+ export { AgentModeWithEnhancedLivenessException, BuilderValidationException, isNetworkErrorCode, isRetryableErrorCode, ConsentDeniedException, DuplicateScreenTypeException, EmptyScreensBlockException, InvalidConsentConfigException, InvalidConsentInformationException, InvalidDocumentCaptureConfigException, InvalidFieldValueException, InvalidJobTypeScreenConfigException, InvalidMissingCaptureTypeException, InvalidScreenOrderException, InvalidPartnerScreenException, InvalidSelfieCaptureConfigException, LivenessFrameCountException, IssueSeverity, MissingCaptureForPreviewException, MissingJobTypeException, MissingMLConfigurationBlockException, MissingNetworkConfigurationBlockException, MissingPartnerConfigException, MissingRequiredFieldException, NavigationFailedException, ProcessingCancelledException, UseSmileIDAttestationException, UseSmileIDBuilderException, UseSmileIDCameraException, UseSmileIDCameraSurfaceException, UseSmileIDErrorCode, UseSmileIDException, UseSmileIDGeneralException, UnusedJobParamsException, UseSmileIDNetworkException, type UseSmileIDNetworkErrorCode, UseSmileIDValidationException, } from "./core/exception";
14
14
  export { UseSmileIDConfigBuilder } from "./presentation/flow/dsl/builder/config_builder";
15
15
  export { ThemeConfigBuilder, type AdaptiveColor, type ThemeConfiguration, } from "./presentation/flow/dsl/builder/theme_builder";
16
16
  export { UseSmileIDNetworkBuilder } from "./data/dsl/use_smile_id_network_builder";
@@ -20,7 +20,8 @@ export { CacheConfigBuilder } from "./data/dsl/builder/cache_config_builder";
20
20
  export { RetryConfigBuilder, RetryStrategy, } from "./data/dsl/builder/retry_config_builder";
21
21
  export { InterceptorConfigBuilder, LoggingInterceptorBuilder, } from "./data/dsl/builder/interceptor_config_builder";
22
22
  export { AnalyzerRegistryBuilder, DocumentAnalyzerScope, FaceAnalyzerScope, UseSmileIDMLBuilder, } from "./presentation/flow/dsl/builder/ml_builder";
23
- export { CaptureConfigBuilder, CaptureType, ConsentConfigBuilder, DocumentCaptureConfigBuilder, InstructionsConfigBuilder, PreviewConfigBuilder, ProcessingConfigBuilder, ScreensBuilder, SelfieCaptureConfigBuilder, type ButtonSlot, type ScreenSpec, type ScreensConfig, } from "./presentation/flow/dsl/builder/screens_builder";
23
+ export { CaptureConfigBuilder, CaptureType, ConsentConfigBuilder, DocumentCaptureConfigBuilder, InstructionsConfigBuilder, PreviewConfigBuilder, ProcessingConfigBuilder, ScreensBuilder, SelfieCaptureConfigBuilder, type ButtonSlot, type PartnerScreenConfig, type PartnerStepScope, type ScreenSpec, type ScreensConfig, } from "./presentation/flow/dsl/builder/screens_builder";
24
+ export { PartnerValueFormat } from "./presentation/flow/dsl/builder/partner_value_format";
24
25
  export type { FlowConfiguration } from "./presentation/flow/config/flow_configuration";
25
26
  export { FlowNavigationManager, type CapturedArtifacts, type FlowExitHandler, type FlowExitReason, } from "./presentation/flow/flow_navigation_manager";
26
27
  export { FlowNavigationProvider, useFlowNavigation, type FlowNavigationProviderProps, } from "./presentation/flow/flow_navigation_context";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";export{UseSmileIDBuilder}from"./presentation/flow/dsl/use_smile_id_builder";export{UseSmileIDFlowBuilder}from"./presentation/flow/dsl/use_smile_id_flow_builder";export{ValidationState}from"./presentation/flow/validation/validation_state";export{AgentModeWithEnhancedLivenessException,BuilderValidationException,isNetworkErrorCode,isRetryableErrorCode,ConsentDeniedException,DuplicateScreenTypeException,EmptyScreensBlockException,InvalidConsentConfigException,InvalidConsentInformationException,InvalidDocumentCaptureConfigException,InvalidFieldValueException,InvalidJobTypeScreenConfigException,InvalidMissingCaptureTypeException,InvalidScreenOrderException,InvalidSelfieCaptureConfigException,LivenessFrameCountException,IssueSeverity,MissingCaptureForPreviewException,MissingJobTypeException,MissingMLConfigurationBlockException,MissingNetworkConfigurationBlockException,MissingPartnerConfigException,MissingRequiredFieldException,ProcessingCancelledException,UseSmileIDAttestationException,UseSmileIDBuilderException,UseSmileIDCameraException,UseSmileIDCameraSurfaceException,UseSmileIDErrorCode,UseSmileIDException,UseSmileIDGeneralException,UnusedJobParamsException,UseSmileIDNetworkException,UseSmileIDValidationException}from"./core/exception";export{UseSmileIDConfigBuilder}from"./presentation/flow/dsl/builder/config_builder";export{ThemeConfigBuilder}from"./presentation/flow/dsl/builder/theme_builder";export{UseSmileIDNetworkBuilder}from"./data/dsl/use_smile_id_network_builder";export{ConfigBuilder,LoggingConfigBuilder,PartnerConfigBuilder}from"./data/dsl/builder/config_builder";export{TimeoutConfigBuilder}from"./data/dsl/builder/timeout_config_builder";export{CacheConfigBuilder}from"./data/dsl/builder/cache_config_builder";export{RetryConfigBuilder,RetryStrategy}from"./data/dsl/builder/retry_config_builder";export{InterceptorConfigBuilder,LoggingInterceptorBuilder}from"./data/dsl/builder/interceptor_config_builder";export{AnalyzerRegistryBuilder,DocumentAnalyzerScope,FaceAnalyzerScope,UseSmileIDMLBuilder}from"./presentation/flow/dsl/builder/ml_builder";export{CaptureConfigBuilder,CaptureType,ConsentConfigBuilder,DocumentCaptureConfigBuilder,InstructionsConfigBuilder,PreviewConfigBuilder,ProcessingConfigBuilder,ScreensBuilder,SelfieCaptureConfigBuilder}from"./presentation/flow/dsl/builder/screens_builder";export{FlowNavigationManager}from"./presentation/flow/flow_navigation_manager";export{FlowNavigationProvider,useFlowNavigation}from"./presentation/flow/flow_navigation_context";export{UseSmileIDOrchestratedScreenHost}from"./presentation/flow/screen/use_smile_id_orchestrated_screen_host";export{OrchestratedInstructionsScreen}from"./presentation/flow/screen/orchestrated_instructions_screen";export{OrchestratedConsentScreen}from"./presentation/flow/screen/orchestrated_consent_screen";export{OrchestratedCaptureScreen}from"./presentation/flow/screen/orchestrated_capture_screen";export{OrchestratedPreviewScreen}from"./presentation/flow/screen/orchestrated_preview_screen";export{OrchestratedProcessingScreen}from"./presentation/flow/screen/orchestrated_processing_screen";export{UseSmileIDCrashReporting}from"@smileid/usesmileid_bridge";export{DocumentSide}from"@smileid/usesmileid_bridge";export{UseSmileIDLocalizations}from"./l10n/use_smile_id_localizations";export{UseSmileIDLocalizationsProvider,useStableLocalizations,useUseSmileIDLocalizations}from"./l10n/use_smile_id_localizations_provider";export{enStrings}from"./l10n/strings_en";export{UseSmileIDKameraCameraSystem}from"./camera/use_smile_id_kamera_camera_system";export{UseSmileIDKameraPreview}from"./camera/use_smile_id_kamera_preview";export{useSmileIDFrameStream}from"./camera/use_smile_id_frame_stream";export{CameraDefaults}from"./camera/camera_defaults";export{CameraLens}from"./camera/camera_lens";export{FocusStates}from"./camera/focus_state";export{getCameraPermissionStatus,requestCameraPermission}from"./camera/camera_permissions";export{JobType,jobTypeFromValue,requiresDocument,requiresSelfie}from"./core/models/job_type";export{FlowStep}from"./core/models/flow_step";export{DocumentType}from"./core/models/document_type";export{DEFAULT_ACTIVATE_MANUAL_AFTER_MS,DocumentCaptureMode}from"./core/models/document_capture_mode";export{cancelled,captured,failure,success}from"./core/models/result";export{GlobalPrivacyControl,GLOBAL_PRIVACY_CONTROL_WIRE_KEY,globalPrivacyControlFromWire}from"./core/models/global_privacy_control";export{LogLevel}from"./core/models/network_config";export{RESIDENCY_ID_TYPE}from"./core/models/params";export{UseSmileIDAnalyticsEventTypes,UseSmileIDAnalyticsParamKeys,UseSmileIDAnalyticsReasons,UseSmileIDAnalyticsScreenNames}from"./presentation/flow/analytics/use_smile_id_analytics_event";export{analyticsEventKind}from"./presentation/flow/analytics/use_smile_id_analytics_event_kind";export{decodeSmileIDToken}from"./data/util/use_smile_id_token_decoder";export{numSamplesOverride}from"./data/model/sdk_config";export{resolveDimensions,resolveJpegQuality}from"./data/model/sdk_config_capture";export{SdkConfigSource}from"./data/model/sdk_config_source";export{defaultDarkTheme,defaultLightTheme,DEFAULT_FONT_FAMILY,DM_SANS_FONT_NAMES,resolveFontFamily,typographyWithFontFamily}from"./presentation/theme/theme";export{UseSmileIDThemeProvider,useUseSmileIDTheme}from"./presentation/theme/theme_context";export{loadUseSmileIDFonts,useUseSmileIDFonts}from"./presentation/theme/use_use_smile_id_fonts";export{UseSmileIDButton}from"./presentation/components/use_smile_id_button";export{UseSmileIDBackButton}from"./presentation/components/use_smile_id_back_button";export{UseSmileIDRoundedCheckbox}from"./presentation/components/use_smile_id_rounded_checkbox";export{UseSmileIDAttribution}from"./presentation/components/use_smile_id_attribution";export{UseSmileIDPartnerIcon}from"./presentation/components/use_smile_id_partner_icon";export{StatusIndicatorState}from"./presentation/components/status_indicator_state";export{UseSmileIDStatusIndicator}from"./presentation/components/use_smile_id_status_indicator";export{UseSmileIDLoadingIndicator}from"./presentation/components/use_smile_id_loading_indicator";export{UseSmileIDExpandableIcon}from"./presentation/components/use_smile_id_expandable_icon";export{UseSmileIDContentCard}from"./presentation/components/use_smile_id_content_card";export{FaceOvalDefaults,computeFaceOvalGeometry}from"./presentation/components/face_oval_defaults";export{UseSmileIDOvalBorderPalette}from"./presentation/components/use_smile_id_oval_border_palette";export{UseSmileIDMotion}from"./presentation/theme/use_smile_id_motion";export{UseSmileIDFaceOverlay}from"./presentation/components/use_smile_id_face_overlay";export{UseSmileIDFaceOvalImage}from"./presentation/components/use_smile_id_face_oval_image";export{UseSmileIDCapturedImageOval}from"./presentation/components/use_smile_id_captured_image_oval";export{UseSmileIDCardSurface}from"./presentation/components/use_smile_id_card_surface";export{computeScaledOvalGeometry}from"./presentation/components/helpers/scaled_oval_geometry";export{UseSmileIDProcessingCenterIndicator}from"./presentation/components/use_smile_id_processing_center_indicator";export{UseSmileIDDocumentOverlay}from"./presentation/components/use_smile_id_document_overlay";export{UseSmileIDInstructionsHero}from"./presentation/components/use_smile_id_instructions_hero";export{UseSmileIDGuidelineThumbnail}from"./presentation/components/use_smile_id_guideline_thumbnail";export{SELFIE_GUIDELINES,SELFIE_HERO_ANIMATION,ESS_HERO_ANIMATION}from"./presentation/flow/model/instructions_defaults";export{UseSmileIDConsentRow}from"./presentation/components/use_smile_id_consent_row";export{UseSmileIDConfirmationButtons}from"./presentation/components/use_smile_id_confirmation_buttons";export{UseSmileIDLoadingContent}from"./presentation/components/use_smile_id_loading_content";export{UseSmileIDSuccessContent}from"./presentation/components/use_smile_id_success_content";export{UseSmileIDFailedContent}from"./presentation/components/use_smile_id_failed_content";export{UseSmileIDLearnMoreContent}from"./presentation/components/use_smile_id_learn_more_content";export{UseSmileIDEnhancedSmartSelfieFullAnimation}from"./presentation/components/use_smile_id_enhanced_smart_selfie_full_animation";export{UseSmileIDEnhancedSmartSelfieDirectionAnimation}from"./presentation/components/use_smile_id_enhanced_smart_selfie_direction_animation";export{EnhancedSmartSelfieAnimationFrames,ENHANCED_SMART_SELFIE_TOTAL_FRAMES,ENHANCED_SMART_SELFIE_FRAME_RATE}from"./presentation/components/helpers/enhanced_smart_selfie_animation_frames";export{UseSmileIDCaptureContent}from"./presentation/components/use_smile_id_capture_content";export{UseSmileIDCaptureInstructionAnimation}from"./presentation/components/use_smile_id_capture_instruction_animation";export{captureInstructionAnimationSpec}from"./presentation/components/helpers/capture_instruction_animation_spec";export{mapCaptureUiState,mapSelfieUiState,mapDocumentUiState,preCaptureUiState,scannedUiState,scannedDocumentUiState,withEnhancedLivenessPolicy}from"./presentation/screen/helpers/capture_ui_state";export{resolveFeedbackCopy,selfieFeedbackKeyFor,documentFeedbackKeyFor}from"./presentation/screen/helpers/capture_screen_helpers";export{UseSmileIDFeedbackDebouncer}from"./presentation/screen/helpers/feedback_debouncer";export{UseSmileIDOverlayState,OVERLAY_STATE_COUNT,isDirectional}from"./presentation/state/use_smile_id_overlay_state";export{HEAD_TURN_DIRECTIONS}from"./core/models/head_turn_direction";export{UseSmileIDCaptureScreen}from"./presentation/screen/use_smile_id_capture_screen";export{UseSmileIDConsentScreen}from"./presentation/screen/use_smile_id_consent_screen";export{UseSmileIDInstructionsScreen}from"./presentation/screen/use_smile_id_instructions_screen";export{UseSmileIDDocumentBackInstructions}from"./presentation/screen/use_smile_id_document_back_instructions";export{UseSmileIDPreviewScreen}from"./presentation/screen/use_smile_id_preview_screen";export{UseSmileIDProcessingScreen}from"./presentation/screen/use_smile_id_processing_screen";export{ForceMaxBrightness}from"./presentation/utils/force_max_brightness";export{UseSmileIDDebug}from"./debug/use_smile_id_debug";export{CapturePerfMark}from"./core/perf/capture_perf_trace";
1
+ "use strict";export{UseSmileIDBuilder}from"./presentation/flow/dsl/use_smile_id_builder";export{UseSmileIDFlowBuilder}from"./presentation/flow/dsl/use_smile_id_flow_builder";export{ValidationState}from"./presentation/flow/validation/validation_state";export{AgentModeWithEnhancedLivenessException,BuilderValidationException,isNetworkErrorCode,isRetryableErrorCode,ConsentDeniedException,DuplicateScreenTypeException,EmptyScreensBlockException,InvalidConsentConfigException,InvalidConsentInformationException,InvalidDocumentCaptureConfigException,InvalidFieldValueException,InvalidJobTypeScreenConfigException,InvalidMissingCaptureTypeException,InvalidScreenOrderException,InvalidPartnerScreenException,InvalidSelfieCaptureConfigException,LivenessFrameCountException,IssueSeverity,MissingCaptureForPreviewException,MissingJobTypeException,MissingMLConfigurationBlockException,MissingNetworkConfigurationBlockException,MissingPartnerConfigException,MissingRequiredFieldException,NavigationFailedException,ProcessingCancelledException,UseSmileIDAttestationException,UseSmileIDBuilderException,UseSmileIDCameraException,UseSmileIDCameraSurfaceException,UseSmileIDErrorCode,UseSmileIDException,UseSmileIDGeneralException,UnusedJobParamsException,UseSmileIDNetworkException,UseSmileIDValidationException}from"./core/exception";export{UseSmileIDConfigBuilder}from"./presentation/flow/dsl/builder/config_builder";export{ThemeConfigBuilder}from"./presentation/flow/dsl/builder/theme_builder";export{UseSmileIDNetworkBuilder}from"./data/dsl/use_smile_id_network_builder";export{ConfigBuilder,LoggingConfigBuilder,PartnerConfigBuilder}from"./data/dsl/builder/config_builder";export{TimeoutConfigBuilder}from"./data/dsl/builder/timeout_config_builder";export{CacheConfigBuilder}from"./data/dsl/builder/cache_config_builder";export{RetryConfigBuilder,RetryStrategy}from"./data/dsl/builder/retry_config_builder";export{InterceptorConfigBuilder,LoggingInterceptorBuilder}from"./data/dsl/builder/interceptor_config_builder";export{AnalyzerRegistryBuilder,DocumentAnalyzerScope,FaceAnalyzerScope,UseSmileIDMLBuilder}from"./presentation/flow/dsl/builder/ml_builder";export{CaptureConfigBuilder,CaptureType,ConsentConfigBuilder,DocumentCaptureConfigBuilder,InstructionsConfigBuilder,PreviewConfigBuilder,ProcessingConfigBuilder,ScreensBuilder,SelfieCaptureConfigBuilder}from"./presentation/flow/dsl/builder/screens_builder";export{PartnerValueFormat}from"./presentation/flow/dsl/builder/partner_value_format";export{FlowNavigationManager}from"./presentation/flow/flow_navigation_manager";export{FlowNavigationProvider,useFlowNavigation}from"./presentation/flow/flow_navigation_context";export{UseSmileIDOrchestratedScreenHost}from"./presentation/flow/screen/use_smile_id_orchestrated_screen_host";export{OrchestratedInstructionsScreen}from"./presentation/flow/screen/orchestrated_instructions_screen";export{OrchestratedConsentScreen}from"./presentation/flow/screen/orchestrated_consent_screen";export{OrchestratedCaptureScreen}from"./presentation/flow/screen/orchestrated_capture_screen";export{OrchestratedPreviewScreen}from"./presentation/flow/screen/orchestrated_preview_screen";export{OrchestratedProcessingScreen}from"./presentation/flow/screen/orchestrated_processing_screen";export{UseSmileIDCrashReporting}from"@smileid/usesmileid_bridge";export{DocumentSide}from"@smileid/usesmileid_bridge";export{UseSmileIDLocalizations}from"./l10n/use_smile_id_localizations";export{UseSmileIDLocalizationsProvider,useStableLocalizations,useUseSmileIDLocalizations}from"./l10n/use_smile_id_localizations_provider";export{enStrings}from"./l10n/strings_en";export{UseSmileIDKameraCameraSystem}from"./camera/use_smile_id_kamera_camera_system";export{UseSmileIDKameraPreview}from"./camera/use_smile_id_kamera_preview";export{useSmileIDFrameStream}from"./camera/use_smile_id_frame_stream";export{CameraDefaults}from"./camera/camera_defaults";export{CameraLens}from"./camera/camera_lens";export{FocusStates}from"./camera/focus_state";export{getCameraPermissionStatus,requestCameraPermission}from"./camera/camera_permissions";export{JobType,jobTypeFromValue,requiresDocument,requiresSelfie}from"./core/models/job_type";export{FlowStep}from"./core/models/flow_step";export{DocumentType}from"./core/models/document_type";export{DEFAULT_ACTIVATE_MANUAL_AFTER_MS,DocumentCaptureMode}from"./core/models/document_capture_mode";export{cancelled,captured,failure,success}from"./core/models/result";export{GlobalPrivacyControl,GLOBAL_PRIVACY_CONTROL_WIRE_KEY,globalPrivacyControlFromWire}from"./core/models/global_privacy_control";export{LogLevel}from"./core/models/network_config";export{RESIDENCY_ID_TYPE}from"./core/models/params";export{UseSmileIDAnalyticsEventTypes,UseSmileIDAnalyticsParamKeys,UseSmileIDAnalyticsReasons,UseSmileIDAnalyticsScreenNames}from"./presentation/flow/analytics/use_smile_id_analytics_event";export{analyticsEventKind}from"./presentation/flow/analytics/use_smile_id_analytics_event_kind";export{decodeSmileIDToken}from"./data/util/use_smile_id_token_decoder";export{numSamplesOverride}from"./data/model/sdk_config";export{resolveDimensions,resolveJpegQuality}from"./data/model/sdk_config_capture";export{SdkConfigSource}from"./data/model/sdk_config_source";export{defaultDarkTheme,defaultLightTheme,DEFAULT_FONT_FAMILY,DM_SANS_FONT_NAMES,resolveFontFamily,typographyWithFontFamily}from"./presentation/theme/theme";export{UseSmileIDThemeProvider,useUseSmileIDTheme}from"./presentation/theme/theme_context";export{loadUseSmileIDFonts,useUseSmileIDFonts}from"./presentation/theme/use_use_smile_id_fonts";export{UseSmileIDButton}from"./presentation/components/use_smile_id_button";export{UseSmileIDBackButton}from"./presentation/components/use_smile_id_back_button";export{UseSmileIDRoundedCheckbox}from"./presentation/components/use_smile_id_rounded_checkbox";export{UseSmileIDAttribution}from"./presentation/components/use_smile_id_attribution";export{UseSmileIDPartnerIcon}from"./presentation/components/use_smile_id_partner_icon";export{StatusIndicatorState}from"./presentation/components/status_indicator_state";export{UseSmileIDStatusIndicator}from"./presentation/components/use_smile_id_status_indicator";export{UseSmileIDLoadingIndicator}from"./presentation/components/use_smile_id_loading_indicator";export{UseSmileIDExpandableIcon}from"./presentation/components/use_smile_id_expandable_icon";export{UseSmileIDContentCard}from"./presentation/components/use_smile_id_content_card";export{FaceOvalDefaults,computeFaceOvalGeometry}from"./presentation/components/face_oval_defaults";export{UseSmileIDOvalBorderPalette}from"./presentation/components/use_smile_id_oval_border_palette";export{UseSmileIDMotion}from"./presentation/theme/use_smile_id_motion";export{UseSmileIDFaceOverlay}from"./presentation/components/use_smile_id_face_overlay";export{UseSmileIDFaceOvalImage}from"./presentation/components/use_smile_id_face_oval_image";export{UseSmileIDCapturedImageOval}from"./presentation/components/use_smile_id_captured_image_oval";export{UseSmileIDCardSurface}from"./presentation/components/use_smile_id_card_surface";export{computeScaledOvalGeometry}from"./presentation/components/helpers/scaled_oval_geometry";export{UseSmileIDProcessingCenterIndicator}from"./presentation/components/use_smile_id_processing_center_indicator";export{UseSmileIDDocumentOverlay}from"./presentation/components/use_smile_id_document_overlay";export{UseSmileIDInstructionsHero}from"./presentation/components/use_smile_id_instructions_hero";export{UseSmileIDGuidelineThumbnail}from"./presentation/components/use_smile_id_guideline_thumbnail";export{SELFIE_GUIDELINES,SELFIE_HERO_ANIMATION,ESS_HERO_ANIMATION}from"./presentation/flow/model/instructions_defaults";export{UseSmileIDConsentRow}from"./presentation/components/use_smile_id_consent_row";export{UseSmileIDConfirmationButtons}from"./presentation/components/use_smile_id_confirmation_buttons";export{UseSmileIDLoadingContent}from"./presentation/components/use_smile_id_loading_content";export{UseSmileIDSuccessContent}from"./presentation/components/use_smile_id_success_content";export{UseSmileIDFailedContent}from"./presentation/components/use_smile_id_failed_content";export{UseSmileIDLearnMoreContent}from"./presentation/components/use_smile_id_learn_more_content";export{UseSmileIDEnhancedSmartSelfieFullAnimation}from"./presentation/components/use_smile_id_enhanced_smart_selfie_full_animation";export{UseSmileIDEnhancedSmartSelfieDirectionAnimation}from"./presentation/components/use_smile_id_enhanced_smart_selfie_direction_animation";export{EnhancedSmartSelfieAnimationFrames,ENHANCED_SMART_SELFIE_TOTAL_FRAMES,ENHANCED_SMART_SELFIE_FRAME_RATE}from"./presentation/components/helpers/enhanced_smart_selfie_animation_frames";export{UseSmileIDCaptureContent}from"./presentation/components/use_smile_id_capture_content";export{UseSmileIDCaptureInstructionAnimation}from"./presentation/components/use_smile_id_capture_instruction_animation";export{captureInstructionAnimationSpec}from"./presentation/components/helpers/capture_instruction_animation_spec";export{mapCaptureUiState,mapSelfieUiState,mapDocumentUiState,preCaptureUiState,scannedUiState,scannedDocumentUiState,withEnhancedLivenessPolicy}from"./presentation/screen/helpers/capture_ui_state";export{resolveFeedbackCopy,selfieFeedbackKeyFor,documentFeedbackKeyFor}from"./presentation/screen/helpers/capture_screen_helpers";export{UseSmileIDFeedbackDebouncer}from"./presentation/screen/helpers/feedback_debouncer";export{UseSmileIDOverlayState,OVERLAY_STATE_COUNT,isDirectional}from"./presentation/state/use_smile_id_overlay_state";export{HEAD_TURN_DIRECTIONS}from"./core/models/head_turn_direction";export{UseSmileIDCaptureScreen}from"./presentation/screen/use_smile_id_capture_screen";export{UseSmileIDConsentScreen}from"./presentation/screen/use_smile_id_consent_screen";export{UseSmileIDInstructionsScreen}from"./presentation/screen/use_smile_id_instructions_screen";export{UseSmileIDDocumentBackInstructions}from"./presentation/screen/use_smile_id_document_back_instructions";export{UseSmileIDPreviewScreen}from"./presentation/screen/use_smile_id_preview_screen";export{UseSmileIDProcessingScreen}from"./presentation/screen/use_smile_id_processing_screen";export{ForceMaxBrightness}from"./presentation/utils/force_max_brightness";export{UseSmileIDDebug}from"./debug/use_smile_id_debug";export{CapturePerfMark}from"./core/perf/capture_perf_trace";
@@ -1 +1 @@
1
- "use strict";import{GlobalPrivacyControl as g}from"../core/models/global_privacy_control";import{AnalyzerFactoryKey as c,DocumentAnalyzerKey as u}from"@smileid/usesmileid_bridge";import{CaptureType as f}from"../core/models/ml_config";import{JobType as y}from"../core/models/job_type";import{autoCaptureWireValue as b}from"../core/models/document_capture_mode";import{flowShowAttribution as w}from"../presentation/flow/config/attribution_resolver";import{builderConfigurationToJson as C}from"./builder_configuration";import{MODEL_DESCRIPTOR_UNKNOWN as _,ModelProvider as r,modelConfigurationToJson as T}from"./model_configuration";export function flowConfigurationToBuilderConfiguration(e){const o=e.screens.steps;let n;const t=[];let d=!1,a=!1,p=!1;for(const i of o)switch(i.kind){case"consent":n=i.config;break;case"instructions":d=!0;break;case"capture":t.push(i.config);break;case"preview":a=!0;break;case"processing":p=!0;break}const l=t.find(i=>i.selfieConfig)?.selfieConfig,s=t.find(i=>i.documentConfig)?.documentConfig,v=l!==void 0||t.some(i=>i.captureType===f.selfie),m=s!==void 0||t.some(i=>i.captureType===f.document);return{consentScreenUsed:n!==void 0,consentIconProvided:n?.partnerIcon!=null,consentIconDimensions:null,consentAttributionShown:n!==void 0&&w(e),instructionsScreenUsed:d,selfiePreviewEnabled:a&&v,documentPreviewEnabled:a&&m,submissionSkipped:!p,allowAgentMode:l?.allowAgentMode??!1,enhancedLivenessEnabled:l?.enableEnhancedLiveness??!1,autoCaptureEnabled:b(s?.captureMode),allowGalleryUpload:s?.allowGalleryUpload??!1,captureBothSides:e.network?.config?.jobType===y.residencyDocumentVerification&&m||(s?.captureBothSides??!1),allowSkipBack:s?.allowSkipBack??!1,globalPrivacyControl:e.config?.globalPrivacyControl??g.OptOut}}export function flowConfigurationToModelConfiguration(e){const o=e.ml?.analyzers.selfieConfig?.analyzerFactoryKey,n=e.ml?.analyzers.document?.key;return{faceModel:h(o),documentModel:k(n)}}export function configurationMetadataEntries(e){const o=[{name:"builder_configuration_object",value:JSON.stringify(C(flowConfigurationToBuilderConfiguration(e)))},{name:"model_configuration_object",value:JSON.stringify(T(flowConfigurationToModelConfiguration(e)))}],n=flowConfigurationToSelfieLivenessTelemetry(e);return n.activeLivenessType!==null&&o.push({name:"active_liveness_type",value:n.activeLivenessType},{name:"active_liveness_version",value:n.activeLivenessVersion},{name:"selfie_image_origin",value:n.selfieImageOrigin}),o}export function flowConfigurationToSelfieLivenessTelemetry(e){let o,n=!1;for(const t of e.screens.steps)t.kind==="capture"&&(o??=t.config.selfieConfig,t.config.captureType===f.selfie&&(n=!0));return!n&&o===void 0?{activeLivenessType:null,activeLivenessVersion:null,selfieImageOrigin:null}:{activeLivenessType:O(o),activeLivenessVersion:"2.0.0",selfieImageOrigin:S(o)}}function O(e){return e?.enableEnhancedLiveness?"head_pose":"smile"}function S(e){return e?.allowAgentMode?"back_camera":"front_camera"}function h(e){switch(e){case c.MLKitFace:return{provider:r.Google,name:"play-services-mlkit-face-detection",version:"17.1.0",bundled:!1};case c.HuaweiFace:return{provider:r.Huawei,name:"ml-computer-vision-face",version:"3.18.1.300",bundled:!1};case c.VisionFace:return{provider:r.Apple,name:"vision_face_detector",version:"system",bundled:!0};default:return _}}function k(e){switch(e){case u.MLKitDocument:return{provider:r.Google,name:"object-detection",version:"17.0.2",bundled:!0};case u.HuaweiDocument:return{provider:r.Huawei,name:"ml-computer-vision-object",version:"3.7.0.301",bundled:!1};case u.VisionDocument:return{provider:r.Apple,name:"vision_document_detector",version:"system",bundled:!0};default:return L}}const L={provider:r.Smile,name:"noop_document_detector",version:"12.3.0",bundled:!0};
1
+ "use strict";import{GlobalPrivacyControl as g}from"../core/models/global_privacy_control";import{AnalyzerFactoryKey as l,DocumentAnalyzerKey as u}from"@smileid/usesmileid_bridge";import{CaptureType as f}from"../core/models/ml_config";import{JobType as y}from"../core/models/job_type";import{autoCaptureWireValue as b}from"../core/models/document_capture_mode";import{flowShowAttribution as w}from"../presentation/flow/config/attribution_resolver";import{builderConfigurationToJson as C}from"./builder_configuration";import{MODEL_DESCRIPTOR_UNKNOWN as _,ModelProvider as r,modelConfigurationToJson as T}from"./model_configuration";export function flowConfigurationToBuilderConfiguration(e){const o=e.screens.steps;let n;const t=[];let d=!1,a=!1,p=!1;for(const i of o)switch(i.kind){case"consent":n=i.config;break;case"instructions":d=!0;break;case"capture":t.push(i.config);break;case"preview":a=!0;break;case"processing":p=!0;break;case"partner":break}const c=t.find(i=>i.selfieConfig)?.selfieConfig,s=t.find(i=>i.documentConfig)?.documentConfig,v=c!==void 0||t.some(i=>i.captureType===f.selfie),m=s!==void 0||t.some(i=>i.captureType===f.document);return{consentScreenUsed:n!==void 0,consentIconProvided:n?.partnerIcon!=null,consentIconDimensions:null,consentAttributionShown:n!==void 0&&w(e),instructionsScreenUsed:d,selfiePreviewEnabled:a&&v,documentPreviewEnabled:a&&m,submissionSkipped:!p,allowAgentMode:c?.allowAgentMode??!1,enhancedLivenessEnabled:c?.enableEnhancedLiveness??!1,autoCaptureEnabled:b(s?.captureMode),allowGalleryUpload:s?.allowGalleryUpload??!1,captureBothSides:e.network?.config?.jobType===y.residencyDocumentVerification&&m||(s?.captureBothSides??!1),allowSkipBack:s?.allowSkipBack??!1,globalPrivacyControl:e.config?.globalPrivacyControl??g.OptOut}}export function flowConfigurationToModelConfiguration(e){const o=e.ml?.analyzers.selfieConfig?.analyzerFactoryKey,n=e.ml?.analyzers.document?.key;return{faceModel:S(o),documentModel:h(n)}}export function configurationMetadataEntries(e){const o=[{name:"builder_configuration_object",value:JSON.stringify(C(flowConfigurationToBuilderConfiguration(e)))},{name:"model_configuration_object",value:JSON.stringify(T(flowConfigurationToModelConfiguration(e)))}],n=flowConfigurationToSelfieLivenessTelemetry(e);return n.activeLivenessType!==null&&o.push({name:"active_liveness_type",value:n.activeLivenessType},{name:"active_liveness_version",value:n.activeLivenessVersion},{name:"selfie_image_origin",value:n.selfieImageOrigin}),o}export function flowConfigurationToSelfieLivenessTelemetry(e){let o,n=!1;for(const t of e.screens.steps)t.kind==="capture"&&(o??=t.config.selfieConfig,t.config.captureType===f.selfie&&(n=!0));return!n&&o===void 0?{activeLivenessType:null,activeLivenessVersion:null,selfieImageOrigin:null}:{activeLivenessType:O(o),activeLivenessVersion:"2.0.0",selfieImageOrigin:k(o)}}function O(e){return e?.enableEnhancedLiveness?"head_pose":"smile"}function k(e){return e?.allowAgentMode?"back_camera":"front_camera"}function S(e){switch(e){case l.MLKitFace:return{provider:r.Google,name:"play-services-mlkit-face-detection",version:"17.1.0",bundled:!1};case l.HuaweiFace:return{provider:r.Huawei,name:"ml-computer-vision-face",version:"3.18.1.300",bundled:!1};case l.VisionFace:return{provider:r.Apple,name:"vision_face_detector",version:"system",bundled:!0};default:return _}}function h(e){switch(e){case u.MLKitDocument:return{provider:r.Google,name:"object-detection",version:"17.0.2",bundled:!0};case u.HuaweiDocument:return{provider:r.Huawei,name:"ml-computer-vision-object",version:"3.7.0.301",bundled:!1};case u.VisionDocument:return{provider:r.Apple,name:"vision_document_detector",version:"system",bundled:!0};default:return L}}const L={provider:r.Smile,name:"noop_document_detector",version:"12.3.0",bundled:!0};
@@ -11,6 +11,8 @@
11
11
  export declare const UseSmileIDAnalyticsEventTypes: {
12
12
  readonly flowStarted: "flow_started";
13
13
  readonly screenViewed: "screen_viewed";
14
+ /** A partner screen became active. Extras: `partner_step`, the id it was added with. */
15
+ readonly partnerScreenViewed: "partner_screen_viewed";
14
16
  readonly consentCaptured: "consent_captured";
15
17
  readonly selfieCaptured: "selfie_captured";
16
18
  readonly documentCaptured: "document_captured";
@@ -38,6 +40,7 @@ export declare const UseSmileIDAnalyticsParamKeys: {
38
40
  /** The numeric job type id, the same on every SDK. */
39
41
  readonly jobTypeId: "job_type_id";
40
42
  readonly screenName: "screen_name";
43
+ readonly partnerStep: "partner_step";
41
44
  readonly sessionId: "session_id";
42
45
  readonly timestamp: "timestamp";
43
46
  readonly documentSide: "document_side";
@@ -1 +1 @@
1
- "use strict";export const UseSmileIDAnalyticsEventTypes={flowStarted:"flow_started",screenViewed:"screen_viewed",consentCaptured:"consent_captured",selfieCaptured:"selfie_captured",documentCaptured:"document_captured",retakeRequested:"retake_requested",jobSubmitted:"job_submitted",jobCaptured:"job_captured",flowCompleted:"flow_completed",selfieSessionRestarted:"selfie_session_restarted",selfieFrameRejected:"selfie_frame_rejected"},UseSmileIDAnalyticsParamKeys={jobType:"job_type",jobTypeId:"job_type_id",screenName:"screen_name",sessionId:"session_id",timestamp:"timestamp",documentSide:"document_side",decision:"decision",livenessImageCount:"liveness_image_count",attempt:"attempt",jobId:"job_id",result:"result",errorMessage:"error_message",reason:"reason",framesDiscarded:"frames_discarded",durationMs:"duration_ms",iou:"iou",probability:"probability"},UseSmileIDAnalyticsScreenNames={consent:"consent",instructions:"instructions",capture:"capture",preview:"preview",processing:"processing"},UseSmileIDAnalyticsReasons={motionBlur:"motion_blur",qualityDropTimeout:"quality_drop_timeout"};
1
+ "use strict";export const UseSmileIDAnalyticsEventTypes={flowStarted:"flow_started",screenViewed:"screen_viewed",partnerScreenViewed:"partner_screen_viewed",consentCaptured:"consent_captured",selfieCaptured:"selfie_captured",documentCaptured:"document_captured",retakeRequested:"retake_requested",jobSubmitted:"job_submitted",jobCaptured:"job_captured",flowCompleted:"flow_completed",selfieSessionRestarted:"selfie_session_restarted",selfieFrameRejected:"selfie_frame_rejected"},UseSmileIDAnalyticsParamKeys={jobType:"job_type",jobTypeId:"job_type_id",screenName:"screen_name",partnerStep:"partner_step",sessionId:"session_id",timestamp:"timestamp",documentSide:"document_side",decision:"decision",livenessImageCount:"liveness_image_count",attempt:"attempt",jobId:"job_id",result:"result",errorMessage:"error_message",reason:"reason",framesDiscarded:"frames_discarded",durationMs:"duration_ms",iou:"iou",probability:"probability"},UseSmileIDAnalyticsScreenNames={consent:"consent",instructions:"instructions",capture:"capture",preview:"preview",processing:"processing"},UseSmileIDAnalyticsReasons={motionBlur:"motion_blur",qualityDropTimeout:"quality_drop_timeout"};
@@ -25,6 +25,11 @@ export type UseSmileIDAnalyticsEventKind =
25
25
  readonly kind: "screenViewed";
26
26
  readonly screen: UseSmileIDAnalyticsScreenName;
27
27
  }
28
+ /** A partner screen became active; `step` is the id it was added with. */
29
+ | {
30
+ readonly kind: "partnerScreenViewed";
31
+ readonly step: string;
32
+ }
28
33
  /** The user granted consent on the consent screen. */
29
34
  | {
30
35
  readonly kind: "consentCaptured";
@@ -1 +1 @@
1
- "use strict";import{DocumentSide as m}from"@smileid/usesmileid_bridge";import{JobType as S}from"../../../core/models/job_type";import{UseSmileIDAnalyticsEventTypes as r,UseSmileIDAnalyticsParamKeys as n,UseSmileIDAnalyticsScreenNames as y}from"./use_smile_id_analytics_event";const a="granted",c="success",f="failure",p="captured";function o(e){return{[n.jobType]:String(e),[n.jobTypeId]:String(e)}}export function encodeAnalyticsEventKind(e){const t=r;switch(e.kind){case"flowStarted":return{type:t.flowStarted,extras:o(e.jobType)};case"screenViewed":return{type:t.screenViewed,extras:{[n.screenName]:e.screen}};case"consentCaptured":return{type:t.consentCaptured,extras:{[n.decision]:a}};case"selfieCaptured":return{type:t.selfieCaptured,extras:{[n.livenessImageCount]:String(e.livenessImageCount)}};case"documentCaptured":return{type:t.documentCaptured,extras:{[n.documentSide]:e.side}};case"retakeRequested":return{type:t.retakeRequested,extras:{}};case"jobSubmitted":return{type:t.jobSubmitted,extras:{...o(e.jobType),[n.attempt]:String(e.attempt)}};case"jobCaptured":return{type:t.jobCaptured,extras:o(e.jobType)};case"flowCompletedSuccess":return{type:t.flowCompleted,extras:{[n.result]:c,...e.jobId?{[n.jobId]:e.jobId}:{}}};case"flowCompletedFailure":return{type:t.flowCompleted,extras:{[n.result]:f,[n.errorMessage]:e.errorMessage}};case"flowCompletedCaptured":return{type:t.flowCompleted,extras:{[n.result]:p}};case"selfieSessionRestarted":return{type:t.selfieSessionRestarted,extras:{[n.reason]:e.reason,[n.framesDiscarded]:String(e.framesDiscarded),[n.durationMs]:String(e.durationMs)}};case"selfieFrameRejected":return{type:t.selfieFrameRejected,extras:{[n.reason]:e.reason}}}}function s(e){if(!(e===void 0||!/^-?\d+$/.test(e)))return Number(e)}function i(e){const t=s(e[n.jobTypeId])??s(e[n.jobType]);return Object.values(S).find(d=>d===t)}const C=Object.values(y),b=Object.values(m),l={[r.flowStarted]:e=>{const t=i(e);return t===void 0?void 0:{kind:"flowStarted",jobType:t}},[r.screenViewed]:e=>{const t=e[n.screenName];return t!==void 0&&C.includes(t)?{kind:"screenViewed",screen:t}:void 0},[r.consentCaptured]:e=>e[n.decision]===a?{kind:"consentCaptured"}:void 0,[r.selfieCaptured]:e=>{const t=s(e[n.livenessImageCount]);return t===void 0?void 0:{kind:"selfieCaptured",livenessImageCount:t}},[r.documentCaptured]:e=>{const t=e[n.documentSide];return t!==void 0&&b.includes(t)?{kind:"documentCaptured",side:t}:void 0},[r.retakeRequested]:()=>({kind:"retakeRequested"}),[r.jobSubmitted]:e=>{const t=i(e),d=s(e[n.attempt]);return t===void 0||d===void 0?void 0:{kind:"jobSubmitted",jobType:t,attempt:d}},[r.jobCaptured]:e=>{const t=i(e);return t===void 0?void 0:{kind:"jobCaptured",jobType:t}},[r.flowCompleted]:e=>{switch(e[n.result]){case c:{const t=e[n.jobId];return t?{kind:"flowCompletedSuccess",jobId:t}:{kind:"flowCompletedSuccess"}}case f:{const t=e[n.errorMessage];return t===void 0?void 0:{kind:"flowCompletedFailure",errorMessage:t}}case p:return{kind:"flowCompletedCaptured"};default:return}},[r.selfieSessionRestarted]:e=>{const t=e[n.reason],d=s(e[n.framesDiscarded]),u=s(e[n.durationMs]);return t===void 0||d===void 0||u===void 0?void 0:{kind:"selfieSessionRestarted",reason:t,framesDiscarded:d,durationMs:u}},[r.selfieFrameRejected]:e=>{const t=e[n.reason];return t===void 0?void 0:{kind:"selfieFrameRejected",reason:t}}};export function analyticsEventKind(e){return Object.prototype.hasOwnProperty.call(l,e.type)?l[e.type]?.(e.extras):void 0}
1
+ "use strict";import{DocumentSide as m}from"@smileid/usesmileid_bridge";import{JobType as S}from"../../../core/models/job_type";import{UseSmileIDAnalyticsEventTypes as r,UseSmileIDAnalyticsParamKeys as n,UseSmileIDAnalyticsScreenNames as y}from"./use_smile_id_analytics_event";const a="granted",c="success",p="failure",f="captured";function i(e){return{[n.jobType]:String(e),[n.jobTypeId]:String(e)}}export function encodeAnalyticsEventKind(e){const t=r;switch(e.kind){case"flowStarted":return{type:t.flowStarted,extras:i(e.jobType)};case"screenViewed":return{type:t.screenViewed,extras:{[n.screenName]:e.screen}};case"partnerScreenViewed":return{type:t.partnerScreenViewed,extras:{[n.partnerStep]:e.step}};case"consentCaptured":return{type:t.consentCaptured,extras:{[n.decision]:a}};case"selfieCaptured":return{type:t.selfieCaptured,extras:{[n.livenessImageCount]:String(e.livenessImageCount)}};case"documentCaptured":return{type:t.documentCaptured,extras:{[n.documentSide]:e.side}};case"retakeRequested":return{type:t.retakeRequested,extras:{}};case"jobSubmitted":return{type:t.jobSubmitted,extras:{...i(e.jobType),[n.attempt]:String(e.attempt)}};case"jobCaptured":return{type:t.jobCaptured,extras:i(e.jobType)};case"flowCompletedSuccess":return{type:t.flowCompleted,extras:{[n.result]:c,...e.jobId?{[n.jobId]:e.jobId}:{}}};case"flowCompletedFailure":return{type:t.flowCompleted,extras:{[n.result]:p,[n.errorMessage]:e.errorMessage}};case"flowCompletedCaptured":return{type:t.flowCompleted,extras:{[n.result]:f}};case"selfieSessionRestarted":return{type:t.selfieSessionRestarted,extras:{[n.reason]:e.reason,[n.framesDiscarded]:String(e.framesDiscarded),[n.durationMs]:String(e.durationMs)}};case"selfieFrameRejected":return{type:t.selfieFrameRejected,extras:{[n.reason]:e.reason}}}}function s(e){if(!(e===void 0||!/^-?\d+$/.test(e)))return Number(e)}function o(e){const t=s(e[n.jobTypeId])??s(e[n.jobType]);return Object.values(S).find(d=>d===t)}const C=Object.values(y),b=Object.values(m),l={[r.flowStarted]:e=>{const t=o(e);return t===void 0?void 0:{kind:"flowStarted",jobType:t}},[r.screenViewed]:e=>{const t=e[n.screenName];return t!==void 0&&C.includes(t)?{kind:"screenViewed",screen:t}:void 0},[r.partnerScreenViewed]:e=>{const t=e[n.partnerStep];return t===void 0?void 0:{kind:"partnerScreenViewed",step:t}},[r.consentCaptured]:e=>e[n.decision]===a?{kind:"consentCaptured"}:void 0,[r.selfieCaptured]:e=>{const t=s(e[n.livenessImageCount]);return t===void 0?void 0:{kind:"selfieCaptured",livenessImageCount:t}},[r.documentCaptured]:e=>{const t=e[n.documentSide];return t!==void 0&&b.includes(t)?{kind:"documentCaptured",side:t}:void 0},[r.retakeRequested]:()=>({kind:"retakeRequested"}),[r.jobSubmitted]:e=>{const t=o(e),d=s(e[n.attempt]);return t===void 0||d===void 0?void 0:{kind:"jobSubmitted",jobType:t,attempt:d}},[r.jobCaptured]:e=>{const t=o(e);return t===void 0?void 0:{kind:"jobCaptured",jobType:t}},[r.flowCompleted]:e=>{switch(e[n.result]){case c:{const t=e[n.jobId];return t?{kind:"flowCompletedSuccess",jobId:t}:{kind:"flowCompletedSuccess"}}case p:{const t=e[n.errorMessage];return t===void 0?void 0:{kind:"flowCompletedFailure",errorMessage:t}}case f:return{kind:"flowCompletedCaptured"};default:return}},[r.selfieSessionRestarted]:e=>{const t=e[n.reason],d=s(e[n.framesDiscarded]),u=s(e[n.durationMs]);return t===void 0||d===void 0||u===void 0?void 0:{kind:"selfieSessionRestarted",reason:t,framesDiscarded:d,durationMs:u}},[r.selfieFrameRejected]:e=>{const t=e[n.reason];return t===void 0?void 0:{kind:"selfieFrameRejected",reason:t}}};export function analyticsEventKind(e){return Object.prototype.hasOwnProperty.call(l,e.type)?l[e.type]?.(e.extras):void 0}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * How a partner screen's own value becomes text the flow keeps, and back, so
3
+ * the screen that hands a value on and the screen that reads it share one
4
+ * type. The flow never reads the text: the format decides what it holds, such
5
+ * as JSON from the partner's own serializer.
6
+ *
7
+ * ```ts
8
+ * const aboutYou = PartnerValueFormat.of<AboutYou>(JSON.stringify, JSON.parse);
9
+ * ```
10
+ */
11
+ export type PartnerValueFormat<T> = {
12
+ /** `value` as text the flow can keep. */
13
+ encode(value: T): string;
14
+ /** The value `text` holds; called only with text this format encoded. */
15
+ decode(text: string): T;
16
+ };
17
+ export declare const PartnerValueFormat: Readonly<{
18
+ /** Text as it is: a string value needs no encoding. */
19
+ text: PartnerValueFormat<string>;
20
+ /** A format from two functions, such as a JSON serializer's encode and decode. */
21
+ of: <T>(encode: (value: T) => string, decode: (text: string) => T) => PartnerValueFormat<T>;
22
+ }>;
@@ -0,0 +1 @@
1
+ "use strict";export const PartnerValueFormat=Object.freeze({text:Object.freeze({encode:e=>e,decode:e=>e}),of:(e,t)=>Object.freeze({encode:e,decode:t})});
@@ -5,6 +5,7 @@ import { DocumentCaptureMode } from "../../../../core/models/document_capture_mo
5
5
  import type { ConsentInformation } from "../../../../core/models/params";
6
6
  import type { InstructionGuideline } from "../../model/instruction_guideline";
7
7
  import type { HeroAnimationSource } from "../../model/instructions_defaults";
8
+ import type { PartnerValueFormat } from "./partner_value_format";
8
9
  export { CaptureType };
9
10
  /**
10
11
  * Screens DSL:
@@ -149,6 +150,43 @@ export declare class ProcessingConfigBuilder {
149
150
  /** Provides a custom exit button in place of the default. */
150
151
  exitButton?: ButtonSlot;
151
152
  }
153
+ /**
154
+ * What a partner screen can do with the flow it sits in. It moves the flow,
155
+ * and hands the partner's own values from one partner screen to the next, and
156
+ * nothing else: no capture, result or job is reachable from here, so a partner
157
+ * screen never sees what the SDK collected.
158
+ */
159
+ export type PartnerStepScope = {
160
+ /** The id the screen was added with. */
161
+ readonly stepId: string;
162
+ /** Moves on to the flow's next screen. */
163
+ next(): void;
164
+ /**
165
+ * Keeps `value` on this screen, encoded by `format`, then moves on as
166
+ * `next()` does. A later partner screen reads it with `value`. It stays
167
+ * while this screen is in the flow's back stack: going back to this screen
168
+ * finds it, and backing out of this screen drops it. A value without its
169
+ * format throws a `TypeError`.
170
+ */
171
+ next<T>(value: T, format: PartnerValueFormat<T>): void;
172
+ /**
173
+ * The value the partner screen `stepId` kept with `next(value, format)`,
174
+ * decoded by `format`, or undefined when it kept none or the user backed out
175
+ * of it. Only partner screens keep values, so this reads nothing of the SDK's.
176
+ */
177
+ value<T>(stepId: string, format: PartnerValueFormat<T>): T | undefined;
178
+ /** Goes back to the screen before this one; on the flow's first screen, cancels the flow. */
179
+ back(): void;
180
+ /** Ends the flow as cancelled, as back does from the first screen. */
181
+ cancel(): void;
182
+ };
183
+ /** A screen the integrator draws between the SDK's own, added with `screens.partner(id, render)`. */
184
+ export type PartnerScreenConfig = {
185
+ /** Names the screen in analytics (`partner_step`) and in the flow's graph (`partner.<id>`). */
186
+ readonly id: string;
187
+ /** Draws the screen, given a scope that moves the flow and reads nothing the SDK captured. */
188
+ readonly render: (scope: PartnerStepScope) => ReactNode;
189
+ };
152
190
  export type ScreenSpec = {
153
191
  readonly kind: "consent";
154
192
  readonly config: ConsentConfigBuilder;
@@ -164,6 +202,9 @@ export type ScreenSpec = {
164
202
  } | {
165
203
  readonly kind: "processing";
166
204
  readonly config: ProcessingConfigBuilder;
205
+ } | {
206
+ readonly kind: "partner";
207
+ readonly config: PartnerScreenConfig;
167
208
  };
168
209
  export type ScreensConfig = {
169
210
  readonly steps: readonly ScreenSpec[];
@@ -194,5 +235,13 @@ export declare class ScreensBuilder {
194
235
  * success, failure, or retry states.
195
236
  */
196
237
  processing(block?: (p: ProcessingConfigBuilder) => void): void;
238
+ /**
239
+ * Adds a screen of your own between the SDK's: a form, an explanation, a
240
+ * hand-off. `render` draws it and gets a {@link PartnerStepScope} to move the
241
+ * flow on, back or out; it sees nothing the SDK has captured. `id` names it
242
+ * in analytics (`partner_screen_viewed`) and must be unique in the flow. A
243
+ * partner screen can't sit between a capture and its preview.
244
+ */
245
+ partner(id: string, render: (scope: PartnerStepScope) => ReactNode): void;
197
246
  build(): ScreensConfig;
198
247
  }
@@ -1 +1 @@
1
- "use strict";import{CaptureType as n}from"../../../../core/models/ml_config";import{DocumentCaptureMode as i}from"../../../../core/models/document_capture_mode";export{n as CaptureType};export class ConsentConfigBuilder{partnerName="";partnerIcon;partnerPrivacyPolicyUrl;onConsentGranted;allowButton;denyButton}export class InstructionsConfigBuilder{titlePrefix;titleEmphasis;heroAnimation;guidelinesSectionTitle;guidelines=[];showHeroOval=!0;continueButton}export class SelfieCaptureConfigBuilder{allowAgentMode=!1;enableEnhancedLiveness=!1}export class DocumentCaptureConfigBuilder{documentType;captureMode=i.AutoCaptureWithManualFallback();allowGalleryUpload=!1;allowSkipBack=!1;knownIdAspectRatio;_captureBothSides;get captureBothSides(){return this._captureBothSides??this.documentType?.kind!=="passport"}set captureBothSides(e){this._captureBothSides=e}get resolvedAspectRatio(){return this.documentType?.knownAspectRatio??this.knownIdAspectRatio}}export class CaptureConfigBuilder{captureType;startButton;_selfie;_document;selfie(e){this._selfie||(this._selfie=new SelfieCaptureConfigBuilder),e(this._selfie)}document(e){this._document||(this._document=new DocumentCaptureConfigBuilder),e(this._document)}get selfieConfig(){return this._selfie}get documentConfig(){return this._document}}export class PreviewConfigBuilder{allowRetake=!0}export class ProcessingConfigBuilder{showProgressPercentage=!0;continueButton;retryButton;exitButton}export class ScreensBuilder{_steps=[];consent(e){const t=new ConsentConfigBuilder;e?.(t),this._steps.push({kind:"consent",config:t})}instructions(e){const t=new InstructionsConfigBuilder;e?.(t),this._steps.push({kind:"instructions",config:t})}capture(e){const t=new CaptureConfigBuilder;e(t),this._steps.push({kind:"capture",config:t})}preview(e){const t=new PreviewConfigBuilder;e?.(t),this._steps.push({kind:"preview",config:t})}processing(e){const t=new ProcessingConfigBuilder;e?.(t),this._steps.push({kind:"processing",config:t})}build(){return Object.freeze({steps:Object.freeze([...this._steps])})}}
1
+ "use strict";import{CaptureType as n}from"../../../../core/models/ml_config";import{DocumentCaptureMode as i}from"../../../../core/models/document_capture_mode";export{n as CaptureType};export class ConsentConfigBuilder{partnerName="";partnerIcon;partnerPrivacyPolicyUrl;onConsentGranted;allowButton;denyButton}export class InstructionsConfigBuilder{titlePrefix;titleEmphasis;heroAnimation;guidelinesSectionTitle;guidelines=[];showHeroOval=!0;continueButton}export class SelfieCaptureConfigBuilder{allowAgentMode=!1;enableEnhancedLiveness=!1}export class DocumentCaptureConfigBuilder{documentType;captureMode=i.AutoCaptureWithManualFallback();allowGalleryUpload=!1;allowSkipBack=!1;knownIdAspectRatio;_captureBothSides;get captureBothSides(){return this._captureBothSides??this.documentType?.kind!=="passport"}set captureBothSides(e){this._captureBothSides=e}get resolvedAspectRatio(){return this.documentType?.knownAspectRatio??this.knownIdAspectRatio}}export class CaptureConfigBuilder{captureType;startButton;_selfie;_document;selfie(e){this._selfie||(this._selfie=new SelfieCaptureConfigBuilder),e(this._selfie)}document(e){this._document||(this._document=new DocumentCaptureConfigBuilder),e(this._document)}get selfieConfig(){return this._selfie}get documentConfig(){return this._document}}export class PreviewConfigBuilder{allowRetake=!0}export class ProcessingConfigBuilder{showProgressPercentage=!0;continueButton;retryButton;exitButton}export class ScreensBuilder{_steps=[];consent(e){const t=new ConsentConfigBuilder;e?.(t),this._steps.push({kind:"consent",config:t})}instructions(e){const t=new InstructionsConfigBuilder;e?.(t),this._steps.push({kind:"instructions",config:t})}capture(e){const t=new CaptureConfigBuilder;e(t),this._steps.push({kind:"capture",config:t})}preview(e){const t=new PreviewConfigBuilder;e?.(t),this._steps.push({kind:"preview",config:t})}processing(e){const t=new ProcessingConfigBuilder;e?.(t),this._steps.push({kind:"processing",config:t})}partner(e,t){this._steps.push({kind:"partner",config:Object.freeze({id:e,render:t})})}build(){return Object.freeze({steps:Object.freeze([...this._steps])})}}
@@ -0,0 +1,12 @@
1
+ import type { NjiaNativeModule } from "@smileid/njia";
2
+ /**
3
+ * The njia native module flows route through: the linked TurboModule unless a
4
+ * test installed another with {@link setFlowNavigationModule}.
5
+ */
6
+ export declare const flowNavigationModule: () => NjiaNativeModule | undefined;
7
+ /**
8
+ * @internal Installs the native module flows route through, or the linked
9
+ * TurboModule again with `undefined`. Tests install njia's
10
+ * `ReferenceNjiaNative`, which runs the reducer with no native code.
11
+ */
12
+ export declare function setFlowNavigationModule(next: NjiaNativeModule | undefined): void;
@@ -0,0 +1 @@
1
+ "use strict";let o;export const flowNavigationModule=()=>o;export function setFlowNavigationModule(t){o=t}
@@ -0,0 +1,32 @@
1
+ import { type NjiaCodec, type NjiaGraph } from "@smileid/njia";
2
+ import type { ScreenSpec } from "./dsl/builder/screens_builder";
3
+ /** What the flow's routing reads from the capture state, by its njia wire name. */
4
+ export declare const FlowFact: {
5
+ /** The front document is captured and its supporting image, a back or a visa, is still to come. */
6
+ readonly supportingSidePending: "supportingSidePending";
7
+ /** The job was handed to the partner, so its files are theirs and nothing may retake them. */
8
+ readonly jobHandedOver: "jobHandedOver";
9
+ };
10
+ /** A fact the flow's routing reads. */
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";
14
+ /** How the flow's step kinds and facts are named on the wire. */
15
+ export declare const flowCodec: NjiaCodec<string, FlowFact>;
16
+ /** The flow's screens as a njia graph, with each step resolving back to the screen it came from. */
17
+ export type FlowGraph = {
18
+ readonly graph: NjiaGraph<string, FlowFact>;
19
+ /** The screen the step `stepId` shows. */
20
+ screenOf(stepId: string): ScreenSpec;
21
+ };
22
+ /**
23
+ * This flow as a graph, as the Android and iOS SDKs build it. Steps are named `kind#ordinal`, so two
24
+ * equal screens, such as a document and a selfie `preview {}`, are two steps. A document capture,
25
+ * with the preview that follows it, is a segment that repeats while
26
+ * {@link FlowFact.supportingSidePending} holds, which captures and previews the back or visa;
27
+ * skipping the back leaves the segment. Back is refused while a hand-over is under way
28
+ * ({@link HANDING_OVER}) and once the job is the partner's ({@link FlowFact.jobHandedOver}).
29
+ */
30
+ export declare function flowGraphOf(screens: readonly ScreenSpec[]): FlowGraph;
31
+ /** The graph's step for the partner screen added with `id`: `partner.<id>`, outside the SDK's own steps. */
32
+ export declare const partnerStepId: (id: string) => string;
@@ -0,0 +1 @@
1
+ "use strict";import{allOf as c,guard as u,njiaCodec as w,njiaGraph as m,njiaSegment as O,njiaStep as f,stringWire as v,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(v,j(Object.values(FlowFact)));export function flowGraphOf(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(O(`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}`;
@@ -14,9 +14,10 @@ import type { CaptureTelemetry } from "../screen/use_smile_id_capture_screen";
14
14
  import type { SdkConfig } from "../../data/model/sdk_config";
15
15
  import { DocumentSide } from "@smileid/usesmileid_bridge";
16
16
  /**
17
- * Internal flow navigation manager — owns the screen cursor, captured
18
- * artifacts, navigation primitives, job submission lifecycle, and a
19
- * subscribe pattern for React re-renders.
17
+ * Internal flow navigation manager — routes through a njia engine running the
18
+ * flow's screens as a graph (`flow_navigation_graph.ts`), and owns the captured
19
+ * artifacts, job submission lifecycle, and a subscribe pattern for React
20
+ * re-renders.
20
21
  *
21
22
  * Custom (not Expo Router / React Navigation) because screens are
22
23
  * partner-configurable via the DSL, not file-based routes; forcing a
@@ -75,11 +76,27 @@ export type FlowNavigationManagerOptions = {
75
76
  */
76
77
  export declare class FlowNavigationManager {
77
78
  /**
78
- * Navigation stack and source of truth — top is the active screen.
79
- * Active screen + first/last predicates derive from this path (no
80
- * parallel index). Mutated only via the navigate* methods.
79
+ * The engine's back stack as screens — top is the active screen. The
80
+ * engine is the source of truth: this mirrors its entries after every
81
+ * transition, and the active screen + first/last predicates derive from it
82
+ * (no parallel index).
81
83
  */
82
84
  private _navigationPath;
85
+ /** The flow's screens as the graph the engine routes. */
86
+ private readonly _flowGraph;
87
+ /**
88
+ * The engine routing this flow, started on the first screen; undefined
89
+ * when no screens are configured (validation rejects that at build time
90
+ * anyway) and once the manager is disposed.
91
+ */
92
+ private _engine;
93
+ /**
94
+ * Why the engine couldn't start, or undefined when it did. The flow's host
95
+ * ends the flow with it from an effect
96
+ * ({@link deliverNavigationStartFailure}), so the partner's `onResult` runs
97
+ * after the render that created this manager, not inside it.
98
+ */
99
+ private _navigationStartFailure;
83
100
  private _captured;
84
101
  /**
85
102
  * Set once the partner skips the document back side via the flip
@@ -183,10 +200,44 @@ export declare class FlowNavigationManager {
183
200
  * `notAttempted`.
184
201
  */
185
202
  navigateToNext(): void;
203
+ /**
204
+ * Keeps `value`, a partner screen's encoded value, on the screen on top,
205
+ * then moves on as `navigateToNext()` does: njia's answer, which stays while
206
+ * that screen is in the back stack.
207
+ * @internal
208
+ */
209
+ navigateToNextWith(value: string): void;
210
+ /**
211
+ * The encoded value the partner screen `id` kept, while it is in the back
212
+ * stack.
213
+ * @internal
214
+ */
215
+ partnerValue(id: string): string | undefined;
216
+ private _moveOn;
186
217
  /** Pop the active screen; from the first screen, exits via `onExit` `{ kind: 'cancelled' }`. */
187
218
  navigateBack(): void;
188
219
  /** Reset the path to the first screen (flow restart after terminal failure, manager kept alive). */
189
220
  navigateToStart(): void;
221
+ /**
222
+ * Starts an engine on the flow's graph, mirroring its stack into the path;
223
+ * undefined with no screens, or when njia refused to start it (kept for
224
+ * {@link deliverNavigationStartFailure}).
225
+ */
226
+ private _startEngine;
227
+ /**
228
+ * Ends the flow with the failure that kept its engine from starting, if one
229
+ * did.
230
+ * @internal
231
+ */
232
+ deliverNavigationStartFailure(): void;
233
+ /**
234
+ * Ends the flow with `error`, a njia engine that couldn't start or a call to
235
+ * it that failed, as the flow's failure: a {@link NavigationFailedException}
236
+ * (`GENERAL_INVALID_STATE`) with njia's error as its cause.
237
+ * @internal
238
+ */
239
+ failNavigation(error: unknown): void;
240
+ private _pathOf;
190
241
  /**
191
242
  * Exit the flow with a partner-supplied reason (processing onExit, consent denied, etc.).
192
243
  * A `captured` reason is ignored: only the skip-submission hand-over produces it.
@@ -1 +1 @@
1
- "use strict";import{File as p}from"expo-file-system";import{deleteImportedDocument as c}from"../../camera/imported_document_folder";import{JobType as m}from"../../core/models/job_type";import{CaptureType as u}from"../../core/models/ml_config";import{defaultFrameAspectRatio as l}from"../../core/models/document_type";import{UseSmileIDMetadataFactory as _}from"../../metadata/use_smile_id_metadata_factory";import{decodeSmileIDToken as g}from"../../data/util/use_smile_id_token_decoder";import{isTokenConsentComplete as k}from"../../data/model/token_payload";import{getNextScreen as S,supportingDocumentSide as b,documentPreviewFollowsCapture as C}from"./flow_navigation_manager_routing";import{currentDocumentCaptureSide as v,currentDocumentPreviewBorderFraction as y,currentDocumentPreviewPath as P,currentPreviewIsDocument as w,documentBorderFraction as D,documentCapturesBack as T,recordDocumentImageOrigin as I,retakeCurrentDocumentSide as F,setCapturedBackDocument as j,setCapturedFrontDocument as x,setCapturedVisaDocument as B,skipDocumentBack as E}from"./flow_navigation_manager_documents";import{logAnalyticsEvent as A,logKind as n,recordDocumentCaptureTelemetry as N,recordSelfieCaptureTelemetry as M,screenAnalyticsName as h}from"./flow_navigation_manager_analytics";import{beginSubmissionIfNeeded as O,retrySubmission as R,submit as J}from"./flow_navigation_manager_submission";import{markCapturedTake as G}from"../components/helpers/captured_image_uri";function f(s){return[s.frontDocumentPath,s.backDocumentPath,s.visaDocumentPath].filter(e=>e!==void 0)}export class FlowNavigationManager{_navigationPath=[];_captured={livenessPaths:[]};_documentBackSkipped=!1;_documentBorderFractions=new Map;_documentImageOrigins=new Map;_selfieCaptureTelemetry;_documentCaptureTelemetry=new Map;_cameraName;_devicePositions=[];_deviceMovementDetected=null;_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 _,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=k(t?.tokenPayload?.consent)?i.filter(o=>o.kind!=="consent"):i;const r=this._steps[0];r&&(this._navigationPath=[r]),n(this,{kind:"flowStarted",jobType:this._jobType()}),r&&n(this,{kind:"screenViewed",screen:h(this,r)})}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(r=>r.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??l(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 S(this)}navigateToNext(){if(this._disposed)return;const e=this.getNextScreen();if(!e){const t=this._jobSubmissionState;if(this._submissionResponse){this._finishFlow({kind:"completed",job:this._submissionResponse});return}if(t.kind==="failure"){this._finishFlow({kind:"failed",error:t.error});return}const i=t.kind==="success"?t.response:{userId:"",jobId:"",status:"",message:""};this._finishFlow({kind:"completed",job:i});return}this._navigationPath=[...this._navigationPath,e],n(this,{kind:"screenViewed",screen:h(this,e)}),e.kind==="processing"&&this._jobSubmissionState.kind==="notAttempted"&&this._repository!==void 0&&(this._jobSubmissionState={kind:"loading"}),this._notify(),e.kind==="processing"&&this._jobSubmissionState.kind==="loading"&&this._repository!==void 0&&setTimeout(()=>{this._disposed||J(this)},0)}navigateBack(){if(!this._disposed&&this._capturedJob===void 0&&!(this._configuration.config?.skipApiSubmission&&this._jobSubmissionState.kind==="loading")){if(this.isFirstScreen){this._finishFlow({kind:"cancelled"});return}n(this,{kind:"retakeRequested"}),this._navigationPath=this._navigationPath.slice(0,-1),this._notify()}}navigateToStart(){if(this._disposed)return;const e=this._steps[0];this._navigationPath=e?[e]:[],this._notify()}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||(G(e),this._captured={...this._captured,selfiePath:e,livenessPaths:Object.freeze([...t])},n(this,{kind:"selfieCaptured",livenessImageCount:t.length}),this._notify())}get selfieCaptureGeometry(){return this._selfieCaptureGeometry}_selfieCaptureGeometry;recordSelfieCaptureGeometry(e){e&&(this._selfieCaptureGeometry=e)}setCapturedFrontDocument(e,t=0){x(this,e,t)}setCapturedBackDocument(e,t=0){j(this,e,t)}supportingDocumentSide(){return b(this)}documentCapturesBack(){return T(this)}currentDocumentCaptureSide(){return v(this)}setCapturedVisaDocument(e,t=0){B(this,e,t)}documentPreviewFollowsCapture(){return C(this)}currentPreviewIsDocument(){return w(this)}currentDocumentPreviewPath(){return P(this)}documentBorderFraction(e){return D(this,e)}currentDocumentPreviewBorderFraction(){return y(this)}retakeCurrentDocumentSide(){F(this)}skipDocumentBack(){E(this)}recordDocumentImageOrigin(e,t){I(this,e,t)}recordSelfieCaptureTelemetry(e){M(this,e)}recordDocumentCaptureTelemetry(e,t){N(this,e,t)}setConsent(e){this._disposed||(this._captured={...this._captured,consentInformation:e},n(this,{kind:"consentCaptured"}),this._notify())}get jobSubmissionState(){return this._jobSubmissionState}beginSubmissionIfNeeded(){O(this)}retrySubmission(){R(this)}_setCaptured(e){const t=new Set(f(e));for(const i of f(this._captured))t.has(i)||c(i);this._captured=e}_deleteCapturedFiles(){if(this._configuration.config?.allowOfflineMode)return;const{selfiePath:e,livenessPaths:t,frontDocumentPath:i,backDocumentPath:r,visaDocumentPath:o}=this._captured;for(const d of[e,...t,i,r,o])if(d){try{const a=new p(d);a.exists&&a.delete()}catch{}c(d)}}_finishFlow(e){this._capturedJob!==void 0&&e.kind!=="captured"||(this._flowEnded=!0,e.kind!=="captured"&&this._deleteCapturedFiles(),e.kind==="completed"?n(this,e.job.jobId?{kind:"flowCompletedSuccess",jobId:e.job.jobId}:{kind:"flowCompletedSuccess"}):e.kind==="failed"&&n(this,{kind:"flowCompletedFailure",errorMessage:e.error instanceof Error?e.error.message:String(e.error)}),e.kind==="captured"&&n(this,{kind:"flowCompletedCaptured"}),this._onExit(e))}logAnalyticsEvent(e){A(this,e)}_jobType(){return this._configuration.network?.config?.jobType??m.unknown}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}dispose(){this._disposed=!0,this._listeners.clear()}static _decodeToken(e){if(e.config?.allowOfflineMode)return;const t=e.network?.config?.token;if(!(!t||t.length===0))return g(t)}_notify(){for(const e of this._listeners)try{e()}catch{}}}
1
+ "use strict";import{File as g}from"expo-file-system";import{deleteImportedDocument as f}from"../../camera/imported_document_folder";import{JobType as k}from"../../core/models/job_type";import{CaptureType as u}from"../../core/models/ml_config";import{defaultFrameAspectRatio as v}from"../../core/models/document_type";import{UseSmileIDMetadataFactory as S}from"../../metadata/use_smile_id_metadata_factory";import{decodeSmileIDToken as w}from"../../data/util/use_smile_id_token_decoder";import{isTokenConsentComplete as C}from"../../data/model/token_payload";import{UseSmileIDCrashReporting as b}from"@smileid/usesmileid_bridge";import{answerOf as y,NjiaException as P,NjiaIntents as h,NjiaKit as D,top as c}from"@smileid/njia";import{getNextScreen as F,nextIntent as T,sendFromTop as p,supportingDocumentSide as I,documentPreviewFollowsCapture as j}from"./flow_navigation_manager_routing";import{flowCodec as E,flowGraphOf as x,partnerStepId as N}from"./flow_navigation_graph";import{NavigationFailedException as O}from"../../core/exception/flow_exceptions";import{flowNavigationModule as B}from"./flow_navigation_engine";import{currentDocumentCaptureSide as G,currentDocumentPreviewBorderFraction as M,currentDocumentPreviewPath as A,currentPreviewIsDocument as R,documentBorderFraction as J,documentCapturesBack as L,recordDocumentImageOrigin as V,retakeCurrentDocumentSide as K,setCapturedBackDocument as U,setCapturedFrontDocument as q,setCapturedVisaDocument as z,skipDocumentBack as W}from"./flow_navigation_manager_documents";import{logAnalyticsEvent as H,logKind as o,recordDocumentCaptureTelemetry as Q,recordSelfieCaptureTelemetry as X,screenViewedEvent as m}from"./flow_navigation_manager_analytics";import{beginSubmissionIfNeeded as Y,retrySubmission as Z,submit as $}from"./flow_navigation_manager_submission";import{markCapturedTake as ee}from"../components/helpers/captured_image_uri";function l(d){return[d.frontDocumentPath,d.backDocumentPath,d.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;_cameraName;_devicePositions=[];_deviceMovementDetected=null;_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=C(t?.tokenPayload?.consent)?i.filter(s=>s.kind!=="consent"):i,this._flowGraph=x(this._steps),this._engine=this._startEngine();const n=this._navigationPath[0];o(this,{kind:"flowStarted",jobType:this._jobType()}),n&&o(this,m(this,n))}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(n=>n.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??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 F(this)}navigateToNext(){this._moveOn(e=>T(this,e))}navigateToNextWith(e){this._moveOn(t=>h.answer(t.id,e))}partnerValue(e){const t=this._engine;return t?y(t.state,N(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 n=i===void 0||i.effects.some(r=>r.kind==="pastEnd"),s=i?.effects.filter(r=>r.kind==="entered").at(-1);if(!n&&(s===void 0||!("entry"in s)))return;const a=s&&"entry"in s?this._flowGraph.screenOf(s.entry.step):void 0;if(!a){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 _=r.kind==="success"?r.response:{userId:"",jobId:"",status:"",message:""};this._finishFlow({kind:"completed",job:_});return}o(this,m(this,a)),a.kind==="processing"&&this._jobSubmissionState.kind==="notAttempted"&&this._repository!==void 0&&(this._jobSubmissionState={kind:"loading"}),this._notify(),a.kind==="processing"&&this._jobSubmissionState.kind==="loading"&&this._repository!==void 0&&setTimeout(()=>{this._disposed||$(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?.kind,i=p(this,n=>h.back(n.id));if(i!==void 0){if(i.effects.some(n=>n.kind==="finished")){this._finishFlow({kind:"cancelled"});return}i.effects.some(n=>n.kind==="left")&&((t==="capture"||t==="preview")&&o(this,{kind:"retakeRequested"}),this._notify())}}navigateToStart(){this._disposed||(this._engine?.dispose(),this._engine=this._startEngine(),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(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){b.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||(ee(e),this._captured={...this._captured,selfiePath:e,livenessPaths:Object.freeze([...t])},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){q(this,e,t)}setCapturedBackDocument(e,t=0){U(this,e,t)}supportingDocumentSide(){return I(this)}documentCapturesBack(){return L(this)}currentDocumentCaptureSide(){return G(this)}setCapturedVisaDocument(e,t=0){z(this,e,t)}documentPreviewFollowsCapture(){return j(this)}currentPreviewIsDocument(){return R(this)}currentDocumentPreviewPath(){return A(this)}documentBorderFraction(e){return J(this,e)}currentDocumentPreviewBorderFraction(){return M(this)}retakeCurrentDocumentSide(){K(this)}skipDocumentBack(){W(this)}recordDocumentImageOrigin(e,t){V(this,e,t)}recordSelfieCaptureTelemetry(e){X(this,e)}recordDocumentCaptureTelemetry(e,t){Q(this,e,t)}setConsent(e){this._disposed||(this._captured={...this._captured,consentInformation:e},o(this,{kind:"consentCaptured"}),this._notify())}get jobSubmissionState(){return this._jobSubmissionState}beginSubmissionIfNeeded(){Y(this)}retrySubmission(){Z(this)}_setCaptured(e){const t=new Set(l(e));for(const i of l(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:n,visaDocumentPath:s}=this._captured;for(const a of[e,...t,i,n,s])if(a){try{const r=new g(a);r.exists&&r.delete()}catch{}f(a)}}_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??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 w(t)}_notify(){for(const e of this._listeners)try{e()}catch{}}}
@@ -20,4 +20,12 @@ export declare function documentImageOriginEntries(manager: FlowNavigationManage
20
20
  export declare function captureTelemetryEntries(manager: FlowNavigationManager): MetadataEntry[];
21
21
  export declare function logAnalyticsEvent(manager: FlowNavigationManager, event: UseSmileIDAnalyticsEventKind): void;
22
22
  export declare function logKind(manager: FlowNavigationManager, event: UseSmileIDAnalyticsEventKind): void;
23
- export declare function screenAnalyticsName(manager: FlowNavigationManager, screen: ScreenSpec): UseSmileIDAnalyticsScreenName;
23
+ /**
24
+ * What logs `screen` becoming active: `partner_screen_viewed` with its id for
25
+ * a partner screen, which has no SDK screen name, and `screen_viewed` for the
26
+ * SDK's own.
27
+ */
28
+ export declare function screenViewedEvent(manager: FlowNavigationManager, screen: ScreenSpec): UseSmileIDAnalyticsEventKind;
29
+ export declare function screenAnalyticsName(manager: FlowNavigationManager, screen: Exclude<ScreenSpec, {
30
+ kind: "partner";
31
+ }>): UseSmileIDAnalyticsScreenName;
@@ -1 +1 @@
1
- "use strict";import{UseSmileIDAnalyticsParamKeys as d,UseSmileIDAnalyticsScreenNames as r}from"./analytics/use_smile_id_analytics_event";import{encodeAnalyticsEventKind as p}from"./analytics/use_smile_id_analytics_event_kind";import{DOCUMENT_BACK_IMAGE_ORIGIN_KEY as l,DOCUMENT_FRONT_IMAGE_ORIGIN_KEY as v,DOCUMENT_VISA_IMAGE_ORIGIN_KEY as E}from"../../metadata/document_image_origin";import{CAPTURE_IMAGE_COLOR_DEPTH as a,CAPTURE_IMAGE_PIXEL_CONFIG as f}from"../../metadata/captured_image_properties";import{DocumentSide as o}from"@smileid/usesmileid_bridge";export function recordSelfieCaptureTelemetry(e,t){e._disposed||(e._selfieCaptureTelemetry=t,m(e,t))}export function recordDocumentCaptureTelemetry(e,t,i){e._disposed||(e._documentCaptureTelemetry.set(t,i),m(e,i))}function m(e,t){t.cameraName&&(e._cameraName=t.cameraName),t.devicePositions.length>0&&(e._devicePositions=t.devicePositions,e._deviceMovementDetected=t.deviceMovementDetected)}export function documentImageOriginEntries(e){const t=[],i=e._documentImageOrigins.get(o.Front);i!==void 0&&t.push({name:v,value:i});const n=e._documentImageOrigins.get(o.Back);n!==void 0&&t.push({name:l,value:n});const _=e._documentImageOrigins.get(o.Visa);return _!==void 0&&t.push({name:E,value:_}),t}export function captureTelemetryEntries(e){const t=[],i=(s,c)=>t.push({name:s,value:c}),n=e._selfieCaptureTelemetry;n&&(i("selfie_capture_duration_ms",String(n.durationMs)),i("selfie_capture_retries",String(n.retries))),e._captured.selfiePath!==void 0&&(i("selfie_image_color_depth",String(a)),i("selfie_image_pixel_config",f)),e._cameraName&&i("camera_name",e._cameraName),e._devicePositions.length>0&&(i("device_positions",JSON.stringify(e._devicePositions)),e._deviceMovementDetected!==null&&i("device_movement_detected",String(e._deviceMovementDetected)));const _=s=>{switch(s){case o.Back:return"back";case o.Visa:return"visa";default:return"front"}};for(const s of[o.Front,o.Back,o.Visa]){const c=_(s),u=e._documentCaptureTelemetry.get(s);u&&(i(`document_${c}_capture_duration_ms`,String(u.durationMs)),i(`document_${c}_capture_retries`,String(u.retries)),i(`document_${c}_image_color_depth`,String(a)),i(`document_${c}_image_pixel_config`,f))}return t}export function logAnalyticsEvent(e,t){e._disposed||logKind(e,t)}export function logKind(e,t){const{type:i,extras:n}=p(t);I(e,i,n)}function I(e,t,i={}){const n=e._configuration.onAnalyticsEvent;n&&n({type:t,extras:{...i,[d.sessionId]:e._sessionId,[d.timestamp]:String(Date.now())}})}export function screenAnalyticsName(e,t){return{consent:r.consent,instructions:r.instructions,capture:r.capture,preview:r.preview,processing:r.processing}[t.kind]}
1
+ "use strict";import{UseSmileIDAnalyticsParamKeys as d,UseSmileIDAnalyticsScreenNames as c}from"./analytics/use_smile_id_analytics_event";import{encodeAnalyticsEventKind as m}from"./analytics/use_smile_id_analytics_event_kind";import{DOCUMENT_BACK_IMAGE_ORIGIN_KEY as l,DOCUMENT_FRONT_IMAGE_ORIGIN_KEY as v,DOCUMENT_VISA_IMAGE_ORIGIN_KEY as E}from"../../metadata/document_image_origin";import{CAPTURE_IMAGE_COLOR_DEPTH as a,CAPTURE_IMAGE_PIXEL_CONFIG as f}from"../../metadata/captured_image_properties";import{DocumentSide as o}from"@smileid/usesmileid_bridge";export function recordSelfieCaptureTelemetry(e,t){e._disposed||(e._selfieCaptureTelemetry=t,p(e,t))}export function recordDocumentCaptureTelemetry(e,t,i){e._disposed||(e._documentCaptureTelemetry.set(t,i),p(e,i))}function p(e,t){t.cameraName&&(e._cameraName=t.cameraName),t.devicePositions.length>0&&(e._devicePositions=t.devicePositions,e._deviceMovementDetected=t.deviceMovementDetected)}export function documentImageOriginEntries(e){const t=[],i=e._documentImageOrigins.get(o.Front);i!==void 0&&t.push({name:v,value:i});const n=e._documentImageOrigins.get(o.Back);n!==void 0&&t.push({name:l,value:n});const _=e._documentImageOrigins.get(o.Visa);return _!==void 0&&t.push({name:E,value:_}),t}export function captureTelemetryEntries(e){const t=[],i=(s,r)=>t.push({name:s,value:r}),n=e._selfieCaptureTelemetry;n&&(i("selfie_capture_duration_ms",String(n.durationMs)),i("selfie_capture_retries",String(n.retries))),e._captured.selfiePath!==void 0&&(i("selfie_image_color_depth",String(a)),i("selfie_image_pixel_config",f)),e._cameraName&&i("camera_name",e._cameraName),e._devicePositions.length>0&&(i("device_positions",JSON.stringify(e._devicePositions)),e._deviceMovementDetected!==null&&i("device_movement_detected",String(e._deviceMovementDetected)));const _=s=>{switch(s){case o.Back:return"back";case o.Visa:return"visa";default:return"front"}};for(const s of[o.Front,o.Back,o.Visa]){const r=_(s),u=e._documentCaptureTelemetry.get(s);u&&(i(`document_${r}_capture_duration_ms`,String(u.durationMs)),i(`document_${r}_capture_retries`,String(u.retries)),i(`document_${r}_image_color_depth`,String(a)),i(`document_${r}_image_pixel_config`,f))}return t}export function logAnalyticsEvent(e,t){e._disposed||logKind(e,t)}export function logKind(e,t){const{type:i,extras:n}=m(t);I(e,i,n)}function I(e,t,i={}){const n=e._configuration.onAnalyticsEvent;n&&n({type:t,extras:{...i,[d.sessionId]:e._sessionId,[d.timestamp]:String(Date.now())}})}export function screenViewedEvent(e,t){return t.kind==="partner"?{kind:"partnerScreenViewed",step:t.config.id}:{kind:"screenViewed",screen:screenAnalyticsName(e,t)}}export function screenAnalyticsName(e,t){return{consent:c.consent,instructions:c.instructions,capture:c.capture,preview:c.preview,processing:c.processing}[t.kind]}
@@ -1,10 +1,35 @@
1
+ import { type NjiaEntry, type NjiaIntent, type NjiaTransition } from "@smileid/njia";
1
2
  import type { ScreenSpec } from "./dsl/builder/screens_builder";
3
+ import { FlowFact } from "./flow_navigation_graph";
2
4
  import { DocumentSide } from "@smileid/usesmileid_bridge";
3
5
  import type { FlowNavigationManager } from "./flow_navigation_manager";
4
6
  /**
5
- * Where the flow goes next, including the per-side document loop. Functions take the `FlowNavigationManager` first; its public methods delegate here.
7
+ * Where the flow goes next. The flow runs as a njia graph (`flow_navigation_graph.ts`), so these
8
+ * keep the engine's facts in step with the capture state and preview or send its intents. Functions
9
+ * take the `FlowNavigationManager` first; its public methods delegate here.
10
+ */
11
+ /**
12
+ * The screen `navigateToNext()` would show, previewed on the engine with the facts as the capture
13
+ * state stands, without moving.
6
14
  */
7
15
  export declare function getNextScreen(manager: FlowNavigationManager): ScreenSpec | undefined;
16
+ /**
17
+ * Brings the engine's facts and busy phase up to the capture state, then sends the intent `intent`
18
+ * makes from the top entry. Undefined when there is no engine or entry to send from, and when called
19
+ * from an engine listener: the engine then queues the intent and applies it once the listeners are
20
+ * done. Undefined too when a send fails: the flow then ends with that failure
21
+ * (`FlowNavigationManager.failNavigation`).
22
+ */
23
+ export declare function sendFromTop(manager: FlowNavigationManager, intent: (top: NjiaEntry) => NjiaIntent<FlowFact>): NjiaTransition<FlowFact> | undefined;
24
+ /** Sends the facts and busy phase the capture state implies, when the engine's differ. */
25
+ export declare function syncNavigationState(manager: FlowNavigationManager): void;
26
+ /**
27
+ * The intent that moves on from `current`: a skip once the user has skipped the document's back on
28
+ * its capture, which leaves the document segment and so passes over its preview, and next otherwise.
29
+ */
30
+ export declare function nextIntent(manager: FlowNavigationManager, current: NjiaEntry): NjiaIntent<FlowFact>;
31
+ /** The facts the graph routes on, as the capture state stands now. */
32
+ export declare function flowFacts(manager: FlowNavigationManager): Set<FlowFact>;
8
33
  export declare function supportingDocumentSide(manager: FlowNavigationManager): DocumentSide | undefined;
9
34
  /** Captured path for {@link supportingDocumentSide}, or undefined when absent or not yet captured. */
10
35
  export declare function capturedSupportingDocument(manager: FlowNavigationManager): string | undefined;
@@ -1 +1 @@
1
- "use strict";import{JobType as o}from"../../core/models/job_type";import{CaptureType as u}from"../../core/models/ml_config";import{DocumentSide as i}from"@smileid/usesmileid_bridge";export function getNextScreen(e){const t=e.currentScreen;if(!t)return;const n=e._steps.indexOf(t);if(!(n<0)){if(t.kind==="preview"&&precedingStepIsDocumentCapture(e,n)&&e.supportingDocumentSide()!==void 0&&capturedSupportingDocument(e)===void 0&&!e._documentBackSkipped){const c=e._steps[n-1];if(c!==void 0)return c}return t.kind==="capture"&&t.config.captureType===u.document&&e._documentBackSkipped&&e._steps[n+1]?.kind==="preview"?e._steps[n+2]:t.kind==="capture"&&t.config.captureType===u.document&&e.supportingDocumentSide()!==void 0&&e._captured.frontDocumentPath!==void 0&&capturedSupportingDocument(e)===void 0&&!e._documentBackSkipped&&!e.documentPreviewFollowsCapture()?t:e._steps[n+1]}}export function supportingDocumentSide(e){if(e._configuration.network?.config?.jobType===o.residencyDocumentVerification)return i.Visa;for(const t of e._steps)if(t.kind==="capture"&&t.config.captureType===u.document){const n=t.config.documentConfig;return n?.documentType?.hasBackSide===!0&&(n?.captureBothSides??!1)?i.Back:void 0}}export function capturedSupportingDocument(e){switch(e.supportingDocumentSide()){case i.Visa:return e._captured.visaDocumentPath;case i.Back:return e._captured.backDocumentPath;default:return}}export function documentPreviewFollowsCapture(e){const t=e._steps.findIndex(n=>n.kind==="capture"&&n.config.captureType===u.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===u.document}
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 +1 @@
1
- "use strict";import{jsx as e}from"react/jsx-runtime";import{OrchestratedCaptureScreen as n}from"../screen/orchestrated_capture_screen";import{OrchestratedConsentScreen as o}from"../screen/orchestrated_consent_screen";import{OrchestratedInstructionsScreen as c}from"../screen/orchestrated_instructions_screen";import{OrchestratedPreviewScreen as t}from"../screen/orchestrated_preview_screen";import{OrchestratedProcessingScreen as i}from"../screen/orchestrated_processing_screen";export function ScreenRenderer({step:r}){switch(r.kind){case"instructions":return e(c,{configuration:r.config});case"consent":return e(o,{configuration:r.config});case"capture":return e(n,{configuration:r.config});case"preview":return e(t,{configuration:r.config});case"processing":return e(i,{configuration:r.config})}}
1
+ "use strict";import{jsx as e}from"react/jsx-runtime";import{OrchestratedCaptureScreen as n}from"../screen/orchestrated_capture_screen";import{OrchestratedConsentScreen as o}from"../screen/orchestrated_consent_screen";import{OrchestratedInstructionsScreen as c}from"../screen/orchestrated_instructions_screen";import{OrchestratedPreviewScreen as t}from"../screen/orchestrated_preview_screen";import{OrchestratedProcessingScreen as i}from"../screen/orchestrated_processing_screen";import{OrchestratedPartnerScreen as a}from"../screen/orchestrated_partner_screen";export function ScreenRenderer({step:r}){switch(r.kind){case"instructions":return e(c,{configuration:r.config});case"consent":return e(o,{configuration:r.config});case"capture":return e(n,{configuration:r.config});case"preview":return e(t,{configuration:r.config});case"processing":return e(i,{configuration:r.config});case"partner":return e(a,{configuration:r.config})}}
@@ -0,0 +1,10 @@
1
+ import type { PartnerScreenConfig } from "../dsl/builder/screens_builder";
2
+ export type OrchestratedPartnerScreenProps = {
3
+ readonly configuration: PartnerScreenConfig;
4
+ };
5
+ /**
6
+ * A partner screen: the integrator's content, given a scope that moves the
7
+ * flow and reads only partner values. The scope acts only while this screen is
8
+ * the one on top, so a second tap after the flow has moved on is harmless.
9
+ */
10
+ export declare function OrchestratedPartnerScreen({ configuration, }: OrchestratedPartnerScreenProps): import("react").JSX.Element;
@@ -0,0 +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 +1 @@
1
- "use strict";import{jsx as i,jsxs as H}from"react/jsx-runtime";import{useEffect as s,useMemo as R,useReducer as j,useRef as m,useState as J}from"react";import{AppState as Y,Text as F,useColorScheme as q,View as P}from"react-native";import{prewarmCameraIfNeeded as Q}from"./config/flow_configuration_camera";import{FlowNavigationManager as X}from"./flow_navigation_manager";import{FlowNavigationProvider as Z}from"./flow_navigation_context";import{ScreenRenderer as ee}from"./graph/screen_renderer";import{ScreenTransition as re}from"./graph/screen_transition";import{defaultDarkTheme as te,defaultLightTheme as oe}from"../theme/theme";import{UseSmileIDThemeProvider as ne}from"../theme/theme_context";import{useUseSmileIDFonts as ie}from"../theme/use_use_smile_id_fonts";import{UseSmileIDCrashReporting as c}from"@smileid/usesmileid_bridge";import{generateSessionId as se}from"../../metadata/use_smile_id_metadata_factory";import{UseSmileIDLocalizationsProvider as ce}from"../../l10n/use_smile_id_localizations_provider";import{UseSmileIDLocalizations as k}from"../../l10n/use_smile_id_localizations";import{cancelled as _,captured as ae,failure as I,success as le}from"../../core/models/result";import{ValidationErrorScreen as de}from"./screen/validation_error_screen";import{BuilderValidationException as A}from"../../core/exception/builder_validation_exception";import{UseSmileIDBuilderException as me}from"../../core/exception/use_smile_id_builder_exception";import{ValidationState as ue}from"./validation/validation_state";import{makeNetworkingFactory as N}from"../../data/factory/networking_factory";import{UseSmileIDRepositoryImpl as pe}from"../../data/repository/use_smile_id_repository_impl";import{JobPackageSealer as fe}from"../../data/security/job_package_sealer";import{EncryptionSecretProvider as he,SigningSecretProvider as Se}from"@smileid/usesmileid_bridge/internal";import{RetryStrategy as ge}from"../../core/models/network_config";const ye=Object.freeze({maxAttempts:1,strategy:ge.none,initialDelay:1,multiplier:2,maxDelay:32,jitter:.2,fixedDelay:1});export function FlowInvalidDispatcher({result:e,onResult:y,enableDebugMode:f}){const o=m(y);o.current=y;const a=m(e.validation);return a.current=e.validation,s(()=>{const v=new A(a.current);try{o.current(I(v))}catch(b){c.captureException(b)}},[]),f?i(de,{validationState:e.validation}):null}const ve=1e3;export function FlowSuccessRenderer({configuration:e}){const f=q()==="dark",o=e.theme?f?e.theme.dark:e.theme.light:f?te:oe,a=ie(),[v,b]=J(!1);s(()=>{if(a)return;const r=setTimeout(()=>b(!0),ve);return()=>clearTimeout(r)},[a]);const D=e.config?.enableCrashReporting!==!1,T=e.network?.config?.partnerConfig?.useSandbox===!0,E=m(null);E.current===null&&(E.current=se()),s(()=>(D&&(c.disable(),c.enable({useSandbox:T}),c.setUserId(E.current),c.captureBreadcrumb({category:"flow.navigation",message:"flow mounted"})),()=>{c.disable()}),[D,T]);const h=m(e.onResult);h.current=e.onResult;const u=m(!1),[,z]=j(r=>r+1,0),l=R(()=>{const r=e.network;if(r?.config?.partnerConfig)try{let t;const n=()=>t??=Se.signingSecret(),{api:x,metadata:W}=N(r,n),$=e.config?.skipApiSubmission?{api:N(r,n,{capturing:!0}).api,sealer:new fe(()=>he.encryptionSecret())}:void 0,G=r.retry??ye;return{repository:new pe(x,G,$),metadataProvider:W}}catch(t){if(t instanceof me)return{configError:t};throw t}},[e.network,e.config?.skipApiSubmission]),p=l!==void 0&&"configError"in l?l.configError:void 0,S=l!==void 0&&"repository"in l?l:void 0;s(()=>{if(p===void 0||u.current)return;u.current=!0;const r=ue.invalid([p]),t=r.valid?p:new A(r);try{h.current(I(t))}catch(n){c.captureException(n)}},[p]);const d=R(()=>{const r=t=>{u.current=!0;const n=h.current;try{t.kind==="completed"?n(le(t.job)):t.kind==="cancelled"?n(_()):t.kind==="captured"?n(ae(t.job)):n(I(t.error))}catch(x){c.captureException(x)}};return new X({configuration:e,onExit:r,...S?{repository:S.repository,metadataProvider:S.metadataProvider}:{}})},[e,S]);s(()=>{Q(e)},[e]),s(()=>{const r=d.subscribe(z);return()=>{r(),d.dispose()}},[d]),s(()=>()=>{u.current||(u.current=!0,h.current(_()))},[]);const[M,O]=j(r=>r+1,0);s(()=>{const r=Y.addEventListener("change",t=>{t==="active"&&O()});return()=>r.remove()},[]);const V=k.activeLocaleKey,U=R(()=>e.localizations?e.localizations:k.hasRegisteredLocales()?k.forActiveLocale():null,[e.localizations,V,M]),w=d.currentScreen,g=d.currentDepth,L=m(g),B=g>=L.current;L.current=g;const K=w?i(Z,{manager:d,children:i(re,{forward:B,children:i(ee,{step:w})},`${g}:${w.kind}`)}):H(P,{style:{flex:1,alignItems:"center",justifyContent:"center",backgroundColor:o.colors.background,padding:o.spacing.large},children:[i(F,{style:{...o.typography.pageHeading,color:o.colors.titleText},children:"UseSmileID"}),i(F,{style:{...o.typography.body,color:o.colors.cardText},children:"No screens configured \u2014 call `b.screens((screens) => screens.instructions(); ...)`"})]}),C=i(ne,{value:o,children:a||v?K:i(P,{style:{flex:1,backgroundColor:o.colors.background},testID:"si_flow_font_gate"})});return p!==void 0?null:U?i(ce,{value:U,children:C}):C}
1
+ "use strict";import{jsx as c,jsxs as J}from"react/jsx-runtime";import{useEffect as o,useMemo as x,useReducer as P,useRef as u,useState as Y}from"react";import{AppState as q,BackHandler as Q,Text as j,useColorScheme as X,View as _}from"react-native";import{prewarmCameraIfNeeded as Z}from"./config/flow_configuration_camera";import{FlowNavigationManager as ee}from"./flow_navigation_manager";import{FlowNavigationProvider as re}from"./flow_navigation_context";import{ScreenRenderer as te}from"./graph/screen_renderer";import{ScreenTransition as ne}from"./graph/screen_transition";import{defaultDarkTheme as oe,defaultLightTheme as ie}from"../theme/theme";import{UseSmileIDThemeProvider as se}from"../theme/theme_context";import{useUseSmileIDFonts as ce}from"../theme/use_use_smile_id_fonts";import{UseSmileIDCrashReporting as a}from"@smileid/usesmileid_bridge";import{generateSessionId as ae}from"../../metadata/use_smile_id_metadata_factory";import{UseSmileIDLocalizationsProvider as le}from"../../l10n/use_smile_id_localizations_provider";import{UseSmileIDLocalizations as R}from"../../l10n/use_smile_id_localizations";import{cancelled as A,captured as de,failure as I,success as me}from"../../core/models/result";import{ValidationErrorScreen as ue}from"./screen/validation_error_screen";import{BuilderValidationException as N}from"../../core/exception/builder_validation_exception";import{UseSmileIDBuilderException as pe}from"../../core/exception/use_smile_id_builder_exception";import{ValidationState as fe}from"./validation/validation_state";import{makeNetworkingFactory as z}from"../../data/factory/networking_factory";import{UseSmileIDRepositoryImpl as he}from"../../data/repository/use_smile_id_repository_impl";import{JobPackageSealer as Se}from"../../data/security/job_package_sealer";import{EncryptionSecretProvider as ge,SigningSecretProvider as ye}from"@smileid/usesmileid_bridge/internal";import{RetryStrategy as ve}from"../../core/models/network_config";const be=Object.freeze({maxAttempts:1,strategy:ve.none,initialDelay:1,multiplier:2,maxDelay:32,jitter:.2,fixedDelay:1});export function FlowInvalidDispatcher({result:e,onResult:v,enableDebugMode:h}){const n=u(v);n.current=v;const l=u(e.validation);return l.current=e.validation,o(()=>{const b=new N(l.current);try{n.current(I(b))}catch(w){a.captureException(w)}},[]),h?c(ue,{validationState:e.validation}):null}const we=1e3;export function FlowSuccessRenderer({configuration:e}){const h=X()==="dark",n=e.theme?h?e.theme.dark:e.theme.light:h?oe:ie,l=ce(),[b,w]=Y(!1);o(()=>{if(l)return;const r=setTimeout(()=>w(!0),we);return()=>clearTimeout(r)},[l]);const D=e.config?.enableCrashReporting!==!1,T=e.network?.config?.partnerConfig?.useSandbox===!0,E=u(null);E.current===null&&(E.current=ae()),o(()=>(D&&(a.disable(),a.enable({useSandbox:T}),a.setUserId(E.current),a.captureBreadcrumb({category:"flow.navigation",message:"flow mounted"})),()=>{a.disable()}),[D,T]);const S=u(e.onResult);S.current=e.onResult;const p=u(!1),[,B]=P(r=>r+1,0),d=x(()=>{const r=e.network;if(r?.config?.partnerConfig)try{let t;const s=()=>t??=ye.signingSecret(),{api:y,metadata:W}=z(r,s),$=e.config?.skipApiSubmission?{api:z(r,s,{capturing:!0}).api,sealer:new Se(()=>ge.encryptionSecret())}:void 0,G=r.retry??be;return{repository:new he(y,G,$),metadataProvider:W,warmUpConnection:()=>y.warmUpConnection()}}catch(t){if(t instanceof pe)return{configError:t};throw t}},[e.network,e.config?.skipApiSubmission]),f=d!==void 0&&"configError"in d?d.configError:void 0,m=d!==void 0&&"repository"in d?d:void 0,U=e.config?.skipApiSubmission===!0;o(()=>{U||m?.warmUpConnection()},[m,U]),o(()=>{if(f===void 0||p.current)return;p.current=!0;const r=fe.invalid([f]),t=r.valid?f:new N(r);try{S.current(I(t))}catch(s){a.captureException(s)}},[f]);const i=x(()=>{const r=t=>{p.current=!0;const s=S.current;try{t.kind==="completed"?s(me(t.job)):t.kind==="cancelled"?s(A()):t.kind==="captured"?s(de(t.job)):s(I(t.error))}catch(y){a.captureException(y)}};return new ee({configuration:e,onExit:r,...m?{repository:m.repository,metadataProvider:m.metadataProvider}:{}})},[e,m]);o(()=>{Z(e)},[e]),o(()=>{const r=i.subscribe(B);return()=>{r(),i.dispose()}},[i]),o(()=>{i.deliverNavigationStartFailure()},[i]),o(()=>()=>{p.current||(p.current=!0,S.current(A()))},[]);const[M,O]=P(r=>r+1,0);o(()=>{const r=q.addEventListener("change",t=>{t==="active"&&O()});return()=>r.remove()},[]),o(()=>{const r=Q.addEventListener("hardwareBackPress",()=>(i.navigateBack(),!0));return()=>r.remove()},[i]);const V=R.activeLocaleKey,C=x(()=>e.localizations?e.localizations:R.hasRegisteredLocales()?R.forActiveLocale():null,[e.localizations,V,M]),k=i.currentScreen,g=i.currentDepth,L=u(g),H=g>=L.current;L.current=g;const K=k?c(re,{manager:i,children:c(ne,{forward:H,children:c(te,{step:k})},`${g}:${k.kind}`)}):J(_,{style:{flex:1,alignItems:"center",justifyContent:"center",backgroundColor:n.colors.background,padding:n.spacing.large},children:[c(j,{style:{...n.typography.pageHeading,color:n.colors.titleText},children:"UseSmileID"}),c(j,{style:{...n.typography.body,color:n.colors.cardText},children:"No screens configured \u2014 call `b.screens((screens) => screens.instructions(); ...)`"})]}),F=c(se,{value:n,children:l||b?K:c(_,{style:{flex:1,backgroundColor:n.colors.background},testID:"si_flow_font_gate"})});return f!==void 0?null:C?c(le,{value:C,children:F}):F}
@@ -1 +1 @@
1
- "use strict";import{CaptureType as d}from"../../../core/models/ml_config";import{JobType as g,jobTypeFromValue as w}from"../../../core/models/job_type";import{InvalidConsentConfigException as c,InvalidConsentInformationException as m}from"../../../core/exception/consent_validation_exceptions";import{InvalidFieldValueException as s,MissingJobTypeException as P,MissingMLConfigurationBlockException as k,MissingNetworkConfigurationBlockException as b}from"../../../core/exception/job_validation_exceptions";import{AgentModeWithEnhancedLivenessException as C,InvalidDocumentCaptureConfigException as u,InvalidMissingCaptureTypeException as I}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 T}from"./job_type_validator";function V(e){return e?.allowAgentMode&&e.enableEnhancedLiveness?[new C]:[]}function x(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),...y(e)]}function l(e){const n=[];for(const o of e)o.kind==="capture"&&(o.config.captureType===void 0&&n.push(new I),o.config.captureType===d.selfie&&n.push(...V(o.config.selfieConfig)),o.config.captureType===d.document&&n.push(...x(o.config.documentConfig)));return n}function y(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));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||w(r)===g.unknown;return o&&!e.ml&&f&&n.push(new k),i&&!e.network&&n.push(new b),i&&f&&n.push(new P),n.push(...y(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)),T(e,n),n}export function runEnhancedKYCParamsValidation(e,n){return h(e,n)}export function runBiometricKYCParamsValidation(e,n){return h(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 h(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 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 +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/builder/screens_builder";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}!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 f(o,e){const n=new Map;let r=0;o.forEach((t,c)=>{if(t.kind==="capture"){r++;return}if(t.kind==="preview")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){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 w(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 S(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),w(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),S(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),w(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),S(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");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 k=new DefaultStructuralValidator;export function resolveJobTypeValidator(o){return o===void 0||o===i.unknown?k:jobTypeValidators.get(o)??k}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 h}from"../../../core/models/params";import{JobType as i}from"../../../core/models/job_type";import{CaptureType as y}from"../dsl/builder/screens_builder";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}!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 w(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 k(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),w(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),k(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),w(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),k(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}"`})}
@@ -0,0 +1,10 @@
1
+ import { InvalidPartnerScreenException } from "../../../core/exception/invalid_partner_screen_exception";
2
+ import type { ScreenSpec } from "../dsl/builder/screens_builder";
3
+ /**
4
+ * The partner screens' own rules, as the Android and iOS SDKs check them: a
5
+ * non-blank id, used once, and never between a capture and its preview. The
6
+ * flow's graph keeps a document capture and its preview together to capture
7
+ * the back or visa, and a preview's Retake goes back one screen, to the
8
+ * capture it previews.
9
+ */
10
+ export declare function partnerScreenIssues(steps: readonly ScreenSpec[]): InvalidPartnerScreenException[];
@@ -0,0 +1 @@
1
+ "use strict";import{InvalidPartnerScreenException as a}from"../../../core/exception/invalid_partner_screen_exception";export function partnerScreenIssues(i){const r=[],o=i.flatMap(n=>n.kind==="partner"?[n.config.id]:[]);o.some(n=>n.trim()==="")&&r.push(new a("a partner screen has a blank id"));const c=new Set,d=new Set;for(const n of o.filter(t=>t.trim()!==""))c.has(n)&&d.add(n),c.add(n);for(const n of d)r.push(new a(`the id "${n}" names more than one partner screen`));let e=0;for(;e<i.length;){if(i[e]?.kind!=="partner"){e++;continue}const n=e;for(;i[e]?.kind==="partner";)e++;if(i[n-1]?.kind==="capture"&&i[e]?.kind==="preview")for(const t of i.slice(n,e))t.kind==="partner"&&r.push(new a(`"${t.config.id}" sits between a capture and its preview`))}return r}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smileid/usesmileid",
3
- "version": "12.3.0",
3
+ "version": "12.3.1-SNAPSHOT.49",
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": {
@@ -49,10 +49,11 @@
49
49
  ],
50
50
  "dependencies": {
51
51
  "@smileid/kamera": "1.2.0",
52
+ "@smileid/njia": "0.0.1-SNAPSHOT.3",
52
53
  "axios": "^1.20.0",
53
54
  "zod": "^4.6.5",
54
- "@smileid/usesmileid_bridge": "12.3.0",
55
- "@smileid/usesmileid_platform_interface": "12.3.0"
55
+ "@smileid/usesmileid_bridge": "12.3.1-SNAPSHOT.49",
56
+ "@smileid/usesmileid_platform_interface": "12.3.1-SNAPSHOT.49"
56
57
  },
57
58
  "peerDependencies": {
58
59
  "@react-native-async-storage/async-storage": ">=1.21.0",
@@ -106,6 +107,7 @@
106
107
  },
107
108
  "devDependencies": {
108
109
  "@smileid/kamera-testing": "1.2.0",
110
+ "@smileid/njia-testing": "0.0.1-SNAPSHOT.3",
109
111
  "@types/react": "^19.2.18",
110
112
  "expo": "~57.0.26",
111
113
  "expo-brightness": "~57.0.2",