@microblink/camera-manager 7.2.1 → 7.2.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 (58) hide show
  1. package/dist/camera-manager.js +182 -48
  2. package/dist/camera-manager.js.map +1 -1
  3. package/package.json +1 -1
  4. package/types/core/Camera.d.ts +73 -0
  5. package/types/core/Camera.d.ts.map +1 -1
  6. package/types/core/CameraManager.d.ts +87 -7
  7. package/types/core/CameraManager.d.ts.map +1 -1
  8. package/types/core/VideoFrameProcessor.d.ts +28 -6
  9. package/types/core/VideoFrameProcessor.d.ts.map +1 -1
  10. package/types/core/cameraError.d.ts +22 -0
  11. package/types/core/cameraError.d.ts.map +1 -0
  12. package/types/core/cameraManagerStore.d.ts +10 -3
  13. package/types/core/cameraManagerStore.d.ts.map +1 -1
  14. package/types/core/cameraNames.d.ts +21 -5
  15. package/types/core/cameraNames.d.ts.map +1 -1
  16. package/types/core/cameraUtils.d.ts +34 -13
  17. package/types/core/cameraUtils.d.ts.map +1 -1
  18. package/types/core/iosCameraNames.d.ts +3 -0
  19. package/types/core/iosCameraNames.d.ts.map +1 -1
  20. package/types/core/utils.d.ts +18 -0
  21. package/types/core/utils.d.ts.map +1 -1
  22. package/types/index.d.ts +11 -1
  23. package/types/index.d.ts.map +1 -1
  24. package/types/index.rollup.d.ts +264 -21
  25. package/types/media-mock/MediaMocker.d.ts +67 -0
  26. package/types/media-mock/MediaMocker.d.ts.map +1 -1
  27. package/types/media-mock/createInputDeviceInfo.d.ts +9 -0
  28. package/types/media-mock/createInputDeviceInfo.d.ts.map +1 -1
  29. package/types/media-mock/defineProperty.d.ts +6 -3
  30. package/types/media-mock/defineProperty.d.ts.map +1 -1
  31. package/types/media-mock/fake-devices.d.ts +6 -0
  32. package/types/media-mock/fake-devices.d.ts.map +1 -1
  33. package/types/ui/CameraErrorModal.d.ts +3 -0
  34. package/types/ui/CameraErrorModal.d.ts.map +1 -1
  35. package/types/ui/CameraSelector.d.ts +3 -0
  36. package/types/ui/CameraSelector.d.ts.map +1 -1
  37. package/types/ui/CameraUiStoreContext.d.ts +14 -0
  38. package/types/ui/CameraUiStoreContext.d.ts.map +1 -1
  39. package/types/ui/CaptureScreen.d.ts +12 -0
  40. package/types/ui/CaptureScreen.d.ts.map +1 -1
  41. package/types/ui/Header.d.ts +3 -0
  42. package/types/ui/Header.d.ts.map +1 -1
  43. package/types/ui/LocalizationContext.d.ts +12 -0
  44. package/types/ui/LocalizationContext.d.ts.map +1 -1
  45. package/types/ui/RootComponent.d.ts +3 -0
  46. package/types/ui/RootComponent.d.ts.map +1 -1
  47. package/types/ui/SolidShadowRoot.d.ts +16 -3
  48. package/types/ui/SolidShadowRoot.d.ts.map +1 -1
  49. package/types/ui/createCameraManagerUi.d.ts +33 -3
  50. package/types/ui/createCameraManagerUi.d.ts.map +1 -1
  51. package/types/ui/determineFitMode.d.ts +7 -6
  52. package/types/ui/determineFitMode.d.ts.map +1 -1
  53. package/types/ui/getVisibleVideoArea.d.ts +7 -1
  54. package/types/ui/getVisibleVideoArea.d.ts.map +1 -1
  55. package/types/ui/locales/en.d.ts +3 -0
  56. package/types/ui/locales/en.d.ts.map +1 -1
  57. package/types/ui/zustandRefStore.d.ts +12 -0
  58. package/types/ui/zustandRefStore.d.ts.map +1 -1
@@ -48,28 +48,6 @@ if (typeof HTMLVideoElement !== "undefined" && !("requestVideoFrameCallback" in
48
48
  delete this._rvfcpolyfillmap[handle];
49
49
  };
50
50
  }
