@smileid/usesmileid 12.3.1-SNAPSHOT.52 → 12.3.1-SNAPSHOT.64

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 (140) hide show
  1. package/README.md +6 -12
  2. package/dist/camera/device_tilt_override.d.ts +8 -0
  3. package/dist/camera/device_tilt_override.js +1 -0
  4. package/dist/camera/use_kamera_orientation.d.ts +6 -1
  5. package/dist/camera/use_kamera_orientation.js +1 -1
  6. package/dist/camera/use_smile_id_frame_stream.js +1 -1
  7. package/dist/camera/use_smile_id_kamera_camera_system.js +1 -1
  8. package/dist/camera/view_mirrors_frames.d.ts +8 -0
  9. package/dist/camera/view_mirrors_frames.js +1 -0
  10. package/dist/core/exception/flow_exceptions.d.ts +10 -0
  11. package/dist/core/exception/flow_exceptions.js +1 -1
  12. package/dist/core/exception/index.d.ts +4 -3
  13. package/dist/core/exception/index.js +1 -1
  14. package/dist/core/exception/invalid_test_route_exception.d.ts +15 -0
  15. package/dist/core/exception/invalid_test_route_exception.js +1 -0
  16. package/dist/core/exception/use_smile_id_error_code.d.ts +20 -0
  17. package/dist/core/exception/use_smile_id_error_code.js +1 -1
  18. package/dist/core/exception/use_smile_id_network_exception.d.ts +0 -25
  19. package/dist/core/exception/use_smile_id_network_exception.js +1 -1
  20. package/dist/core/models/network_config.d.ts +9 -17
  21. package/dist/core/models/params.d.ts +9 -0
  22. package/dist/core/models/params.js +1 -1
  23. package/dist/core/perf/capture_perf_trace.d.ts +9 -0
  24. package/dist/core/perf/capture_perf_trace.js +1 -1
  25. package/dist/data/api/bridge_submissions.d.ts +40 -0
  26. package/dist/data/api/bridge_submissions.js +1 -0
  27. package/dist/data/api/environment.d.ts +8 -0
  28. package/dist/data/api/environment.js +1 -0
  29. package/dist/data/api/hooks/partner_hooks.d.ts +27 -0
  30. package/dist/data/api/hooks/partner_hooks.js +1 -0
  31. package/dist/data/api/smile_id_api.d.ts +17 -31
  32. package/dist/data/api/smile_id_api.js +1 -1
  33. package/dist/data/api/test_route.d.ts +13 -0
  34. package/dist/data/api/test_route.js +1 -0
  35. package/dist/data/dsl/builder/interceptor_config_builder.d.ts +28 -31
  36. package/dist/data/dsl/builder/interceptor_config_builder.js +1 -1
  37. package/dist/data/dsl/use_smile_id_network_builder.d.ts +1 -4
  38. package/dist/data/dsl/use_smile_id_network_builder.js +1 -1
  39. package/dist/data/factory/networking_factory.d.ts +16 -43
  40. package/dist/data/factory/networking_factory.js +1 -1
  41. package/dist/data/model/job_form.d.ts +15 -0
  42. package/dist/data/model/job_form.js +1 -0
  43. package/dist/data/model/sealed_job_request.d.ts +1 -1
  44. package/dist/data/repository/use_smile_id_repository.d.ts +2 -2
  45. package/dist/data/repository/use_smile_id_repository_impl.d.ts +7 -25
  46. package/dist/data/repository/use_smile_id_repository_impl.js +1 -1
  47. package/dist/data/util/file_path.d.ts +2 -0
  48. package/dist/data/util/file_path.js +1 -0
  49. package/dist/debug/capture_debug_geometry.d.ts +0 -8
  50. package/dist/debug/capture_debug_geometry.js +1 -1
  51. package/dist/debug/debug_face_light.d.ts +35 -0
  52. package/dist/debug/debug_face_light.js +1 -0
  53. package/dist/debug/debug_face_mesh.d.ts +65 -0
  54. package/dist/debug/debug_face_mesh.js +1 -0
  55. package/dist/debug/use_smile_id_debug_hud.d.ts +83 -0
  56. package/dist/debug/use_smile_id_debug_hud.js +1 -0
  57. package/dist/debug/use_smile_id_debug_tap.d.ts +22 -0
  58. package/dist/debug/use_smile_id_debug_tap.js +1 -1
  59. package/dist/debug/use_smile_id_document_capture_debug_overlay.d.ts +1 -1
  60. package/dist/debug/use_smile_id_document_preview_debug_overlay.js +1 -1
  61. package/dist/debug/use_smile_id_selfie_capture_debug_overlay.d.ts +10 -11
  62. package/dist/debug/use_smile_id_selfie_capture_debug_overlay.js +1 -1
  63. package/dist/debug/use_smile_id_selfie_preview_debug_overlay.js +1 -1
  64. package/dist/index.d.ts +8 -3
  65. package/dist/index.js +1 -1
  66. package/dist/l10n/strings_en.d.ts +3 -1
  67. package/dist/l10n/strings_en.js +1 -1
  68. package/dist/l10n/use_smile_id_localizations.d.ts +4 -0
  69. package/dist/l10n/use_smile_id_localizations.js +1 -1
  70. package/dist/metadata/head_pose_recorder.d.ts +29 -0
  71. package/dist/metadata/head_pose_recorder.js +1 -0
  72. package/dist/metadata/optional_native_modules.js +1 -1
  73. package/dist/metadata/use_smile_id_metadata.d.ts +7 -0
  74. package/dist/metadata/use_smile_id_metadata.js +1 -1
  75. package/dist/metadata/use_smile_id_metadata_factory.d.ts +14 -0
  76. package/dist/metadata/use_smile_id_metadata_factory.js +1 -1
  77. package/dist/presentation/components/helpers/captured_oval_region.d.ts +4 -1
  78. package/dist/presentation/components/use_smile_id_captured_image_oval.js +1 -1
  79. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +1 -1
  80. package/dist/presentation/flow/flow_navigation_manager.d.ts +18 -0
  81. package/dist/presentation/flow/flow_navigation_manager.js +1 -1
  82. package/dist/presentation/flow/flow_navigation_manager_analytics.d.ts +1 -0
  83. package/dist/presentation/flow/flow_navigation_manager_analytics.js +1 -1
  84. package/dist/presentation/flow/flow_navigation_manager_documents.js +1 -1
  85. package/dist/presentation/flow/flow_navigation_manager_job_request.js +1 -1
  86. package/dist/presentation/flow/screen/helpers/failure_message.js +1 -1
  87. package/dist/presentation/flow/screen/orchestrated_capture_screen.js +1 -1
  88. package/dist/presentation/flow/use_smile_id_flow.js +1 -1
  89. package/dist/presentation/flow/validation/flow_validator.d.ts +1 -0
  90. package/dist/presentation/flow/validation/job_type_validator.d.ts +2 -0
  91. package/dist/presentation/flow/validation/job_type_validator.js +1 -1
  92. package/dist/presentation/screen/helpers/capture_screen_helpers.d.ts +6 -0
  93. package/dist/presentation/screen/helpers/capture_screen_helpers.js +1 -1
  94. package/dist/presentation/screen/helpers/capture_ui_state.js +1 -1
  95. package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js +1 -1
  96. package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +9 -0
  97. package/dist/presentation/screen/use_smile_id_capture_screen.js +1 -1
  98. package/dist/testing/index.d.ts +1 -0
  99. package/dist/testing/index.js +1 -1
  100. package/package.json +8 -13
  101. package/dist/data/api/auth/token_holder.d.ts +0 -39
  102. package/dist/data/api/auth/token_holder.js +0 -1
  103. package/dist/data/api/connection_warmer.d.ts +0 -27
  104. package/dist/data/api/connection_warmer.js +0 -1
  105. package/dist/data/api/interceptors/gzip_interceptor.d.ts +0 -20
  106. package/dist/data/api/interceptors/gzip_interceptor.js +0 -1
  107. package/dist/data/api/interceptors/logging_interceptor.d.ts +0 -25
  108. package/dist/data/api/interceptors/logging_interceptor.js +0 -1
  109. package/dist/data/api/interceptors/sensitive_headers.d.ts +0 -25
  110. package/dist/data/api/interceptors/sensitive_headers.js +0 -1
  111. package/dist/data/api/interceptors/smile_auth_interceptor.d.ts +0 -21
  112. package/dist/data/api/interceptors/smile_auth_interceptor.js +0 -1
  113. package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts +0 -49
  114. package/dist/data/api/interceptors/smile_integrity_interceptor.js +0 -1
  115. package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts +0 -41
  116. package/dist/data/api/interceptors/smile_request_mac_interceptor.js +0 -1
  117. package/dist/data/api/interceptors/token_refresh_interceptor.d.ts +0 -44
  118. package/dist/data/api/interceptors/token_refresh_interceptor.js +0 -1
  119. package/dist/data/api/request_capture.d.ts +0 -16
  120. package/dist/data/api/request_capture.js +0 -1
  121. package/dist/data/security/job_package_crypto.d.ts +0 -41
  122. package/dist/data/security/job_package_crypto.js +0 -1
  123. package/dist/data/security/job_package_sealer.d.ts +0 -35
  124. package/dist/data/security/job_package_sealer.js +0 -1
  125. package/dist/data/security/request_canonicalizer.d.ts +0 -3
  126. package/dist/data/security/request_canonicalizer.js +0 -1
  127. package/dist/data/security/request_timestamp.d.ts +0 -10
  128. package/dist/data/security/request_timestamp.js +0 -1
  129. package/dist/data/security/security_policy.d.ts +0 -42
  130. package/dist/data/security/security_policy.js +0 -1
  131. package/dist/data/security/signing_crypto.d.ts +0 -58
  132. package/dist/data/security/signing_crypto.js +0 -1
  133. package/dist/data/security/smile_id_crypto_error.d.ts +0 -10
  134. package/dist/data/security/smile_id_crypto_error.js +0 -1
  135. package/dist/data/security/smile_id_crypto_manager.d.ts +0 -29
  136. package/dist/data/security/smile_id_crypto_manager.js +0 -1
  137. package/dist/data/smile_id_urls.d.ts +0 -11
  138. package/dist/data/smile_id_urls.js +0 -1
  139. package/dist/data/util/retry_util.d.ts +0 -29
  140. package/dist/data/util/retry_util.js +0 -1
