@smileid/web-components 11.4.1 → 11.4.3

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 (33) hide show
  1. package/dist/esm/{DocumentCaptureScreens-wvJcTVkA.js → DocumentCaptureScreens-D1oMAv4n.js} +4 -4
  2. package/dist/esm/{DocumentCaptureScreens-wvJcTVkA.js.map → DocumentCaptureScreens-D1oMAv4n.js.map} +1 -1
  3. package/dist/esm/{EndUserConsent-BXvS7t8z.js → EndUserConsent-D26UoVk5.js} +3 -3
  4. package/dist/esm/{EndUserConsent-BXvS7t8z.js.map → EndUserConsent-D26UoVk5.js.map} +1 -1
  5. package/dist/esm/{Navigation-BRFmg7s1.js → Navigation-nvehze1F.js} +2 -2
  6. package/dist/esm/{Navigation-BRFmg7s1.js.map → Navigation-nvehze1F.js.map} +1 -1
  7. package/dist/esm/{SelfieCaptureScreens-BkJBfzHv.js → SelfieCaptureScreens-CC-y0CpT.js} +1900 -1794
  8. package/dist/esm/SelfieCaptureScreens-CC-y0CpT.js.map +1 -0
  9. package/dist/esm/{TotpConsent-Cn2DkVza.js → TotpConsent-owUOdKzP.js} +2 -2
  10. package/dist/esm/{TotpConsent-Cn2DkVza.js.map → TotpConsent-owUOdKzP.js.map} +1 -1
  11. package/dist/esm/combobox.js +1 -1
  12. package/dist/esm/document.js +1 -1
  13. package/dist/esm/end-user-consent.js +1 -1
  14. package/dist/esm/{index-DBUdxnp9.js → index-5Nn2kzHI.js} +4 -4
  15. package/dist/esm/{index-DBUdxnp9.js.map → index-5Nn2kzHI.js.map} +1 -1
  16. package/dist/esm/localisation.js +1 -1
  17. package/dist/esm/main.js +6 -6
  18. package/dist/esm/navigation.js +1 -1
  19. package/dist/esm/{package-Dax8ezDK.js → package-BxstV9r_.js} +3 -3
  20. package/dist/esm/{package-Dax8ezDK.js.map → package-BxstV9r_.js.map} +1 -1
  21. package/dist/esm/selfie.js +1 -1
  22. package/dist/esm/smart-camera-web.js +5 -5
  23. package/dist/esm/totp-consent.js +1 -1
  24. package/dist/smart-camera-web.js +61 -52
  25. package/dist/smart-camera-web.js.map +1 -1
  26. package/dist/types/main.d.ts +4 -1
  27. package/lib/components/selfie/src/selfie-capture-wrapper/SelfieCaptureWrapper.tsx +113 -8
  28. package/lib/components/selfie/src/smartselfie-capture/SmartSelfieCapture.tsx +72 -39
  29. package/lib/components/selfie/src/smartselfie-capture/hooks/useCamera.ts +12 -0
  30. package/lib/components/selfie/src/smartselfie-capture/utils/mediapipeManager.ts +65 -0
  31. package/lib/components/signature-pad/package.json +2 -2
  32. package/package.json +10 -1
  33. package/dist/esm/SelfieCaptureScreens-BkJBfzHv.js.map +0 -1