51
- const initialState$1 = {
52
- cameras: [],
53
- facingFilter: void 0,
54
- videoElement: void 0,
55
- playbackState: "idle",
56
- selectedCamera: void 0,
57
- isSwappingCamera: false,
58
- isQueryingCameras: false,
59
- mirrorX: false,
60
- errorState: void 0
61
- };
62
- const cameraManagerStore = createStore()(
63
- // this is important! Otherwise solid-zustand will start mutating the initial state
64
- subscribeWithSelector(() => structuredClone(initialState$1))
65
- );
66
- const resetCameraManagerStore = () => {
67
- console.debug("Stopping all cameras and resetting the `cameraManagerStore`.");
68
- cameraManagerStore.getState().cameras.forEach((camera) => {
69
- camera.stopStream();
70
- });
71
- cameraManagerStore.setState(structuredClone(initialState$1));
72
- };
73
51
  const backCameraKeywords = [
74
52
  // English
75
53
  "back",
@@ -538,6 +516,13 @@ const asError = (thrown) => {
538
516
  };
539
517
  class CameraError extends Error {
540
518
  code;
519
+ /**
520
+ * Creates a new camera error.
521
+ *
522
+ * @param message - The error message.
523
+ * @param code - The error code.
524
+ * @param cause - The cause of the error.
525
+ */
541
526
  constructor(message, code, cause) {
542
527
  super(message);
543
528
  this.code = code;
@@ -741,6 +726,9 @@ function findResolutionKey(videoTrackResolution) {
741
726
  return resolutionKey;
742
727
  }
743
728
  class Camera {
729
+ /**
730
+ * The device info.
731
+ */
744
732
  deviceInfo;
745
733
  /**
746
734
  * Stream capabilities as reported by the stream.
@@ -774,6 +762,11 @@ class Camera {
774
762
  * @deprecated Not used. Reconsider using once Firefox and Chrome align on this.
775
763
  */
776
764
  #deviceCapabilities;
765
+ /**
766
+ * Creates a new Camera instance.
767
+ *
768
+ * @param deviceInfo - The device info.
769
+ */
777
770
  constructor(deviceInfo) {
778
771
  if (deviceInfo.kind !== "videoinput") {
779
772
  throw new Error("Device is not a video input device");
@@ -804,6 +797,12 @@ class Camera {
804
797
  };
805
798
  return proxy;
806
799
  }
800
+ /**
801
+ * Starts a stream with the specified resolution.
802
+ *
803
+ * @param resolution - The resolution to start the stream with.
804
+ * @returns The stream.
805
+ */
807
806
  async startStream(resolution) {
808
807
  if (this.activeStream) {
809
808
  return this.activeStream;
@@ -827,6 +826,9 @@ class Camera {
827
826
  /**
828
827
  * Acquires a camera stream with the specified resolution.
829
828
  * If acquisition fails, it tries a lower resolution as fallback.
829
+ *
830
+ * @param resolution - The resolution to acquire the stream with.
831
+ * @returns The stream.
830
832
  */
831
833
  async acquireStreamWithFallback(resolution) {
832
834
  try {
@@ -851,6 +853,8 @@ class Camera {
851
853
  }
852
854
  /**
853
855
  * Populates the camera instance with capabilities from the stream.
856
+ *
857
+ * @param stream - The stream to populate the capabilities from.
854
858
  */
855
859
  populateCapabilities(stream) {
856
860
  this.streamCapabilities = stream.getVideoTracks()[0].getCapabilities();
@@ -892,6 +896,11 @@ class Camera {
892
896
  }
893
897
  }
894
898
  }
899
+ /**
900
+ * Toggles the torch on the camera.
901
+ *
902
+ * @returns The torch status.
903
+ */
895
904
  async toggleTorch() {
896
905
  const videoTrack = this.getVideoTrack();
897
906
  if (!videoTrack) {
@@ -917,6 +926,9 @@ class Camera {
917
926
  }
918
927
  return this.torchEnabled;
919
928
  }
929
+ /**
930
+ * Stops the stream on the camera.
931
+ */
920
932
  stopStream() {
921
933
  if (this.activeStream) {
922
934
  console.debug(`Stopping active stream on ${this.name}`);
@@ -926,6 +938,11 @@ class Camera {
926
938
  this.torchEnabled = false;
927
939
  }
928
940
  }
941
+ /**
942
+ * Gets the video track on the camera.
943
+ *
944
+ * @returns The video track.
945
+ */
929
946
  getVideoTrack() {
930
947
  if (!this.activeStream) {
931
948
  console.warn(`No active stream on Camera instance: ${this.name}.`);
@@ -934,6 +951,28 @@ class Camera {
934
951
  return this.activeStream.getVideoTracks()[0];
935
952
  }
936
953
  }
954
+ const initialState$1 = {
955
+ cameras: [],
956
+ facingFilter: void 0,
957
+ videoElement: void 0,
958
+ playbackState: "idle",
959
+ selectedCamera: void 0,
960
+ isSwappingCamera: false,
961
+ isQueryingCameras: false,
962
+ mirrorX: false,
963
+ errorState: void 0
964
+ };
965
+ const cameraManagerStore = createStore()(
966
+ // this is important! Otherwise solid-zustand will start mutating the initial state
967
+ subscribeWithSelector(() => structuredClone(initialState$1))
968
+ );
969
+ const resetCameraManagerStore = () => {
970
+ console.debug("Stopping all cameras and resetting the `cameraManagerStore`.");
971
+ cameraManagerStore.getState().cameras.forEach((camera) => {
972
+ camera.stopStream();
973
+ });
974
+ cameraManagerStore.setState(structuredClone(initialState$1));
975
+ };
937
976
  const ORIGINAL_ATTACH_SHADOW = Element.prototype.attachShadow;
938
977
  function isShady() {
939
978
  return typeof window.ShadyDOM !== "undefined" && typeof ShadowRoot !== "undefined";
@@ -1248,6 +1287,11 @@ class VideoFrameProcessor {
1248
1287
  #cachedHeight = 0;
1249
1288
  #canvasRenderingMode;
1250
1289
  #requiredPackAlignment = 4;
1290
+ /**
1291
+ * Creates a new VideoFrameProcessor.
1292
+ *
1293
+ * @param options - The options for the VideoFrameProcessor.
1294
+ */
1251
1295
  constructor(options = {}) {
1252
1296
  const { canvasRenderingMode = "webgl2", fallbackWebGlTo2d = true } = options;
1253
1297
  this.#canvasRenderingMode = canvasRenderingMode;
@@ -1275,7 +1319,7 @@ class VideoFrameProcessor {
1275
1319
  }
1276
1320
  }
1277
1321
  /**
1278
- * Initializes the 2D canvas context
1322
+ * Initializes the 2D canvas context.
1279
1323
  */
1280
1324
  #initialize2dContext() {
1281
1325
  const ctx = this.#canvas.getContext("2d", {
@@ -1286,7 +1330,7 @@ class VideoFrameProcessor {
1286
1330
  this.#context2d = ctx;
1287
1331
  }
1288
1332
  /**
1289
- * Initializes the WebGL2 context and resources
1333
+ * Initializes the WebGL2 context and resources.
1290
1334
  */
1291
1335
  #initializeWebGl2Context() {
1292
1336
  const ctx = this.#canvas.getContext("webgl2", {
@@ -1322,9 +1366,12 @@ class VideoFrameProcessor {
1322
1366
  );
1323
1367
  }
1324
1368
  /**
1325
- * Returns ownership of an ArrayBuffer to the processor for reuse
1326
- * This should only be called with ArrayBuffers that were originally from this processor
1327
- * Typically used after transferring the buffer to/from a worker
1369
+ * Returns ownership of an ArrayBuffer to the processor for reuse.
1370
+ *
1371
+ * This should only be called with ArrayBuffers that were originally from this processor.
1372
+ * Typically used after transferring the buffer to/from a worker.
1373
+ *
1374
+ * @param arrayBuffer - The array buffer to reattach.
1328
1375
  */
1329
1376
  reattachArrayBuffer(arrayBuffer) {
1330
1377
  const actualBuffer = getBuffer(arrayBuffer);
@@ -1341,7 +1388,9 @@ class VideoFrameProcessor {
1341
1388
  }
1342
1389
  }
1343
1390
  /**
1344
- * Used to check if the processor owns the buffer
1391
+ * Used to check if the processor owns the buffer.
1392
+ *
1393
+ * @returns true if the processor owns the buffer, false otherwise.
1345
1394
  */
1346
1395
  isBufferDetached() {
1347
1396
  if (!this.#buffer) {
@@ -1350,7 +1399,11 @@ class VideoFrameProcessor {
1350
1399
  return isBufferDetached(this.#buffer.buffer);
1351
1400
  }
1352
1401
  /**
1353
- * Extracts image data from a source element
1402
+ * Extracts image data from a source element.
1403
+ *
1404
+ * @param source - The source element to extract image data from.
1405
+ * @param area - The extraction area.
1406
+ * @returns The image data.
1354
1407
  */
1355
1408
  getImageData(source, area) {
1356
1409
  return this.#canvasRenderingMode === "2d" ? this.#getImageData2d(source, area) : this.#getImageDataWebGl2(source, area);
@@ -1359,6 +1412,7 @@ class VideoFrameProcessor {
1359
1412
  * Used to get the current ImageData object with the current buffer. Useful
1360
1413
  * when you need to get the same `ImageData` object multiple times after the
1361
1414
  * original `ImageData` buffer has been detached
1415
+ *
1362
1416
  * @returns ImageData object with the current buffer
1363
1417
  */
1364
1418
  getCurrentImageData() {
@@ -1368,7 +1422,11 @@ class VideoFrameProcessor {
1368
1422
  return new ImageData(this.#buffer, this.#cachedWidth, this.#cachedHeight);
1369
1423
  }
1370
1424
  /**
1371
- * Extract image data using 2D canvas
1425
+ * Extract image data using 2D canvas.
1426
+ *
1427
+ * @param source - The source element to extract image data from.
1428
+ * @param area - The extraction area.
1429
+ * @returns The image data.
1372
1430
  */
1373
1431
  #getImageData2d(source, area) {
1374
1432
  if (!this.#context2d)
@@ -1384,7 +1442,11 @@ class VideoFrameProcessor {
1384
1442
  return this.#context2d.getImageData(0, 0, w, h);
1385
1443
  }
1386
1444
  /**
1387
- * Extract image data using WebGL2
1445
+ * Extract image data using WebGL2.
1446
+ *
1447
+ * @param source - The source element to extract image data from.
1448
+ * @param area - The extraction area.
1449
+ * @returns The image data.
1388
1450
  */
1389
1451
  #getImageDataWebGl2(source, area) {
1390
1452
  if (!this.#contextWebGl2 || !this.#webGl2Texture || !this.#webGl2Framebuffer) {
@@ -1425,9 +1487,12 @@ class VideoFrameProcessor {
1425
1487
  return new ImageData(this.#buffer, w, h);
1426
1488
  }
1427
1489
  /**
1428
- * Update canvas dimensions if needed
1490
+ * Update canvas dimensions if needed.
1491
+ *
1492
+ * This canvas is the orientation-aware.
1429
1493
  *
1430
- * This canvas is the orientation-aware
1494
+ * @param width - The width of the canvas.
1495
+ * @param height - The height of the canvas.
1431
1496
  */
1432
1497
  #updateCanvasSize(width, height) {
1433
1498
  if (this.#cachedWidth !== width || this.#cachedHeight !== height) {
@@ -1440,7 +1505,7 @@ class VideoFrameProcessor {
1440
1505
  }
1441
1506
  }
1442
1507
  /**
1443
- * Clean up resources
1508
+ * Clean up resources.
1444
1509
  */
1445
1510
  dispose() {
1446
1511
  if (this.#contextWebGl2) {
@@ -1481,6 +1546,10 @@ class CameraManager {
1481
1546
  * CameraManager from throwing errors when the user interrupts the process.
1482
1547
  */
1483
1548
  #userInitiatedAbort = false;
1549
+ /**
1550
+ * If true, the user has initiated an abort. This will prevent the
1551
+ * CameraManager from throwing errors when the user interrupts the process.
1552
+ */
1484
1553
  get userInitiatedAbort() {
1485
1554
  return this.#userInitiatedAbort;
1486
1555
  }
@@ -1489,6 +1558,7 @@ class CameraManager {
1489
1558
  }
1490
1559
  /**
1491
1560
  * Sets the area of the video frame that will be extracted.
1561
+ *
1492
1562
  * @param extractionArea The area of the video frame that will be extracted.
1493
1563
  */
1494
1564
  setExtractionArea(extractionArea) {
@@ -1499,6 +1569,12 @@ class CameraManager {
1499
1569
  * "capturing".
1500
1570
  */
1501
1571
  #frameCaptureCallbacks = /* @__PURE__ */ new Set();
1572
+ /**
1573
+ * Creates a new CameraManager instance.
1574
+ *
1575
+ * @param options - The options for the CameraManager.
1576
+ * @param videoFrameProcessorOptions - The options for the VideoFrameProcessor.
1577
+ */
1502
1578
  constructor(options = {}, videoFrameProcessorOptions) {
1503
1579
  const { mirrorFrontCameras } = {
1504
1580
  ...defaultCameraManagerOptions,
@@ -1510,7 +1586,9 @@ class CameraManager {
1510
1586
  this.#mirrorFrontCameras = mirrorFrontCameras;
1511
1587
  }
1512
1588
  /**
1513
- * Sets the resolution of the camera stream
1589
+ * Sets the resolution of the camera stream.
1590
+ *
1591
+ * @param resolution - The resolution to set.
1514
1592
  */
1515
1593
  setResolution = async (resolution) => {
1516
1594
  this.#resolution = resolution;
@@ -1521,16 +1599,25 @@ class CameraManager {
1521
1599
  await this.startCameraStream();
1522
1600
  }
1523
1601
  };
1602
+ /**
1603
+ * The resolution of the camera stream.
1604
+ */
1524
1605
  get resolution() {
1525
1606
  return this.#resolution;
1526
1607
  }
1527
1608
  /**
1528
1609
  * True if there is a video playing or capturing
1529
- * TODO: see if we can simplify this, by observing the video playback state
1610
+ *
1611
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaSession/playbackState for more details.
1530
1612
  */
1531
1613
  get isActive() {
1532
1614
  return cameraManagerStore.getState().playbackState !== "idle";
1533
1615
  }
1616
+ /**
1617
+ * Sets the facing filter.
1618
+ *
1619
+ * @param facingFilter - The facing filter.
1620
+ */
1534
1621
  setFacingFilter(facingFilter) {
1535
1622
  cameraManagerStore.setState({
1536
1623
  facingFilter
@@ -1539,6 +1626,8 @@ class CameraManager {
1539
1626
  /**
1540
1627
  * Returns the cameras that are available to the user, filtered by the facing mode.
1541
1628
  * If no facing mode is set, all cameras are returned.
1629
+ *
1630
+ * @returns The cameras that are available to the user, filtered by the facing mode.
1542
1631
  */
1543
1632
  async getCameraDevices() {
1544
1633
  let allCameras = cameraManagerStore.getState().cameras;
@@ -1556,7 +1645,9 @@ class CameraManager {
1556
1645
  return filteredCameras;
1557
1646
  }
1558
1647
  /**
1559
- * Single-time setup for a video element
1648
+ * Single-time setup for a video element.
1649
+ *
1650
+ * @param videoElement - The video element to initialize.
1560
1651
  */
1561
1652
  #initVideoElement(videoElement) {
1562
1653
  if (!(videoElement instanceof HTMLVideoElement)) {
@@ -1636,6 +1727,8 @@ class CameraManager {
1636
1727
  }
1637
1728
  /**
1638
1729
  * Initializes the CameraManager with a video element.
1730
+ *
1731
+ * @param videoElement - The video element to initialize.
1639
1732
  */
1640
1733
  initVideoElement(videoElement) {
1641
1734
  try {
@@ -1652,13 +1745,16 @@ class CameraManager {
1652
1745
  * Adds a callback that will be triggered on each frame when the playback state
1653
1746
  * is "capturing".
1654
1747
  *
1655
- * @param frameCaptureCallback
1748
+ * @param frameCaptureCallback - The callback to add.
1656
1749
  * @returns a cleanup function to remove the callback
1657
1750
  */
1658
1751
  addFrameCaptureCallback(frameCaptureCallback) {
1659
1752
  this.#frameCaptureCallbacks.add(frameCaptureCallback);
1660
1753
  return () => this.#frameCaptureCallbacks.delete(frameCaptureCallback);
1661
1754
  }
1755
+ /**
1756
+ * Cleans up the video element, and stops the stream.
1757
+ */
1662
1758
  releaseVideoElement() {
1663
1759
  this.#eventListenerCleanup?.();
1664
1760
  cameraManagerStore.setState({
@@ -1666,10 +1762,11 @@ class CameraManager {
1666
1762
  });
1667
1763
  this.stopStream();
1668
1764
  }
1765
+ // TODO: might become a private method in the future as an implementation detail of `startStream`
1669
1766
  /**
1670
1767
  * Select a camera device from available ones.
1671
1768
  *
1672
- * TODO: might become a private method in the future as an implementation detail of `startStream`
1769
+ * @param camera - The camera to select.
1673
1770
  */
1674
1771
  async selectCamera(camera) {
1675
1772
  const playbackState = cameraManagerStore.getState().playbackState;
@@ -1711,6 +1808,8 @@ class CameraManager {
1711
1808
  }
1712
1809
  /**
1713
1810
  * Refreshes available devices on the system and updates the state.
1811
+ *
1812
+ * @returns resolves when the camera devices are refreshed
1714
1813
  */
1715
1814
  async refreshCameraDevices() {
1716
1815
  if (cameraManagerStore.getState().isQueryingCameras || cameraManagerStore.getState().isSwappingCamera) {
@@ -1797,6 +1896,8 @@ class CameraManager {
1797
1896
  }
1798
1897
  /**
1799
1898
  * Starts playback and frame capturing.
1899
+ *
1900
+ * @returns resolves when frame capture starts
1800
1901
  */
1801
1902
  async #startFrameCapture() {
1802
1903
  const state = cameraManagerStore.getState();
@@ -1827,6 +1928,8 @@ class CameraManager {
1827
1928
  }
1828
1929
  /**
1829
1930
  * Starts capturing frames from the video element.
1931
+ *
1932
+ * @returns resolves when frame capture starts
1830
1933
  */
1831
1934
  startFrameCapture = async () => {
1832
1935
  try {
@@ -1839,6 +1942,12 @@ class CameraManager {
1839
1942
  }
1840
1943
  }
1841
1944
  };
1945
+ /**
1946
+ * Starts a camera stream.
1947
+ *
1948
+ * @param params - The parameters for the camera stream.
1949
+ * @returns resolves when the camera stream starts
1950
+ */
1842
1951
  async #startCameraStream({
1843
1952
  autoplay = true,
1844
1953
  preferredCamera,
@@ -1919,6 +2028,9 @@ class CameraManager {
1919
2028
  /**
1920
2029
  * Starts a best-effort camera stream. Will pick a camera automatically if
1921
2030
  * none is selected.
2031
+ *
2032
+ * @param params - The parameters for the camera stream.
2033
+ * @returns resolves when the camera stream starts
1922
2034
  */
1923
2035
  async startCameraStream(params = {}) {
1924
2036
  try {
@@ -1931,12 +2043,17 @@ class CameraManager {
1931
2043
  }
1932
2044
  }
1933
2045
  }
2046
+ /**
2047
+ * Checks if the error state is a permission error.
2048
+ *
2049
+ * @returns true if the error state is a permission error
2050
+ */
1934
2051
  #hasPermissionError = () => {
1935
2052
  const errorState = cameraManagerStore.getState().errorState;
1936
2053
  return errorState instanceof CameraError && errorState.code === "PERMISSION_DENIED";
1937
2054
  };
1938
2055
  /**
1939
- * Pauses capturing frames without pausing playback.
2056
+ * Pauses capturing frames, without stopping playback.
1940
2057
  */
1941
2058
  stopFrameCapture() {
1942
2059
  cameraManagerStore.setState({
@@ -1973,7 +2090,7 @@ class CameraManager {
1973
2090
  video.pause();
1974
2091
  }
1975
2092
  /**
1976
- * The main recognition loop. Do not call this method directly, use #queueFrame instead.
2093
+ * The main recognition loop. Do not call this method directly, use `#queueFrame` instead.
1977
2094
  */
1978
2095
  async #loop() {
1979
2096
  const state = cameraManagerStore.getState();
@@ -2014,7 +2131,7 @@ class CameraManager {
2014
2131
  this.#queueFrame();
2015
2132
  }
2016
2133
  /**
2017
- * Queues the next frame to be processed
2134
+ * Queues the next frame to be processed.
2018
2135
  */
2019
2136
  #queueFrame() {
2020
2137
  const state = cameraManagerStore.getState();
@@ -2053,6 +2170,8 @@ class CameraManager {
2053
2170
  }
2054
2171
  /**
2055
2172
  * If true, the video and captured frames will be mirrored horizontally.
2173
+ *
2174
+ * @param mirrorX - If true, the video and captured frames will be mirrored horizontally.
2056
2175
  */
2057
2176
  setCameraMirrorX(mirrorX) {
2058
2177
  const currentState = cameraManagerStore.getState();
@@ -2075,15 +2194,19 @@ class CameraManager {
2075
2194
  /**
2076
2195
  * Allows the user to subscribe to state changes inside the Camera Manager.
2077
2196
  * Implemented using Zustand. For usage information, see
2078
- * {@link https://github.com/pmndrs/zustand#using-subscribe-with-selector}
2197
+ * @see https://github.com/pmndrs/zustand#using-subscribe-with-selector for more details.
2198
+ *
2199
+ * @returns a cleanup function to remove the subscription
2079
2200
  */
2080
2201
  subscribe = cameraManagerStore.subscribe;
2081
2202
  /**
2082
2203
  * Gets the current internal state of the CameraManager.
2204
+ *
2205
+ * @returns the current state of the CameraManager
2083
2206
  */
2084
2207
  getState = cameraManagerStore.getState;
2085
2208
  /**
2086
- * Resets the CameraManager and stop all streams
2209
+ * Resets the CameraManager and stops all streams.
2087
2210
  */
2088
2211
  reset() {
2089
2212
  console.debug("Resetting camera manager");
@@ -2115,7 +2238,9 @@ const CameraUiStoreProvider = (props) => {
2115
2238
  // eslint-disable-next-line solid/reactivity
2116
2239
  showTorchButton: props.showTorchButton,
2117
2240
  // eslint-disable-next-line solid/reactivity
2118
- showCloseButton: props.showCloseButton
2241
+ showCloseButton: props.showCloseButton,
2242
+ // eslint-disable-next-line solid/reactivity
2243
+ showCameraErrorModal: props.showCameraErrorModal
2119
2244
  };
2120
2245
  onCleanup(() => {
2121
2246
  console.debug("CameraUiStoreProvider cleanup");
@@ -2942,7 +3067,8 @@ const CAPTURE_SCREEN_SHADOW_ROOT_HOST_ID = "capture-screen-host";
2942
3067
  const CaptureScreen = () => {
2943
3068
  const {
2944
3069
  cameraManager,
2945
- mountTarget
3070
+ mountTarget,
3071
+ showCameraErrorModal
2946
3072
  } = useCameraUiStore();
2947
3073
  const [videoRef, setVideoRef] = createSignal();
2948
3074
  const [feedbackRef, setFeedbackRef] = createSignal();
@@ -3049,7 +3175,12 @@ const CaptureScreen = () => {
3049
3175
  use(setVideoRef, _el$6);
3050
3176
  use(setFeedbackRef, _el$7);
3051
3177
  use(setOverlayLayerRef, _el$8);
3052
- insert(_el$5, createComponent(CameraErrorModal, {}), null);
3178
+ insert(_el$5, createComponent(Show, {
3179
+ when: showCameraErrorModal,
3180
+ get children() {
3181
+ return createComponent(CameraErrorModal, {});
3182
+ }
3183
+ }), null);
3053
3184
  effect((_$p) => (_$p = fitMode()) != null ? _el$6.style.setProperty("object-fit", _$p) : _el$6.style.removeProperty("object-fit"));
3054
3185
  return _el$5;
3055
3186
  })()];
@@ -3135,7 +3266,8 @@ function createCameraManagerUi(cameraManager, target, {
3135
3266
  localizationStrings,
3136
3267
  showMirrorCameraButton = false,
3137
3268
  showTorchButton = true,
3138
- showCloseButton = true
3269
+ showCloseButton = true,
3270
+ showCameraErrorModal = true
3139
3271
  } = {}) {
3140
3272
  let mountTarget;
3141
3273
  const dismountCallbacks = /* @__PURE__ */ new Set();
@@ -3193,6 +3325,7 @@ function createCameraManagerUi(cameraManager, target, {
3193
3325
  showMirrorCameraButton,
3194
3326
  showTorchButton,
3195
3327
  showCloseButton,
3328
+ showCameraErrorModal,
3196
3329
  mountTarget,
3197
3330
  get children() {
3198
3331
  return createComponent(RootComponent, {});
@@ -3277,6 +3410,7 @@ if (globalThis.__CAMERA_MANAGER__ !== testSymbol) {
3277
3410
  }
3278
3411
  export {
3279
3412
  Camera,
3413
+ CameraError,
3280
3414
  CameraManager,
3281
3415
  MOUNT_POINT_ID,
3282
3416
  VideoFrameProcessor,