package/README.md CHANGED
@@ -42,7 +42,6 @@ Add the SDK, its native peer dependencies, and the analyzer providers that match
42
42
  pnpm add @smileid/usesmileid \
43
43
  @smileid/usesmileid_mlkit_face @smileid/usesmileid_mlkit_document \
44
44
  @smileid/usesmileid_vision_face @smileid/usesmileid_vision_document \
45
- react-native-quick-crypto react-native-quick-base64 react-native-nitro-modules \
46
45
  react-native-safe-area-context react-native-svg lottie-react-native
47
46
  ```
48
47
 
@@ -53,11 +52,11 @@ npx expo install expo-brightness expo-file-system expo-font expo-haptics \
53
52
  expo-image-manipulator expo-image-picker expo-keep-awake expo-screen-orientation
54
53
  ```
55
54
 
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.)
55
+ (For Android phones without Google Play services, add `@smileid/usesmileid_huawei_{face,document}` and pick with `UseSmileIDMobileServices.analyzerProvider()`, in one build for every store or a build per store whose AppGallery flavor uses them instead of the ML Kit packages: see the [repository README's Huawei section](https://github.com/smileidentity/react-native-expo#huawei).)
57
56
 
58
57
  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
58
 
60
- `react-native-quick-crypto`, `react-native-quick-base64` and the `react-native-nitro-modules` runtime it needs handle native request signing. The camera itself is supplied by the bundled kamera engine, so there is no camera package for you to install or pin.
59
+ The camera itself is supplied by the bundled kamera engine, so there is no camera package for you to install or pin.
61
60
 
62
61
  Babel needs nothing beyond `babel-preset-expo` — the SDK ships no Babel plugin. Upgrading from `12.0.2` or earlier, drop `react-native-worklets-core/plugin` from `babel.config.js` together with the `react-native-vision-camera` and `react-native-worklets-core` packages and the VisionCamera config plugin: kamera replaced the frame processors they backed.
63
62
 
@@ -273,13 +272,8 @@ b.network((n) => {
273
272
  c.maxSize = 100 * 1024 * 1024; // 100 MB
274
273
  });
275
274
  n.interceptors((i) => {
276
- i.add(i.gzip());
277
- i.add(
278
- i.logging((l) => {
279
- l.level = LogLevel.body; // bodies in a development build only
280
- }),
281
- );
282
- i.add(myCustomInterceptor); // partner-supplied
275
+ i.onRequest(async () => ({ "x-request-id": requestId() }));
276
+ i.onResponse((response) => log(`${response.status} ${response.url}`));
283
277
  });
284
278
  });
285
279
  ```
@@ -364,7 +358,7 @@ export const faceAnalyzer = useSmileIDMlkitFace;
364
358
  export const documentAnalyzer = useSmileIDMlkitDocument;
365
359
  ```
366
360
 
