tempest-react-sdk 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/README.md +72 -70
  2. package/dist/audio/audio-output.cjs +2 -0
  3. package/dist/audio/audio-output.cjs.map +1 -0
  4. package/dist/audio/audio-output.js +17 -0
  5. package/dist/audio/audio-output.js.map +1 -0
  6. package/dist/audio/audio-player.cjs +1 -1
  7. package/dist/audio/audio-player.cjs.map +1 -1
  8. package/dist/audio/audio-player.js +21 -20
  9. package/dist/audio/audio-player.js.map +1 -1
  10. package/dist/audio/audio-recorder.cjs +2 -0
  11. package/dist/audio/audio-recorder.cjs.map +1 -0
  12. package/dist/audio/audio-recorder.js +30 -0
  13. package/dist/audio/audio-recorder.js.map +1 -0
  14. package/dist/audio/duration.cjs +2 -0
  15. package/dist/audio/duration.cjs.map +1 -0
  16. package/dist/audio/duration.js +10 -0
  17. package/dist/audio/duration.js.map +1 -0
  18. package/dist/audio/level-meter.cjs +2 -0
  19. package/dist/audio/level-meter.cjs.map +1 -0
  20. package/dist/audio/level-meter.js +34 -0
  21. package/dist/audio/level-meter.js.map +1 -0
  22. package/dist/audio/media-access.cjs +2 -0
  23. package/dist/audio/media-access.cjs.map +1 -0
  24. package/dist/audio/media-access.js +51 -0
  25. package/dist/audio/media-access.js.map +1 -0
  26. package/dist/audio/use-audio-recorder.cjs +2 -0
  27. package/dist/audio/use-audio-recorder.cjs.map +1 -0
  28. package/dist/audio/use-audio-recorder.js +94 -0
  29. package/dist/audio/use-audio-recorder.js.map +1 -0
  30. package/dist/audio/use-audio.cjs.map +1 -1
  31. package/dist/audio/use-audio.js.map +1 -1
  32. package/dist/audio/use-microphone.cjs +2 -0
  33. package/dist/audio/use-microphone.cjs.map +1 -0
  34. package/dist/audio/use-microphone.js +54 -0
  35. package/dist/audio/use-microphone.js.map +1 -0
  36. package/dist/audio/wav.cjs +2 -0
  37. package/dist/audio/wav.cjs.map +1 -0
  38. package/dist/audio/wav.js +49 -0
  39. package/dist/audio/wav.js.map +1 -0
  40. package/dist/auth/passkey.cjs +2 -0
  41. package/dist/auth/passkey.cjs.map +1 -0
  42. package/dist/auth/passkey.js +171 -0
  43. package/dist/auth/passkey.js.map +1 -0
  44. package/dist/auth/use-passkey.cjs +2 -0
  45. package/dist/auth/use-passkey.cjs.map +1 -0
  46. package/dist/auth/use-passkey.js +120 -0
  47. package/dist/auth/use-passkey.js.map +1 -0
  48. package/dist/br/PixQRCode.cjs +2 -0
  49. package/dist/br/PixQRCode.cjs.map +1 -0
  50. package/dist/br/PixQRCode.js +70 -0
  51. package/dist/br/PixQRCode.js.map +1 -0
  52. package/dist/br/PixQRCode.module.cjs +2 -0
  53. package/dist/br/PixQRCode.module.cjs.map +1 -0
  54. package/dist/br/PixQRCode.module.js +15 -0
  55. package/dist/br/PixQRCode.module.js.map +1 -0
  56. package/dist/br/boleto.cjs +2 -0
  57. package/dist/br/boleto.cjs.map +1 -0
  58. package/dist/br/boleto.js +225 -0
  59. package/dist/br/boleto.js.map +1 -0
  60. package/dist/br/holidays.cjs +2 -0
  61. package/dist/br/holidays.cjs.map +1 -0
  62. package/dist/br/holidays.js +148 -0
  63. package/dist/br/holidays.js.map +1 -0
  64. package/dist/br/nfe.cjs +2 -0
  65. package/dist/br/nfe.cjs.map +1 -0
  66. package/dist/br/nfe.js +104 -0
  67. package/dist/br/nfe.js.map +1 -0
  68. package/dist/br/pix.cjs +2 -0
  69. package/dist/br/pix.cjs.map +1 -0
  70. package/dist/br/pix.js +148 -0
  71. package/dist/br/pix.js.map +1 -0
  72. package/dist/br.cjs +1 -1
  73. package/dist/br.cjs.map +1 -1
  74. package/dist/br.d.ts +878 -0
  75. package/dist/br.js +7 -2
  76. package/dist/br.js.map +1 -1
  77. package/dist/capture/barcode.cjs +2 -0
  78. package/dist/capture/barcode.cjs.map +1 -0
  79. package/dist/capture/barcode.js +59 -0
  80. package/dist/capture/barcode.js.map +1 -0
  81. package/dist/capture/media-recorder.cjs +2 -0
  82. package/dist/capture/media-recorder.cjs.map +1 -0
  83. package/dist/capture/media-recorder.js +64 -0
  84. package/dist/capture/media-recorder.js.map +1 -0
  85. package/dist/capture/use-barcode-scanner.cjs +2 -0
  86. package/dist/capture/use-barcode-scanner.cjs.map +1 -0
  87. package/dist/capture/use-barcode-scanner.js +86 -0
  88. package/dist/capture/use-barcode-scanner.js.map +1 -0
  89. package/dist/capture/use-screen-capture.cjs +2 -0
  90. package/dist/capture/use-screen-capture.cjs.map +1 -0
  91. package/dist/capture/use-screen-capture.js +79 -0
  92. package/dist/capture/use-screen-capture.js.map +1 -0
  93. package/dist/capture/use-speech-recognition.cjs +2 -0
  94. package/dist/capture/use-speech-recognition.cjs.map +1 -0
  95. package/dist/capture/use-speech-recognition.js +118 -0
  96. package/dist/capture/use-speech-recognition.js.map +1 -0
  97. package/dist/capture/use-torch.cjs +2 -0
  98. package/dist/capture/use-torch.cjs.map +1 -0
  99. package/dist/capture/use-torch.js +33 -0
  100. package/dist/capture/use-torch.js.map +1 -0
  101. package/dist/capture/use-video-recorder.cjs +2 -0
  102. package/dist/capture/use-video-recorder.cjs.map +1 -0
  103. package/dist/capture/use-video-recorder.js +90 -0
  104. package/dist/capture/use-video-recorder.js.map +1 -0
  105. package/dist/capture/video-recorder.cjs +2 -0
  106. package/dist/capture/video-recorder.cjs.map +1 -0
  107. package/dist/capture/video-recorder.js +31 -0
  108. package/dist/capture/video-recorder.js.map +1 -0
  109. package/dist/components/AIChat/AIChat.cjs +1 -1
  110. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  111. package/dist/components/AIChat/AIChat.js +93 -97
  112. package/dist/components/AIChat/AIChat.js.map +1 -1
  113. package/dist/components/AIChat/AIChatComposer.cjs +1 -1
  114. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  115. package/dist/components/AIChat/AIChatComposer.js +2 -1
  116. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  117. package/dist/components/AIChat/AIChatTurn.cjs +2 -2
  118. package/dist/components/AIChat/AIChatTurn.js +6 -6
  119. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  120. package/dist/components/Alert/Alert.module.cjs.map +1 -1
  121. package/dist/components/Alert/Alert.module.js.map +1 -1
  122. package/dist/components/AudioPlayer/AudioPlayer.cjs +2 -0
  123. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -0
  124. package/dist/components/AudioPlayer/AudioPlayer.js +123 -0
  125. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -0
  126. package/dist/components/AudioPlayer/AudioPlayer.module.cjs +2 -0
  127. package/dist/components/AudioPlayer/AudioPlayer.module.cjs.map +1 -0
  128. package/dist/components/AudioPlayer/AudioPlayer.module.js +12 -0
  129. package/dist/components/AudioPlayer/AudioPlayer.module.js.map +1 -0
  130. package/dist/components/AudioRecorder/AudioRecorder.cjs +2 -0
  131. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -0
  132. package/dist/components/AudioRecorder/AudioRecorder.js +179 -0
  133. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -0
  134. package/dist/components/AudioRecorder/AudioRecorder.module.cjs +2 -0
  135. package/dist/components/AudioRecorder/AudioRecorder.module.cjs.map +1 -0
  136. package/dist/components/AudioRecorder/AudioRecorder.module.js +19 -0
  137. package/dist/components/AudioRecorder/AudioRecorder.module.js.map +1 -0
  138. package/dist/components/Badge/Badge.module.cjs.map +1 -1
  139. package/dist/components/Badge/Badge.module.js.map +1 -1
  140. package/dist/components/BarcodeScanner/BarcodeScanner.cjs +2 -0
  141. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -0
  142. package/dist/components/BarcodeScanner/BarcodeScanner.js +123 -0
  143. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -0
  144. package/dist/components/BarcodeScanner/BarcodeScanner.module.cjs +2 -0
  145. package/dist/components/BarcodeScanner/BarcodeScanner.module.cjs.map +1 -0
  146. package/dist/components/BarcodeScanner/BarcodeScanner.module.js +22 -0
  147. package/dist/components/BarcodeScanner/BarcodeScanner.module.js.map +1 -0
  148. package/dist/components/BottomNavigation/BottomNavigation.module.cjs.map +1 -1
  149. package/dist/components/BottomNavigation/BottomNavigation.module.js.map +1 -1
  150. package/dist/components/Button/Button.module.cjs.map +1 -1
  151. package/dist/components/Button/Button.module.js.map +1 -1
  152. package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
  153. package/dist/components/Combobox/Combobox.module.js.map +1 -1
  154. package/dist/components/DataTable/DataTable.cjs +1 -1
  155. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  156. package/dist/components/DataTable/DataTable.js +203 -66
  157. package/dist/components/DataTable/DataTable.js.map +1 -1
  158. package/dist/components/DataTable/DataTable.module.cjs +1 -1
  159. package/dist/components/DataTable/DataTable.module.cjs.map +1 -1
  160. package/dist/components/DataTable/DataTable.module.js +9 -3
  161. package/dist/components/DataTable/DataTable.module.js.map +1 -1
  162. package/dist/components/DataTable/EditableCell.cjs +2 -0
  163. package/dist/components/DataTable/EditableCell.cjs.map +1 -0
  164. package/dist/components/DataTable/EditableCell.js +77 -0
  165. package/dist/components/DataTable/EditableCell.js.map +1 -0
  166. package/dist/components/DataTable/edit-labels.cjs +2 -0
  167. package/dist/components/DataTable/edit-labels.cjs.map +1 -0
  168. package/dist/components/DataTable/edit-labels.js +11 -0
  169. package/dist/components/DataTable/edit-labels.js.map +1 -0
  170. package/dist/components/DateRangePicker/DateRangePicker.module.cjs.map +1 -1
  171. package/dist/components/DateRangePicker/DateRangePicker.module.js.map +1 -1
  172. package/dist/components/MultiSelect/MultiSelect.module.cjs.map +1 -1
  173. package/dist/components/MultiSelect/MultiSelect.module.js.map +1 -1
  174. package/dist/components/NavigationRail/NavigationRail.module.cjs.map +1 -1
  175. package/dist/components/NavigationRail/NavigationRail.module.js.map +1 -1
  176. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs +1 -1
  177. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  178. package/dist/components/SyncStatusBadge/SyncStatusBadge.js +33 -32
  179. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  180. package/dist/components/Toast/ToastProvider.cjs +1 -1
  181. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  182. package/dist/components/Toast/ToastProvider.js +1 -2
  183. package/dist/components/Toast/ToastProvider.js.map +1 -1
  184. package/dist/hooks/use-announce.cjs +2 -0
  185. package/dist/hooks/use-announce.cjs.map +1 -0
  186. package/dist/hooks/use-announce.js +50 -0
  187. package/dist/hooks/use-announce.js.map +1 -0
  188. package/dist/hooks/use-media-devices.cjs +2 -0
  189. package/dist/hooks/use-media-devices.cjs.map +1 -0
  190. package/dist/hooks/use-media-devices.js +46 -0
  191. package/dist/hooks/use-media-devices.js.map +1 -0
  192. package/dist/hooks/use-media-permission.cjs +2 -0
  193. package/dist/hooks/use-media-permission.cjs.map +1 -0
  194. package/dist/hooks/use-media-permission.js +33 -0
  195. package/dist/hooks/use-media-permission.js.map +1 -0
  196. package/dist/http/resumable-upload.cjs +2 -0
  197. package/dist/http/resumable-upload.cjs.map +1 -0
  198. package/dist/http/resumable-upload.js +249 -0
  199. package/dist/http/resumable-upload.js.map +1 -0
  200. package/dist/styles.css +1 -1
  201. package/dist/tempest-react-sdk.cjs +1 -1
  202. package/dist/tempest-react-sdk.d.ts +2485 -29
  203. package/dist/tempest-react-sdk.js +268 -244
  204. package/dist/vision/use-camera-stream.cjs +1 -1
  205. package/dist/vision/use-camera-stream.cjs.map +1 -1
  206. package/dist/vision/use-camera-stream.js +40 -57
  207. package/dist/vision/use-camera-stream.js.map +1 -1
  208. package/dist/vision.cjs +1 -1
  209. package/dist/vision.d.ts +25 -3
  210. package/dist/vision.js +19 -19
  211. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- let e=require("react");var t={video:{facingMode:{ideal:`environment`},width:{ideal:1920},height:{ideal:1080}},audio:!1};function n(e){if(typeof window>`u`)return{kind:`unsupported`,message:`Camera is unavailable in this environment.`};if(!window.isSecureContext)return{kind:`insecure`,message:`Camera access requires a secure (HTTPS) connection.`};if(e instanceof DOMException)switch(e.name){case`NotAllowedError`:case`SecurityError`:return{kind:`permission-denied`,message:`Camera permission denied. Enable access in your browser settings.`};case`NotFoundError`:case`OverconstrainedError`:return{kind:`no-camera`,message:`No camera available on this device.`};case`NotReadableError`:case`AbortError`:return{kind:`in-use`,message:`The camera is in use by another app. Close it and try again.`}}return{kind:`unknown`,message:e instanceof Error?e.message:`Unexpected error while accessing the camera.`}}function r(r={}){let[i,a]=(0,e.useState)(`loading`),[o,s]=(0,e.useState)(null),[c,l]=(0,e.useState)(0),u=(0,e.useRef)(null),d=(0,e.useRef)(r.constraints??t);return(0,e.useEffect)(()=>{d.current=r.constraints??t},[r.constraints]),(0,e.useEffect)(()=>{let e=!1,t=null,r=null;async function i(){if(a(`loading`),s(null),typeof navigator>`u`||!navigator.mediaDevices||typeof navigator.mediaDevices.getUserMedia!=`function`){e||(s(typeof window<`u`&&!window.isSecureContext?n(null):{kind:`unsupported`,message:`Camera capture is not supported in this browser.`}),a(`error`));return}try{if(t=await navigator.mediaDevices.getUserMedia(d.current),e){t.getTracks().forEach(e=>e.stop());return}let n=u.current;if(!n){t.getTracks().forEach(e=>e.stop());return}r=n,n.srcObject=t,await n.play().catch(()=>void 0),e||a(`ready`)}catch(t){e||(s(n(t)),a(`error`))}}return i(),()=>{e=!0,t&&t.getTracks().forEach(e=>e.stop()),r&&(r.srcObject=null)}},[c]),{status:i,error:o,videoRef:u,retry:()=>l(e=>e+1)}}exports.useCameraStream=r;
