@smileid/usesmileid 12.1.0 → 12.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/README.md +28 -17
- package/dist/camera/document_image_pipeline.d.ts +1 -1
- package/dist/camera/document_image_pipeline.js +1 -1
- package/dist/camera/use_smile_id_frame_stream.js +1 -1
- package/dist/camera/use_smile_id_kamera_camera_system.d.ts +6 -0
- package/dist/camera/use_smile_id_kamera_camera_system.js +1 -1
- package/dist/core/exception/invalid_job_type_screen_config_exception.js +1 -1
- package/dist/core/exception/missing_partner_config_exception.d.ts +2 -0
- package/dist/core/exception/missing_partner_config_exception.js +1 -1
- package/dist/core/exception/unused_job_params_exception.js +1 -1
- package/dist/core/exception/use_smile_id_error_code.d.ts +1 -0
- package/dist/core/exception/use_smile_id_error_code.js +1 -1
- package/dist/core/exception/use_smile_id_network_exception.d.ts +2 -1
- package/dist/core/exception/use_smile_id_network_exception.js +1 -1
- package/dist/core/models/document_type.d.ts +1 -1
- package/dist/core/models/job_type.d.ts +5 -0
- package/dist/core/models/job_type.js +1 -1
- package/dist/core/models/network_config.d.ts +2 -3
- package/dist/core/models/params.d.ts +18 -0
- package/dist/core/models/params.js +1 -1
- package/dist/data/api/interceptors/smile_auth_interceptor.js +1 -1
- package/dist/data/api/smile_id_api.d.ts +6 -12
- package/dist/data/api/smile_id_api.js +1 -1
- package/dist/data/compression/compressible_asset.d.ts +9 -1
- package/dist/data/compression/compressible_asset.js +1 -1
- package/dist/data/compression/payload_compression_runner.d.ts +3 -0
- package/dist/data/compression/payload_compression_runner.js +1 -1
- package/dist/data/compression/payload_compressor.js +1 -1
- package/dist/data/factory/networking_factory.d.ts +2 -0
- package/dist/data/factory/networking_factory.js +1 -1
- package/dist/data/model/job_request.d.ts +20 -1
- package/dist/data/model/token_payload.d.ts +17 -1
- package/dist/data/model/token_payload.js +1 -1
- package/dist/data/repository/use_smile_id_repository_impl.js +1 -1
- package/dist/debug/capture_debug_geometry.d.ts +29 -0
- package/dist/debug/capture_debug_geometry.js +1 -0
- package/dist/debug/document_preview_debug_geometry.d.ts +36 -0
- package/dist/debug/document_preview_debug_geometry.js +1 -0
- package/dist/debug/preview_debug_drawing.d.ts +51 -0
- package/dist/debug/preview_debug_drawing.js +1 -0
- package/dist/debug/selfie_preview_debug_geometry.d.ts +55 -0
- package/dist/debug/selfie_preview_debug_geometry.js +1 -0
- package/dist/debug/use_smile_id_debug.d.ts +61 -0
- package/dist/debug/use_smile_id_debug.js +1 -0
- package/dist/debug/use_smile_id_debug_tap.d.ts +25 -0
- package/dist/debug/use_smile_id_debug_tap.js +1 -0
- package/dist/debug/use_smile_id_document_capture_debug_overlay.d.ts +56 -0
- package/dist/debug/use_smile_id_document_capture_debug_overlay.js +1 -0
- package/dist/debug/use_smile_id_document_preview_debug_overlay.d.ts +32 -0
- package/dist/debug/use_smile_id_document_preview_debug_overlay.js +1 -0
- package/dist/debug/use_smile_id_selfie_capture_debug_overlay.d.ts +27 -0
- package/dist/debug/use_smile_id_selfie_capture_debug_overlay.js +1 -0
- package/dist/debug/use_smile_id_selfie_preview_debug_overlay.d.ts +60 -0
- package/dist/debug/use_smile_id_selfie_preview_debug_overlay.js +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +1 -1
- package/dist/l10n/strings_en.d.ts +2 -1
- package/dist/l10n/strings_en.js +2 -2
- package/dist/l10n/use_smile_id_localizations.d.ts +1 -0
- package/dist/l10n/use_smile_id_localizations.js +1 -1
- package/dist/metadata/document_image_origin.d.ts +1 -0
- package/dist/metadata/document_image_origin.js +1 -1
- package/dist/metadata/metadata_configuration_mappers.js +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.d.ts +4 -4
- package/dist/metadata/use_smile_id_metadata_factory.js +1 -1
- package/dist/presentation/assets/si_document_visa_hero_animation.json +1 -0
- package/dist/presentation/components/helpers/document_interior_crop.d.ts +54 -0
- package/dist/presentation/components/helpers/document_interior_crop.js +1 -0
- package/dist/presentation/components/helpers/selfie_interior_crop.d.ts +60 -0
- package/dist/presentation/components/helpers/selfie_interior_crop.js +1 -0
- package/dist/presentation/components/use_smile_id_capture_content.d.ts +7 -1
- package/dist/presentation/components/use_smile_id_capture_content.js +1 -1
- package/dist/presentation/components/use_smile_id_captured_document_image.d.ts +16 -0
- package/dist/presentation/components/use_smile_id_captured_document_image.js +1 -1
- package/dist/presentation/components/use_smile_id_captured_image_oval.d.ts +12 -4
- package/dist/presentation/components/use_smile_id_captured_image_oval.js +1 -1
- package/dist/presentation/components/use_smile_id_document_overlay.d.ts +12 -1
- package/dist/presentation/components/use_smile_id_document_overlay.js +1 -1
- package/dist/presentation/components/use_smile_id_document_shimmer.d.ts +10 -5
- package/dist/presentation/components/use_smile_id_document_shimmer.js +1 -1
- package/dist/presentation/flow/analytics/use_smile_id_analytics_event.d.ts +4 -1
- package/dist/presentation/flow/analytics/use_smile_id_analytics_event.js +1 -1
- package/dist/presentation/flow/analytics/use_smile_id_analytics_event_kind.d.ts +89 -0
- package/dist/presentation/flow/analytics/use_smile_id_analytics_event_kind.js +1 -0
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +4 -2
- package/dist/presentation/flow/dsl/builder/screens_builder.js +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts +17 -13
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +1 -1
- package/dist/presentation/flow/flow_navigation_manager.d.ts +52 -6
- package/dist/presentation/flow/flow_navigation_manager.js +1 -1
- package/dist/presentation/flow/model/instructions_defaults.d.ts +1 -0
- package/dist/presentation/flow/model/instructions_defaults.js +1 -1
- package/dist/presentation/flow/screen/helpers/always_enabled_slot.d.ts +8 -0
- package/dist/presentation/flow/screen/helpers/always_enabled_slot.js +1 -0
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js +1 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.js +1 -1
- package/dist/presentation/flow/screen/orchestrated_instructions_screen.js +1 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js +1 -1
- package/dist/presentation/flow/validation/flow_validator.d.ts +13 -12
- package/dist/presentation/flow/validation/flow_validator.js +1 -1
- package/dist/presentation/flow/validation/job_type_validator.d.ts +9 -1
- package/dist/presentation/flow/validation/job_type_validator.js +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +6 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_document_back_instructions.js +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts +5 -0
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.d.ts +5 -0
- package/dist/presentation/screen/use_smile_id_processing_screen.js +1 -1
- package/package.json +15 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
Full release notes: [Smile ID docs](https://docs.usesmileid.com/developer-resources/sdks/mobile/release-notes/react-native-expo).
|
|
2
2
|
|
|
3
|
+
## 12.2.0
|
|
4
|
+
|
|
5
|
+
See the repository CHANGELOG for the 12.2.0 release notes.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## 12.1.1
|
|
9
|
+
|
|
10
|
+
See the repository CHANGELOG for the 12.1.1 release notes.
|
|
11
|
+
|
|
3
12
|
## 12.1.0
|
|
4
13
|
|
|
5
14
|
See the repository CHANGELOG for the 12.1.0 release notes.
|
|
6
15
|
|
|
7
|
-
|
|
8
16
|
## 12.0.2
|
|
9
17
|
|
|
10
18
|
See the repository CHANGELOG for the 12.0.2 release notes.
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Sizes are measured on every push to `main` and updated automatically by CI.
|
|
|
32
32
|
- Xcode (latest stable) — iOS 16.4 deployment target (set by Expo SDK 56's modules; the Smile ID iOS SDK itself supports iOS 15)
|
|
33
33
|
- Android Gradle Plugin 8.11.1+ — `compileSdk` 36 or newer (React Native's default; nothing to set) and `minSdk` 24, matching the native Smile ID SDK and the kamera engine. The ML Kit config plugins set the Kotlin and KSP versions the AARs were compiled with. The 12.0.0–12.0.2 AARs required compileSdk 37 and `minSdk` 26 instead; on those releases, install platform 37 before Gradle runs (on EAS, an `eas-build-pre-install` script: `yes | sdkmanager --licenses >/dev/null; sdkmanager "platforms;android-37.0"`).
|
|
34
34
|
|
|
35
|
-
`12.
|
|
35
|
+
`12.2.0` is built and verified against Expo SDK 57 and React Native 0.86. The floors above are the supported minimum and keep working.
|
|
36
36
|
|
|
37
37
|
## Installation
|
|
38
38
|
|
|
@@ -143,7 +143,7 @@ export default function VerificationScreen() {
|
|
|
143
143
|
|
|
144
144
|
## Full Builder Reference
|
|
145
145
|
|
|
146
|
-
`useSmileIDBuilder` takes a callback that receives a mutable builder. Top-level mutable properties (`consentInformation`, `enhancedKYCParams`, `biometricKYCParams`, `documentVerificationParams`, `enhancedDocumentVerificationParams`, `userDetails`, `localizations`, `onResult`, `onAnalyticsEvent`) are property-assigned. Nested blocks (`config`, `theme`, `network`, `ml`, `screens`) take closures.
|
|
146
|
+
`useSmileIDBuilder` takes a callback that receives a mutable builder. Top-level mutable properties (`consentInformation`, `enhancedKYCParams`, `biometricKYCParams`, `documentVerificationParams`, `enhancedDocumentVerificationParams`, `residencyDocumentVerificationParams`, `userDetails`, `localizations`, `onResult`, `onAnalyticsEvent`) are property-assigned. Nested blocks (`config`, `theme`, `network`, `ml`, `screens`) take closures.
|
|
147
147
|
|
|
148
148
|
The server issues `userId` and `jobId` and returns them in the submission response — partners receive both via `onResult`. Don't construct them client-side.
|
|
149
149
|
|
|
@@ -246,7 +246,7 @@ b.network((n) => {
|
|
|
246
246
|
c.onTokenExpired = async (previous) => fetchFreshToken();
|
|
247
247
|
c.partnerConfig((p) => {
|
|
248
248
|
p.partnerId = "your-partner-id";
|
|
249
|
-
p.callbackUrl = "https://
|
|
249
|
+
p.callbackUrl = "https://your-registered-domain/webhook";
|
|
250
250
|
p.useSandbox = false;
|
|
251
251
|
});
|
|
252
252
|
c.logging((l) => {
|
|
@@ -286,12 +286,12 @@ b.network((n) => {
|
|
|
286
286
|
|
|
287
287
|
#### `partnerConfig` block
|
|
288
288
|
|
|
289
|
-
| Property | Type | Default | Description
|
|
290
|
-
| --------------- | ------------------------- | ----------- |
|
|
291
|
-
| `partnerId` | `string` | `""` | Your Smile ID partner ID
|
|
292
|
-
| `callbackUrl` | `string` | `""` | Webhook URL for job results
|
|
293
|
-
| `useSandbox` | `boolean` | `false` | Route requests to the sandbox environment
|
|
294
|
-
| `partnerParams` | `Record<string, string>?` | `undefined` | Optional partner-defined key/value pairs forwarded as the `partner_params` JSON multipart part on Enhanced/Biometric KYC submissions
|
|
289
|
+
| Property | Type | Default | Description |
|
|
290
|
+
| --------------- | ------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
291
|
+
| `partnerId` | `string` | `""` | Your Smile ID partner ID |
|
|
292
|
+
| `callbackUrl` | `string` | `""` | Webhook URL for job results. Sent on every product when non-empty; blank omits it and the job uses the account's default for that environment |
|
|
293
|
+
| `useSandbox` | `boolean` | `false` | Route requests to the sandbox environment |
|
|
294
|
+
| `partnerParams` | `Record<string, string>?` | `undefined` | Optional partner-defined key/value pairs forwarded as the `partner_params` JSON multipart part on Enhanced/Biometric KYC submissions |
|
|
295
295
|
|
|
296
296
|
#### `logging` block
|
|
297
297
|
|
|
@@ -469,12 +469,13 @@ Calling `useFlowNavigation()` outside `<UseSmileIDBuilder>` throws — the misus
|
|
|
469
469
|
|
|
470
470
|
Each job type that needs identity fields reads them from a top-level builder property. The shared `user_details` part (`b.userDetails`) is required by every KYC and document job; `country` is the ISO 3166-1 alpha-2 code.
|
|
471
471
|
|
|
472
|
-
| Job type
|
|
473
|
-
|
|
|
474
|
-
| `JobType.enhancedKyc`
|
|
475
|
-
| `JobType.biometricKyc`
|
|
476
|
-
| `JobType.documentVerification`
|
|
477
|
-
| `JobType.enhancedDocumentVerification`
|
|
472
|
+
| Job type | Builder property | Required fields | Notes |
|
|
473
|
+
| --------------------------------------- | --------------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
474
|
+
| `JobType.enhancedKyc` | `b.enhancedKYCParams` | `idType`, `idNumber`, `country` | Optional `bankCode`, `mobileOperator` |
|
|
475
|
+
| `JobType.biometricKyc` | `b.biometricKYCParams` | `idType`, `idNumber`, `country` | `useEnrolledImage` toggles the enrolled-image path |
|
|
476
|
+
| `JobType.documentVerification` | `b.documentVerificationParams` | `country` | `idType` **optional** — omit it to let the backend classify the document |
|
|
477
|
+
| `JobType.enhancedDocumentVerification` | `b.enhancedDocumentVerificationParams` | `country`, `idType` | `idType` **required** — drives the ID-authority cross-check |
|
|
478
|
+
| `JobType.residencyDocumentVerification` | `b.residencyDocumentVerificationParams` | `country`, `idType` | `idType` must be `"PASSPORT"` (exported as `RESIDENCY_ID_TYPE`); passport data page plus a mandatory visa page from one document capture step; the step must use `DocumentType.Passport`, and `allowSkipBack` is rejected |
|
|
478
479
|
|
|
479
480
|
```ts
|
|
480
481
|
// Document Verification — idType optional
|
|
@@ -492,8 +493,18 @@ b.userDetails = {
|
|
|
492
493
|
lastName: "Doe",
|
|
493
494
|
phoneNumber: "+254700000000",
|
|
494
495
|
};
|
|
496
|
+
|
|
497
|
+
// Residency Document Verification — passport data page, then a mandatory visa page
|
|
498
|
+
b.residencyDocumentVerificationParams = { country: "AE", idType: "PASSPORT" };
|
|
499
|
+
b.userDetails = {
|
|
500
|
+
givenNames: "Jane",
|
|
501
|
+
lastName: "Doe",
|
|
502
|
+
email: "jane@example.com",
|
|
503
|
+
};
|
|
495
504
|
```
|
|
496
505
|
|
|
506
|
+
`DocumentSide` (exported from `@smileid/usesmileid`) gains `Visa` (`"visa"`) for the residency visa page, so an exhaustive `switch` over it needs the new case.
|
|
507
|
+
|
|
497
508
|
`user_details` requires non-blank `givenNames` and `lastName` plus at least one of `email` / `phoneNumber`. Pre-flight any payload with `b.validateDocumentVerificationParams(...)`, `b.validateEnhancedDocumentVerificationParams(...)`, or `b.validateUserDetails(...)` before assigning.
|
|
498
509
|
|
|
499
510
|
---
|
|
@@ -576,7 +587,7 @@ Every event automatically includes `session_id` and `timestamp` (epoch milliseco
|
|
|
576
587
|
| `screen_viewed` | Each screen becomes active | `screen_name` |
|
|
577
588
|
| `consent_captured` | User grants consent | `decision: "granted"` |
|
|
578
589
|
| `selfie_captured` | Selfie + liveness captured | `liveness_image_count` |
|
|
579
|
-
| `document_captured` | Document image captured | `document_side: "front"` or `"
|
|
590
|
+
| `document_captured` | Document image captured | `document_side: "front"`, `"back"` or `"visa"`, one event per image |
|
|
580
591
|
| `retake_requested` | User navigates back to redo a step | — |
|
|
581
592
|
| `job_submitted` | API submission begins | `job_type`, `attempt` |
|
|
582
593
|
| `flow_completed` | Flow finishes | `result: "success"` or `"failure"`, `job_id` (success), `error_message` (failure) |
|
|
@@ -690,7 +701,7 @@ export function DocumentVerificationScreen({
|
|
|
690
701
|
c.token = "your-v3-token";
|
|
691
702
|
c.partnerConfig((p) => {
|
|
692
703
|
p.partnerId = "your-partner-id";
|
|
693
|
-
p.callbackUrl = "https://
|
|
704
|
+
p.callbackUrl = "https://your-registered-domain/webhook";
|
|
694
705
|
p.useSandbox = true;
|
|
695
706
|
});
|
|
696
707
|
c.logging((l) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DocumentSide } from "@smileid/usesmileid_bridge";
|
|
2
2
|
export { computeDocumentResizeTarget } from "./document_resize_target";
|
|
3
|
-
/** Canonical per-
|
|
3
|
+
/** Canonical per-image artifact basename, matching the auto-capture naming. */
|
|
4
4
|
export declare function documentArtifactFileName(side: DocumentSide): string;
|
|
5
5
|
/** Source image for an imported document capture (manual shutter or gallery). */
|
|
6
6
|
export type ImportedDocumentSource = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{Directory as
|
|
1
|
+
"use strict";import{Directory as m,File as i,Paths as s}from"expo-file-system";import{ImageManipulator as u,SaveFormat as d}from"expo-image-manipulator";import{DocumentSide as o,UseSmileIDCrashReporting as p}from"@smileid/usesmileid_bridge";import{CameraDefaults as a}from"./camera_defaults";import{computeDocumentResizeTarget as f}from"./document_resize_target";export{computeDocumentResizeTarget}from"./document_resize_target";const l="usesmileid_documents";export function documentArtifactFileName(e){switch(e){case o.Back:return"document_back.jpg";case o.Visa:return"document_visa.jpg";default:return"document_front.jpg"}}export async function resampleImportedDocument(e,n){const t=e.width!==void 0&&e.height!==void 0?f(e.width,e.height,a.documentMaxDimension):null,r=u.manipulate(e.uri);t&&r.resize(t);const c=await(await r.renderAsync()).saveAsync({compress:a.documentJpegQuality,format:d.JPEG});return g(c.uri,n)}function g(e,n){try{const t=new m(s.cache,l);t.exists||t.create({intermediates:!0});const r=new i(t,documentArtifactFileName(n));return r.exists&&r.delete(),new i(e).move(r),r.uri}catch(t){return p.captureException(t instanceof Error?t:new Error(String(t))),e}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{useCallback as
|
|
1
|
+
"use strict";import{useCallback as y,useEffect as l,useMemo as E,useRef as a}from"react";import{documentScanResultSchema as S,faceScanResultSchema as h,FrameProcessingException as B}from"@smileid/usesmileid_bridge";import{isDevBuild as R}from"../debug/use_smile_id_debug";import{UseSmileIDDebugTap as d}from"../debug/use_smile_id_debug_tap";export function useSmileIDFrameStream(e,r,u){const i=a(e),s=a(r),o=a(u?.onError),c=a(!1),f=a(!0);l(()=>{i.current=e},[e]),l(()=>{s.current=r},[r]),l(()=>{o.current=u?.onError},[u?.onError]),l(()=>(f.current=!0,()=>{f.current=!1}),[]);const n=y(t=>{const m=o.current;dispatchFrameResult({raw:t,analyzer:i.current,isBusy:()=>c.current,setBusy:p=>{c.current=p},isMounted:()=>f.current,onResult:s.current,...m!==void 0?{onError:m}:{}})},[]);return E(()=>({onFrameResult:n}),[n])}function D(e){if(e===null||typeof e!="object")return null;const r=e.error;return typeof r=="string"?r:null}const _=new Set(["no_frame","session_not_configured"]);export function dispatchFrameResult(e){const{raw:r,analyzer:u,isBusy:i,setBusy:s,isMounted:o,onResult:c,onError:f}=e;if(u&&!i()){s(!0);try{const n=D(r);if(n!==null){if(_.has(n))return;throw new B({reason:n})}if(u.kind==="face"){const t=h.parse(r);if(!o())return;c(t),R()&&d.analyzedFace(t.output)}else{const t=S.parse(r);if(!o())return;c(t),R()&&d.analyzedDocument(t.output)}}catch(n){if(!o())return;f?.(n)}finally{s(!1)}}}
|
|
@@ -28,6 +28,12 @@ export declare class UseSmileIDKameraCameraSystem {
|
|
|
28
28
|
get focusState(): FocusState;
|
|
29
29
|
/** Device/session capabilities, available once running. */
|
|
30
30
|
get capabilities(): KameraCapabilities | null;
|
|
31
|
+
/**
|
|
32
|
+
* The upright preview's width over its height on a portrait screen: the configured session's
|
|
33
|
+
* preview ratio with its short side across. kamera binds the analysis stream to the same ratio,
|
|
34
|
+
* so it is also the analysed frame's.
|
|
35
|
+
*/
|
|
36
|
+
get uprightPreviewAspect(): number;
|
|
31
37
|
/**
|
|
32
38
|
* The active session, for `UseSmileIDKameraPreview` only — drive it through this class's API.
|
|
33
39
|
* Null until `start()` succeeds.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{KameraSession as
|
|
1
|
+
"use strict";import{AspectRatio as _,KameraSession as h}from"@smileid/kamera";import{CaptureType as r}from"../core/models/ml_config";import{CameraDefaults as c}from"./camera_defaults";import{CameraLens as o}from"./camera_lens";import{FocusStates as i}from"./focus_state";import{KameraConfigFactory as u}from"./kamera_config_factory";export class UseSmileIDKameraCameraSystem{_createSession;_session=null;_removeEventListener=null;_state;_focusState=i.unspecified();_listeners=new Set;_eventListeners=new Set;_capabilities=null;_config={};_released=!1;_focusRunningTimeout=null;_focusSettledTimeout=null;constructor(e=o.front,t=()=>new h){this._createSession=t,this._state={isCameraRunning:!1,isStreaming:!1,currentLens:e,hasPermission:!1}}get state(){return this._state}get focusState(){return this._focusState}get capabilities(){return this._capabilities}get uprightPreviewAspect(){const e=this._config.captureType??r.selfie;return u.create(e,this._state.currentLens).preview.aspectRatio===_.Ratio16x9?9/16:3/4}get session(){return this._session}subscribe(e){return this._listeners.add(e),()=>this._listeners.delete(e)}addEventListener(e){return this._eventListeners.add(e),()=>this._eventListeners.delete(e)}configure(e){this._config=e,e.lens&&e.lens!==this._state.currentLens&&this._setState({...this._state,currentLens:e.lens})}async start(){if(this._released)throw new Error("UseSmileIDKameraCameraSystem.start() after release() \u2014 create a new system.");await this._teardownSession();const e=this._createSession(),t=e.addEventListener(n=>this._onKameraEvent(n)),s=this._config.captureType??r.selfie,a=this._config.lens??(s===r.document?o.back:o.front);try{await e.start(u.create(s,a)),this._capabilities=await e.capabilities()}catch(n){throw t(),await e.release(),n}this._removeEventListener=t,this._session=e,this._setState({...this._state,isCameraRunning:!0,isStreaming:!0,currentLens:a,hasPermission:!0})}async stop(){await this._session?.stop(),this._setState({...this._state,isCameraRunning:!1,isStreaming:!1})}async capture(){const e=this._session;if(!e)throw new Error("Cannot capture: camera is not initialised.");return e.capture()}async setZoomRatio(e){const t=this._session;if(!t)return;const s=this._capabilities,a=s?Math.min(s.maxZoomRatio,Math.max(s.minZoomRatio,e)):e;await t.setZoomRatio(a)}async setTorch(e){await this._session?.setTorch(e)}async tapToFocus(e){const t=this._session;t&&(this._clearFocusTimers(),this._setFocusState(i.running(e)),t.tapToFocus(e.x,e.y).catch(()=>{this._clearFocusTimers(),this._setFocusState(i.unspecified())}),this._focusRunningTimeout=setTimeout(()=>{this._setFocusState(i.success(e)),this._focusSettledTimeout=setTimeout(()=>{this._setFocusState(i.unspecified())},c.focusSettledDurationMs)},c.focusRunningDurationMs))}async release(){this._released=!0,this._clearFocusTimers(),await this._teardownSession(),this._setState({...this._state,isCameraRunning:!1,isStreaming:!1})}_onKameraEvent(e){for(const t of[...this._eventListeners])t(e);e.type==="error"&&this._setState({...this._state,isStreaming:!1})}async _teardownSession(){this._removeEventListener?.(),this._removeEventListener=null;const e=this._session;this._session=null,this._capabilities=null,e&&await e.release()}_clearFocusTimers(){this._focusRunningTimeout&&clearTimeout(this._focusRunningTimeout),this._focusSettledTimeout&&clearTimeout(this._focusSettledTimeout),this._focusRunningTimeout=null,this._focusSettledTimeout=null}_setState(e){this._state=e,this._notify()}_setFocusState(e){this._focusState=e,this._notify()}_notify(){for(const e of[...this._listeners])e(this._state,this._focusState)}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{JobType as e}from"../../core/models/job_type";import{UseSmileIDBuilderException as i}from"./use_smile_id_builder_exception";import{UseSmileIDErrorCode as r}from"./use_smile_id_error_code";export class InvalidJobTypeScreenConfigException extends i{errorCode=r.Builder.InvalidJobTypeScreenConfig;constructor(n){super({message:n.message,suggestedFix:n.suggestedFix??"Adjust the screens block to match the configured jobType."})}static forJob(n){const t=jobTypeName(n.jobType);return new InvalidJobTypeScreenConfigException({message:`Invalid configuration for ${t}: ${n.reason}`,suggestedFix:n.suggestedFix})}}const c=new Map([[e.biometricKyc,"BiometricKyc"],[e.smartSelfieAuthentication,"SmartSelfieAuthentication"],[e.smartSelfieEnrollment,"SmartSelfieEnrollment"],[e.enhancedKyc,"EnhancedKyc"],[e.documentVerification,"DocumentVerification"],[e.bvn,"BVN"],[e.enhancedDocumentVerification,"EnhancedDocumentVerification"],[e.unknown,"Unknown"]]);export function jobTypeName(o){return c.get(o)??"Unknown"}
|
|
1
|
+
"use strict";import{JobType as e}from"../../core/models/job_type";import{UseSmileIDBuilderException as i}from"./use_smile_id_builder_exception";import{UseSmileIDErrorCode as r}from"./use_smile_id_error_code";export class InvalidJobTypeScreenConfigException extends i{errorCode=r.Builder.InvalidJobTypeScreenConfig;constructor(n){super({message:n.message,suggestedFix:n.suggestedFix??"Adjust the screens block to match the configured jobType."})}static forJob(n){const t=jobTypeName(n.jobType);return new InvalidJobTypeScreenConfigException({message:`Invalid configuration for ${t}: ${n.reason}`,suggestedFix:n.suggestedFix})}}const c=new Map([[e.biometricKyc,"BiometricKyc"],[e.smartSelfieAuthentication,"SmartSelfieAuthentication"],[e.smartSelfieEnrollment,"SmartSelfieEnrollment"],[e.enhancedKyc,"EnhancedKyc"],[e.documentVerification,"DocumentVerification"],[e.bvn,"BVN"],[e.enhancedDocumentVerification,"EnhancedDocumentVerification"],[e.residencyDocumentVerification,"ResidencyDocumentVerification"],[e.unknown,"Unknown"]]);export function jobTypeName(o){return c.get(o)??"Unknown"}
|
|
@@ -18,4 +18,6 @@ export declare class MissingPartnerConfigException extends UseSmileIDBuilderExce
|
|
|
18
18
|
static controlCharacterPartnerId(): MissingPartnerConfigException;
|
|
19
19
|
/** The auth `token` contains a control character (usually a pasted newline). */
|
|
20
20
|
static controlCharacterAuthToken(): MissingPartnerConfigException;
|
|
21
|
+
/** The `callbackUrl` is a value the server could not resolve. */
|
|
22
|
+
static unresolvableCallbackUrl(): MissingPartnerConfigException;
|
|
21
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{UseSmileIDBuilderException as
|
|
1
|
+
"use strict";import{UseSmileIDBuilderException as t}from"./use_smile_id_builder_exception";import{UseSmileIDErrorCode as r}from"./use_smile_id_error_code";export class MissingPartnerConfigException extends t{errorCode=r.Builder.InvalidConfiguration;constructor(e){super({message:e.message,suggestedFix:`Configure the missing field '${e.fieldName}' in the network config block.`,errorDetails:{fieldName:e.fieldName}})}static missingPartnerId(){return new MissingPartnerConfigException({message:"Partner ID is required but was not configured",fieldName:"partnerId"})}static missingAuthToken(){return new MissingPartnerConfigException({message:"Auth token is required but was not configured",fieldName:"authToken"})}static controlCharacterPartnerId(){return new MissingPartnerConfigException({message:"Partner ID must not contain control characters",fieldName:"partnerId"})}static controlCharacterAuthToken(){return new MissingPartnerConfigException({message:"Auth token must not contain control characters",fieldName:"authToken"})}static unresolvableCallbackUrl(){return new MissingPartnerConfigException({message:"Callback URL must be left unset, an absolute http or https URL, or a callback ID",fieldName:"callbackUrl"})}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{JobType as
|
|
1
|
+
"use strict";import{JobType as i}from"../../core/models/job_type";import{jobTypeName as n}from"./invalid_job_type_screen_config_exception";import{IssueSeverity as t}from"./issue_severity";import{UseSmileIDBuilderException as a}from"./use_smile_id_builder_exception";import{UseSmileIDErrorCode as d}from"./use_smile_id_error_code";export const JOB_PARAMS_OWNERS=[{fieldName:"enhancedKYCParams",owner:i.enhancedKyc},{fieldName:"biometricKYCParams",owner:i.biometricKyc},{fieldName:"documentVerificationParams",owner:i.documentVerification},{fieldName:"enhancedDocumentVerificationParams",owner:i.enhancedDocumentVerification},{fieldName:"residencyDocumentVerificationParams",owner:i.residencyDocumentVerification}];function c(o){return JOB_PARAMS_OWNERS.find(e=>e.fieldName===o)?.owner}export class UnusedJobParamsException extends a{errorCode=d.Builder.UnusedJobParams;fieldName;constructor(e){const r=c(e.fieldName),m=r===void 0?`Remove builder.${e.fieldName} \u2014 the configured job type does not read it`:`Remove builder.${e.fieldName} \u2014 it belongs to ${n(r)} jobs`;super({message:`${e.fieldName} is set but ${n(e.jobType)} jobs never read it`,severity:t.warning,suggestedFix:m}),this.fieldName=e.fieldName}}
|
|
@@ -56,6 +56,7 @@ export declare const UseSmileIDErrorCode: {
|
|
|
56
56
|
readonly NotFound: "NETWORK_NOT_FOUND";
|
|
57
57
|
readonly RateLimit: "NETWORK_RATE_LIMIT";
|
|
58
58
|
readonly ServerError: "NETWORK_SERVER_ERROR";
|
|
59
|
+
readonly CallbackUrlRequired: "NETWORK_CALLBACK_URL_REQUIRED";
|
|
59
60
|
};
|
|
60
61
|
/** Generic input / state validation. */
|
|
61
62
|
readonly Validation: {
|
|
@@ -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"},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.RequestFailed,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"},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.RequestFailed,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)}
|
|
@@ -34,11 +34,12 @@ export declare abstract class UseSmileIDNetworkException extends UseSmileIDExcep
|
|
|
34
34
|
export declare class NetworkServerException extends UseSmileIDNetworkException {
|
|
35
35
|
readonly errorCode: NetworkCode;
|
|
36
36
|
readonly statusCode: number;
|
|
37
|
-
constructor({ statusCode, cause, message, errorDetails, }: {
|
|
37
|
+
constructor({ statusCode, cause, message, errorDetails, errorCode, }: {
|
|
38
38
|
readonly statusCode: number;
|
|
39
39
|
readonly cause?: unknown;
|
|
40
40
|
readonly message?: string;
|
|
41
41
|
readonly errorDetails?: Readonly<Record<string, unknown>>;
|
|
42
|
+
readonly errorCode?: NetworkCode;
|
|
42
43
|
});
|
|
43
44
|
}
|
|
44
45
|
/** Network reachability / DNS / TLS / socket failure — never reached the server. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{isAxiosError as
|
|
1
|
+
"use strict";import{isAxiosError as a}from"axios";import{UseSmileIDErrorCode as r}from"./use_smile_id_error_code";import{UseSmileIDException as c}from"./use_smile_id_exception";export class UseSmileIDNetworkException extends c{}export class NetworkServerException extends UseSmileIDNetworkException{errorCode;statusCode;constructor({statusCode:t,cause:s,message:o,errorDetails:n,errorCode:i}){super({message:o??`HTTP ${t}`,suggestedFix:"Inspect the server response body and retry if the failure is transient.",cause:s,errorDetails:n}),this.statusCode=t,this.errorCode=i??u(t)}}export class NetworkTransportException extends UseSmileIDNetworkException{errorCode=r.Network.ConnectionFailed;constructor({cause:t,message:s="Network transport failure.",errorDetails:o}={}){super({message:s,suggestedFix:"Check the device's network connection and verify the configured base URL is reachable.",cause:t,errorDetails:o})}}export class NetworkTimeoutException extends UseSmileIDNetworkException{errorCode=r.Network.Timeout;constructor({cause:t,message:s="The request timed out.",errorDetails:o}={}){super({message:s,suggestedFix:"Increase the timeout via `n.timeouts(...)` if appropriate, or retry once connectivity recovers.",cause:t,errorDetails:o})}}export class NetworkResponseParseException extends UseSmileIDNetworkException{errorCode=r.Network.ResponseParseError;constructor({cause:t,message:s="Failed to parse response body.",errorDetails:o}={}){super({message:s,suggestedFix:"Confirm the SDK version matches the backend's response schema.",cause:t,errorDetails:o})}}export class NetworkRequestBuildException extends UseSmileIDNetworkException{errorCode=r.Network.RequestFailed;constructor({cause:t,message:s="Failed to build request.",errorDetails:o}={}){super({message:s,suggestedFix:"Verify the request payload satisfies the multipart / URL contract before submission.",cause:t,errorDetails:o})}}export class NetworkUnknownException extends UseSmileIDNetworkException{errorCode=r.Network.RequestFailed;constructor({cause:t,message:s="Unknown network error.",errorDetails:o}={}){super({message:s,suggestedFix:"Log the wrapped `cause` for triage \u2014 anything reaching this branch represents a gap in error mapping.",cause:t,errorDetails:o})}}function u(e){return e===401?r.Network.Unauthorized:e===403?r.Network.Forbidden:e===404?r.Network.NotFound:e===429?r.Network.RateLimit:e>=500&&e<600?r.Network.ServerError:r.Network.RequestFailed}export function mapAxiosError(e){return e instanceof UseSmileIDNetworkException?e:a(e)?d(e):e instanceof Error?new NetworkUnknownException({message:e.message,cause:e}):new NetworkUnknownException({message:String(e),cause:e})}function d(e){if(e.code==="ERR_BAD_OPTION"||e.code==="ERR_BAD_OPTION_VALUE"||e.code==="ERR_INVALID_URL")return new NetworkRequestBuildException({message:e.message,cause:e});if(e.code==="ECONNABORTED")return new NetworkTimeoutException({message:e.message,cause:e});if(!e.response)return new NetworkTransportException({message:e.message,cause:e});const t=e.response.status,s=e.response.data;return new NetworkServerException({statusCode:t,message:s?.message??`HTTP ${t}: ${e.message}`,cause:e,...s?.message?.trim()===p?{errorCode:r.Network.CallbackUrlRequired}:{}})}const p="A valid callback_url is required in the request or a default callback URL must be configured in the portal.";
|
|
@@ -35,7 +35,7 @@ export declare const DocumentType: {
|
|
|
35
35
|
readonly SouthAfricaGreenBook: {
|
|
36
36
|
readonly kind: "southAfricaGreenBook";
|
|
37
37
|
} & DocumentTypeFields;
|
|
38
|
-
/** Passport — landscape data page
|
|
38
|
+
/** Passport — landscape data page. */
|
|
39
39
|
readonly Passport: {
|
|
40
40
|
readonly kind: "passport";
|
|
41
41
|
} & DocumentTypeFields;
|
|
@@ -13,6 +13,11 @@ export declare const JobType: {
|
|
|
13
13
|
readonly documentVerification: 6;
|
|
14
14
|
readonly bvn: 7;
|
|
15
15
|
readonly enhancedDocumentVerification: 11;
|
|
16
|
+
/**
|
|
17
|
+
* Residency Document Verification — a primary passport capture followed by
|
|
18
|
+
* a mandatory supporting visa capture, submitted as one job.
|
|
19
|
+
*/
|
|
20
|
+
readonly residencyDocumentVerification: 16;
|
|
16
21
|
/**
|
|
17
22
|
* Sentinel used when no job type has been configured, or when the
|
|
18
23
|
* server returns a value not recognised by this SDK version. Update
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";export const JobType={biometricKyc:1,smartSelfieAuthentication:2,smartSelfieEnrollment:4,enhancedKyc:5,documentVerification:6,bvn:7,enhancedDocumentVerification:11,unknown:-1};export function jobTypeFromValue(e){return Object.values(JobType).find(n=>n===e)??JobType.unknown}export function requiresSelfie(e){return e===JobType.biometricKyc||e===JobType.smartSelfieAuthentication||e===JobType.smartSelfieEnrollment}export function requiresDocument(e){return e===JobType.biometricKyc||e===JobType.documentVerification||e===JobType.enhancedDocumentVerification}
|
|
1
|
+
"use strict";export const JobType={biometricKyc:1,smartSelfieAuthentication:2,smartSelfieEnrollment:4,enhancedKyc:5,documentVerification:6,bvn:7,enhancedDocumentVerification:11,residencyDocumentVerification:16,unknown:-1};export function jobTypeFromValue(e){return Object.values(JobType).find(n=>n===e)??JobType.unknown}export function requiresSelfie(e){return e===JobType.biometricKyc||e===JobType.smartSelfieAuthentication||e===JobType.smartSelfieEnrollment}export function requiresDocument(e){return e===JobType.biometricKyc||e===JobType.documentVerification||e===JobType.enhancedDocumentVerification||e===JobType.residencyDocumentVerification}
|
|
@@ -42,9 +42,8 @@ export type NetworkLoggingConfig = {
|
|
|
42
42
|
export type PartnerConfig = {
|
|
43
43
|
readonly partnerId: string;
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* multipart form part on Enhanced/Biometric KYC submissions.
|
|
45
|
+
* Sent as the `callback_url` part on every product when non-empty; blank uses
|
|
46
|
+
* the account's default for that environment.
|
|
48
47
|
*/
|
|
49
48
|
readonly callbackUrl: string;
|
|
50
49
|
readonly useSandbox: boolean;
|
|
@@ -89,3 +89,21 @@ export type EnhancedDocumentVerificationParams = {
|
|
|
89
89
|
/** Document type. Required — drives the ID-authority cross-check. */
|
|
90
90
|
readonly idType: string;
|
|
91
91
|
};
|
|
92
|
+
/**
|
|
93
|
+
* The only `idType` `/v3/residency_document_verification` accepts.
|
|
94
|
+
*
|
|
95
|
+
* A South African visa is issued into a passport and nothing else can carry one, so the backend
|
|
96
|
+
* pins the field rather than classifying the document.
|
|
97
|
+
*/
|
|
98
|
+
export declare const RESIDENCY_ID_TYPE = "PASSPORT";
|
|
99
|
+
/**
|
|
100
|
+
* Identity fields for a Residency Document Verification job — a passport data
|
|
101
|
+
* page plus a mandatory visa page. `userDetails` rides on the top-level builder
|
|
102
|
+
* via `b.userDetails = ...`, not on this type.
|
|
103
|
+
*/
|
|
104
|
+
export type ResidencyDocumentVerificationParams = {
|
|
105
|
+
/** ISO 3166-1 alpha-2 country code (e.g. `"AE"`). */
|
|
106
|
+
readonly country: string;
|
|
107
|
+
/** Document type. Required — drives the ID-authority cross-check. */
|
|
108
|
+
readonly idType: string;
|
|
109
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";export
|
|
1
|
+
"use strict";export const RESIDENCY_ID_TYPE="PASSPORT";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{sourceSdkIdentifier as t}from"@smileid/usesmileid_bridge";import{currentRequestTimestamp as s}from"../../security/request_timestamp";const n="12.
|
|
1
|
+
"use strict";import{sourceSdkIdentifier as t}from"@smileid/usesmileid_bridge";import{currentRequestTimestamp as s}from"../../security/request_timestamp";const n="12.2.0";export class SmileAuthInterceptor{_partnerConfig;_tokenHolder;constructor(e){this._partnerConfig=e.partnerConfig,this._tokenHolder=e.tokenHolder}attach(e){return{request:e.interceptors.request.use(async r=>this._onRequest(r))}}async _onRequest(e){return e.headers.set("smileid-token",this._tokenHolder.current),e.headers.set("smileid-source-sdk",t()),e.headers.set("smileid-source-sdk-version",n),e.headers.set("smileid-partner-id",this._partnerConfig.partnerId),e.headers.set("smileid-request-timestamp",s()),e}}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type AxiosInstance } from "axios";
|
|
2
2
|
import type { NetworkConfig, PartnerConfig } from "../../core/models/network_config";
|
|
3
|
-
import type { BiometricKycRequest, DocumentVerificationRequest, EnhancedDocumentVerificationRequest, EnhancedKycRequest, SmartSelfieAuthenticationRequest, SmartSelfieEnrollmentRequest } from "../model/job_request";
|
|
3
|
+
import type { BiometricKycRequest, DocumentVerificationRequest, EnhancedDocumentVerificationRequest, ResidencyDocumentVerificationRequest, EnhancedKycRequest, SmartSelfieAuthenticationRequest, SmartSelfieEnrollmentRequest } from "../model/job_request";
|
|
4
4
|
import { SmileAuthInterceptor } from "./interceptors/smile_auth_interceptor";
|
|
5
5
|
import { attachLoggingInterceptor } from "./interceptors/logging_interceptor";
|
|
6
6
|
import type { JobSubmissionResponse } from "../model/job_submission_response";
|
|
@@ -54,6 +54,7 @@ export declare class SmileIDAPI {
|
|
|
54
54
|
biometricKyc(request: BiometricKycRequest): Promise<JobSubmissionResponse>;
|
|
55
55
|
documentVerification(request: DocumentVerificationRequest): Promise<JobSubmissionResponse>;
|
|
56
56
|
enhancedDocumentVerification(request: EnhancedDocumentVerificationRequest): Promise<JobSubmissionResponse>;
|
|
57
|
+
residencyDocumentVerification(request: ResidencyDocumentVerificationRequest): Promise<JobSubmissionResponse>;
|
|
57
58
|
private _postDocumentVerification;
|
|
58
59
|
/**
|
|
59
60
|
* Build the selfie + liveness portion of a multipart form. No
|
|
@@ -83,20 +84,13 @@ export declare class SmileIDAPI {
|
|
|
83
84
|
* `id_number`, `country`). PII fields move into the `user_details`
|
|
84
85
|
* JSON part; partner-supplied per-job overrides (`callback_url`,
|
|
85
86
|
* `partner_params`, `use_enrolled_image`) are appended by the
|
|
86
|
-
* endpoint-specific path.
|
|
87
|
+
* endpoint-specific path. A blank field is one the token binds:
|
|
88
|
+
* assembly blanked it, so its part is omitted and the server injects it.
|
|
87
89
|
*/
|
|
88
90
|
private _appendIdFields;
|
|
89
91
|
/**
|
|
90
|
-
* Append the partner-config-level `callback_url` + `partner_params`
|
|
91
|
-
*
|
|
92
|
-
* own per-job override path that already prefers `request.params.*`
|
|
93
|
-
* over the partner config and is handled inline; this helper covers
|
|
94
|
-
* the no-per-job-override case for Enhanced KYC.
|
|
95
|
-
*
|
|
96
|
-
* `callback_url` rides as a string part; `partner_params` as a JSON
|
|
97
|
-
* part. The `callback-url` HTTP header (attached by
|
|
98
|
-
* `SmileAuthInterceptor`) is independent and is preserved on every
|
|
99
|
-
* request regardless of this helper.
|
|
92
|
+
* Append the partner-config-level `callback_url` + `partner_params` parts.
|
|
93
|
+
* Called on every product; a blank `callbackUrl` omits its part.
|
|
100
94
|
*/
|
|
101
95
|
private _appendPartnerConfigParts;
|
|
102
96
|
/**
|
|
@@ -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
|
|
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;if(n===void 0)return;const e=g(n);Object.keys(e).length!==0&&c(a,"user_details",e)}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};
|
|
@@ -27,14 +27,22 @@ export declare class CompressibleAssets {
|
|
|
27
27
|
readonly liveness: readonly CompressibleAsset[];
|
|
28
28
|
readonly documentFront: CompressibleAsset | undefined;
|
|
29
29
|
readonly documentBack: CompressibleAsset | undefined;
|
|
30
|
+
/** Supporting visa page; a submission carries a back or a visa image, never both. */
|
|
31
|
+
readonly documentVisa: CompressibleAsset | undefined;
|
|
30
32
|
constructor(args: {
|
|
31
33
|
selfie?: CompressibleAsset | undefined;
|
|
32
34
|
liveness?: readonly CompressibleAsset[] | undefined;
|
|
33
35
|
documentFront?: CompressibleAsset | undefined;
|
|
34
36
|
documentBack?: CompressibleAsset | undefined;
|
|
37
|
+
documentVisa?: CompressibleAsset | undefined;
|
|
35
38
|
});
|
|
36
39
|
/** All present assets, in submission order. */
|
|
37
40
|
all(): CompressibleAsset[];
|
|
38
|
-
/** Combined size of
|
|
41
|
+
/** Combined size of every document image in the submission (0 when none is present). */
|
|
39
42
|
documentCombinedSize(): number;
|
|
43
|
+
/**
|
|
44
|
+
* The submission's secondary document image — the back side or the visa page.
|
|
45
|
+
* Compression reduces it before the primary front page.
|
|
46
|
+
*/
|
|
47
|
+
get documentSupporting(): CompressibleAsset | undefined;
|
|
40
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";export class CompressibleAssets{selfie;liveness;documentFront;documentBack;constructor(e){this.selfie=e.selfie,this.liveness=e.liveness??[],this.documentFront=e.documentFront,this.documentBack=e.documentBack}all(){const e=[];return this.selfie&&e.push(this.selfie),e.push(...this.liveness),this.documentFront&&e.push(this.documentFront),this.documentBack&&e.push(this.documentBack),e}documentCombinedSize(){return(this.documentFront?.encodedSize()??0)+(this.documentBack?.encodedSize()??0)}}
|
|
1
|
+
"use strict";export class CompressibleAssets{selfie;liveness;documentFront;documentBack;documentVisa;constructor(e){this.selfie=e.selfie,this.liveness=e.liveness??[],this.documentFront=e.documentFront,this.documentBack=e.documentBack,this.documentVisa=e.documentVisa}all(){const e=[];return this.selfie&&e.push(this.selfie),e.push(...this.liveness),this.documentFront&&e.push(this.documentFront),this.documentBack&&e.push(this.documentBack),this.documentVisa&&e.push(this.documentVisa),e}documentCombinedSize(){return(this.documentFront?.encodedSize()??0)+(this.documentBack?.encodedSize()??0)+(this.documentVisa?.encodedSize()??0)}get documentSupporting(){return this.documentBack??this.documentVisa}}
|
|
@@ -17,6 +17,8 @@ export interface PayloadCompressionSizes {
|
|
|
17
17
|
readonly frontFinalMb?: number | undefined;
|
|
18
18
|
readonly backOriginalMb?: number | undefined;
|
|
19
19
|
readonly backFinalMb?: number | undefined;
|
|
20
|
+
readonly visaOriginalMb?: number | undefined;
|
|
21
|
+
readonly visaFinalMb?: number | undefined;
|
|
20
22
|
}
|
|
21
23
|
/**
|
|
22
24
|
* Builds `CompressibleAssets` from a submission's captured JPEG URIs and runs `PayloadCompressor`
|
|
@@ -30,6 +32,7 @@ export declare const PayloadCompressionRunner: {
|
|
|
30
32
|
livenessImages?: readonly string[] | undefined;
|
|
31
33
|
frontDocument?: string | undefined;
|
|
32
34
|
backDocument?: string | undefined;
|
|
35
|
+
visaDocument?: string | undefined;
|
|
33
36
|
metadataBytes: number;
|
|
34
37
|
sdkConfig?: SdkConfig | undefined;
|
|
35
38
|
}): Promise<PayloadCompressionSizes>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{File as
|
|
1
|
+
"use strict";import{File as l}from"expo-file-system";import{ImageType as n}from"@smileid/usesmileid_bridge";import{CameraDefaults as a}from"../../camera/camera_defaults";import{resolveJpegQuality as r}from"../model/sdk_config_capture";import{CompressibleAssets as d}from"./compressible_asset";import{PayloadCompressor as p}from"./payload_compressor";import{UriCompressibleAsset as i}from"./uri_compressible_asset";const b=.95,D=.8;export function resolveCaptureQuality(e,t){const[s,c]=t===n.Selfie?[e?.selfie,b]:t===n.Liveness?[e?.liveness,D]:[e?.document,a.documentJpegQuality],m=r(s);return m===void 0?c:m/100}const v=1024*1024;function o(e){if(e===void 0)return;const t=new l(e).size??0;return t>0?t/v:void 0}export const PayloadCompressionRunner={async compress(e){const t=o(e.selfieImage),s=o(e.frontDocument),c=o(e.backDocument),m=o(e.visaDocument),u=new d({selfie:e.selfieImage?new i(n.Selfie,e.selfieImage,resolveCaptureQuality(e.sdkConfig,n.Selfie)):void 0,liveness:(e.livenessImages??[]).map(f=>new i(n.Liveness,f,resolveCaptureQuality(e.sdkConfig,n.Liveness))),documentFront:e.frontDocument?new i(n.DocumentFront,e.frontDocument,resolveCaptureQuality(e.sdkConfig,n.DocumentFront)):void 0,documentBack:e.backDocument?new i(n.DocumentBack,e.backDocument,resolveCaptureQuality(e.sdkConfig,n.DocumentBack)):void 0,documentVisa:e.visaDocument?new i(n.DocumentVisa,e.visaDocument,resolveCaptureQuality(e.sdkConfig,n.DocumentVisa)):void 0});return await p.prepareBundleForTransmission(u,e.metadataBytes),{selfieOriginalMb:t,selfieFinalMb:o(e.selfieImage),frontOriginalMb:s,frontFinalMb:o(e.frontDocument),backOriginalMb:c,backFinalMb:o(e.backDocument),visaOriginalMb:m,visaFinalMb:o(e.visaDocument)}}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{base64Len as d,PayloadCompressionConfig as i}from"./payload_compression_config";export const PayloadCompressor={rawBundleSize(e
|
|
1
|
+
"use strict";import{base64Len as d,PayloadCompressionConfig as i}from"./payload_compression_config";export const PayloadCompressor={rawBundleSize(o,e){return o.all().reduce((n,r)=>n+r.encodedSize(),0)+e},projectedEncodedSize(o,e){return o.all().reduce((n,r)=>n+d(r.encodedSize()),0)+e+i.structuralOverheadBytes},buildCompressionPlan(o){const e=[],n=o.selfie?.encodedSize()??0,r=o.documentCombinedSize();if(o.selfie&&n>i.selfieTrigger){e.push([o.selfie,i.faceMinQ]);for(const u of o.liveness)e.push([u,i.faceMinQ]);o.documentSupporting&&e.push([o.documentSupporting,i.docMinQ]),o.documentFront&&e.push([o.documentFront,i.docMinQ])}else if(r>i.docCombinedTrigger){o.documentSupporting&&e.push([o.documentSupporting,i.docMinQ]),o.documentFront&&e.push([o.documentFront,i.docMinQ]),o.selfie&&e.push([o.selfie,i.faceMinQ]);for(const u of o.liveness)e.push([u,i.faceMinQ])}else{o.selfie&&e.push([o.selfie,i.faceMinQ]);for(const u of o.liveness)e.push([u,i.faceMinQ]);o.documentSupporting&&e.push([o.documentSupporting,i.docMinQ]),o.documentFront&&e.push([o.documentFront,i.docMinQ])}return e},async prepareBundleForTransmission(o,e){if(!(this.projectedEncodedSize(o,e)<=i.hardEncodedCap&&this.rawBundleSize(o,e)<=i.rawTarget)){if(o.documentCombinedSize()>i.docCombinedTrigger){const n=[o.documentSupporting,o.documentFront].filter(r=>r!==void 0);await this._compressGroupToTarget(n,i.docMinQ,i.docCombinedTarget,()=>o.documentCombinedSize())}for(const[n,r]of this.buildCompressionPlan(o)){for(;this.rawBundleSize(o,e)>i.rawTarget&&n.quality()>r;)await n.recompress(Math.max(r,n.quality()-i.qualityStep));if(this.rawBundleSize(o,e)<=i.rawTarget)return}for(const[n]of this.buildCompressionPlan(o)){for(;this._overRelaxedCap(o,e)&&n.quality()>i.absoluteMinQ;)await n.recompress(Math.max(i.absoluteMinQ,n.quality()-i.qualityStep));if(!this._overRelaxedCap(o,e))return}}},_overRelaxedCap(o,e){return this.rawBundleSize(o,e)>i.rawFallback||this.projectedEncodedSize(o,e)>i.hardEncodedCap},async _compressGroupToTarget(o,e,n,r){for(const u of o){for(;r()>n&&u.quality()>e;)await u.recompress(Math.max(e,u.quality()-i.qualityStep));if(r()<=n)return}}};
|
|
@@ -50,3 +50,5 @@ export declare function makeNetworkingFactory(config: NetworkConfig, signingSecr
|
|
|
50
50
|
readonly client: AxiosInstance;
|
|
51
51
|
readonly metadata: MetadataProvider;
|
|
52
52
|
};
|
|
53
|
+
/** Mirrors the server's resolver: blank, a callback ID, or an absolute http(s) URL with a host. */
|
|
54
|
+
export declare function isResolvableCallbackUrl(value: string): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{SmileIDAPI as
|
|
1
|
+
"use strict";import{SmileIDAPI as u,buildAxiosClient as g,SmileAuthInterceptor as I,attachLoggingInterceptor as k}from"../api/smile_id_api";import{createGzipInterceptor as d}from"../api/interceptors/gzip_interceptor";import{SmileRequestMacInterceptor as y}from"../api/interceptors/smile_request_mac_interceptor";import{SmileIntegrityInterceptor as w}from"../api/interceptors/smile_integrity_interceptor";import{TokenRefreshInterceptor as C}from"../api/interceptors/token_refresh_interceptor";import{TokenHolder as S}from"../api/auth/token_holder";import{SmileIDCryptoManager as A}from"../security/smile_id_crypto_manager";import{SecurityPolicy as P}from"../security/security_policy";import{decodeSecurityPolicyBitCode as F}from"../util/use_smile_id_token_decoder";import{Attestation as T}from"@smileid/usesmileid_bridge";import{SigningSecretProvider as b}from"@smileid/usesmileid_bridge/internal";import{MissingPartnerConfigException as n}from"../../core/exception";import{UseSmileIDMetadataFactory as x}from"../../metadata/use_smile_id_metadata_factory";export function makeNetworkingFactory(t,o=()=>b.signingSecret()){const r=t.config?.partnerConfig;if(!r||r.partnerId.trim()==="")throw n.missingPartnerId();if(!t.config?.token||t.config.token.trim()==="")throw n.missingAuthToken();const c=/[\u0000-\u001F\u007F-\u009F]/;if(c.test(r.partnerId))throw n.controlCharacterPartnerId();if(c.test(t.config.token))throw n.controlCharacterAuthToken();if(!isResolvableCallbackUrl(r.callbackUrl??""))throw n.unresolvableCallbackUrl();const e=g(t),m=new x,f=new u(e,r);T.warmUp().catch(()=>{});const a=new S(t.config?.token??""),s=P.fromBitCode(F(t.config?.token??""));d().attach(e);const p=t.config?.logging;p&&k(e,p),new w({securityPolicy:s}).attach(e);const l=new A(o());if(new y({cryptoManager:l,securityPolicy:s}).attach(e),new I({partnerConfig:r,tokenHolder:a}).attach(e),new C({tokenHolder:a,onTokenExpired:t.config?.onTokenExpired}).attach(e),t.interceptors)for(const h of t.interceptors){const i=h;typeof i=="function"?i(e):typeof i?.attach=="function"&&i.attach(e)}return{api:f,client:e,metadata:m}}const M=/^callback_[0-9a-hjkmnp-tv-z]{26}$/;export function isResolvableCallbackUrl(t){if(t===""||M.test(t))return!0;const o=t.indexOf("://");if(o<=0)return!1;const r=t.slice(0,o).toLowerCase();if(r!=="http"&&r!=="https")return!1;const e=((t.slice(o+3).split(/[/?#]/)[0]??"").split("@").pop()??"").split(":")[0]??"";return e!==""&&!/[\s\u0000-\u001F\u007F-\u009F]/.test(e)}
|
|
@@ -141,4 +141,23 @@ export type EnhancedDocumentVerificationRequest = BaseJobRequest & {
|
|
|
141
141
|
/** See `SmartSelfieEnrollmentRequest.expectedLivenessImageCount`. */
|
|
142
142
|
readonly expectedLivenessImageCount: number;
|
|
143
143
|
};
|
|
144
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Residency Document Verification: a passport data page plus a mandatory
|
|
146
|
+
* supporting visa page. Dispatches through `/v3/residency_document_verification`.
|
|
147
|
+
*/
|
|
148
|
+
export type ResidencyDocumentVerificationRequest = BaseJobRequest & {
|
|
149
|
+
readonly jobType: typeof JobType.residencyDocumentVerification;
|
|
150
|
+
readonly selfieImage: string;
|
|
151
|
+
readonly livenessImages: readonly string[];
|
|
152
|
+
/** Passport data page. Sent as the `document` part. */
|
|
153
|
+
readonly frontDocument: string;
|
|
154
|
+
/** Supporting visa page. Sent as the `visa` part; the flow has no skip path for it. */
|
|
155
|
+
readonly visaDocument: string;
|
|
156
|
+
readonly country: string;
|
|
157
|
+
readonly idType: string;
|
|
158
|
+
/** Omitted when the token binds every required field, or reduced to the unbound remainder. */
|
|
159
|
+
readonly userDetails?: UserDetailsPayload;
|
|
160
|
+
/** See `SmartSelfieEnrollmentRequest.expectedLivenessImageCount`. */
|
|
161
|
+
readonly expectedLivenessImageCount: number;
|
|
162
|
+
};
|
|
163
|
+
export type JobRequest = SmartSelfieEnrollmentRequest | SmartSelfieAuthenticationRequest | EnhancedKycRequest | BvnRequest | BiometricKycRequest | DocumentVerificationRequest | EnhancedDocumentVerificationRequest | ResidencyDocumentVerificationRequest;
|