367
- Add `"moduleSuffixes": [".ios", ".android", ""]` to your `tsconfig.json` so `tsc` resolves `./src/providers` correctly. See `sample-expo/` for a complete reference.
361
+ Add `"moduleSuffixes": [".ios", ".android", ""]` to your `tsconfig.json` so `tsc` resolves `./src/providers` correctly. The [public Expo sample app](https://github.com/smileidentity/usesmileid-sample-apps/tree/main/expo) is a complete reference.
368
362
 
369
363
  ---
370
364
 
@@ -576,7 +570,7 @@ Every exception the SDK surfaces extends `UseSmileIDException`, which carries:
576
570
  - `errorCode` — a stable UPPER_SNAKE_CASE string (e.g. `"NETWORK_TIMEOUT"`, `"BUILDER_VALIDATION_ERROR"`) suitable for grouping. Stable across SDK releases, so Sentry pivots and analytics dashboards keyed on it keep working after upgrades.
577
571
  - `message` — partner-safe message; never contains PII.
578
572
  - `suggestedFix` — concrete remediation hint for triage.
579
- - `cause` — the wrapped underlying error (`AxiosError` / `Error`) for stack trace forwarding.
573
+ - `cause` — the wrapped underlying error (`NativeNetworkError` / `Error`) for stack trace forwarding.
580
574
 
581
575
  Forward failures to Sentry, Bugsnag, or Crashlytics from inside the failure branch of `onResult`:
582
576
 
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A device tilt (0 / 90 / 180 / 270) the capture screen reads instead of the accelerometer, so an
3
+ * end-to-end test can capture with the phone lying flat; null restores the sensor. Set it before
4
+ * the flow mounts. Exposed from `@smileid/usesmileid/testing` only.
5
+ */
6
+ export declare function overrideDeviceTilt(degrees: number | null): void;
7
+ /** The overridden tilt, or null to read the sensor. */
8
+ export declare function deviceTiltOverride(): number | null;
@@ -0,0 +1 @@
1
+ "use strict";let e=null;export function overrideDeviceTilt(r){e=r}export function deviceTiltOverride(){return e}
@@ -1,5 +1,10 @@
1
+ /** What a selfie on a phone lying flat reads as: a quarter turn, past the capture's orientation limit. */
2
+ export declare const FLAT_TILT_DEGREES = 90;
1
3
  export declare function useDeviceTiltDegrees(options?: {
2
- /** Keep the last decisive tilt while the phone is near-flat (a document held over a table). */
4
+ /**
5
+ * Keep the last decisive tilt while the phone is near-flat (a document held over a table); otherwise
6
+ * a near-flat phone reads as `FLAT_TILT_DEGREES`.
7
+ */
3
8
  readonly retainWhenFlat?: boolean;
4
9
  }): number;
5
10
  /**
@@ -1 +1 @@
1
- "use strict";import{useEffect as D,useState as h}from"react";import{Platform as S}from"react-native";import*as t from"expo-screen-orientation";import{loadExpoSensors as I}from"../metadata/optional_native_modules";const T=2;export function useDeviceTiltDegrees(c){const n=c?.retainWhenFlat??!1,r=useLockedInterfaceOrientationDegrees(),[o,s]=h(null);return D(()=>{const e=I();if(!e)return;e.Accelerometer.setUpdateInterval(200);let u=null,i=0;const p=e.Accelerometer.addListener(({x:A,y:L})=>{const l=S.OS==="android"?-1:1,f=A*l,g=L*l,d=Math.abs(f),m=Math.abs(g);if(d<.5&&m<.5){u=null,i=0,n||s(null);return}const a=d>m?f>0?270:90:g>0?180:0;i=a===u?i+1:1,u=a,!(i<T)&&s(O=>O===a?O:a)});return()=>p.remove()},[n]),o??r}export function useLockedInterfaceOrientationDegrees(){const[c,n]=h(0);return D(()=>{let r=!0;const o=e=>{switch(e){case t.Orientation.LANDSCAPE_LEFT:return 90;case t.Orientation.LANDSCAPE_RIGHT:return 270;case t.Orientation.PORTRAIT_DOWN:return 180;default:return 0}};t.getOrientationAsync().then(e=>{r&&n(o(e))}).catch(()=>{});const s=t.addOrientationChangeListener(e=>{n(o(e.orientationInfo.orientation))});return()=>{r=!1,t.removeOrientationChangeListener(s)}},[]),c}
1
+ "use strict";import{useEffect as A,useState as D}from"react";import{Platform as I}from"react-native";import*as n from"expo-screen-orientation";import{loadExpoSensors as S}from"../metadata/optional_native_modules";import{deviceTiltOverride as v}from"./device_tilt_override";const T=2;export const FLAT_TILT_DEGREES=90;const L=-1;export function useDeviceTiltDegrees(u){const r=u?.retainWhenFlat??!1,i=useLockedInterfaceOrientationDegrees(),[s,a]=D(null);return A(()=>{const e=S();if(!e)return;e.Accelerometer.setUpdateInterval(200);let o=null,t=0;const p=e.Accelerometer.addListener(({x:E,y:h})=>{const f=I.OS==="android"?-1:1,l=E*f,d=h*f,g=Math.abs(l),m=Math.abs(d);if(g<.5&&m<.5){if(r){o=null,t=0;return}t=o===L?t+1:1,o=L,t>=T&&a(FLAT_TILT_DEGREES);return}const c=g>m?l>0?270:90:d>0?180:0;t=c===o?t+1:1,o=c,!(t<T)&&a(O=>O===c?O:c)});return()=>p.remove()},[r]),v()??s??i}export function useLockedInterfaceOrientationDegrees(){const[u,r]=D(0);return A(()=>{let i=!0;const s=e=>{switch(e){case n.Orientation.LANDSCAPE_LEFT:return 90;case n.Orientation.LANDSCAPE_RIGHT:return 270;case n.Orientation.PORTRAIT_DOWN:return 180;default:return 0}};n.getOrientationAsync().then(e=>{i&&r(s(e))}).catch(()=>{});const a=n.addOrientationChangeListener(e=>{r(s(e.orientationInfo.orientation))});return()=>{i=!1,n.removeOrientationChangeListener(a)}},[]),u}
@@ -1 +1 @@
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{isDevelopmentBuild as p}from"../core/is_development_build";import{UseSmileIDDebugTap as R}from"../debug/use_smile_id_debug_tap";export function useSmileIDFrameStream(e,r,o){const i=a(e),s=a(r),u=a(o?.onError),c=a(!1),f=a(!0);l(()=>{i.current=e},[e]),l(()=>{s.current=r},[r]),l(()=>{u.current=o?.onError},[o?.onError]),l(()=>(f.current=!0,()=>{f.current=!1}),[]);const n=y(t=>{const m=u.current;dispatchFrameResult({raw:t,analyzer:i.current,isBusy:()=>c.current,setBusy:d=>{c.current=d},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:o,isBusy:i,setBusy:s,isMounted:u,onResult:c,onError:f}=e;if(o&&!i()){s(!0);try{const n=D(r);if(n!==null){if(_.has(n))return;throw new B({reason:n})}if(o.kind==="face"){const t=h.parse(r);if(!u())return;c(t),p()&&R.analyzedFace(t.output)}else{const t=S.parse(r);if(!u())return;c(t),p()&&R.analyzedDocument(t.output)}}catch(n){if(!u())return;f?.(n)}finally{s(!1)}}}
1
+ "use strict";import{useCallback as E,useEffect as s,useMemo as S,useRef as f}from"react";import{documentScanResultSchema as F,faceScanResultSchema as h,FrameProcessingException as g}from"@smileid/usesmileid_bridge";import{isDevelopmentBuild as p}from"../core/is_development_build";import{UseSmileIDDebugTap as d}from"../debug/use_smile_id_debug_tap";export function useSmileIDFrameStream(e,t,u){const m=f(e),c=f(t),o=f(u?.onError),i=f(!1),a=f(!0);s(()=>{m.current=e},[e]),s(()=>{if(!p()||e?.kind!=="face")return;const r=e.takeCameraFrames;if(r)return d.countCameraFramesWith(()=>r.call(e))},[e]),s(()=>{if(!p()||e?.kind!=="face")return;const r=e.setFaceLumaSampling;if(r)return d.sampleFaceLumaWith(l=>r.call(e,l))},[e]),s(()=>{c.current=t},[t]),s(()=>{o.current=u?.onError},[u?.onError]),s(()=>(a.current=!0,()=>{a.current=!1}),[]);const n=E(r=>{const l=o.current;dispatchFrameResult({raw:r,analyzer:m.current,isBusy:()=>i.current,setBusy:R=>{i.current=R},isMounted:()=>a.current,onResult:c.current,...l!==void 0?{onError:l}:{}})},[]);return S(()=>({onFrameResult:n}),[n])}function k(e){if(e===null||typeof e!="object")return null;const t=e.error;return typeof t=="string"?t:null}const B=new Set(["no_frame","session_not_configured"]);export function dispatchFrameResult(e){const{raw:t,analyzer:u,isBusy:m,setBusy:c,isMounted:o,onResult:i,onError:a}=e;if(u&&!m()){c(!0);try{const n=k(t);if(n!==null){if(B.has(n))return;throw new g({reason:n})}if(u.kind==="face"){const r=h.parse(t);if(!o())return;i(r),p()&&d.analyzedFace(r.output)}else{const r=F.parse(t);if(!o())return;i(r),p()&&d.analyzedDocument(r.output)}}catch(n){if(!o())return;a?.(n)}finally{c(!1)}}}
@@ -1 +1 @@
1
- "use strict";import{AspectRatio as f,KameraSession as p}from"@smileid/kamera";import{UseSmileIDCrashReporting as l}from"@smileid/usesmileid_bridge";import{Platform as S}from"react-native";import{CaptureType as c}from"../core/models/ml_config";import{captureDebugBoxesMirrored as g}from"../debug/capture_debug_geometry";import{meteringRegion as w}from"./bounding_box_metering_region";import{CameraDefaults as h}from"./camera_defaults";import{CameraLens as a}from"./camera_lens";import{FocusStates as n}from"./focus_state";import{KameraConfigFactory as _}from"./kamera_config_factory";let m=!1,o=null;export function setKameraMetricsWanted(i){m=i}async function y(i){const e=m;if(e===o)return;o=e;const t=Promise.resolve().then(()=>i.setMetricsEnabled?.(e)).catch(s=>{o=null,l.captureException(s instanceof Error?s:new Error(String(s)))});e&&await t}export function resetKameraMetricsForTesting(){m=!1,o=null}export class UseSmileIDKameraCameraSystem{_createSession;_session=null;_removeEventListener=null;_state;_focusState=n.unspecified();_listeners=new Set;_eventListeners=new Set;_capabilities=null;_config={};_released=!1;_focusRunningTimeout=null;_focusSettledTimeout=null;constructor(e=a.front,t=()=>new p){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??c.selfie;return _.create(e,this._state.currentLens).preview.aspectRatio===f.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(u=>this._onKameraEvent(u)),s=this._config.captureType??c.selfie,r=this._config.lens??(s===c.document?a.back:a.front);try{await y(e),await e.start(_.create(s,r)),this._capabilities=await e.capabilities()}catch(u){throw t(),await e.release(),u}this._removeEventListener=t,this._session=e,this._documentGuideApplied=this._documentGuide===null,await this._applyDocumentGuide(),this._setState({...this._state,isCameraRunning:!0,isStreaming:!0,currentLens:r,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,r=s?Math.min(s.maxZoomRatio,Math.max(s.minZoomRatio,e)):e;await t.setZoomRatio(r)}_documentGuide=null;_documentGuideApplied=!0;_documentGuideSendingTo=null;_documentGuideFailureReported=!1;async setDocumentGuide(e){d(e,this._documentGuide)||(this._documentGuide=e,this._documentGuideApplied=!1),await this._applyDocumentGuide()}async _applyDocumentGuide(){const e=this._session;if(!(e===null||this._documentGuideApplied||this._documentGuideSendingTo===e)){this._documentGuideSendingTo=e;try{for(;!this._documentGuideApplied&&this._session===e;){const t=this._documentGuide;if(!await this._sendDocumentGuide(e,t))return;this._session===e&&d(t,this._documentGuide)&&(this._documentGuideApplied=!0)}}finally{this._documentGuideSendingTo===e&&(this._documentGuideSendingTo=null)}}}async _sendDocumentGuide(e,t){try{return await e.setDocumentGuide?.(t?.widthMm??0,t?.frameWidthFraction??0),!0}catch(s){return this._documentGuideFailureReported||(this._documentGuideFailureReported=!0,l.captureException(s instanceof Error?s:new Error(String(s)))),!1}}async setTorch(e){await this._session?.setTorch(e)}async tapToFocus(e){const t=this._session;t&&(this._clearFocusTimers(),this._setFocusState(n.running(e)),t.tapToFocus(e.x,e.y).catch(()=>{this._clearFocusTimers(),this._setFocusState(n.unspecified())}),this._focusRunningTimeout=setTimeout(()=>{this._setFocusState(n.success(e)),this._focusSettledTimeout=setTimeout(()=>{this._setFocusState(n.unspecified())},h.focusSettledDurationMs)},h.focusRunningDurationMs))}meterExposure(e){const t=this._session;if(!t)return;const s=e?w(e,g(this._state.currentLens===a.front,S.OS==="android")):null;t.setMeteringRegion?.(s).catch(()=>{})}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)}}function d(i,e){return i?.widthMm===e?.widthMm&&i?.frameWidthFraction===e?.frameWidthFraction}
1
+ "use strict";import{AspectRatio as f,KameraSession as p}from"@smileid/kamera";import{UseSmileIDCrashReporting as l}from"@smileid/usesmileid_bridge";import{Platform as S}from"react-native";import{CaptureType as c}from"../core/models/ml_config";import{viewMirrorsFrames as g}from"./view_mirrors_frames";import{meteringRegion as w}from"./bounding_box_metering_region";import{CameraDefaults as h}from"./camera_defaults";import{CameraLens as a}from"./camera_lens";import{FocusStates as n}from"./focus_state";import{KameraConfigFactory as _}from"./kamera_config_factory";let m=!1,o=null;export function setKameraMetricsWanted(i){m=i}async function y(i){const e=m;if(e===o)return;o=e;const t=Promise.resolve().then(()=>i.setMetricsEnabled?.(e)).catch(s=>{o=null,l.captureException(s instanceof Error?s:new Error(String(s)))});e&&await t}export function resetKameraMetricsForTesting(){m=!1,o=null}export class UseSmileIDKameraCameraSystem{_createSession;_session=null;_removeEventListener=null;_state;_focusState=n.unspecified();_listeners=new Set;_eventListeners=new Set;_capabilities=null;_config={};_released=!1;_focusRunningTimeout=null;_focusSettledTimeout=null;constructor(e=a.front,t=()=>new p){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??c.selfie;return _.create(e,this._state.currentLens).preview.aspectRatio===f.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(u=>this._onKameraEvent(u)),s=this._config.captureType??c.selfie,r=this._config.lens??(s===c.document?a.back:a.front);try{await y(e),await e.start(_.create(s,r)),this._capabilities=await e.capabilities()}catch(u){throw t(),await e.release(),u}this._removeEventListener=t,this._session=e,this._documentGuideApplied=this._documentGuide===null,await this._applyDocumentGuide(),this._setState({...this._state,isCameraRunning:!0,isStreaming:!0,currentLens:r,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,r=s?Math.min(s.maxZoomRatio,Math.max(s.minZoomRatio,e)):e;await t.setZoomRatio(r)}_documentGuide=null;_documentGuideApplied=!0;_documentGuideSendingTo=null;_documentGuideFailureReported=!1;async setDocumentGuide(e){d(e,this._documentGuide)||(this._documentGuide=e,this._documentGuideApplied=!1),await this._applyDocumentGuide()}async _applyDocumentGuide(){const e=this._session;if(!(e===null||this._documentGuideApplied||this._documentGuideSendingTo===e)){this._documentGuideSendingTo=e;try{for(;!this._documentGuideApplied&&this._session===e;){const t=this._documentGuide;if(!await this._sendDocumentGuide(e,t))return;this._session===e&&d(t,this._documentGuide)&&(this._documentGuideApplied=!0)}}finally{this._documentGuideSendingTo===e&&(this._documentGuideSendingTo=null)}}}async _sendDocumentGuide(e,t){try{return await e.setDocumentGuide?.(t?.widthMm??0,t?.frameWidthFraction??0),!0}catch(s){return this._documentGuideFailureReported||(this._documentGuideFailureReported=!0,l.captureException(s instanceof Error?s:new Error(String(s)))),!1}}async setTorch(e){await this._session?.setTorch(e)}async tapToFocus(e){const t=this._session;t&&(this._clearFocusTimers(),this._setFocusState(n.running(e)),t.tapToFocus(e.x,e.y).catch(()=>{this._clearFocusTimers(),this._setFocusState(n.unspecified())}),this._focusRunningTimeout=setTimeout(()=>{this._setFocusState(n.success(e)),this._focusSettledTimeout=setTimeout(()=>{this._setFocusState(n.unspecified())},h.focusSettledDurationMs)},h.focusRunningDurationMs))}meterExposure(e){const t=this._session;if(!t)return;const s=e?w(e,g(this._state.currentLens===a.front,S.OS==="android")):null;t.setMeteringRegion?.(s).catch(()=>{})}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)}}function d(i,e){return i?.widthMm===e?.widthMm&&i?.frameWidthFraction===e?.frameWidthFraction}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Whether the camera's view is a mirror image of the frames it hands the SDK: the frames the
3
+ * detector reads and the selfie is saved from. The front lens's view is mirrored on both
4
+ * platforms. On iOS the Vision plugin reads the frames in their mirrored orientation and the selfie
5
+ * is saved that way, so they match the view; on Android they stay unmirrored, so boxes drawn on the
6
+ * view and a selfie shown for review are flipped to match it.
7
+ */
8
+ export declare function viewMirrorsFrames(frontLens: boolean, isAndroid: boolean): boolean;
@@ -0,0 +1 @@
1
+ "use strict";export function viewMirrorsFrames(r,e){return r&&e}
@@ -38,3 +38,13 @@ export declare class NavigationFailedException extends UseSmileIDGeneralExceptio
38
38
  cause: unknown;
39
39
  });