1
+ const e=require("../audio/media-access.cjs");let t=require("react");var n={video:{facingMode:{ideal:`environment`},width:{ideal:1920},height:{ideal:1080}},audio:!1};function r({kind:e,message:t}){return{kind:e===`not-found`?`no-camera`:e,message:t}}function i(t){return r(e.classifyMediaError(t,`camera`))}function a(a={}){let[o,s]=(0,t.useState)(`loading`),[c,l]=(0,t.useState)(null),[u,d]=(0,t.useState)(null),[f,p]=(0,t.useState)(0),m=(0,t.useRef)(null),h=(0,t.useRef)(a.constraints??n);(0,t.useEffect)(()=>{h.current=a.constraints??n},[a.constraints]);let g=a.enabled??!0;return(0,t.useEffect)(()=>{let t=!1,n=null,a=null;async function o(){if(!g){s(`idle`),l(null);return}if(s(`loading`),l(null),typeof navigator>`u`||!navigator.mediaDevices||typeof navigator.mediaDevices.getUserMedia!=`function`){t||(l(r(e.missingCaptureApiError(`camera`))),s(`error`));return}try{if(n=await navigator.mediaDevices.getUserMedia(h.current),t){n.getTracks().forEach(e=>e.stop());return}let e=m.current;if(!e){n.getTracks().forEach(e=>e.stop());return}a=e,e.srcObject=n,d(n),await e.play().catch(()=>void 0),t||s(`ready`)}catch(e){t||(l(i(e)),s(`error`))}}return o(),()=>{t=!0,n&&n.getTracks().forEach(e=>e.stop()),a&&(a.srcObject=null),d(null)}},[f,g]),{status:o,error:c,videoRef:m,stream:u,retry:()=>p(e=>e+1)}}exports.useCameraStream=a;
2
2
  //# sourceMappingURL=use-camera-stream.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-camera-stream.cjs","names":[],"sources":["../../src/vision/use-camera-stream.ts"],"sourcesContent":["import { useEffect, useRef, useState, type RefObject } from \"react\";\n\n/** Lifecycle status of the camera stream. */\nexport type CameraStreamStatus = \"idle\" | \"loading\" | \"ready\" | \"error\";\n\n/** Classified reason a camera stream could not be acquired. */\nexport type CameraStreamErrorKind =\n \"unsupported\" | \"permission-denied\" | \"no-camera\" | \"in-use\" | \"insecure\" | \"unknown\";\n\n/** A classified camera error with a human-readable, English message. */\nexport interface CameraStreamError {\n kind: CameraStreamErrorKind;\n message: string;\n}\n\n/** Options for {@link useCameraStream}. */\nexport interface UseCameraStreamOptions {\n /**\n * Constraints passed to `getUserMedia`. Defaults to the rear\n * (\"environment\") camera at Full-HD ideal resolution with audio off.\n * Read when the stream (re)starts — change it and call `retry()` to apply.\n */\n constraints?: MediaStreamConstraints;\n}\n\n/** Value returned by {@link useCameraStream}. */\nexport interface UseCameraStreamApi {\n /** Current lifecycle status. */\n status: CameraStreamStatus;\n /** The classified error, or `null` while not in the `error` status. */\n error: CameraStreamError | null;\n /** Attach to a `<video ref={…} />`. The stream is wired to it once ready. */\n videoRef: RefObject<HTMLVideoElement | null>;\n /** Manually re-attempt after an error (e.g. the user changed permissions). */\n retry: () => void;\n}\n\n/** Rear-camera Full-HD defaults used when no `constraints` are supplied. */\nconst DEFAULT_CONSTRAINTS: MediaStreamConstraints = {\n video: {\n facingMode: { ideal: \"environment\" },\n width: { ideal: 1920 },\n height: { ideal: 1080 },\n },\n audio: false,\n};\n\n/**\n * Map an unknown failure into a {@link CameraStreamError}. Secure-context and\n * environment checks run first (they are the reason `getUserMedia` is missing\n * or rejects), then the `DOMException.name` is mapped to a stable `kind`.\n */\nfunction classifyError(err: unknown): CameraStreamError {\n if (typeof window === \"undefined\") {\n return { kind: \"unsupported\", message: \"Camera is unavailable in this environment.\" };\n }\n if (!window.isSecureContext) {\n return {\n kind: \"insecure\",\n message: \"Camera access requires a secure (HTTPS) connection.\",\n };\n }\n if (err instanceof DOMException) {\n switch (err.name) {\n case \"NotAllowedError\":\n case \"SecurityError\":\n return {\n kind: \"permission-denied\",\n message: \"Camera permission denied. Enable access in your browser settings.\",\n };\n case \"NotFoundError\":\n case \"OverconstrainedError\":\n return {\n kind: \"no-camera\",\n message: \"No camera available on this device.\",\n };\n case \"NotReadableError\":\n case \"AbortError\":\n return {\n kind: \"in-use\",\n message: \"The camera is in use by another app. Close it and try again.\",\n };\n }\n }\n return {\n kind: \"unknown\",\n message:\n err instanceof Error ? err.message : \"Unexpected error while accessing the camera.\",\n };\n}\n\n/**\n * Acquire a `MediaStream` via `getUserMedia`, attach it to a `<video>` element,\n * and expose status/error so the page can render permission and error states.\n * The stream is automatically released on unmount or retry.\n *\n * Defaults to the rear (\"environment\") camera; desktops fall back to whatever\n * single camera they expose. Pass `options.constraints` to override.\n *\n * Implementation notes:\n * - Cleanup detaches the stream from a *snapshotted* video node, so it releases\n * the same element it attached to even if the page remounts the `<video>`.\n * - When `getUserMedia` is missing, an insecure context is the usual cause, so\n * the hook prefers that (actionable) error; otherwise it reports `unsupported`.\n * - `video.play()` rejections are swallowed: autoplay may be blocked, but the\n * user gesture that opened the camera usually counts and playback resumes on\n * the next interaction.\n *\n * @param options - optional configuration (see {@link UseCameraStreamOptions}).\n * @returns The stream status, classified error, a `videoRef` to attach, and a\n * `retry()` to re-attempt acquisition.\n */\nexport function useCameraStream(options: UseCameraStreamOptions = {}): UseCameraStreamApi {\n const [status, setStatus] = useState<CameraStreamStatus>(\"loading\");\n const [error, setError] = useState<CameraStreamError | null>(null);\n const [retryToken, setRetryToken] = useState(0);\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const constraintsRef = useRef<MediaStreamConstraints>(\n options.constraints ?? DEFAULT_CONSTRAINTS,\n );\n useEffect(() => {\n constraintsRef.current = options.constraints ?? DEFAULT_CONSTRAINTS;\n }, [options.constraints]);\n\n useEffect(() => {\n let cancelled = false;\n let stream: MediaStream | null = null;\n let attachedVideo: HTMLVideoElement | null = null;\n\n async function start(): Promise<void> {\n setStatus(\"loading\");\n setError(null);\n\n if (\n typeof navigator === \"undefined\" ||\n !navigator.mediaDevices ||\n typeof navigator.mediaDevices.getUserMedia !== \"function\"\n ) {\n if (!cancelled) {\n setError(\n typeof window !== \"undefined\" && !window.isSecureContext\n ? classifyError(null)\n : {\n kind: \"unsupported\",\n message: \"Camera capture is not supported in this browser.\",\n },\n );\n setStatus(\"error\");\n }\n return;\n }\n\n try {\n stream = await navigator.mediaDevices.getUserMedia(constraintsRef.current);\n if (cancelled) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n const video = videoRef.current;\n if (!video) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n attachedVideo = video;\n video.srcObject = stream;\n await video.play().catch(() => undefined);\n if (!cancelled) setStatus(\"ready\");\n } catch (err) {\n if (!cancelled) {\n setError(classifyError(err));\n setStatus(\"error\");\n }\n }\n }\n\n void start();\n\n return () => {\n cancelled = true;\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n if (attachedVideo) {\n attachedVideo.srcObject = null;\n }\n };\n }, [retryToken]);\n\n return {\n status,\n error,\n videoRef,\n retry: () => setRetryToken((n) => n + 1),\n };\n}\n"],"mappings":"uBAsCA,IAAM,EAA8C,CAChD,MAAO,CACH,WAAY,CAAE,MAAO,aAAc,EACnC,MAAO,CAAE,MAAO,IAAK,EACrB,OAAQ,CAAE,MAAO,IAAK,CAC1B,EACA,MAAO,EACX,EAOA,SAAS,EAAc,EAAiC,CACpD,GAAI,OAAO,OAAW,IAClB,MAAO,CAAE,KAAM,cAAe,QAAS,4CAA6C,EAExF,GAAI,CAAC,OAAO,gBACR,MAAO,CACH,KAAM,WACN,QAAS,qDACb,EAEJ,GAAI,aAAe,aACf,OAAQ,EAAI,KAAZ,CACI,IAAK,kBACL,IAAK,gBACD,MAAO,CACH,KAAM,oBACN,QAAS,mEACb,EACJ,IAAK,gBACL,IAAK,uBACD,MAAO,CACH,KAAM,YACN,QAAS,qCACb,EACJ,IAAK,mBACL,IAAK,aACD,MAAO,CACH,KAAM,SACN,QAAS,8DACb,CACR,CAEJ,MAAO,CACH,KAAM,UACN,QACI,aAAe,MAAQ,EAAI,QAAU,8CAC7C,CACJ,CAuBA,SAAgB,EAAgB,EAAkC,CAAC,EAAuB,CACtF,GAAM,CAAC,EAAQ,IAAA,EAAA,EAAA,SAAA,CAA0C,SAAS,EAC5D,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAA+C,IAAI,EAC3D,CAAC,EAAY,IAAA,EAAA,EAAA,SAAA,CAA0B,CAAC,EACxC,GAAA,EAAA,EAAA,OAAA,CAA2C,IAAI,EAC/C,GAAA,EAAA,EAAA,OAAA,CACF,EAAQ,aAAe,CAC3B,EAqEA,OApEA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAe,QAAU,EAAQ,aAAe,CACpD,EAAG,CAAC,EAAQ,WAAW,CAAC,GAExB,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAY,GACZ,EAA6B,KAC7B,EAAyC,KAE7C,eAAe,GAAuB,CAIlC,GAHA,EAAU,SAAS,EACnB,EAAS,IAAI,EAGT,OAAO,UAAc,KACrB,CAAC,UAAU,cACX,OAAO,UAAU,aAAa,cAAiB,WACjD,CACO,IACD,EACI,OAAO,OAAW,KAAe,CAAC,OAAO,gBACnC,EAAc,IAAI,EAClB,CACI,KAAM,cACN,QAAS,kDACb,CACV,EACA,EAAU,OAAO,GAErB,MACJ,CAEA,GAAI,CAEA,GADA,EAAS,MAAM,UAAU,aAAa,aAAa,EAAe,OAAO,EACrE,EAAW,CACX,EAAO,UAAU,CAAC,CAAC,QAAS,GAAU,EAAM,KAAK,CAAC,EAClD,MACJ,CACA,IAAM,EAAQ,EAAS,QACvB,GAAI,CAAC,EAAO,CACR,EAAO,UAAU,CAAC,CAAC,QAAS,GAAU,EAAM,KAAK,CAAC,EAClD,MACJ,CACA,EAAgB,EAChB,EAAM,UAAY,EAClB,MAAM,EAAM,KAAK,CAAC,CAAC,UAAY,IAAA,EAAS,EACnC,GAAW,EAAU,OAAO,CACrC,OAAS,EAAK,CACL,IACD,EAAS,EAAc,CAAG,CAAC,EAC3B,EAAU,OAAO,EAEzB,CACJ,CAIA,OAFA,EAAW,MAEE,CACT,EAAY,GACR,GACA,EAAO,UAAU,CAAC,CAAC,QAAS,GAAU,EAAM,KAAK,CAAC,EAElD,IACA,EAAc,UAAY,KAElC,CACJ,EAAG,CAAC,CAAU,CAAC,EAER,CACH,SACA,QACA,WACA,UAAa,EAAe,GAAM,EAAI,CAAC,CAC3C,CACJ"}