@@ -38,6 +38,8 @@ declare class ComboboxRoot extends HTMLElement {
38
38
  declare class ComboboxTrigger extends HTMLElement {
39
39
  handleKeyUp(event: any): void;
40
40
  handleKeyDown(event: any): void;
41
+ handleInput(event: any): void;
42
+ handleChange(event: any): void;
41
43
  handleSelection(event: any): void;
42
44
  toggleExpansionState(): void;
43
45
  get type(): string;
@@ -87,13 +89,13 @@ export declare class DocumentCaptureScreens extends HTMLElement {
87
89
  setUpEventListeners(): void;
88
90
  _publishSelectedImages(): void;
89
91
  get hideInstructions(): boolean;
90
- get autoCapture(): boolean;
91
92
  get hideBackOfId(): boolean;
92
93
  get showNavigation(): "" | "show-navigation";
93
94
  get title(): string;
94
95
  get documentCaptureModes(): string;
95
96
  get documentType(): string;
96
97
  get hideAttribution(): "" | "hide-attribution";
98
+ get newInstructions(): boolean;
97
99
  get themeColor(): string;
98
100
  handleBackEvents(): void;
99
101
  handleCloseEvents(): void;
@@ -329,6 +331,7 @@ export declare class SmartCameraWeb extends HTMLElement {
329
331
  get isPortraitCaptureView(): boolean;
330
332
  get hideInstructions(): "" | "hide-instructions";
331
333
  get hideBackOfId(): "" | "hide-back-of-id";
334
+ get newInstructions(): "" | "new-instructions";
332
335
  get showNavigation(): "" | "show-navigation";
333
336
  get hideBackToHost(): "" | "hide-back";
334
337
  get allowAgentMode(): string;
@@ -9,7 +9,25 @@ import SmartSelfieCapture from '../smartselfie-capture/SmartSelfieCapture';
9
9
  // Legacy web component fallback (used when Mediapipe isn't available)
10
10
  import '../selfie-capture/SelfieCapture';
11
11
  // Mediapipe loader/manager used by SmartSelfieCapture
12
- import { getMediapipeInstance } from '../smartselfie-capture/utils/mediapipeManager';
12
+ import {
13
+ getMediapipeInstance,
14
+ UnsupportedMediapipeEnvironmentError,
15
+ } from '../smartselfie-capture/utils/mediapipeManager';
16
+
17
+ // Minimal typing for the optional Sentry SDK that host pages may expose on
18
+ // `window`. We only depend on `captureException`, so keep the surface tight.
19
+ // Sentry tag values are expected to be strings, so the type enforces that.
20
+ type SentryTags = Record<string, string>;
21
+ declare global {
22
+ interface Window {
23
+ Sentry?: {
24
+ captureException: (
25
+ error: unknown,
26
+ context?: { tags?: SentryTags },
27
+ ) => void;
28
+ };
29
+ }
30
+ }
13
31
 
14
32
  interface Props {
15
33
  timeout?: number;
@@ -29,6 +47,12 @@ interface Props {
29
47
 
30
48
  const DEFAULT_MEDIAPIPE_WAIT_MS = 90 * 1000; // For when legacy fallback is NOT allowed, we wait the full 90s for mediapipe to load before showing an error.
31
49
  const DEFAULT_WAIT_MS = 20 * 1000; // default for when legacy fallback is allowed we wait for 20s
50
+ // Cap retries on transient init failures so we don't spin forever, while still
51
+ // allowing recovery from short-lived issues (e.g. CDN hiccups while the
52
+ // wrapper is preloading in a hidden state). Retries are spaced with
53
+ // exponential backoff (base * 2^(attempt-1)) so we don't hammer the CDN.
54
+ const MAX_MEDIAPIPE_INIT_ATTEMPTS = 3;
55
+ const MEDIAPIPE_RETRY_BASE_DELAY_MS = 500;
32
56
 
33
57
  // Wrapper component that decides whether to use the modern
34
58
  // SmartSelfieCapture (Mediapipe-based) or fallback to the legacy `selfie-capture`
@@ -73,29 +97,110 @@ const SelfieCaptureWrapper: FunctionComponent<Props> = ({
73
97
  const [loadingProgress, setLoadingProgress] = useState(isCypress ? 100 : 0);
74
98
  const [initialSessionCompleted, setInitialSessionCompleted] = useState(false);
75
99
  const [mediapipeLoading, setMediapipeLoading] = useState(false);
100
+ // `unsupportedEnvironment` is a permanent, one-shot signal: we know
101
+ // MediaPipe cannot run here, so stop trying.
102
+ const [unsupportedEnvironment, setUnsupportedEnvironment] = useState(false);
103
+ // Bounded retry counter for transient init failures.
104
+ const [mediapipeInitAttempts, setMediapipeInitAttempts] = useState(0);
105
+ // Dedup flag so we only report a given init failure to Sentry once per
106
+ // wrapper instance, even if we end up retrying.
107
+ const [mediapipeInitReported, setMediapipeInitReported] = useState(false);
76
108
  const [usingSelfieCapture, setUsingSelfieCapture] = useState(false);
77
109
 
78
- // Attempt to load Mediapipe (once). If Mediapipe is already ready, loading,
79
- // or running under Cypress, skip the attempt. This side-effect flips
80
- // mediapipeReady/mediapipeLoading flags which control which component is used.
110
+ // Attempt to load Mediapipe (with a small bounded retry budget). If
111
+ // Mediapipe is already ready, currently loading, the environment is
112
+ // definitively unsupported, we've exhausted our retry budget, or we're
113
+ // running under Cypress, skip the attempt. On transient failure we wait
114
+ // (exponential backoff) before allowing the effect to re-run.
81
115
  useEffect(() => {
82
- if (mediapipeReady || mediapipeLoading || isCypress) return;
116
+ if (
117
+ mediapipeReady ||
118
+ mediapipeLoading ||
119
+ unsupportedEnvironment ||
120
+ mediapipeInitAttempts >= MAX_MEDIAPIPE_INIT_ATTEMPTS ||
121
+ isCypress
122
+ )
123
+ return undefined;
124
+
125
+ let cancelled = false;
126
+ let retryTimeoutId: ReturnType<typeof setTimeout> | null = null;
83
127
 
84
128
  const loadMediapipe = async () => {
85
129
  setMediapipeLoading(true);
130
+ const attemptNumber = mediapipeInitAttempts + 1;
131
+ setMediapipeInitAttempts(attemptNumber);
86
132
  try {
87
133
  await getMediapipeInstance();
134
+ if (cancelled) return;
88
135
  setMediapipeReady(true);
136
+ setMediapipeLoading(false);
89
137
  } catch (error) {
138
+ if (cancelled) return;
90
139
  // Loading failed; we'll fall back to the legacy selfie-capture component
91
- // after the loadingProgress reaches 100%.
140
+ // after the loadingProgress reaches 100% (or sooner for definitively
141
+ // unsupported environments — see below).
92
142
  console.error('Failed to load Mediapipe:', error);
143
+ const isUnsupportedEnvironment =
144
+ error instanceof UnsupportedMediapipeEnvironmentError;
145
+ // Report to Sentry (when the host page has exposed it on window) so we
146
+ // can observe how often users land on the fallback path and which
147
+ // environments are affected. Dedup so retries don't flood Sentry.
148
+ if (!mediapipeInitReported) {
149
+ setMediapipeInitReported(true);
150
+ window.Sentry?.captureException(error, {
151
+ tags: {
152
+ area: 'mediapipe_init',
153
+ mediapipe_unsupported_environment: isUnsupportedEnvironment
154
+ ? 'true'
155
+ : 'false',
156
+ },
157
+ });
158
+ }
159
+ // When the environment definitively cannot run MediaPipe (e.g. no
160
+ // WebAssembly reftypes support), there is no point retrying or keeping
161
+ // the user staring at the loading spinner for the full countdown —
162
+ // mark as unsupported and short-circuit to the fallback decision
163
+ // immediately.
164
+ if (isUnsupportedEnvironment) {
165
+ setUnsupportedEnvironment(true);
166
+ setLoadingProgress(100);
167
+ setMediapipeLoading(false);
168
+ return;
169
+ }
170
+ // Transient failure: wait with exponential backoff before allowing the
171
+ // effect to re-run by flipping mediapipeLoading back to false. If
172
+ // we've exhausted our retry budget, just release the loading flag so
173
+ // the countdown / fallback UI can proceed.
174
+ const hasRetriesLeft = attemptNumber < MAX_MEDIAPIPE_INIT_ATTEMPTS;
175
+ if (!hasRetriesLeft) {
176
+ setMediapipeLoading(false);
177
+ return;
178
+ }
179
+ const backoffMs =
180
+ MEDIAPIPE_RETRY_BASE_DELAY_MS * 2 ** (attemptNumber - 1);
181
+ retryTimeoutId = setTimeout(() => {
182
+ retryTimeoutId = null;
183
+ if (cancelled) return;
184
+ setMediapipeLoading(false);
185
+ }, backoffMs);
93
186
  }
94
- setMediapipeLoading(false);
95
187
  };
96
188
 
97
189
  loadMediapipe();
98
- }, [mediapipeReady, mediapipeLoading]);
190
+
191
+ return () => {
192
+ cancelled = true;
193
+ if (retryTimeoutId !== null) {
194
+ clearTimeout(retryTimeoutId);
195
+ }
196
+ };
197
+ }, [
198
+ mediapipeReady,
199
+ mediapipeLoading,
200
+ unsupportedEnvironment,
201
+ mediapipeInitAttempts,
202
+ mediapipeInitReported,
203
+ ]);
99
204
 
100
205
  // When using the loading countdown (startCountdown), increment the
101
206
  // visible loading progress. This is only used while mediapipe hasn't
@@ -3,6 +3,7 @@ import register from 'preact-custom-element';
3
3
  import type { FunctionComponent } from 'preact';
4
4
 
5
5
  import { getBoolProp } from '../../../../utils/props';
6
+ import { translate } from '../../../../domain/localisation';
6
7
  import { useFaceCapture, useCamera } from './hooks';
7
8
  import { CameraPreview } from './components/CameraPreview';
8
9
  import { AlertDisplay } from './components/AlertDisplay';
@@ -61,8 +62,8 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
61
62
  getFacingMode: () => camera.facingMode,
62
63
  });
63
64
 
64
- useEffect(() => {
65
- const initializeCamera = async () => {
65
+ const initializeCamera = async () => {
66
+ try {
66
67
  await camera.startCamera(initialFacingMode, (cameraName) => {
67
68
  const smartCameraWeb = document.querySelector('smart-camera-web');
68
69
  smartCameraWeb?.dispatchEvent(
@@ -71,15 +72,20 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
71
72
  }),
72
73
  );
73
74
  });
74
- await camera.checkAgentSupport();
75
- await faceCapture.initializeFaceLandmarker();
75
+ } catch {
76
+ // startCamera already set cameraError; surface UI and skip downstream init
77
+ return;
78
+ }
79
+ await camera.checkAgentSupport();
80
+ await faceCapture.initializeFaceLandmarker();
76
81
 
77
- setTimeout(() => {
78
- faceCapture.setupCanvas();
79
- faceCapture.startDetectionLoop();
80
- }, 500);
81
- };
82
+ setTimeout(() => {
83
+ faceCapture.setupCanvas();
84
+ faceCapture.startDetectionLoop();
85
+ }, 500);
86
+ };
82
87
 
88
+ useEffect(() => {
83
89
  camera.registerCameraSwitchCallback(() => {
84
90
  try {
85
91
  faceCapture.resetFaceDetectionState();
@@ -142,39 +148,57 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
142
148
  <smileid-navigation ref={navigationRef} theme-color={themeColor} />
143
149
  )}
144
150
 
145
- <CameraPreview
146
- videoRef={camera.videoRef}
147
- canvasRef={canvasRef}
148
- facingMode={camera.facingMode}
149
- progress={
150
- faceCapture.capturesTaken.value > 0
151
- ? faceCapture.capturesTaken.value / faceCapture.totalCaptures.value
152
- : 0
153
- }
154
- interval={interval}
155
- themeColor={themeColor}
156
- />
157
-
158
- <AlertDisplay alertTitle={faceCapture.alertTitle.value} />
159
-
160
- {!faceCapture.isCapturing.value &&
161
- !faceCapture.hasFinishedCapture.value && (
162
- <CaptureControls
163
- isCapturing={faceCapture.isCapturing.value}
164
- hasFinishedCapture={faceCapture.hasFinishedCapture.value}
165
- isReadyToCapture={faceCapture.isReadyToCapture.value}
166
- captureButtonFallbackEnabled={
167
- faceCapture.captureButtonFallbackEnabled.value
168
- }
169
- allowAgentMode={allowAgentMode}
170
- agentSupported={camera.agentSupported}
171
- showAgentModeForTests={showAgentModeForTests}
151
+ {camera.cameraError ? (
152
+ <div className="camera-error" role="alert">
153
+ <p>{camera.cameraError}</p>
154
+ <button
155
+ type="button"
156
+ className="btn-primary"
157
+ onClick={() => {
158
+ initializeCamera();
159
+ }}
160
+ >
161
+ {translate('camera.error.retry')}
162
+ </button>
163
+ </div>
164
+ ) : (
165
+ <>
166
+ <CameraPreview
167
+ videoRef={camera.videoRef}
168
+ canvasRef={canvasRef}
172
169
  facingMode={camera.facingMode}
170
+ progress={
171
+ faceCapture.capturesTaken.value > 0
172
+ ? faceCapture.capturesTaken.value /
173
+ faceCapture.totalCaptures.value
174
+ : 0
175
+ }
176
+ interval={interval}
173
177
  themeColor={themeColor}
174
- onStartCapture={faceCapture.startCapture}
175
- onSwitchCamera={camera.switchCamera}
176
178
  />
177
- )}
179
+
180
+ <AlertDisplay alertTitle={faceCapture.alertTitle.value} />
181
+
182
+ {!faceCapture.isCapturing.value &&
183
+ !faceCapture.hasFinishedCapture.value && (
184
+ <CaptureControls
185
+ isCapturing={faceCapture.isCapturing.value}
186
+ hasFinishedCapture={faceCapture.hasFinishedCapture.value}
187
+ isReadyToCapture={faceCapture.isReadyToCapture.value}
188
+ captureButtonFallbackEnabled={
189
+ faceCapture.captureButtonFallbackEnabled.value
190
+ }
191
+ allowAgentMode={allowAgentMode}
192
+ agentSupported={camera.agentSupported}
193
+ showAgentModeForTests={showAgentModeForTests}
194
+ facingMode={camera.facingMode}
195
+ themeColor={themeColor}
196
+ onStartCapture={faceCapture.startCapture}
197
+ onSwitchCamera={camera.switchCamera}
198
+ />
199
+ )}
200
+ </>
201
+ )}
178
202
 
179
203
  {/* @ts-expect-error -- preact-custom-element doesn't have proper types for refs */}
180
204
  {!hideAttribution && <powered-by-smile-id />}
@@ -227,6 +251,15 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
227
251
  padding: 1rem;
228
252
  font-family: sans-serif;
229
253
  }
254
+
255
+ .camera-error {
256
+ margin-top: 1.5rem;
257
+ padding: 1rem 1.5rem;
258
+ color: #b00020;
259
+ text-align: center;
260
+ font-size: 1rem;
261
+ font-weight: 500;
262
+ }
230
263
  `}</style>
231
264
  </div>
232
265
  );
@@ -1,10 +1,12 @@
1
1
  import { useRef, useState, useEffect } from 'preact/hooks';
2
+ import SmartCamera from '../../../../../domain/camera/src/SmartCamera';
2
3
 
3
4
  export const useCamera = (initialFacingMode: CameraFacingMode = 'user') => {
4
5
  const videoRef = useRef<HTMLVideoElement>(null);
5
6
  const streamRef = useRef<MediaStream | null>(null);
6
7
  const [facingMode, setFacingMode] = useState(initialFacingMode);
7
8
  const [agentSupported, setAgentSupported] = useState(false);
9
+ const [cameraError, setCameraError] = useState<string | null>(null);
8
10
  const onCameraSwitchCallbackRef = useRef<(() => void) | null>(null);
9
11
  const isSwitchingCameraRef = useRef(false);
10
12
  const timeoutIdsRef = useRef<Set<NodeJS.Timeout>>(new Set());
@@ -63,6 +65,7 @@ export const useCamera = (initialFacingMode: CameraFacingMode = 'user') => {
63
65
  video: { facingMode: targetFacingMode || facingMode },
64
66
  });
65
67
  streamRef.current = stream;
68
+ setCameraError(null);
66
69
 
67
70
  const track = stream.getVideoTracks()[0];
68
71
  const settings = track.getSettings();
@@ -94,9 +97,15 @@ export const useCamera = (initialFacingMode: CameraFacingMode = 'user') => {
94
97
  }
95
98
  } catch (error) {
96
99
  console.error('Failed to start camera:', error);
100
+ setCameraError(SmartCamera.handleCameraError(error as Error));
101
+ throw error;
97
102
  }
98
103
  };
99
104
 
105
+ const retryCamera = async () => {
106
+ await startCamera(facingMode);
107
+ };
108
+
100
109
  const switchCamera = async () => {
101
110
  const newFacingMode = facingMode === 'user' ? 'environment' : 'user';
102
111
  isSwitchingCameraRef.current = true;
@@ -118,6 +127,7 @@ export const useCamera = (initialFacingMode: CameraFacingMode = 'user') => {
118
127
  await startCamera(previousFacingMode);
119
128
  } catch (restoreError) {
120
129
  console.error('Failed to restore previous camera:', restoreError);
130
+ setCameraError(SmartCamera.handleCameraError(restoreError as Error));
121
131
  }
122
132
  }
123
133
  };
@@ -229,7 +239,9 @@ export const useCamera = (initialFacingMode: CameraFacingMode = 'user') => {
229
239
  streamRef,
230
240
  facingMode,
231
241
  agentSupported,
242
+ cameraError,
232
243
  startCamera,
244
+ retryCamera,
233
245
  switchCamera,
234
246
  checkAgentSupport,
235
247
  stopCamera,
@@ -67,10 +67,61 @@ declare global {
67
67
  instance: FaceLandmarker | null;
68
68
  loading: Promise<FaceLandmarker> | null;
69
69
  loaded: boolean;
70
+ supportsWasmReftypes?: boolean;
70
71
  };
71
72
  }
72
73
  }
73
74
 
75
+ /**
76
+ * @description Detects whether the current runtime supports the WebAssembly
77
+ * reference-types proposal (the `externref` value type). MediaPipe Tasks
78
+ * Vision ships a .wasm that uses `externref`; on older engines (e.g. Chrome
79
+ * < 96, Safari < 15, Firefox < 79) `WebAssembly.instantiate` throws
80
+ * `CompileError: invalid value type 'externref'`. We probe support once with
81
+ * `WebAssembly.validate` against a tiny module whose only feature is an
82
+ * `externref`-typed global so callers can short-circuit and fall back to the
83
+ * legacy selfie capture flow instead of triggering an unhandled rejection.
84
+ * @returns {boolean} True if the runtime accepts reftypes / externref.
85
+ */
86
+ const supportsWasmReftypes = (): boolean => {
87
+ if (typeof WebAssembly === 'undefined' || !WebAssembly.validate) {
88
+ return false;
89
+ }
90
+
91
+ try {
92
+ // Minimal module: magic + version + global section with one externref
93
+ // global (value type 0x6f) initialized to ref.null extern (0xd0 0x6f 0x0b).
94
+ const bytes = new Uint8Array([
95
+ 0x00,
96
+ 0x61,
97
+ 0x73,
98
+ 0x6d, // \0asm magic
99
+ 0x01,
100
+ 0x00,
101
+ 0x00,
102
+ 0x00, // version 1
103
+ 0x06,
104
+ 0x06,
105
+ 0x01, // global section, 6 bytes, 1 global
106
+ 0x6f,
107
+ 0x00, // externref, immutable
108
+ 0xd0,
109
+ 0x6f,
110
+ 0x0b, // ref.null extern; end
111
+ ]);
112
+ return WebAssembly.validate(bytes);
113
+ } catch {
114
+ return false;
115
+ }
116
+ };
117
+
118
+ export class UnsupportedMediapipeEnvironmentError extends Error {
119
+ constructor(message: string) {
120
+ super(message);
121
+ this.name = 'UnsupportedMediapipeEnvironmentError';
122
+ }
123
+ }
124
+
74
125
  /**
75
126
  * @description Reads system architecture hints from User-Agent Client Hints.
76
127
  * @returns {Promise<string | null>} Lower-cased hint string or null when hints are unavailable.
@@ -175,6 +226,19 @@ export const getMediapipeInstance = async (): Promise<FaceLandmarker> => {
175
226
  return mediapipeGlobal.loading;
176
227
  }
177
228
 
229
+ // Fail fast on engines that don't support WebAssembly reftypes/externref.
230
+ // The MediaPipe Tasks Vision .wasm uses externref globals; instantiating it
231
+ // on older browsers throws an unhandled `CompileError`. We detect once and
232
+ // cache the result so callers fall back to the legacy capture flow.
233
+ if (mediapipeGlobal.supportsWasmReftypes === undefined) {
234
+ mediapipeGlobal.supportsWasmReftypes = supportsWasmReftypes();
235
+ }
236
+ if (!mediapipeGlobal.supportsWasmReftypes) {
237
+ throw new UnsupportedMediapipeEnvironmentError(
238
+ 'WebAssembly reference types (externref) are not supported in this browser; MediaPipe Tasks Vision cannot be loaded.',
239
+ );
240
+ }
241
+
178
242
  mediapipeGlobal.loading = (async () => {
179
243
  try {
180
244
  const vision = await FilesetResolver.forVisionTasks(
@@ -212,4 +276,5 @@ export const getMediapipeInstance = async (): Promise<FaceLandmarker> => {
212
276
  export const __testUtils = {
213
277
  matchesExcludedGpu,
214
278
  getDelegateFromGpuDetection,
279
+ supportsWasmReftypes,
215
280
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@smileid/signature-pad",
3
- "version": "11.4.1",
4
- "private": "true",
3
+ "version": "11.4.3",
4
+ "private": true,
5
5
  "exports": {
6
6
  ".": "./index.js"
7
7
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smileid/web-components",
3
- "version": "11.4.1",
3
+ "version": "11.4.3",
4
4
  "private": false,
5
5
  "main": "dist/esm/main.js",
6
6
  "module": "dist/esm/main.js",
@@ -76,6 +76,15 @@
76
76
  ],
77
77
  "type": "module",
78
78
  "author": "SmileID <support@usesmileid.com> (https://usesmileid.com)",
79
+ "repository": {
80
+ "type": "git",
81
+ "url": "git+https://github.com/smileidentity/web-client.git",
82
+ "directory": "packages/web-components"
83
+ },
84
+ "bugs": {
85
+ "url": "https://github.com/smileidentity/web-client/issues"
86
+ },
87
+ "homepage": "https://github.com/smileidentity/web-client#readme",
79
88
  "dependencies": {
80
89
  "@lottiefiles/dotlottie-web": "^0.71.0",
81
90
  "@mediapipe/tasks-vision": "^0.10.22-rc.20250304",