40
40
  }
41
+ /**
42
+ * The flow's native network client couldn't be set up, so the flow ends at start rather than run
43
+ * with no network. Surfaced through `onResult.failure`; `cause` says why.
44
+ */
45
+ export declare class NetworkSetupException extends UseSmileIDGeneralException {
46
+ readonly errorCode: "GENERAL_OPERATION_FAILED";
47
+ constructor(args: {
48
+ cause: unknown;
49
+ });
50
+ }
@@ -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}:{}})}}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})}}
1
+ "use strict";import{UseSmileIDErrorCode as s}from"./use_smile_id_error_code";import{UseSmileIDGeneralException as t}from"./use_smile_id_general_exception";export class ConsentDeniedException extends t{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 t{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 t{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})}}export class NetworkSetupException extends t{errorCode=s.General.OperationFailed;constructor(e){super({message:"The flow's network client couldn't be set up",suggestedFix:"Check the cause. A missing or outdated native module needs @smileid/usesmileid_bridge at the SDK's version and a rebuild of the app's native code.",cause:e.cause})}}
@@ -10,7 +10,7 @@
10
10
  * class lists so partner code that deep-imports them keeps compiling.
11
11
  */
12
12
  export { IssueSeverity } from "./issue_severity";
13
- export { UseSmileIDErrorCode, isNetworkErrorCode, isRetryableErrorCode, type UseSmileIDNetworkErrorCode, } from "./use_smile_id_error_code";
13
+ export { UseSmileIDErrorCode, errorCodeDetails, isNetworkErrorCode, isRetryableErrorCode, type UseSmileIDErrorCategory, type UseSmileIDErrorCodeDetails, type UseSmileIDNetworkErrorCode, } from "./use_smile_id_error_code";
14
14
  export { UseSmileIDException } from "./use_smile_id_exception";
15
15
  export { UseSmileIDValidationException } from "./use_smile_id_validation_exception";
16
16
  export { UseSmileIDBuilderException } from "./use_smile_id_builder_exception";
@@ -20,7 +20,7 @@ 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, NavigationFailedException, ProcessingCancelledException, } from "./flow_exceptions";
23
+ export { ConsentDeniedException, NavigationFailedException, ProcessingCancelledException, NetworkSetupException, } from "./flow_exceptions";
24
24
  export { EmptyScreensBlockException } from "./empty_screens_block_exception";
25
25
  export { InvalidScreenOrderException } from "./invalid_screen_order_exception";
26
26
  export { InvalidPartnerScreenException } from "./invalid_partner_screen_exception";
@@ -35,10 +35,11 @@ export { InvalidConsentInformationException } from "./invalid_consent_informatio
35
35
  export { MissingMLConfigurationBlockException } from "./missing_ml_configuration_block_exception";
36
36
  export { MissingNetworkConfigurationBlockException } from "./missing_network_configuration_block_exception";
37
37
  export { MissingPartnerConfigException } from "./missing_partner_config_exception";
38
+ export { InvalidTestRouteException } from "./invalid_test_route_exception";
38
39
  export { LivenessFrameCountException } from "./liveness_frame_count_exception";
39
40
  export { MissingJobTypeException } from "./missing_job_type_exception";
40
41
  export { MissingRequiredFieldException } from "./missing_required_field_exception";
41
42
  export { InvalidJobTypeScreenConfigException } from "./invalid_job_type_screen_config_exception";
42
43
  export { UnusedJobParamsException } from "./unused_job_params_exception";
43
44
  export { InvalidFieldValueException } from "./invalid_field_value_exception";