1
+ {"version":3,"file":"use-camera-stream.cjs","names":[],"sources":["../../src/vision/use-camera-stream.ts"],"sourcesContent":["import { useEffect, useRef, useState, type RefObject } from \"react\";\n\nimport {\n classifyMediaError,\n missingCaptureApiError,\n type MediaAccessError,\n} from \"@/audio/media-access\";\n\n/** Lifecycle status of the camera stream. */\nexport type CameraStreamStatus = \"idle\" | \"loading\" | \"ready\" | \"error\";\n\n/** Classified reason a camera stream could not be acquired. */\nexport type CameraStreamErrorKind =\n \"unsupported\" | \"permission-denied\" | \"no-camera\" | \"in-use\" | \"insecure\" | \"unknown\";\n\n/** A classified camera error with a human-readable, English message. */\nexport interface CameraStreamError {\n kind: CameraStreamErrorKind;\n message: string;\n}\n\n/** Options for {@link useCameraStream}. */\nexport interface UseCameraStreamOptions {\n /**\n * Constraints passed to `getUserMedia`. Defaults to the rear\n * (\"environment\") camera at Full-HD ideal resolution with audio off.\n * Read when the stream (re)starts — change it and call `retry()` to apply.\n */\n constraints?: MediaStreamConstraints;\n /**\n * Hold off acquiring the camera until this is `true`. Default `true`.\n *\n * The point is to be able to *not* prompt. A permission prompt costs the user a\n * decision and, if they refuse, costs the app the feature permanently — so a\n * surface that already knows it cannot do its job (a barcode scanner in a browser\n * with no decoder) must not open the camera to then say so. Flipping this to `false`\n * also releases a stream that is already live.\n */\n enabled?: boolean;\n}\n\n/** Value returned by {@link useCameraStream}. */\nexport interface UseCameraStreamApi {\n /** Current lifecycle status. */\n status: CameraStreamStatus;\n /** The classified error, or `null` while not in the `error` status. */\n error: CameraStreamError | null;\n /** Attach to a `<video ref={…} />`. The stream is wired to it once ready. */\n videoRef: RefObject<HTMLVideoElement | null>;\n /**\n * The live stream, or `null`.\n *\n * Exposed for the things that need the **track** rather than the picture — the LED\n * torch (`useTorch`), the real frame size from `getSettings()`, recording it with\n * `useVideoRecorder`. Do not stop it yourself: the hook owns its lifetime and\n * releases it on unmount and on `retry()`.\n */\n stream: MediaStream | null;\n /** Manually re-attempt after an error (e.g. the user changed permissions). */\n retry: () => void;\n}\n\n/** Rear-camera Full-HD defaults used when no `constraints` are supplied. */\nconst DEFAULT_CONSTRAINTS: MediaStreamConstraints = {\n video: {\n facingMode: { ideal: \"environment\" },\n width: { ideal: 1920 },\n height: { ideal: 1080 },\n },\n audio: false,\n};\n\n/**\n * Re-label a {@link MediaAccessError} as a {@link CameraStreamError}.\n *\n * The classification itself lives in one place for the whole SDK\n * (`classifyMediaError`), so a microphone and a camera failure are never explained\n * two different ways. Only the name of one kind differs: this surface shipped\n * `\"no-camera\"` where the shared taxonomy says `\"not-found\"`, and renaming a\n * published union member would break every consumer switching on it.\n *\n * @param error - The shared classification.\n * @returns The same error under this module's kind names.\n */\nfunction toCameraError({ kind, message }: MediaAccessError): CameraStreamError {\n return { kind: kind === \"not-found\" ? \"no-camera\" : kind, message };\n}\n\n/**\n * Map an unknown `getUserMedia` failure into a {@link CameraStreamError}. Secure-context\n * and environment checks run first (they are the reason `getUserMedia` is missing or\n * rejects), then the `DOMException.name` is mapped to a stable `kind`.\n */\nfunction classifyError(err: unknown): CameraStreamError {\n return toCameraError(classifyMediaError(err, \"camera\"));\n}\n\n/**\n * Acquire a `MediaStream` via `getUserMedia`, attach it to a `<video>` element,\n * and expose status/error so the page can render permission and error states.\n * The stream is automatically released on unmount or retry.\n *\n * Defaults to the rear (\"environment\") camera; desktops fall back to whatever\n * single camera they expose. Pass `options.constraints` to override, or\n * `options.enabled: false` to render the surface without prompting for the camera\n * at all.\n *\n * Implementation notes:\n * - Cleanup detaches the stream from a *snapshotted* video node, so it releases\n * the same element it attached to even if the page remounts the `<video>`.\n * - When `getUserMedia` is missing, an insecure context is the usual cause, so\n * the hook prefers that (actionable) error; otherwise it reports `unsupported`.\n * - `video.play()` rejections are swallowed: autoplay may be blocked, but the\n * user gesture that opened the camera usually counts and playback resumes on\n * the next interaction.\n *\n * @param options - optional configuration (see {@link UseCameraStreamOptions}).\n * @returns The stream status, classified error, a `videoRef` to attach, the live\n * `stream` for whatever needs the track itself, and a `retry()` to re-attempt\n * acquisition.\n */\nexport function useCameraStream(options: UseCameraStreamOptions = {}): UseCameraStreamApi {\n const [status, setStatus] = useState<CameraStreamStatus>(\"loading\");\n const [error, setError] = useState<CameraStreamError | null>(null);\n const [live, setLive] = useState<MediaStream | null>(null);\n const [retryToken, setRetryToken] = useState(0);\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const constraintsRef = useRef<MediaStreamConstraints>(\n options.constraints ?? DEFAULT_CONSTRAINTS,\n );\n useEffect(() => {\n constraintsRef.current = options.constraints ?? DEFAULT_CONSTRAINTS;\n }, [options.constraints]);\n\n const enabled = options.enabled ?? true;\n\n useEffect(() => {\n let cancelled = false;\n let stream: MediaStream | null = null;\n let attachedVideo: HTMLVideoElement | null = null;\n\n async function start(): Promise<void> {\n if (!enabled) {\n setStatus(\"idle\");\n setError(null);\n return;\n }\n setStatus(\"loading\");\n setError(null);\n\n if (\n typeof navigator === \"undefined\" ||\n !navigator.mediaDevices ||\n typeof navigator.mediaDevices.getUserMedia !== \"function\"\n ) {\n if (!cancelled) {\n setError(toCameraError(missingCaptureApiError(\"camera\")));\n setStatus(\"error\");\n }\n return;\n }\n\n try {\n stream = await navigator.mediaDevices.getUserMedia(constraintsRef.current);\n if (cancelled) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n const video = videoRef.current;\n if (!video) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n attachedVideo = video;\n video.srcObject = stream;\n setLive(stream);\n await video.play().catch(() => undefined);\n if (!cancelled) setStatus(\"ready\");\n } catch (err) {\n if (!cancelled) {\n setError(classifyError(err));\n setStatus(\"error\");\n }\n }\n }\n\n void start();\n\n return () => {\n cancelled = true;\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n if (attachedVideo) {\n attachedVideo.srcObject = null;\n }\n setLive(null);\n };\n }, [retryToken, enabled]);\n\n return {\n status,\n error,\n videoRef,\n stream: live,\n retry: () => setRetryToken((n) => n + 1),\n };\n}\n"],"mappings":"oEA+DA,IAAM,EAA8C,CAChD,MAAO,CACH,WAAY,CAAE,MAAO,aAAc,EACnC,MAAO,CAAE,MAAO,IAAK,EACrB,OAAQ,CAAE,MAAO,IAAK,CAC1B,EACA,MAAO,EACX,EAcA,SAAS,EAAc,CAAE,OAAM,WAAgD,CAC3E,MAAO,CAAE,KAAM,IAAS,YAAc,YAAc,EAAM,SAAQ,CACtE,CAOA,SAAS,EAAc,EAAiC,CACpD,OAAO,EAAc,EAAA,mBAAmB,EAAK,QAAQ,CAAC,CAC1D,CA0BA,SAAgB,EAAgB,EAAkC,CAAC,EAAuB,CACtF,GAAM,CAAC,EAAQ,IAAA,EAAA,EAAA,SAAA,CAA0C,SAAS,EAC5D,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAA+C,IAAI,EAC3D,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAAwC,IAAI,EACnD,CAAC,EAAY,IAAA,EAAA,EAAA,SAAA,CAA0B,CAAC,EACxC,GAAA,EAAA,EAAA,OAAA,CAA2C,IAAI,EAC/C,GAAA,EAAA,EAAA,OAAA,CACF,EAAQ,aAAe,CAC3B,GACA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAe,QAAU,EAAQ,aAAe,CACpD,EAAG,CAAC,EAAQ,WAAW,CAAC,EAExB,IAAM,EAAU,EAAQ,SAAW,GAkEnC,OAhEA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAY,GACZ,EAA6B,KAC7B,EAAyC,KAE7C,eAAe,GAAuB,CAClC,GAAI,CAAC,EAAS,CACV,EAAU,MAAM,EAChB,EAAS,IAAI,EACb,MACJ,CAIA,GAHA,EAAU,SAAS,EACnB,EAAS,IAAI,EAGT,OAAO,UAAc,KACrB,CAAC,UAAU,cACX,OAAO,UAAU,aAAa,cAAiB,WACjD,CACO,IACD,EAAS,EAAc,EAAA,uBAAuB,QAAQ,CAAC,CAAC,EACxD,EAAU,OAAO,GAErB,MACJ,CAEA,GAAI,CAEA,GADA,EAAS,MAAM,UAAU,aAAa,aAAa,EAAe,OAAO,EACrE,EAAW,CACX,EAAO,UAAU,CAAC,CAAC,QAAS,GAAU,EAAM,KAAK,CAAC,EAClD,MACJ,CACA,IAAM,EAAQ,EAAS,QACvB,GAAI,CAAC,EAAO,CACR,EAAO,UAAU,CAAC,CAAC,QAAS,GAAU,EAAM,KAAK,CAAC,EAClD,MACJ,CACA,EAAgB,EAChB,EAAM,UAAY,EAClB,EAAQ,CAAM,EACd,MAAM,EAAM,KAAK,CAAC,CAAC,UAAY,IAAA,EAAS,EACnC,GAAW,EAAU,OAAO,CACrC,OAAS,EAAK,CACL,IACD,EAAS,EAAc,CAAG,CAAC,EAC3B,EAAU,OAAO,EAEzB,CACJ,CAIA,OAFA,EAAW,MAEE,CACT,EAAY,GACR,GACA,EAAO,UAAU,CAAC,CAAC,QAAS,GAAU,EAAM,KAAK,CAAC,EAElD,IACA,EAAc,UAAY,MAE9B,EAAQ,IAAI,CAChB,CACJ,EAAG,CAAC,EAAY,CAAO,CAAC,EAEjB,CACH,SACA,QACA,WACA,OAAQ,EACR,UAAa,EAAe,GAAM,EAAI,CAAC,CAC3C,CACJ"}
@@ -1,6 +1,7 @@
1
- import { useEffect as e, useRef as t, useState as n } from "react";
1
+ import { classifyMediaError as e, missingCaptureApiError as t } from "../audio/media-access.js";
2
+ import { useEffect as n, useRef as r, useState as i } from "react";
2
3
  //#region src/vision/use-camera-stream.ts