44
- export { NetworkServerException, NetworkTransportException, NetworkTimeoutException, NetworkResponseParseException, NetworkRequestBuildException, NetworkUnknownException, mapAxiosError, } from "./use_smile_id_network_exception";
45
+ export { NetworkServerException, NetworkTransportException, NetworkTimeoutException, NetworkResponseParseException, NetworkRequestBuildException, NetworkUnknownException, } from "./use_smile_id_network_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,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";
1
+ "use strict";export{IssueSeverity}from"./issue_severity";export{UseSmileIDErrorCode,errorCodeDetails,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,NetworkSetupException}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{InvalidTestRouteException}from"./invalid_test_route_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}from"./use_smile_id_network_exception";
@@ -0,0 +1,15 @@
1
+ import { UseSmileIDBuilderException } from "./use_smile_id_builder_exception";
2
+ /**
3
+ * A testing package's route can't be used, so the flow's network client isn't built rather than
4
+ * let a request reach Smile ID unrouted. Thrown only when a test route is registered.
5
+ */
6
+ export declare class InvalidTestRouteException extends UseSmileIDBuilderException {
7
+ readonly errorCode: "BUILDER_INVALID_CONFIG";
8
+ private constructor();
9
+ /** More than one route was registered. */
10
+ static moreThanOne(count: number): InvalidTestRouteException;
11
+ /** A release build on production registered a route. */
12
+ static notAllowed(): InvalidTestRouteException;
13
+ /** The route's server is closed, or answered no usable port. */
14
+ static noServer(port: number | undefined, cause?: unknown): InvalidTestRouteException;
15
+ }
@@ -0,0 +1 @@
1
+ "use strict";import{UseSmileIDBuilderException as o}from"./use_smile_id_builder_exception";import{UseSmileIDErrorCode as n}from"./use_smile_id_error_code";export class InvalidTestRouteException extends o{errorCode=n.Builder.InvalidConfiguration;constructor(e,t,r){super({message:e,suggestedFix:t,errorDetails:{fieldName:"interceptors"},cause:r})}static moreThanOne(e){return new InvalidTestRouteException(`Only one test route can be registered; found ${e}`,"Install one test in the network block.")}static notAllowed(){return new InvalidTestRouteException("A test route works only in a development build or on the sandbox","Run the test in a development build, or on the sandbox.")}static noServer(e,t){return new InvalidTestRouteException(e===void 0?"The test server is closed":`The test server's port ${e} is not a port`,"Start the test before the flow, and close it after.",t)}}
@@ -81,8 +81,28 @@ type UseSmileIDErrorCodeNamespace = typeof UseSmileIDErrorCode;
81
81
  export type UseSmileIDErrorCode = UseSmileIDErrorCodeNamespace["Builder"][keyof UseSmileIDErrorCodeNamespace["Builder"]] | UseSmileIDErrorCodeNamespace["Camera"][keyof UseSmileIDErrorCodeNamespace["Camera"]] | UseSmileIDErrorCodeNamespace["Network"][keyof UseSmileIDErrorCodeNamespace["Network"]] | UseSmileIDErrorCodeNamespace["Validation"][keyof UseSmileIDErrorCodeNamespace["Validation"]] | UseSmileIDErrorCodeNamespace["General"][keyof UseSmileIDErrorCodeNamespace["General"]];
82
82
  /** Union of the `NETWORK_*` codes only. */
83
83
  export type UseSmileIDNetworkErrorCode = UseSmileIDErrorCodeNamespace["Network"][keyof UseSmileIDErrorCodeNamespace["Network"]];
84
+ /** An error code's category, as the cross-SDK contract names it. */
85
+ export type UseSmileIDErrorCategory = "BUILDER" | "CAMERA" | "NETWORK" | "VALIDATION" | "GENERAL";
86
+ /**
87
+ * What a code tells an integrator: its category, whether retrying can succeed,
88
+ * and for camera, network and general codes a user message and a suggested
89
+ * fix. Builder and validation exceptions carry their own, so theirs are empty.
90
+ * The same for every code on the four v12 SDKs (`error-codes-contract.json`).
91
+ */
92
+ export interface UseSmileIDErrorCodeDetails {
93
+ readonly category: UseSmileIDErrorCategory;
94
+ readonly isRetryable: boolean;
95
+ readonly userMessage: string;
96
+ readonly suggestedFix: string;
97
+ }
84
98
  /** Whether retrying `code` can plausibly succeed — a property of the code itself, so it covers camera failures too. */
85
99
  export declare function isRetryableErrorCode(code: UseSmileIDErrorCode): boolean;
100
+ /**
101
+ * `code`'s category, retryability, user message and suggested fix. A string
102
+ * outside the registry, such as an ML or attestation code or a cast wire value,
103
+ * gets `GENERAL_UNKNOWN_ERROR`'s details, so callers in error handling never throw.
104
+ */
105
+ export declare function errorCodeDetails(code: UseSmileIDErrorCode): UseSmileIDErrorCodeDetails;
86
106
  /** Whether `code` belongs to the `NETWORK_*` category. */
87
107
  export declare function isNetworkErrorCode(code: UseSmileIDErrorCode): code is UseSmileIDNetworkErrorCode;
88
108
  export {};
@@ -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",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)}
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 s={[UseSmileIDErrorCode.Camera.InitializationFailed]:{category:"CAMERA",isRetryable:!1,userMessage:"Failed to initialize camera. Please restart the app and try again.",suggestedFix:"Restart the app. If the issue persists, check camera permissions."},[UseSmileIDErrorCode.Camera.PermissionDenied]:{category:"CAMERA",isRetryable:!1,userMessage:"Camera permission is required to use this feature.",suggestedFix:"Grant camera permission in device settings."},[UseSmileIDErrorCode.Camera.CaptureFailed]:{category:"CAMERA",isRetryable:!0,userMessage:"Failed to capture image. Please try again.",suggestedFix:"Ensure good lighting and the camera is properly initialised, then try again."},[UseSmileIDErrorCode.Camera.UseCaseNotSupported]:{category:"CAMERA",isRetryable:!1,userMessage:"This camera feature is not supported on your device.",suggestedFix:"Check device capabilities or try using a different camera mode."},[UseSmileIDErrorCode.Camera.VideoCaptureDisabled]:{category:"CAMERA",isRetryable:!1,userMessage:"Video capture is not enabled.",suggestedFix:"Enable video capture in your flow configuration."},[UseSmileIDErrorCode.Camera.Unknown]:{category:"CAMERA",isRetryable:!1,userMessage:"A camera error occurred. Please try again.",suggestedFix:"Check camera availability and try again."},[UseSmileIDErrorCode.Network.ConnectionFailed]:{category:"NETWORK",isRetryable:!0,userMessage:"Unable to connect to the server. Please check your internet connection.",suggestedFix:"Check internet connectivity and retry the request."},[UseSmileIDErrorCode.Network.Timeout]:{category:"NETWORK",isRetryable:!0,userMessage:"Request timed out. Please check your connection and try again.",suggestedFix:"Check network stability or increase timeout settings."},[UseSmileIDErrorCode.Network.RequestFailed]:{category:"NETWORK",isRetryable:!1,userMessage:"Network error occurred. Please check your connection and try again.",suggestedFix:"Check your network configuration and retry."},[UseSmileIDErrorCode.Network.ResponseParseError]:{category:"NETWORK",isRetryable:!1,userMessage:"Failed to process server response. Please try again.",suggestedFix:"Ensure SDK version is up to date and matches the API version."},[UseSmileIDErrorCode.Network.Unauthorized]:{category:"NETWORK",isRetryable:!1,userMessage:"Authentication failed. Please check your credentials.",suggestedFix:"Verify your partner credentials in the network { config { } } block."},[UseSmileIDErrorCode.Network.Forbidden]:{category:"NETWORK",isRetryable:!1,userMessage:"Access denied. Please check your permissions.",suggestedFix:"Check your account permissions or contact support."},[UseSmileIDErrorCode.Network.NotFound]:{category:"NETWORK",isRetryable:!1,userMessage:"Resource not found. Please check your request.",suggestedFix:"Verify the request URL and parameters are correct."},[UseSmileIDErrorCode.Network.RateLimit]:{category:"NETWORK",isRetryable:!0,userMessage:"Too many requests. Please wait and try again.",suggestedFix:"Rate limited \u2014 wait and try again."},[UseSmileIDErrorCode.Network.ServerError]:{category:"NETWORK",isRetryable:!0,userMessage:"Server error occurred. Please try again later.",suggestedFix:"Wait a moment and retry. If the issue persists, contact support."},[UseSmileIDErrorCode.Network.CallbackUrlRequired]:{category:"NETWORK",isRetryable:!1,userMessage:"Verification could not be submitted. Please contact support.",suggestedFix:"Set callbackUrl in the partner configuration, or configure a default callback URL for this environment in the Smile ID portal."},[UseSmileIDErrorCode.Builder.ValidationError]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.InvalidConfiguration]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.MissingRequiredField]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.InvalidConsentConfig]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.MissingCaptureType]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.EmptyScreensBlock]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.MissingScreenConfiguration]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.DuplicateScreenType]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.InvalidSelfieCaptureConfig]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.AgentModeWithEnhancedLiveness]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.InvalidDocumentCaptureConfig]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.MissingMLConfiguration]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.MissingNetworkConfiguration]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.MissingJobType]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.MissingCaptureForPreview]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.InvalidScreenOrder]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.InvalidPartnerScreen]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.ConfigurationBlockFailed]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.InvalidConsentInformation]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.InvalidJobTypeScreenConfig]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Builder.UnusedJobParams]:{category:"BUILDER",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Validation.InvalidInput]:{category:"VALIDATION",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Validation.InvalidState]:{category:"VALIDATION",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.Validation.ConstraintViolation]:{category:"VALIDATION",isRetryable:!1,userMessage:"",suggestedFix:""},[UseSmileIDErrorCode.General.Unknown]:{category:"GENERAL",isRetryable:!1,userMessage:"An unexpected error occurred. Please try again.",suggestedFix:"Contact SmileID support if the issue persists."},[UseSmileIDErrorCode.General.InvalidState]:{category:"GENERAL",isRetryable:!1,userMessage:"Invalid operation state. Please restart the process.",suggestedFix:"Ensure operations are called in the correct order."},[UseSmileIDErrorCode.General.OperationFailed]:{category:"GENERAL",isRetryable:!1,userMessage:"Operation failed. Please try again.",suggestedFix:"Check the error details and retry the operation."}};for(const e of Object.values(s))Object.freeze(e);Object.freeze(s);const r=new Set(Object.values(UseSmileIDErrorCode.Network));export function isRetryableErrorCode(e){return errorCodeDetails(e).isRetryable}export function errorCodeDetails(e){return Object.prototype.hasOwnProperty.call(s,e)?s[e]:s[UseSmileIDErrorCode.General.Unknown]}export function isNetworkErrorCode(e){return r.has(e)}
@@ -96,29 +96,4 @@ export declare class NetworkUnknownException extends UseSmileIDNetworkException
96
96
  readonly errorDetails?: Readonly<Record<string, unknown>>;