3
- var r = {
4
+ var a = {
4
5
  video: {
5
6
  facingMode: { ideal: "environment" },
6
7
  width: { ideal: 1920 },
@@ -8,77 +9,59 @@ var r = {
8
9
  },
9
10
  audio: !1
10
11
  };
11
- function i(e) {
12
- if (typeof window > "u") return {
13
- kind: "unsupported",
14
- message: "Camera is unavailable in this environment."
15
- };
16
- if (!window.isSecureContext) return {
17
- kind: "insecure",
18
- message: "Camera access requires a secure (HTTPS) connection."
19
- };
20
- if (e instanceof DOMException) switch (e.name) {
21
- case "NotAllowedError":
22
- case "SecurityError": return {
23
- kind: "permission-denied",
24
- message: "Camera permission denied. Enable access in your browser settings."
25
- };
26
- case "NotFoundError":
27
- case "OverconstrainedError": return {
28
- kind: "no-camera",
29
- message: "No camera available on this device."
30
- };
31
- case "NotReadableError":
32
- case "AbortError": return {
33
- kind: "in-use",
34
- message: "The camera is in use by another app. Close it and try again."
35
- };
36
- }
12
+ function o({ kind: e, message: t }) {
37
13
  return {
38
- kind: "unknown",
39
- message: e instanceof Error ? e.message : "Unexpected error while accessing the camera."
14
+ kind: e === "not-found" ? "no-camera" : e,
15
+ message: t
40
16
  };
41
17
  }
42
- function a(a = {}) {
43
- let [o, s] = n("loading"), [c, l] = n(null), [u, d] = n(0), f = t(null), p = t(a.constraints ?? r);
44
- return e(() => {
45
- p.current = a.constraints ?? r;
46
- }, [a.constraints]), e(() => {
47
- let e = !1, t = null, n = null;
48
- async function r() {
49
- if (s("loading"), l(null), typeof navigator > "u" || !navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia != "function") {
50
- e || (l(typeof window < "u" && !window.isSecureContext ? i(null) : {
51
- kind: "unsupported",
52
- message: "Camera capture is not supported in this browser."
53
- }), s("error"));
18
+ function s(t) {
19
+ return o(e(t, "camera"));
20
+ }
21
+ function c(e = {}) {
22
+ let [c, l] = i("loading"), [u, d] = i(null), [f, p] = i(null), [m, h] = i(0), g = r(null), _ = r(e.constraints ?? a);
23
+ n(() => {
24
+ _.current = e.constraints ?? a;
25
+ }, [e.constraints]);
26
+ let v = e.enabled ?? !0;
27
+ return n(() => {
28
+ let e = !1, n = null, r = null;
29
+ async function i() {
30
+ if (!v) {
31
+ l("idle"), d(null);
32
+ return;
33
+ }
34
+ if (l("loading"), d(null), typeof navigator > "u" || !navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia != "function") {
35
+ e || (d(o(t("camera"))), l("error"));
54
36
  return;
55
37
  }
56
38
  try {
57
- if (t = await navigator.mediaDevices.getUserMedia(p.current), e) {
58
- t.getTracks().forEach((e) => e.stop());
39
+ if (n = await navigator.mediaDevices.getUserMedia(_.current), e) {
40
+ n.getTracks().forEach((e) => e.stop());
59
41
  return;
60
42
  }
61
- let r = f.current;
62
- if (!r) {
63
- t.getTracks().forEach((e) => e.stop());
43
+ let t = g.current;
44
+ if (!t) {
45
+ n.getTracks().forEach((e) => e.stop());
64
46
  return;
65
47
  }
66
- n = r, r.srcObject = t, await r.play().catch(() => void 0), e || s("ready");
48
+ r = t, t.srcObject = n, p(n), await t.play().catch(() => void 0), e || l("ready");
67
49
  } catch (t) {
68
- e || (l(i(t)), s("error"));
50
+ e || (d(s(t)), l("error"));
69
51
  }
70
52
  }
71
- return r(), () => {
72
- e = !0, t && t.getTracks().forEach((e) => e.stop()), n && (n.srcObject = null);
53
+ return i(), () => {
54
+ e = !0, n && n.getTracks().forEach((e) => e.stop()), r && (r.srcObject = null), p(null);
73
55
  };
74
- }, [u]), {
75
- status: o,
76
- error: c,
77
- videoRef: f,
78
- retry: () => d((e) => e + 1)
56
+ }, [m, v]), {
57
+ status: c,
58
+ error: u,
59
+ videoRef: g,
60
+ stream: f,
61
+ retry: () => h((e) => e + 1)
79
62
  };
80
63
  }
81
64
  //#endregion
82
- export { a as useCameraStream };
65
+ export { c as useCameraStream };
83
66
 
84
67
  //# sourceMappingURL=use-camera-stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-camera-stream.js","names":[],"sources":["../../src/vision/use-camera-stream.ts"],"sourcesContent":["import { useEffect, useRef, useState, type RefObject } from \"react\";\n\n/** Lifecycle status of the camera stream. */\nexport type CameraStreamStatus = \"idle\" | \"loading\" | \"ready\" | \"error\";\n\n/** Classified reason a camera stream could not be acquired. */\nexport type CameraStreamErrorKind =\n \"unsupported\" | \"permission-denied\" | \"no-camera\" | \"in-use\" | \"insecure\" | \"unknown\";\n\n/** A classified camera error with a human-readable, English message. */\nexport interface CameraStreamError {\n kind: CameraStreamErrorKind;\n message: string;\n}\n\n/** Options for {@link useCameraStream}. */\nexport interface UseCameraStreamOptions {\n /**\n * Constraints passed to `getUserMedia`. Defaults to the rear\n * (\"environment\") camera at Full-HD ideal resolution with audio off.\n * Read when the stream (re)starts — change it and call `retry()` to apply.\n */\n constraints?: MediaStreamConstraints;\n}\n\n/** Value returned by {@link useCameraStream}. */\nexport interface UseCameraStreamApi {\n /** Current lifecycle status. */\n status: CameraStreamStatus;\n /** The classified error, or `null` while not in the `error` status. */\n error: CameraStreamError | null;\n /** Attach to a `<video ref={…} />`. The stream is wired to it once ready. */\n videoRef: RefObject<HTMLVideoElement | null>;\n /** Manually re-attempt after an error (e.g. the user changed permissions). */\n retry: () => void;\n}\n\n/** Rear-camera Full-HD defaults used when no `constraints` are supplied. */\nconst DEFAULT_CONSTRAINTS: MediaStreamConstraints = {\n video: {\n facingMode: { ideal: \"environment\" },\n width: { ideal: 1920 },\n height: { ideal: 1080 },\n },\n audio: false,\n};\n\n/**\n * Map an unknown failure into a {@link CameraStreamError}. Secure-context and\n * environment checks run first (they are the reason `getUserMedia` is missing\n * or rejects), then the `DOMException.name` is mapped to a stable `kind`.\n */\nfunction classifyError(err: unknown): CameraStreamError {\n if (typeof window === \"undefined\") {\n return { kind: \"unsupported\", message: \"Camera is unavailable in this environment.\" };\n }\n if (!window.isSecureContext) {\n return {\n kind: \"insecure\",\n message: \"Camera access requires a secure (HTTPS) connection.\",\n };\n }\n if (err instanceof DOMException) {\n switch (err.name) {\n case \"NotAllowedError\":\n case \"SecurityError\":\n return {\n kind: \"permission-denied\",\n message: \"Camera permission denied. Enable access in your browser settings.\",\n };\n case \"NotFoundError\":\n case \"OverconstrainedError\":\n return {\n kind: \"no-camera\",\n message: \"No camera available on this device.\",\n };\n case \"NotReadableError\":\n case \"AbortError\":\n return {\n kind: \"in-use\",\n message: \"The camera is in use by another app. Close it and try again.\",\n };\n }\n }\n return {\n kind: \"unknown\",\n message:\n err instanceof Error ? err.message : \"Unexpected error while accessing the camera.\",\n };\n}\n\n/**\n * Acquire a `MediaStream` via `getUserMedia`, attach it to a `<video>` element,\n * and expose status/error so the page can render permission and error states.\n * The stream is automatically released on unmount or retry.\n *\n * Defaults to the rear (\"environment\") camera; desktops fall back to whatever\n * single camera they expose. Pass `options.constraints` to override.\n *\n * Implementation notes:\n * - Cleanup detaches the stream from a *snapshotted* video node, so it releases\n * the same element it attached to even if the page remounts the `<video>`.\n * - When `getUserMedia` is missing, an insecure context is the usual cause, so\n * the hook prefers that (actionable) error; otherwise it reports `unsupported`.\n * - `video.play()` rejections are swallowed: autoplay may be blocked, but the\n * user gesture that opened the camera usually counts and playback resumes on\n * the next interaction.\n *\n * @param options - optional configuration (see {@link UseCameraStreamOptions}).\n * @returns The stream status, classified error, a `videoRef` to attach, and a\n * `retry()` to re-attempt acquisition.\n */\nexport function useCameraStream(options: UseCameraStreamOptions = {}): UseCameraStreamApi {\n const [status, setStatus] = useState<CameraStreamStatus>(\"loading\");\n const [error, setError] = useState<CameraStreamError | null>(null);\n const [retryToken, setRetryToken] = useState(0);\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const constraintsRef = useRef<MediaStreamConstraints>(\n options.constraints ?? DEFAULT_CONSTRAINTS,\n );\n useEffect(() => {\n constraintsRef.current = options.constraints ?? DEFAULT_CONSTRAINTS;\n }, [options.constraints]);\n\n useEffect(() => {\n let cancelled = false;\n let stream: MediaStream | null = null;\n let attachedVideo: HTMLVideoElement | null = null;\n\n async function start(): Promise<void> {\n setStatus(\"loading\");\n setError(null);\n\n if (\n typeof navigator === \"undefined\" ||\n !navigator.mediaDevices ||\n typeof navigator.mediaDevices.getUserMedia !== \"function\"\n ) {\n if (!cancelled) {\n setError(\n typeof window !== \"undefined\" && !window.isSecureContext\n ? classifyError(null)\n : {\n kind: \"unsupported\",\n message: \"Camera capture is not supported in this browser.\",\n },\n );\n setStatus(\"error\");\n }\n return;\n }\n\n try {\n stream = await navigator.mediaDevices.getUserMedia(constraintsRef.current);\n if (cancelled) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n const video = videoRef.current;\n if (!video) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n attachedVideo = video;\n video.srcObject = stream;\n await video.play().catch(() => undefined);\n if (!cancelled) setStatus(\"ready\");\n } catch (err) {\n if (!cancelled) {\n setError(classifyError(err));\n setStatus(\"error\");\n }\n }\n }\n\n void start();\n\n return () => {\n cancelled = true;\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n if (attachedVideo) {\n attachedVideo.srcObject = null;\n }\n };\n }, [retryToken]);\n\n return {\n status,\n error,\n videoRef,\n retry: () => setRetryToken((n) => n + 1),\n };\n}\n"],"mappings":";;AAsCA,IAAM,IAA8C;CAChD,OAAO;EACH,YAAY,EAAE,OAAO,cAAc;EACnC,OAAO,EAAE,OAAO,KAAK;EACrB,QAAQ,EAAE,OAAO,KAAK;CAC1B;CACA,OAAO;AACX;AAOA,SAAS,EAAc,GAAiC;CACpD,IAAI,OAAO,SAAW,KAClB,OAAO;EAAE,MAAM;EAAe,SAAS;CAA6C;CAExF,IAAI,CAAC,OAAO,iBACR,OAAO;EACH,MAAM;EACN,SAAS;CACb;CAEJ,IAAI,aAAe,cACf,QAAQ,EAAI,MAAZ;EACI,KAAK;EACL,KAAK,iBACD,OAAO;GACH,MAAM;GACN,SAAS;EACb;EACJ,KAAK;EACL,KAAK,wBACD,OAAO;GACH,MAAM;GACN,SAAS;EACb;EACJ,KAAK;EACL,KAAK,cACD,OAAO;GACH,MAAM;GACN,SAAS;EACb;CACR;CAEJ,OAAO;EACH,MAAM;EACN,SACI,aAAe,QAAQ,EAAI,UAAU;CAC7C;AACJ;AAuBA,SAAgB,EAAgB,IAAkC,CAAC,GAAuB;CACtF,IAAM,CAAC,GAAQ,KAAa,EAA6B,SAAS,GAC5D,CAAC,GAAO,KAAY,EAAmC,IAAI,GAC3D,CAAC,GAAY,KAAiB,EAAS,CAAC,GACxC,IAAW,EAAgC,IAAI,GAC/C,IAAiB,EACnB,EAAQ,eAAe,CAC3B;CAqEA,OApEA,QAAgB;EACZ,EAAe,UAAU,EAAQ,eAAe;CACpD,GAAG,CAAC,EAAQ,WAAW,CAAC,GAExB,QAAgB;EACZ,IAAI,IAAY,IACZ,IAA6B,MAC7B,IAAyC;EAE7C,eAAe,IAAuB;GAIlC,IAHA,EAAU,SAAS,GACnB,EAAS,IAAI,GAGT,OAAO,YAAc,OACrB,CAAC,UAAU,gBACX,OAAO,UAAU,aAAa,gBAAiB,YACjD;IACE,AAAK,MACD,EACI,OAAO,SAAW,OAAe,CAAC,OAAO,kBACnC,EAAc,IAAI,IAClB;KACI,MAAM;KACN,SAAS;IACb,CACV,GACA,EAAU,OAAO;IAErB;GACJ;GAEA,IAAI;IAEA,IADA,IAAS,MAAM,UAAU,aAAa,aAAa,EAAe,OAAO,GACrE,GAAW;KACX,EAAO,UAAU,CAAC,CAAC,SAAS,MAAU,EAAM,KAAK,CAAC;KAClD;IACJ;IACA,IAAM,IAAQ,EAAS;IACvB,IAAI,CAAC,GAAO;KACR,EAAO,UAAU,CAAC,CAAC,SAAS,MAAU,EAAM,KAAK,CAAC;KAClD;IACJ;IAIA,AAHA,IAAgB,GAChB,EAAM,YAAY,GAClB,MAAM,EAAM,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS,GACnC,KAAW,EAAU,OAAO;GACrC,SAAS,GAAK;IACV,AAAK,MACD,EAAS,EAAc,CAAG,CAAC,GAC3B,EAAU,OAAO;GAEzB;EACJ;EAIA,OAFA,EAAW,SAEE;GAKT,AAJA,IAAY,IACR,KACA,EAAO,UAAU,CAAC,CAAC,SAAS,MAAU,EAAM,KAAK,CAAC,GAElD,MACA,EAAc,YAAY;EAElC;CACJ,GAAG,CAAC,CAAU,CAAC,GAER;EACH;EACA;EACA;EACA,aAAa,GAAe,MAAM,IAAI,CAAC;CAC3C;AACJ"}
1
+ {"version":3,"file":"use-camera-stream.js","names":[],"sources":["../../src/vision/use-camera-stream.ts"],"sourcesContent":["import { useEffect, useRef, useState, type RefObject } from \"react\";\n\nimport {\n classifyMediaError,\n missingCaptureApiError,\n type MediaAccessError,\n} from \"@/audio/media-access\";\n\n/** Lifecycle status of the camera stream. */\nexport type CameraStreamStatus = \"idle\" | \"loading\" | \"ready\" | \"error\";\n\n/** Classified reason a camera stream could not be acquired. */\nexport type CameraStreamErrorKind =\n \"unsupported\" | \"permission-denied\" | \"no-camera\" | \"in-use\" | \"insecure\" | \"unknown\";\n\n/** A classified camera error with a human-readable, English message. */\nexport interface CameraStreamError {\n kind: CameraStreamErrorKind;\n message: string;\n}\n\n/** Options for {@link useCameraStream}. */\nexport interface UseCameraStreamOptions {\n /**\n * Constraints passed to `getUserMedia`. Defaults to the rear\n * (\"environment\") camera at Full-HD ideal resolution with audio off.\n * Read when the stream (re)starts — change it and call `retry()` to apply.\n */\n constraints?: MediaStreamConstraints;\n /**\n * Hold off acquiring the camera until this is `true`. Default `true`.\n *\n * The point is to be able to *not* prompt. A permission prompt costs the user a\n * decision and, if they refuse, costs the app the feature permanently — so a\n * surface that already knows it cannot do its job (a barcode scanner in a browser\n * with no decoder) must not open the camera to then say so. Flipping this to `false`\n * also releases a stream that is already live.\n */\n enabled?: boolean;\n}\n\n/** Value returned by {@link useCameraStream}. */\nexport interface UseCameraStreamApi {\n /** Current lifecycle status. */\n status: CameraStreamStatus;\n /** The classified error, or `null` while not in the `error` status. */\n error: CameraStreamError | null;\n /** Attach to a `<video ref={…} />`. The stream is wired to it once ready. */\n videoRef: RefObject<HTMLVideoElement | null>;\n /**\n * The live stream, or `null`.\n *\n * Exposed for the things that need the **track** rather than the picture — the LED\n * torch (`useTorch`), the real frame size from `getSettings()`, recording it with\n * `useVideoRecorder`. Do not stop it yourself: the hook owns its lifetime and\n * releases it on unmount and on `retry()`.\n */\n stream: MediaStream | null;\n /** Manually re-attempt after an error (e.g. the user changed permissions). */\n retry: () => void;\n}\n\n/** Rear-camera Full-HD defaults used when no `constraints` are supplied. */\nconst DEFAULT_CONSTRAINTS: MediaStreamConstraints = {\n video: {\n facingMode: { ideal: \"environment\" },\n width: { ideal: 1920 },\n height: { ideal: 1080 },\n },\n audio: false,\n};\n\n/**\n * Re-label a {@link MediaAccessError} as a {@link CameraStreamError}.\n *\n * The classification itself lives in one place for the whole SDK\n * (`classifyMediaError`), so a microphone and a camera failure are never explained\n * two different ways. Only the name of one kind differs: this surface shipped\n * `\"no-camera\"` where the shared taxonomy says `\"not-found\"`, and renaming a\n * published union member would break every consumer switching on it.\n *\n * @param error - The shared classification.\n * @returns The same error under this module's kind names.\n */\nfunction toCameraError({ kind, message }: MediaAccessError): CameraStreamError {\n return { kind: kind === \"not-found\" ? \"no-camera\" : kind, message };\n}\n\n/**\n * Map an unknown `getUserMedia` failure into a {@link CameraStreamError}. Secure-context\n * and environment checks run first (they are the reason `getUserMedia` is missing or\n * rejects), then the `DOMException.name` is mapped to a stable `kind`.\n */\nfunction classifyError(err: unknown): CameraStreamError {\n return toCameraError(classifyMediaError(err, \"camera\"));\n}\n\n/**\n * Acquire a `MediaStream` via `getUserMedia`, attach it to a `<video>` element,\n * and expose status/error so the page can render permission and error states.\n * The stream is automatically released on unmount or retry.\n *\n * Defaults to the rear (\"environment\") camera; desktops fall back to whatever\n * single camera they expose. Pass `options.constraints` to override, or\n * `options.enabled: false` to render the surface without prompting for the camera\n * at all.\n *\n * Implementation notes:\n * - Cleanup detaches the stream from a *snapshotted* video node, so it releases\n * the same element it attached to even if the page remounts the `<video>`.\n * - When `getUserMedia` is missing, an insecure context is the usual cause, so\n * the hook prefers that (actionable) error; otherwise it reports `unsupported`.\n * - `video.play()` rejections are swallowed: autoplay may be blocked, but the\n * user gesture that opened the camera usually counts and playback resumes on\n * the next interaction.\n *\n * @param options - optional configuration (see {@link UseCameraStreamOptions}).\n * @returns The stream status, classified error, a `videoRef` to attach, the live\n * `stream` for whatever needs the track itself, and a `retry()` to re-attempt\n * acquisition.\n */\nexport function useCameraStream(options: UseCameraStreamOptions = {}): UseCameraStreamApi {\n const [status, setStatus] = useState<CameraStreamStatus>(\"loading\");\n const [error, setError] = useState<CameraStreamError | null>(null);\n const [live, setLive] = useState<MediaStream | null>(null);\n const [retryToken, setRetryToken] = useState(0);\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const constraintsRef = useRef<MediaStreamConstraints>(\n options.constraints ?? DEFAULT_CONSTRAINTS,\n );\n useEffect(() => {\n constraintsRef.current = options.constraints ?? DEFAULT_CONSTRAINTS;\n }, [options.constraints]);\n\n const enabled = options.enabled ?? true;\n\n useEffect(() => {\n let cancelled = false;\n let stream: MediaStream | null = null;\n let attachedVideo: HTMLVideoElement | null = null;\n\n async function start(): Promise<void> {\n if (!enabled) {\n setStatus(\"idle\");\n setError(null);\n return;\n }\n setStatus(\"loading\");\n setError(null);\n\n if (\n typeof navigator === \"undefined\" ||\n !navigator.mediaDevices ||\n typeof navigator.mediaDevices.getUserMedia !== \"function\"\n ) {\n if (!cancelled) {\n setError(toCameraError(missingCaptureApiError(\"camera\")));\n setStatus(\"error\");\n }\n return;\n }\n\n try {\n stream = await navigator.mediaDevices.getUserMedia(constraintsRef.current);\n if (cancelled) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n const video = videoRef.current;\n if (!video) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n attachedVideo = video;\n video.srcObject = stream;\n setLive(stream);\n await video.play().catch(() => undefined);\n if (!cancelled) setStatus(\"ready\");\n } catch (err) {\n if (!cancelled) {\n setError(classifyError(err));\n setStatus(\"error\");\n }\n }\n }\n\n void start();\n\n return () => {\n cancelled = true;\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n if (attachedVideo) {\n attachedVideo.srcObject = null;\n }\n setLive(null);\n };\n }, [retryToken, enabled]);\n\n return {\n status,\n error,\n videoRef,\n stream: live,\n retry: () => setRetryToken((n) => n + 1),\n };\n}\n"],"mappings":";;;AA+DA,IAAM,IAA8C;CAChD,OAAO;EACH,YAAY,EAAE,OAAO,cAAc;EACnC,OAAO,EAAE,OAAO,KAAK;EACrB,QAAQ,EAAE,OAAO,KAAK;CAC1B;CACA,OAAO;AACX;AAcA,SAAS,EAAc,EAAE,SAAM,cAAgD;CAC3E,OAAO;EAAE,MAAM,MAAS,cAAc,cAAc;EAAM;CAAQ;AACtE;AAOA,SAAS,EAAc,GAAiC;CACpD,OAAO,EAAc,EAAmB,GAAK,QAAQ,CAAC;AAC1D;AA0BA,SAAgB,EAAgB,IAAkC,CAAC,GAAuB;CACtF,IAAM,CAAC,GAAQ,KAAa,EAA6B,SAAS,GAC5D,CAAC,GAAO,KAAY,EAAmC,IAAI,GAC3D,CAAC,GAAM,KAAW,EAA6B,IAAI,GACnD,CAAC,GAAY,KAAiB,EAAS,CAAC,GACxC,IAAW,EAAgC,IAAI,GAC/C,IAAiB,EACnB,EAAQ,eAAe,CAC3B;CACA,QAAgB;EACZ,EAAe,UAAU,EAAQ,eAAe;CACpD,GAAG,CAAC,EAAQ,WAAW,CAAC;CAExB,IAAM,IAAU,EAAQ,WAAW;CAkEnC,OAhEA,QAAgB;EACZ,IAAI,IAAY,IACZ,IAA6B,MAC7B,IAAyC;EAE7C,eAAe,IAAuB;GAClC,IAAI,CAAC,GAAS;IAEV,AADA,EAAU,MAAM,GAChB,EAAS,IAAI;IACb;GACJ;GAIA,IAHA,EAAU,SAAS,GACnB,EAAS,IAAI,GAGT,OAAO,YAAc,OACrB,CAAC,UAAU,gBACX,OAAO,UAAU,aAAa,gBAAiB,YACjD;IACE,AAAK,MACD,EAAS,EAAc,EAAuB,QAAQ,CAAC,CAAC,GACxD,EAAU,OAAO;IAErB;GACJ;GAEA,IAAI;IAEA,IADA,IAAS,MAAM,UAAU,aAAa,aAAa,EAAe,OAAO,GACrE,GAAW;KACX,EAAO,UAAU,CAAC,CAAC,SAAS,MAAU,EAAM,KAAK,CAAC;KAClD;IACJ;IACA,IAAM,IAAQ,EAAS;IACvB,IAAI,CAAC,GAAO;KACR,EAAO,UAAU,CAAC,CAAC,SAAS,MAAU,EAAM,KAAK,CAAC;KAClD;IACJ;IAKA,AAJA,IAAgB,GAChB,EAAM,YAAY,GAClB,EAAQ,CAAM,GACd,MAAM,EAAM,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS,GACnC,KAAW,EAAU,OAAO;GACrC,SAAS,GAAK;IACV,AAAK,MACD,EAAS,EAAc,CAAG,CAAC,GAC3B,EAAU,OAAO;GAEzB;EACJ;EAIA,OAFA,EAAW,SAEE;GAQT,AAPA,IAAY,IACR,KACA,EAAO,UAAU,CAAC,CAAC,SAAS,MAAU,EAAM,KAAK,CAAC,GAElD,MACA,EAAc,YAAY,OAE9B,EAAQ,IAAI;EAChB;CACJ,GAAG,CAAC,GAAY,CAAO,CAAC,GAEjB;EACH;EACA;EACA;EACA,QAAQ;EACR,aAAa,GAAe,MAAM,IAAI,CAAC;CAC3C;AACJ"}
package/dist/vision.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./vision/core/exceptions.cjs"),t=require("./vision/types.cjs"),n=require("./vision/core/timing.cjs"),r=require("./vision/results.cjs"),i=require("./vision/labels.cjs"),a=require("./vision/core/providers.cjs"),o=require("./vision/core/session.cjs"),s=require("./vision/io/image.cjs"),c=require("./vision/preprocess/image.cjs"),l=require("./vision/postprocess/classification.cjs"),u=require("./vision/postprocess/detection.cjs"),d=require("./vision/postprocess/segmentation.cjs"),f=require("./vision/tasks/base.cjs"),p=require("./vision/tasks/classifier.cjs"),m=require("./vision/tasks/detector.cjs"),h=require("./vision/tasks/segmenter.cjs"),g=require("./vision/index.cjs"),_=require("./vision/use-camera-stream.cjs"),v=require("./vision/luminance.cjs"),y=require("./vision/use-live-luminance.cjs");exports.BoundingBox=t.BoundingBox,exports.Boxes=r.Boxes,exports.COCO_CLASSES=i.COCO_CLASSES,exports.ClassificationResults=r.ClassificationResults,exports.Classifier=p.Classifier,exports.DEFAULT_PROVIDERS=a.DEFAULT_PROVIDERS,exports.DetectionResults=r.DetectionResults,exports.Detector=m.Detector,exports.ImageLoadError=e.ImageLoadError,exports.InferenceError=e.InferenceError,exports.LUMINANCE_SAMPLE_MAX_EDGE=v.LUMINANCE_SAMPLE_MAX_EDGE,exports.LabelMapError=e.LabelMapError,exports.LowLuminanceError=v.LowLuminanceError,exports.Mask=t.Mask,exports.Masks=r.Masks,exports.ModelLoadError=e.ModelLoadError,exports.OrtSession=o.OrtSession,exports.OrtVisionError=e.OrtVisionError,exports.Probs=r.Probs,exports.ProviderNotAvailableError=e.ProviderNotAvailableError,exports.RGBImage=t.RGBImage,exports.SegmentationResults=r.SegmentationResults,exports.Segmenter=h.Segmenter,exports.SpeedTimer=n.SpeedTimer,exports.VERSION=g.VERSION,exports.VisionTask=f.VisionTask,exports.batchedNms=u.batchedNms,exports.computeImageLuminance=v.computeImageLuminance,exports.decodeYolo=u.decodeYolo,exports.decodeYoloAnchors=u.decodeYoloAnchors,exports.decodeYoloSeg=d.decodeYoloSeg,exports.decodeYoloV8=u.decodeYoloV8,exports.decodeYoloV8Anchors=u.decodeYoloV8Anchors,exports.decodeYoloV8Seg=d.decodeYoloV8Seg,exports.fromCv2=c.fromCv2,exports.isLuminanceAcceptable=v.isLuminanceAcceptable,exports.letterbox=c.letterbox,exports.loadImage=s.loadImage,exports.nms=u.nms,exports.normalize=c.normalize,exports.resize=c.resize,exports.resolveLabels=i.resolveLabels,exports.resolveProviders=a.resolveProviders,exports.softmax=l.softmax,exports.toCHW=c.toCHW,exports.toCv2=c.toCv2,exports.toFloat32=c.toFloat32,exports.toFloat32Tensor=c.toFloat32Tensor,exports.toTensor=c.toTensor,exports.topK=l.topK,exports.useCameraStream=_.useCameraStream,exports.useLiveLuminance=y.useLiveLuminance;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./vision/use-camera-stream.cjs"),t=require("./vision/core/exceptions.cjs"),n=require("./vision/types.cjs"),r=require("./vision/core/timing.cjs"),i=require("./vision/results.cjs"),a=require("./vision/labels.cjs"),o=require("./vision/core/providers.cjs"),s=require("./vision/core/session.cjs"),c=require("./vision/io/image.cjs"),l=require("./vision/preprocess/image.cjs"),u=require("./vision/postprocess/classification.cjs"),d=require("./vision/postprocess/detection.cjs"),f=require("./vision/postprocess/segmentation.cjs"),p=require("./vision/tasks/base.cjs"),m=require("./vision/tasks/classifier.cjs"),h=require("./vision/tasks/detector.cjs"),g=require("./vision/tasks/segmenter.cjs"),_=require("./vision/index.cjs"),v=require("./vision/luminance.cjs"),y=require("./vision/use-live-luminance.cjs");exports.BoundingBox=n.BoundingBox,exports.Boxes=i.Boxes,exports.COCO_CLASSES=a.COCO_CLASSES,exports.ClassificationResults=i.ClassificationResults,exports.Classifier=m.Classifier,exports.DEFAULT_PROVIDERS=o.DEFAULT_PROVIDERS,exports.DetectionResults=i.DetectionResults,exports.Detector=h.Detector,exports.ImageLoadError=t.ImageLoadError,exports.InferenceError=t.InferenceError,exports.LUMINANCE_SAMPLE_MAX_EDGE=v.LUMINANCE_SAMPLE_MAX_EDGE,exports.LabelMapError=t.LabelMapError,exports.LowLuminanceError=v.LowLuminanceError,exports.Mask=n.Mask,exports.Masks=i.Masks,exports.ModelLoadError=t.ModelLoadError,exports.OrtSession=s.OrtSession,exports.OrtVisionError=t.OrtVisionError,exports.Probs=i.Probs,exports.ProviderNotAvailableError=t.ProviderNotAvailableError,exports.RGBImage=n.RGBImage,exports.SegmentationResults=i.SegmentationResults,exports.Segmenter=g.Segmenter,exports.SpeedTimer=r.SpeedTimer,exports.VERSION=_.VERSION,exports.VisionTask=p.VisionTask,exports.batchedNms=d.batchedNms,exports.computeImageLuminance=v.computeImageLuminance,exports.decodeYolo=d.decodeYolo,exports.decodeYoloAnchors=d.decodeYoloAnchors,exports.decodeYoloSeg=f.decodeYoloSeg,exports.decodeYoloV8=d.decodeYoloV8,exports.decodeYoloV8Anchors=d.decodeYoloV8Anchors,exports.decodeYoloV8Seg=f.decodeYoloV8Seg,exports.fromCv2=l.fromCv2,exports.isLuminanceAcceptable=v.isLuminanceAcceptable,exports.letterbox=l.letterbox,exports.loadImage=c.loadImage,exports.nms=d.nms,exports.normalize=l.normalize,exports.resize=l.resize,exports.resolveLabels=a.resolveLabels,exports.resolveProviders=o.resolveProviders,exports.softmax=u.softmax,exports.toCHW=l.toCHW,exports.toCv2=l.toCv2,exports.toFloat32=l.toFloat32,exports.toFloat32Tensor=l.toFloat32Tensor,exports.toTensor=l.toTensor,exports.topK=u.topK,exports.useCameraStream=e.useCameraStream,exports.useLiveLuminance=y.useLiveLuminance;
package/dist/vision.d.ts CHANGED
@@ -1156,7 +1156,9 @@ export declare interface LetterboxResult {
1156
1156
  * The stream is automatically released on unmount or retry.
1157
1157
  *
1158
1158
  * Defaults to the rear ("environment") camera; desktops fall back to whatever
1159
- * single camera they expose. Pass `options.constraints` to override.
1159
+ * single camera they expose. Pass `options.constraints` to override, or
1160
+ * `options.enabled: false` to render the surface without prompting for the camera
1161
+ * at all.
1160
1162
  *
1161
1163
  * Implementation notes:
1162
1164
  * - Cleanup detaches the stream from a *snapshotted* video node, so it releases
@@ -1168,8 +1170,9 @@ export declare interface LetterboxResult {
1168
1170
  * the next interaction.
1169
1171
  *
1170
1172
  * @param options - optional configuration (see {@link UseCameraStreamOptions}).
1171
- * @returns The stream status, classified error, a `videoRef` to attach, and a
1172
- * `retry()` to re-attempt acquisition.
1173
+ * @returns The stream status, classified error, a `videoRef` to attach, the live
1174
+ * `stream` for whatever needs the track itself, and a `retry()` to re-attempt
1175
+ * acquisition.
1173
1176
  */
1174
1177
  export declare function useCameraStream(options?: UseCameraStreamOptions): UseCameraStreamApi;
1175
1178
 
@@ -1181,6 +1184,15 @@ export declare interface LetterboxResult {
1181
1184
  error: CameraStreamError | null;
1182
1185
  /** Attach to a `<video ref={…} />`. The stream is wired to it once ready. */
1183
1186
  videoRef: RefObject<HTMLVideoElement | null>;
1187
+ /**
1188
+ * The live stream, or `null`.
1189
+ *
1190
+ * Exposed for the things that need the **track** rather than the picture — the LED
1191
+ * torch (`useTorch`), the real frame size from `getSettings()`, recording it with
1192
+ * `useVideoRecorder`. Do not stop it yourself: the hook owns its lifetime and
1193
+ * releases it on unmount and on `retry()`.
1194
+ */
1195
+ stream: MediaStream | null;
1184
1196
  /** Manually re-attempt after an error (e.g. the user changed permissions). */
1185
1197
  retry: () => void;
1186
1198
  }
@@ -1193,6 +1205,16 @@ export declare interface LetterboxResult {
1193
1205
  * Read when the stream (re)starts — change it and call `retry()` to apply.
1194
1206
  */
1195
1207
  constraints?: MediaStreamConstraints;
1208
+ /**
1209
+ * Hold off acquiring the camera until this is `true`. Default `true`.
1210
+ *
1211
+ * The point is to be able to *not* prompt. A permission prompt costs the user a
1212
+ * decision and, if they refuse, costs the app the feature permanently — so a
1213
+ * surface that already knows it cannot do its job (a barcode scanner in a browser
1214
+ * with no decoder) must not open the camera to then say so. Flipping this to `false`
1215
+ * also releases a stream that is already live.
1216
+ */
1217
+ enabled?: boolean;
1196
1218
  }
1197
1219
 
1198
1220
  /**
package/dist/vision.js CHANGED
@@ -1,21 +1,21 @@
1
- import { ImageLoadError as e, InferenceError as t, LabelMapError as n, ModelLoadError as r, OrtVisionError as i, ProviderNotAvailableError as a } from "./vision/core/exceptions.js";
2
- import { BoundingBox as o, Mask as s, RGBImage as c } from "./vision/types.js";
3
- import { SpeedTimer as l } from "./vision/core/timing.js";
4
- import { Boxes as u, ClassificationResults as d, DetectionResults as f, Masks as p, Probs as m, SegmentationResults as h } from "./vision/results.js";
5
- import { COCO_CLASSES as g, resolveLabels as _ } from "./vision/labels.js";
6
- import { DEFAULT_PROVIDERS as v, resolveProviders as y } from "./vision/core/providers.js";
7
- import { OrtSession as b } from "./vision/core/session.js";
8
- import { loadImage as x } from "./vision/io/image.js";
9
- import { fromCv2 as S, letterbox as C, normalize as w, resize as T, toCHW as E, toCv2 as D, toFloat32 as O, toFloat32Tensor as k, toTensor as A } from "./vision/preprocess/image.js";
10
- import { softmax as j, topK as M } from "./vision/postprocess/classification.js";
11
- import { batchedNms as N, decodeYolo as P, decodeYoloAnchors as F, decodeYoloV8 as I, decodeYoloV8Anchors as L, nms as R } from "./vision/postprocess/detection.js";
12
- import { decodeYoloSeg as z, decodeYoloV8Seg as B } from "./vision/postprocess/segmentation.js";
13
- import { VisionTask as V } from "./vision/tasks/base.js";
14
- import { Classifier as H } from "./vision/tasks/classifier.js";
15
- import { Detector as U } from "./vision/tasks/detector.js";
16
- import { Segmenter as W } from "./vision/tasks/segmenter.js";
17
- import { VERSION as G } from "./vision/index.js";
18
- import { useCameraStream as K } from "./vision/use-camera-stream.js";
1
+ import { useCameraStream as e } from "./vision/use-camera-stream.js";
2
+ import { ImageLoadError as t, InferenceError as n, LabelMapError as r, ModelLoadError as i, OrtVisionError as a, ProviderNotAvailableError as o } from "./vision/core/exceptions.js";
3
+ import { BoundingBox as s, Mask as c, RGBImage as l } from "./vision/types.js";
4
+ import { SpeedTimer as u } from "./vision/core/timing.js";
5
+ import { Boxes as d, ClassificationResults as f, DetectionResults as p, Masks as m, Probs as h, SegmentationResults as g } from "./vision/results.js";
6
+ import { COCO_CLASSES as _, resolveLabels as v } from "./vision/labels.js";
7
+ import { DEFAULT_PROVIDERS as y, resolveProviders as b } from "./vision/core/providers.js";
8
+ import { OrtSession as x } from "./vision/core/session.js";
9
+ import { loadImage as S } from "./vision/io/image.js";
10
+ import { fromCv2 as C, letterbox as w, normalize as T, resize as E, toCHW as D, toCv2 as O, toFloat32 as k, toFloat32Tensor as A, toTensor as j } from "./vision/preprocess/image.js";
11
+ import { softmax as M, topK as N } from "./vision/postprocess/classification.js";
12
+ import { batchedNms as P, decodeYolo as F, decodeYoloAnchors as I, decodeYoloV8 as L, decodeYoloV8Anchors as R, nms as z } from "./vision/postprocess/detection.js";
13
+ import { decodeYoloSeg as B, decodeYoloV8Seg as V } from "./vision/postprocess/segmentation.js";
14
+ import { VisionTask as H } from "./vision/tasks/base.js";
15
+ import { Classifier as U } from "./vision/tasks/classifier.js";
16
+ import { Detector as W } from "./vision/tasks/detector.js";
17
+ import { Segmenter as G } from "./vision/tasks/segmenter.js";
18
+ import { VERSION as K } from "./vision/index.js";
19
19
  import { LUMINANCE_SAMPLE_MAX_EDGE as q, LowLuminanceError as J, computeImageLuminance as Y, isLuminanceAcceptable as X } from "./vision/luminance.js";
20
20
  import { useLiveLuminance as Z } from "./vision/use-live-luminance.js";
21
- export { o as BoundingBox, u as Boxes, g as COCO_CLASSES, d as ClassificationResults, H as Classifier, v as DEFAULT_PROVIDERS, f as DetectionResults, U as Detector, e as ImageLoadError, t as InferenceError, q as LUMINANCE_SAMPLE_MAX_EDGE, n as LabelMapError, J as LowLuminanceError, s as Mask, p as Masks, r as ModelLoadError, b as OrtSession, i as OrtVisionError, m as Probs, a as ProviderNotAvailableError, c as RGBImage, h as SegmentationResults, W as Segmenter, l as SpeedTimer, G as VERSION, V as VisionTask, N as batchedNms, Y as computeImageLuminance, P as decodeYolo, F as decodeYoloAnchors, z as decodeYoloSeg, I as decodeYoloV8, L as decodeYoloV8Anchors, B as decodeYoloV8Seg, S as fromCv2, X as isLuminanceAcceptable, C as letterbox, x as loadImage, R as nms, w as normalize, T as resize, _ as resolveLabels, y as resolveProviders, j as softmax, E as toCHW, D as toCv2, O as toFloat32, k as toFloat32Tensor, A as toTensor, M as topK, K as useCameraStream, Z as useLiveLuminance };
21
+ export { s as BoundingBox, d as Boxes, _ as COCO_CLASSES, f as ClassificationResults, U as Classifier, y as DEFAULT_PROVIDERS, p as DetectionResults, W as Detector, t as ImageLoadError, n as InferenceError, q as LUMINANCE_SAMPLE_MAX_EDGE, r as LabelMapError, J as LowLuminanceError, c as Mask, m as Masks, i as ModelLoadError, x as OrtSession, a as OrtVisionError, h as Probs, o as ProviderNotAvailableError, l as RGBImage, g as SegmentationResults, G as Segmenter, u as SpeedTimer, K as VERSION, H as VisionTask, P as batchedNms, Y as computeImageLuminance, F as decodeYolo, I as decodeYoloAnchors, B as decodeYoloSeg, L as decodeYoloV8, R as decodeYoloV8Anchors, V as decodeYoloV8Seg, C as fromCv2, X as isLuminanceAcceptable, w as letterbox, S as loadImage, z as nms, T as normalize, E as resize, v as resolveLabels, b as resolveProviders, M as softmax, D as toCHW, O as toCv2, k as toFloat32, A as toFloat32Tensor, j as toTensor, N as topK, e as useCameraStream, Z as useLiveLuminance };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tempest-react-sdk",
3
- "version": "0.35.0",
3
+ "version": "0.36.0",
4
4
  "description": "SDK público da Tempest com componentes, hooks e integrações para projetos React.",
5
5
  "type": "module",
6
6
  "license": "MIT",