97
97
  });
98
98
  }
99
- /**
100
- * Translate axios's catch-all `AxiosError` onto the typed
101
- * [UseSmileIDNetworkException] hierarchy. Repositories call this so
102
- * the raw `AxiosError` never leaks past their boundary — partners can
103
- * branch on `e instanceof NetworkTimeoutException` etc. instead of
104
- * sniffing `error.code` strings.
105
- *
106
- * Maps:
107
- * - `AxiosError.code === "ECONNABORTED"` → [NetworkTimeoutException]
108
- * (axios's signal for both connect and read timeouts).
109
- * - `AxiosError` with no `response` → [NetworkTransportException]
110
- * (DNS / TLS / socket-level failure; request never reached the
111
- * server).
112
- * - `AxiosError` with `response` → [NetworkServerException] carrying
113
- * the wire status code; status routing via [statusToErrorCode]
114
- * covers 401/403/404/408/429/5xx + a generic fallback. A 408 keeps this
115
- * type, with its `statusCode`, and carries `NETWORK_TIMEOUT`.
116
- * - Already-typed [UseSmileIDNetworkException] → pass-through so the
117
- * mapper is safe to call idempotently across retry / wrap paths.
118
- * - Anything else → [NetworkUnknownException] with the underlying
119
- * value preserved as `cause` for triage.
120
- */
121
- export declare function mapAxiosError(error: unknown): UseSmileIDNetworkException;
122
- /** axios's code for a request aborted through a signal or cancel token. */
123
- export declare const CANCELED = "ERR_CANCELED";
124
99
  export {};
@@ -1 +1 @@
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;constructor({cause:t,message:s="Network transport failure.",errorDetails:o,errorCode:n=r.Network.ConnectionFailed}={}){super({message:s,suggestedFix:"Check the device's network connection and verify the configured base URL is reachable.",cause:t,errorDetails:o}),this.errorCode=n}}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===408?r.Network.Timeout: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===CANCELED)return new NetworkTransportException({message:e.message,cause:e,errorCode:r.Network.RequestFailed});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}:{}})}export const CANCELED="ERR_CANCELED";const p="A valid callback_url is required in the request or a default callback URL must be configured in the portal.";
1
+ "use strict";import{UseSmileIDErrorCode as t}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:r,cause:o,message:s,errorDetails:i,errorCode:n}){super({message:s??`HTTP ${r}`,suggestedFix:"Inspect the server response body and retry if the failure is transient.",cause:o,errorDetails:i}),this.statusCode=r,this.errorCode=n??a(r)}}export class NetworkTransportException extends UseSmileIDNetworkException{errorCode;constructor({cause:r,message:o="Network transport failure.",errorDetails:s,errorCode:i=t.Network.ConnectionFailed}={}){super({message:o,suggestedFix:"Check the device's network connection and verify the configured base URL is reachable.",cause:r,errorDetails:s}),this.errorCode=i}}export class NetworkTimeoutException extends UseSmileIDNetworkException{errorCode=t.Network.Timeout;constructor({cause:r,message:o="The request timed out.",errorDetails:s}={}){super({message:o,suggestedFix:"Increase the timeout via `n.timeouts(...)` if appropriate, or retry once connectivity recovers.",cause:r,errorDetails:s})}}export class NetworkResponseParseException extends UseSmileIDNetworkException{errorCode=t.Network.ResponseParseError;constructor({cause:r,message:o="Failed to parse response body.",errorDetails:s}={}){super({message:o,suggestedFix:"Confirm the SDK version matches the backend's response schema.",cause:r,errorDetails:s})}}export class NetworkRequestBuildException extends UseSmileIDNetworkException{errorCode=t.Network.RequestFailed;constructor({cause:r,message:o="Failed to build request.",errorDetails:s}={}){super({message:o,suggestedFix:"Verify the request payload satisfies the multipart / URL contract before submission.",cause:r,errorDetails:s})}}export class NetworkUnknownException extends UseSmileIDNetworkException{errorCode=t.Network.RequestFailed;constructor({cause:r,message:o="Unknown network error.",errorDetails:s}={}){super({message:o,suggestedFix:"Log the wrapped `cause` for triage \u2014 anything reaching this branch represents a gap in error mapping.",cause:r,errorDetails:s})}}function a(e){return e===401?t.Network.Unauthorized:e===403?t.Network.Forbidden:e===404?t.Network.NotFound:e===408?t.Network.Timeout:e===429?t.Network.RateLimit:e>=500&&e<600?t.Network.ServerError:t.Network.RequestFailed}
@@ -1,13 +1,9 @@
1
1
  /**
2
2
  * Network stack types — partner credentials, transport tuning, logging
3
- * controls.
4
- *
5
- * Stub note: the network stack itself is not yet wired (see
6
- * `docs/Architecture.md § Rollout`). The DSL builder accepts these
7
- * values for forward-compatibility — the orchestrator will start
8
- * honouring them when the network/job-submission milestone lands.
3
+ * controls — as the native network client reads them.
9
4
  */
10
- import type { AxiosInstance } from "axios";
5
+ import type { UseSmileIDTestRoute } from "@smileid/usesmileid_bridge/internal";
6
+ import type { UseSmileIDOnRequest, UseSmileIDOnResponse } from "../../data/api/hooks/partner_hooks";
11
7
  import type { JobType } from "./job_type";
12
8
  /**
13
9
  * HTTP log verbosity — progressively reveals more of each request as
@@ -110,19 +106,15 @@ export type RetryConfig = {
110
106
  readonly jitter: number;
111
107
  readonly fixedDelay: number;
112
108
  };
113
- /**
114
- * A request interceptor that hooks into the SDK's axios client. The
115
- * SDK's built-in interceptors (gzip, auth, request-MAC, integrity)
116
- * implement this shape, and partners can supply their own.
117
- */
118
- export interface Interceptor {
119
- /** Wire the interceptor's request/response hooks onto the client. */
120
- attach(client: AxiosInstance): void;
121
- }
122
109
  export type NetworkConfig = {
123
110
  readonly config?: NetworkInnerConfig;
124
111
  readonly timeouts?: TimeoutConfig;
125
112
  readonly cache?: CacheConfig;
126
113
  readonly retry?: RetryConfig;
127
- readonly interceptors?: readonly Interceptor[];
114
+ /** See `interceptors((i) => i.testRoute(…))`. */
115
+ readonly testRoutes?: readonly UseSmileIDTestRoute[];
116
+ /** See `interceptors((i) => i.onRequest(…))`. */
117
+ readonly onRequest?: UseSmileIDOnRequest;
118
+ /** See `interceptors((i) => i.onResponse(…))`. */
119
+ readonly onResponse?: UseSmileIDOnResponse;
128
120
  };
@@ -14,6 +14,15 @@ export type ConsentInformation = {
14
14
  /** URL of the partner's privacy policy shown at consent time. */
15
15
  readonly noticePrivacyPolicyUrl: string;
16
16
  };
17
+ /**
18
+ * The consent a flow that skips submission seals when the partner supplied none: written as `{}`,
19
+ * so the partner can send the consent record beside the package when forwarding it. Compared by
20
+ * value (`isEmptyConsent`), so a copy is still written as `{}`; a supplied consent is validated as
21
+ * granted, so it never equals this one. Internal, not exported from the package.
22
+ */
23
+ export declare const EMPTY_CONSENT: ConsentInformation;
24
+ /** Whether `consent` is `EMPTY_CONSENT` or a copy of it. */
25
+ export declare const isEmptyConsent: (consent: ConsentInformation) => boolean;
17
26
  /**
18
27
  * Subject's personal details, sent as the `user_details` JSON part.
19
28
  * The SDK checks none of these fields: it submits them as given, empty
@@ -1 +1 @@
1
- "use strict";export const RESIDENCY_ID_TYPE="PASSPORT";
1
+ "use strict";export const EMPTY_CONSENT=Object.freeze({granted:!1,grantedAt:"",noticeLanguage:"",noticePrivacyPolicyUrl:""}),isEmptyConsent=e=>!e.granted&&e.grantedAt===""&&e.noticeLanguage===""&&e.noticePrivacyPolicyUrl==="",RESIDENCY_ID_TYPE="PASSPORT";
@@ -48,6 +48,13 @@ export type CapturePerfSnapshot = {
48
48
  readonly wait?: CapturePerfStat;
49
49
  /** The last still's capture-to-result latency. */
50
50
  readonly captureLatencyMs?: number;
51
+ /**
52
+ * How many of the analysed frames kamera reported stalled: held so long the camera had no fresh
53
+ * frame to give.
54
+ */
55
+ readonly analysisStalls: number;
56
+ /** How long the longest of those had been held when kamera reported it; absent without one. */
57
+ readonly longestStallMs?: number;
51
58
  };
52
59
  /**
53
60
  * What one capture attempt measured, as `UseSmileIDDebug.setPerfTraceListener` hands it over: the
@@ -74,6 +81,8 @@ export declare class CapturePerfTrace {
74
81
  private _timeToFirstFrameMs;
75
82
  private _coldStart;
76
83
  private _captureLatencyMs;
84
+ private _analysisStalls;
85
+ private _longestStallMs;
77
86
  constructor(now?: () => number);
78
87
  /** Records `mark` the first time it is reached; a repeat keeps the first. */
79
88
  mark(mark: CapturePerfMark): void;
@@ -1 +1 @@
1
- "use strict";export const CapturePerfMark={screenShown:"screen_shown",cameraStartRequested:"camera_start_requested",cameraRunning:"camera_running",firstFrame:"first_frame",streamingStarted:"streaming_started",firstScanResult:"first_scan_result",captureComplete:"capture_complete",filesReady:"files_ready"};const u=[CapturePerfMark.screenShown,CapturePerfMark.cameraStartRequested,CapturePerfMark.cameraRunning,CapturePerfMark.firstFrame,CapturePerfMark.streamingStarted,CapturePerfMark.firstScanResult,CapturePerfMark.captureComplete,CapturePerfMark.filesReady];export function capturePerfOutcomeContinues(e){return e==="failed"||e==="retake"||e==="timeout"}export class CapturePerfTrace{_now;_startedAt;_marks={};_analysisMs=[];_waitMs=[];_timeToFirstFrameMs;_coldStart;_captureLatencyMs;constructor(t=m){this._now=t,this._startedAt=t(),this._marks[CapturePerfMark.screenShown]=0}mark(t){this._marks[t]===void 0&&(this._marks[t]=Math.max(0,Math.round(this._now()-this._startedAt)))}onMetric(t){switch(t.name){case"firstFrame":if(this._timeToFirstFrameMs!==void 0)return;this.mark(CapturePerfMark.firstFrame),this._timeToFirstFrameMs=t.timeToFirstFrameMs,this._coldStart=t.coldStart;break;case"frameAnalyzed":if(this._marks[CapturePerfMark.streamingStarted]===void 0||this._marks[CapturePerfMark.captureComplete]!==void 0)return;this._analysisMs.push(t.analysisMs),this._waitMs.push(t.waitMs);break;case"captureCompleted":this._captureLatencyMs=t.latencyMs;break}}snapshot(){return{marks:{...this._marks},...this._timeToFirstFrameMs!==void 0?{timeToFirstFrameMs:this._timeToFirstFrameMs}:{},...this._coldStart!==void 0?{coldStart:this._coldStart}:{},...this._analysisMs.length>0?{analysis:n(this._analysisMs)}:{},...this._waitMs.length>0?{wait:n(this._waitMs)}:{},...this._captureLatencyMs!==void 0?{captureLatencyMs:this._captureLatencyMs}:{}}}report(t,s){return{...this.snapshot(),capture:t,outcome:s,line:this.summaryLine(`${t} ${s}`)}}summaryLine(t){const s=this.snapshot(),a=u.filter(r=>s.marks[r]!==void 0).map(r=>`${r}=${s.marks[r]}ms`);return s.timeToFirstFrameMs!==void 0&&a.push(`kamera_first_frame=${s.timeToFirstFrameMs}ms${s.coldStart?"(cold)":""}`),s.analysis&&a.push(`analysis=${c(s.analysis)}`),s.wait&&a.push(`wait=${c(s.wait)}`),s.captureLatencyMs!==void 0&&a.push(`still=${s.captureLatencyMs}ms`),`[UseSmileID perf] ${t} ${a.join(" ")}`}}function m(){const e=globalThis.performance;return e?e.now():Date.now()}function n(e){const t=[...e].sort((s,a)=>s-a);return{count:t.length,p50Ms:i(t,.5),p95Ms:i(t,.95)}}function i(e,t){const s=Math.ceil(t*e.length);return e[Math.min(e.length,Math.max(1,s))-1]??0}function c(e){return`${Math.round(e.p50Ms)}/${Math.round(e.p95Ms)}ms(${e.count})`}
1
+ "use strict";export const CapturePerfMark={screenShown:"screen_shown",cameraStartRequested:"camera_start_requested",cameraRunning:"camera_running",firstFrame:"first_frame",streamingStarted:"streaming_started",firstScanResult:"first_scan_result",captureComplete:"capture_complete",filesReady:"files_ready"};const o=[CapturePerfMark.screenShown,CapturePerfMark.cameraStartRequested,CapturePerfMark.cameraRunning,CapturePerfMark.firstFrame,CapturePerfMark.streamingStarted,CapturePerfMark.firstScanResult,CapturePerfMark.captureComplete,CapturePerfMark.filesReady];export function capturePerfOutcomeContinues(e){return e==="failed"||e==="retake"||e==="timeout"}export class CapturePerfTrace{_now;_startedAt;_marks={};_analysisMs=[];_waitMs=[];_timeToFirstFrameMs;_coldStart;_captureLatencyMs;_analysisStalls=0;_longestStallMs;constructor(t=u){this._now=t,this._startedAt=t(),this._marks[CapturePerfMark.screenShown]=0}mark(t){this._marks[t]===void 0&&(this._marks[t]=Math.max(0,Math.round(this._now()-this._startedAt)))}onMetric(t){switch(t.name){case"firstFrame":if(this._timeToFirstFrameMs!==void 0)return;this.mark(CapturePerfMark.firstFrame),this._timeToFirstFrameMs=t.timeToFirstFrameMs,this._coldStart=t.coldStart;break;case"frameAnalyzed":if(this._marks[CapturePerfMark.streamingStarted]===void 0||this._marks[CapturePerfMark.captureComplete]!==void 0)return;this._analysisMs.push(t.analysisMs),this._waitMs.push(t.waitMs);break;case"captureCompleted":this._captureLatencyMs=t.latencyMs;break;case"analysisStalled":if(this._marks[CapturePerfMark.streamingStarted]===void 0||this._marks[CapturePerfMark.captureComplete]!==void 0)return;this._analysisStalls+=1,this._longestStallMs=Math.max(this._longestStallMs??0,t.openForMs);break}}snapshot(){return{marks:{...this._marks},...this._timeToFirstFrameMs!==void 0?{timeToFirstFrameMs:this._timeToFirstFrameMs}:{},...this._coldStart!==void 0?{coldStart:this._coldStart}:{},...this._analysisMs.length>0?{analysis:n(this._analysisMs)}:{},...this._waitMs.length>0?{wait:n(this._waitMs)}:{},...this._captureLatencyMs!==void 0?{captureLatencyMs:this._captureLatencyMs}:{},analysisStalls:this._analysisStalls,...this._longestStallMs!==void 0?{longestStallMs:this._longestStallMs}:{}}}report(t,s){return{...this.snapshot(),capture:t,outcome:s,line:this.summaryLine(`${t} ${s}`)}}summaryLine(t){const s=this.snapshot(),a=o.filter(r=>s.marks[r]!==void 0).map(r=>`${r}=${s.marks[r]}ms`);return s.timeToFirstFrameMs!==void 0&&a.push(`kamera_first_frame=${s.timeToFirstFrameMs}ms${s.coldStart?"(cold)":""}`),s.analysis&&a.push(`analysis=${l(s.analysis)}`),s.wait&&a.push(`wait=${l(s.wait)}`),s.captureLatencyMs!==void 0&&a.push(`still=${s.captureLatencyMs}ms`),s.longestStallMs!==void 0&&a.push(`stalls=${s.analysisStalls} longest_stall=${s.longestStallMs}ms`),`[UseSmileID perf] ${t} ${a.join(" ")}`}}function u(){const e=globalThis.performance;return e?e.now():Date.now()}function n(e){const t=[...e].sort((s,a)=>s-a);return{count:t.length,p50Ms:i(t,.5),p95Ms:i(t,.95)}}function i(e,t){const s=Math.ceil(t*e.length);return e[Math.min(e.length,Math.max(1,s))-1]??0}function l(e){return`${Math.round(e.p50Ms)}/${Math.round(e.p95Ms)}ms(${e.count})`}
@@ -0,0 +1,40 @@
1
+ import type { SealedJobRequest } from "../model/sealed_job_request";
2
+ import type { JobForm } from "../model/job_form";
3
+ import { NativeNetworkClient } from "@smileid/usesmileid_bridge/internal";
4
+ import { type NetworkConfig } from "../../core/models/network_config";
5
+ /**
6
+ * Sends job submissions through the native network client: the same OkHttp chain, request signing
7
+ * and attestation the native SDKs use.
8
+ *
9
+ * The native client runs the partner's retry policy and stamps `network_retries` on each retry. Its
10
+ * failures come back as `UseSmileIDNetworkException`s.
11
+ */
12
+ export declare class BridgeSubmissions {
13
+ private readonly _client;
14
+ private readonly _routed;
15
+ private constructor();
16
+ /**
17
+ * Configures the native client for `config`: the partner's `onRequest`, `onResponse` and
18
+ * `onTokenExpired`, and the SDK's logging. `routePort` is the testing package's server, read once by the caller (`testRoutePort`); null
19
+ * when the caller checked and none is registered.
20
+ */
21
+ static configure(config: NetworkConfig, client?: NativeNetworkClient, routePort?: number | null): BridgeSubmissions;
22
+ /** The `network { }` block as the native client reads it. */
23
+ static wireConfig(config: NetworkConfig): Record<string, unknown>;
24
+ /** Opens the connection the submission will use; a routed client has no Smile ID connection to open. */
25
+ warm(): void;
26
+ /** Sends `form` to `path` and answers the response body. */
27
+ submit(path: string, form: JobForm): Promise<Record<string, unknown>>;
28
+ /**
29
+ * Signs and seals `form` for `path` through the native client, as a skipped submission
30
+ * (`skipApiSubmission`) is. The package crosses the bridge as a file, which goes once it is read.
31
+ */
32
+ seal(path: string, form: JobForm): Promise<SealedJobRequest>;
33
+ }
34
+ /**
35
+ * A job the native client signed and sealed instead of sending, carried out of the API call.
36
+ */
37
+ export declare class BridgeSealed extends Error {
38
+ readonly sealed: SealedJobRequest;
39
+ constructor(sealed: SealedJobRequest);
40
+ }
@@ -0,0 +1 @@
1
+ "use strict";import{Directory as S,File as w,Paths as x}from"expo-file-system";import{filePath as k}from"../util/file_path";import{sourceSdkIdentifier as b}from"@smileid/usesmileid_bridge";import{NativeNetworkClient as y,NativeNetworkError as E,toNativeNetworkError as D}from"@smileid/usesmileid_bridge/internal";import{usesSandbox as C}from"./environment";import{testRoutePort as M}from"./test_route";import{LogLevel as d,RetryStrategy as m}from"../../core/models/network_config";import{decodeSecurityPolicyBitCode as _}from"../util/use_smile_id_token_decoder";import{NetworkServerException as T,NetworkTimeoutException as v,NetworkTransportException as I}from"../../core/exception/use_smile_id_network_exception";import{UseSmileIDErrorCode as c}from"../../core/exception/use_smile_id_error_code";const O="12.3.0";export class BridgeSubmissions{_client;_routed;constructor(t,n){this._client=t,this._routed=n}static configure(t,n=y.shared(),i=M(t)??null){const a=t.config?.logging,o=t.config?.onTokenExpired,{onRequest:s,onResponse:l}=t,h={...BridgeSubmissions.wireConfig(t),...i===null?{}:{testRoute:{port:i}}},N={onRequest:s?r=>s({method:String(r.method??""),url:String(r.url??""),headers:p(r.headers)}):void 0,onResponse:l?r=>l({method:String(r.method??""),url:String(r.url??""),status:Number(r.status??0),durationMillis:Number(r.durationMillis??0),headers:p(r.headers)}):void 0,onTokenExpired:o,onLog:a?.enabled&&a.level!==d.none?r=>console.log(`[UseSmileID] ${r}`):void 0};try{n.configure(h,N)}catch(r){throw D(r)}return new BridgeSubmissions(n,i!==null)}static wireConfig(t){const n=t.config,i=n?.token??"",a=t.timeouts,o=n?.logging;return{partnerId:n?.partnerConfig?.partnerId??"",environment:C(n?.partnerConfig)?"sandbox":"production",token:i,sourceSdk:b(),sourceSdkVersion:O,policy:_(i)??null,timeouts:{connectSeconds:a?.connect??60,readSeconds:a?.read??60,writeSeconds:a?.write??60,callSeconds:a?.call??120},retry:j(t.retry),cache:{enabled:t.cache?.enabled??!0,maxSizeBytes:t.cache?.maxSize??50*1024*1024},logging:{enabled:o?.enabled??!0,level:(o?.level??d.basic).toUpperCase(),redactHeaders:o?.redactHeaders??[]}}}warm(){this._routed||this._client.warm()}async submit(t,n){try{return await this._client.submit({path:t,parts:n.toWire()})}catch(i){throw g(i)}}async seal(t,n){const i=new S(x.cache,`si_sealed_${Date.now()}_${Math.random().toString(36).slice(2)}`);i.create({intermediates:!0});try{const a=new w(i,"package.json");try{await this._client.seal({path:t,parts:n.toWire()},k(a.uri))}catch(s){throw g(s)}const o=JSON.parse(await a.text());return{headers:Object.fromEntries(Object.entries(o.headers??{}).map(([s,l])=>[s,String(l)])),encryptedPackage:o.encryptedPackage,packageNonce:o.packageNonce,packageTag:o.packageTag}}finally{i.exists&&i.delete()}}}function g(e){if(!(e instanceof E))return e;const t=R.find(n=>n===e.code);return e.status!==void 0?new T({statusCode:e.status,message:e.message,cause:e,...t===c.Network.CallbackUrlRequired?{errorCode:t}:{}}):t===c.Network.Timeout?new v({message:e.message,cause:e}):new I({message:e.message,cause:e,errorCode:t??(e.retryable===!0?c.Network.ConnectionFailed:c.Network.RequestFailed)})}const R=Object.values(c.Network);export class BridgeSealed extends Error{sealed;constructor(t){super("Sealed by the native client"),this.sealed=t,this.name="BridgeSealed"}}function p(e){const t={};if(e===null||typeof e!="object")return t;for(const[n,i]of Object.entries(e))t[n]=Array.isArray(i)?i.map(String).join(", "):String(i);return t}function j(e){if(e===void 0||e.strategy===m.none)return{strategy:"none"};const t=Number.isNaN(e.maxAttempts)?1:Math.min(A,Math.max(1,Math.ceil(e.maxAttempts)));return e.strategy===m.fixed?{strategy:"fixed",maxAttempts:t,fixedDelaySeconds:u(e.fixedDelay)}:{strategy:"exponential",maxAttempts:t,initialDelaySeconds:u(e.initialDelay),multiplier:P(e),maxDelaySeconds:f(e),jitter:Number.isNaN(e.jitter)?0:Math.min(1,Math.max(0,e.jitter))}}const A=2**31-1,F=86400;function f(e){return e.maxDelay===Number.POSITIVE_INFINITY?F:u(e.maxDelay)}function u(e){return Number.isFinite(e)?Math.max(0,e):0}function P(e){const t=u(e.initialDelay);return t===0||Number.isNaN(e.multiplier)?1:Number.isFinite(e.multiplier)?Math.max(0,e.multiplier):e.multiplier>0?Math.max(1,f(e)/t):0}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Whether a partner configuration talks to the sandbox. One owner for the rule, so the native
3
+ * client's environment and the test-route check can't disagree: an unset
4
+ * `useSandbox` means the sandbox.
5
+ */
6
+ export declare function usesSandbox(partnerConfig: {
7
+ readonly useSandbox?: boolean;
8
+ } | undefined): boolean;
@@ -0,0 +1 @@
1
+ "use strict";export function usesSandbox(e){return e?.useSandbox??!0}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A request the SDK is about to send, as `onRequest` sees it: before the SDK stamps its token and
3
+ * signs it. The body never leaves the SDK.
4
+ */
5
+ export type UseSmileIDRequestInfo = {
6
+ readonly method: string;
7
+ readonly url: string;
8
+ readonly headers: Readonly<Record<string, string>>;
9
+ };
10
+ /**
11
+ * A response the SDK received, as `onResponse` sees it, for logging: its status, how long the
12
+ * request took, and its headers with credentials and cookies removed.
13
+ */
14
+ export type UseSmileIDResponseInfo = {
15
+ readonly method: string;
16
+ readonly url: string;
17
+ readonly status: number;
18
+ readonly durationMillis: number;
19
+ readonly headers: Readonly<Record<string, string>>;
20
+ };
21
+ /**
22
+ * Called before each request is sent, on every attempt and on the resend after a token refresh.
23
+ * Answers the headers to add; only tracing and correlation headers and `x-partner-*` are sent.
24
+ */
25
+ export type UseSmileIDOnRequest = (request: UseSmileIDRequestInfo) => Promise<Record<string, string>>;
26
+ /** Called after each response, for logging. */
27
+ export type UseSmileIDOnResponse = (response: UseSmileIDResponseInfo) => void;
@@ -0,0 +1 @@
1
+ "use strict";export{};