@agicash/qr-scanner 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +33 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +33 -19
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,15 @@ __export(index_exports, {
|
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(index_exports);
|
|
28
28
|
|
|
29
|
+
// src/debug.ts
|
|
30
|
+
var enabled = false;
|
|
31
|
+
function setDebug(on) {
|
|
32
|
+
enabled = on;
|
|
33
|
+
}
|
|
34
|
+
function debug(...args) {
|
|
35
|
+
if (enabled) console.debug(...args);
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
// src/camera.ts
|
|
30
39
|
var CameraPermissionError = class extends Error {
|
|
31
40
|
constructor(message = "Camera access denied. Please grant camera permission and try again.") {
|
|
@@ -66,16 +75,16 @@ var CameraManager = class {
|
|
|
66
75
|
const t0 = performance.now();
|
|
67
76
|
this.stream = await this.acquireStream();
|
|
68
77
|
const t1 = performance.now();
|
|
69
|
-
|
|
78
|
+
debug(`[QrScanner] acquireStream: ${(t1 - t0).toFixed(0)}ms`);
|
|
70
79
|
await this.ensureBestCamera();
|
|
71
80
|
const t2 = performance.now();
|
|
72
|
-
|
|
81
|
+
debug(`[QrScanner] ensureBestCamera: ${(t2 - t1).toFixed(0)}ms`);
|
|
73
82
|
video.srcObject = this.stream;
|
|
74
83
|
video.setAttribute("playsinline", "true");
|
|
75
84
|
await video.play();
|
|
76
85
|
const t3 = performance.now();
|
|
77
|
-
|
|
78
|
-
|
|
86
|
+
debug(`[QrScanner] video.play: ${(t3 - t2).toFixed(0)}ms`);
|
|
87
|
+
debug(`[QrScanner] camera.start total: ${(t3 - t0).toFixed(0)}ms`);
|
|
79
88
|
if (this.facingMode === "environment" || this.facingMode === "user") {
|
|
80
89
|
const finalDeviceId = this.getVideoTrack()?.getSettings().deviceId;
|
|
81
90
|
if (finalDeviceId) {
|
|
@@ -150,9 +159,7 @@ var CameraManager = class {
|
|
|
150
159
|
*/
|
|
151
160
|
async ensureBestCamera() {
|
|
152
161
|
if (this.facingMode !== "environment" && this.facingMode !== "user") {
|
|
153
|
-
|
|
154
|
-
"[QrScanner] ensureBestCamera: skipped (specific deviceId)"
|
|
155
|
-
);
|
|
162
|
+
debug("[QrScanner] ensureBestCamera: skipped (specific deviceId)");
|
|
156
163
|
return;
|
|
157
164
|
}
|
|
158
165
|
const track = this.getVideoTrack();
|
|
@@ -160,12 +167,12 @@ var CameraManager = class {
|
|
|
160
167
|
try {
|
|
161
168
|
const capabilities = track.getCapabilities();
|
|
162
169
|
if (!capabilities.focusMode || capabilities.focusMode.includes("continuous")) {
|
|
163
|
-
|
|
170
|
+
debug(
|
|
164
171
|
`[QrScanner] ensureBestCamera: skipped (focusMode: ${JSON.stringify(capabilities.focusMode)})`
|
|
165
172
|
);
|
|
166
173
|
return;
|
|
167
174
|
}
|
|
168
|
-
|
|
175
|
+
debug(
|
|
169
176
|
`[QrScanner] ensureBestCamera: current camera lacks autofocus (focusMode: ${JSON.stringify(capabilities.focusMode)})`
|
|
170
177
|
);
|
|
171
178
|
} catch {
|
|
@@ -182,7 +189,7 @@ var CameraManager = class {
|
|
|
182
189
|
const candidates = devices.filter(
|
|
183
190
|
(d) => d.kind === "videoinput" && d.deviceId !== currentDeviceId
|
|
184
191
|
);
|
|
185
|
-
|
|
192
|
+
debug(
|
|
186
193
|
`[QrScanner] ensureBestCamera: testing ${candidates.length} candidate camera(s)`
|
|
187
194
|
);
|
|
188
195
|
if (candidates.length === 0) return;
|
|
@@ -199,11 +206,11 @@ var CameraManager = class {
|
|
|
199
206
|
},
|
|
200
207
|
audio: false
|
|
201
208
|
});
|
|
202
|
-
|
|
209
|
+
debug(
|
|
203
210
|
`[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia ${(performance.now() - t).toFixed(0)}ms`
|
|
204
211
|
);
|
|
205
212
|
} catch {
|
|
206
|
-
|
|
213
|
+
debug(
|
|
207
214
|
`[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia failed ${(performance.now() - t).toFixed(0)}ms`
|
|
208
215
|
);
|
|
209
216
|
continue;
|
|
@@ -289,12 +296,12 @@ var CameraManager = class {
|
|
|
289
296
|
const t = performance.now();
|
|
290
297
|
try {
|
|
291
298
|
const stream = await navigator.mediaDevices.getUserMedia(attempts[i]);
|
|
292
|
-
|
|
299
|
+
debug(
|
|
293
300
|
`[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms \u2713`
|
|
294
301
|
);
|
|
295
302
|
return stream;
|
|
296
303
|
} catch (err) {
|
|
297
|
-
|
|
304
|
+
debug(
|
|
298
305
|
`[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms \u2717 ${err instanceof DOMException ? err.name : err}`
|
|
299
306
|
);
|
|
300
307
|
if (err instanceof DOMException) {
|
|
@@ -683,7 +690,7 @@ var Scanner = class {
|
|
|
683
690
|
}
|
|
684
691
|
}
|
|
685
692
|
await this.camera.start(this.video);
|
|
686
|
-
|
|
693
|
+
debug(
|
|
687
694
|
`[QrScanner] start: camera ready ${(performance.now() - t0).toFixed(0)}ms`
|
|
688
695
|
);
|
|
689
696
|
if (this.overlay) {
|
|
@@ -692,7 +699,7 @@ var Scanner = class {
|
|
|
692
699
|
if (!this.worker) {
|
|
693
700
|
const tw = performance.now();
|
|
694
701
|
this.worker = this.createWorker();
|
|
695
|
-
|
|
702
|
+
debug(
|
|
696
703
|
`[QrScanner] start: worker created ${(performance.now() - tw).toFixed(0)}ms`
|
|
697
704
|
);
|
|
698
705
|
}
|
|
@@ -707,9 +714,7 @@ var Scanner = class {
|
|
|
707
714
|
});
|
|
708
715
|
this.active = true;
|
|
709
716
|
this.paused = false;
|
|
710
|
-
|
|
711
|
-
`[QrScanner] start: total ${(performance.now() - t0).toFixed(0)}ms`
|
|
712
|
-
);
|
|
717
|
+
debug(`[QrScanner] start: total ${(performance.now() - t0).toFixed(0)}ms`);
|
|
713
718
|
}
|
|
714
719
|
stop() {
|
|
715
720
|
this.frameExtractor?.stop();
|
|
@@ -1051,6 +1056,15 @@ var QrScanner = class {
|
|
|
1051
1056
|
static setWorkerUrl(url) {
|
|
1052
1057
|
setWorkerUrl(url);
|
|
1053
1058
|
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Enable or disable debug logging (performance timings, camera selection).
|
|
1061
|
+
* Off by default. Useful for diagnosing camera issues in the browser console.
|
|
1062
|
+
* @example
|
|
1063
|
+
* QrScanner.setDebug(true);
|
|
1064
|
+
*/
|
|
1065
|
+
static setDebug(enabled2) {
|
|
1066
|
+
setDebug(enabled2);
|
|
1067
|
+
}
|
|
1054
1068
|
/** Scan a single image (not a video stream). */
|
|
1055
1069
|
static scanImage(source, options) {
|
|
1056
1070
|
return scanImage(source, options);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/camera.ts","../src/frame-extractor.ts","../src/overlay.ts","../src/scan-region.ts","../src/scanner.ts","../src/scan-image.ts","../src/utils.ts"],"sourcesContent":["import { Scanner, setWorkerUrl } from './scanner.js';\nimport {\n CameraManager,\n CameraNotFoundError,\n CameraPermissionError,\n} from './camera.js';\nimport { scanImage } from './scan-image.js';\nimport { setZXingModuleOverrides } from 'zxing-wasm/reader';\nimport type {\n ScanResult,\n ScanRegion,\n ScannerOptions,\n Camera,\n Point,\n FacingMode,\n DeviceId,\n InversionMode,\n} from './types.js';\nimport type { ReaderOptions } from 'zxing-wasm/reader';\n\nexport { CameraNotFoundError, CameraPermissionError };\n\nexport type {\n ScanResult,\n ScanRegion,\n ScannerOptions,\n Camera,\n Point,\n FacingMode,\n DeviceId,\n InversionMode,\n};\n\n/**\n * High-performance QR code scanner for the web, powered by ZXing-C++ WebAssembly.\n */\nclass QrScanner {\n private scanner: Scanner;\n\n constructor(\n videoElement: HTMLVideoElement,\n onDecode: (result: ScanResult) => void,\n options: ScannerOptions = {},\n ) {\n this.scanner = new Scanner(videoElement, onDecode, options);\n }\n\n /** Start camera and begin scanning. Resolves when camera is ready. */\n async start(): Promise<void> {\n return this.scanner.start();\n }\n\n /** Stop scanning and release the camera stream. */\n stop(): void {\n this.scanner.stop();\n }\n\n /** Stop scanning, release camera, terminate worker, clean up DOM. */\n destroy(): void {\n this.scanner.destroy();\n }\n\n /** Pause scanning. If stopStreamImmediately is false, camera stays on. */\n async pause(stopStreamImmediately?: boolean): Promise<boolean> {\n return this.scanner.pause(stopStreamImmediately);\n }\n\n /** Switch to a different camera by facing mode or device ID. */\n async setCamera(facingModeOrDeviceId: FacingMode | DeviceId): Promise<void> {\n return this.scanner.setCamera(facingModeOrDeviceId);\n }\n\n /** Check if the current camera supports flash/torch. */\n async hasFlash(): Promise<boolean> {\n return this.scanner.hasFlash();\n }\n\n /** Whether flash is currently on. */\n isFlashOn(): boolean {\n return this.scanner.isFlashOn();\n }\n\n /** Toggle flash on/off. */\n async toggleFlash(): Promise<void> {\n return this.scanner.toggleFlash();\n }\n\n /** Turn flash on. */\n async turnFlashOn(): Promise<void> {\n return this.scanner.turnFlashOn();\n }\n\n /** Turn flash off. */\n async turnFlashOff(): Promise<void> {\n return this.scanner.turnFlashOff();\n }\n\n /** Set the inversion mode for detecting inverted QR codes. */\n setInversionMode(mode: InversionMode): void {\n this.scanner.setInversionMode(mode);\n }\n\n // --- Static methods ---\n\n /** Check if the device has at least one camera. */\n static hasCamera(): Promise<boolean> {\n return CameraManager.hasCamera();\n }\n\n /** List available cameras. Pass true to request labels (triggers permission prompt). */\n static listCameras(requestLabels?: boolean): Promise<Camera[]> {\n return CameraManager.listCameras(requestLabels);\n }\n\n /**\n * Pre-load the WASM binary so it's ready when the scanner starts.\n * Call this early (e.g., on app init) to avoid delay on first scan.\n */\n static async preload(): Promise<void> {\n // Trigger WASM loading by doing a minimal scan\n const pixel = new Uint8ClampedArray([255, 255, 255, 255]);\n const img = new ImageData(pixel, 1, 1);\n try {\n await scanImage(img);\n } catch {\n // Expected — no QR code in a 1x1 image. The point was to load WASM.\n }\n }\n\n /**\n * Configure WASM loading. Call before creating any scanner instance.\n * @example\n * QrScanner.configureWasm({ locateFile: (filename) => `/wasm/${filename}` });\n */\n static configureWasm(overrides: Partial<EmscriptenModule>): void {\n setZXingModuleOverrides(overrides);\n }\n\n /**\n * Set a custom URL for the worker script. Call before creating any scanner.\n * Needed for CJS consumers or non-standard bundler setups.\n * By default, the worker URL is resolved via `new URL('./worker.js', import.meta.url)`,\n * which works with Vite, webpack 5, Parcel, and other modern bundlers.\n * @example\n * QrScanner.setWorkerUrl('/assets/qr-scanner-worker.js');\n */\n static setWorkerUrl(url: string | URL): void {\n setWorkerUrl(url);\n }\n\n /** Scan a single image (not a video stream). */\n static scanImage(\n source:\n | HTMLImageElement\n | HTMLCanvasElement\n | OffscreenCanvas\n | ImageBitmap\n | ImageData\n | Blob\n | ArrayBuffer\n | Uint8Array\n | File\n | URL\n | string,\n options?: {\n scanRegion?: ScanRegion | null;\n canvas?: HTMLCanvasElement | null;\n decoderOptions?: Partial<ReaderOptions>;\n },\n ): Promise<ScanResult> {\n return scanImage(source, options);\n }\n}\n\nexport default QrScanner;\n","import type { FacingMode, DeviceId, Camera } from './types.js';\n\nexport class CameraPermissionError extends Error {\n constructor(\n message = 'Camera access denied. Please grant camera permission and try again.',\n ) {\n super(message);\n this.name = 'CameraPermissionError';\n }\n}\n\nexport class CameraNotFoundError extends Error {\n constructor(\n message = 'No camera found. Please connect a camera and try again.',\n ) {\n super(message);\n this.name = 'CameraNotFoundError';\n }\n}\n\nconst CACHE_KEY_PREFIX = '@agicash/qr-scanner:camera:';\n\nfunction getCachedDeviceId(facingMode: string): string | null {\n try {\n return localStorage.getItem(`${CACHE_KEY_PREFIX}${facingMode}`);\n } catch {\n return null;\n }\n}\n\nfunction setCachedDeviceId(facingMode: string, deviceId: string): void {\n try {\n localStorage.setItem(`${CACHE_KEY_PREFIX}${facingMode}`, deviceId);\n } catch {\n // localStorage unavailable or full — ignore\n }\n}\n\nexport interface CameraConfig {\n preferredCamera?: FacingMode | DeviceId;\n cameraResolution?: {\n width?: MediaTrackConstraintSet['width'];\n height?: MediaTrackConstraintSet['height'];\n };\n}\n\nexport class CameraManager {\n private stream: MediaStream | null = null;\n private facingMode: FacingMode | DeviceId;\n private resolution: CameraConfig['cameraResolution'];\n\n constructor(config: CameraConfig = {}) {\n this.facingMode = config.preferredCamera ?? 'environment';\n this.resolution = config.cameraResolution;\n }\n\n async start(video: HTMLVideoElement): Promise<MediaStream> {\n if (this.stream) {\n return this.stream;\n }\n\n const t0 = performance.now();\n\n this.stream = await this.acquireStream();\n const t1 = performance.now();\n console.debug(`[QrScanner] acquireStream: ${(t1 - t0).toFixed(0)}ms`);\n\n // On some devices (e.g. Samsung S24 + Brave), facingMode: 'environment'\n // picks an ultrawide camera that lacks autofocus. Check and switch to a\n // better camera BEFORE showing on screen to avoid visible flicker.\n await this.ensureBestCamera();\n const t2 = performance.now();\n console.debug(`[QrScanner] ensureBestCamera: ${(t2 - t1).toFixed(0)}ms`);\n\n video.srcObject = this.stream;\n video.setAttribute('playsinline', 'true');\n await video.play();\n const t3 = performance.now();\n console.debug(`[QrScanner] video.play: ${(t3 - t2).toFixed(0)}ms`);\n console.debug(`[QrScanner] camera.start total: ${(t3 - t0).toFixed(0)}ms`);\n\n // Cache the final camera so subsequent starts skip ensureBestCamera\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n const finalDeviceId = this.getVideoTrack()?.getSettings().deviceId;\n if (finalDeviceId) {\n setCachedDeviceId(this.facingMode, finalDeviceId);\n }\n }\n\n return this.stream;\n }\n\n stop(): void {\n if (this.stream) {\n for (const track of this.stream.getTracks()) {\n track.stop();\n }\n this.stream = null;\n }\n }\n\n async setCamera(\n facingModeOrDeviceId: FacingMode | DeviceId,\n video: HTMLVideoElement,\n ): Promise<void> {\n this.stop();\n this.facingMode = facingModeOrDeviceId;\n await this.start(video);\n }\n\n getStream(): MediaStream | null {\n return this.stream;\n }\n\n async hasFlash(): Promise<boolean> {\n const track = this.getVideoTrack();\n if (!track) return false;\n\n try {\n const capabilities = track.getCapabilities() as MediaTrackCapabilities & {\n torch?: boolean;\n };\n return capabilities.torch === true;\n } catch {\n return false;\n }\n }\n\n isFlashOn(): boolean {\n const track = this.getVideoTrack();\n if (!track) return false;\n\n const settings = track.getSettings() as MediaTrackSettings & {\n torch?: boolean;\n };\n return settings.torch === true;\n }\n\n async toggleFlash(): Promise<void> {\n if (this.isFlashOn()) {\n await this.turnFlashOff();\n } else {\n await this.turnFlashOn();\n }\n }\n\n async turnFlashOn(): Promise<void> {\n await this.setTorch(true);\n }\n\n async turnFlashOff(): Promise<void> {\n await this.setTorch(false);\n }\n\n private async setTorch(on: boolean): Promise<void> {\n const track = this.getVideoTrack();\n if (!track) {\n throw new Error('No active camera stream');\n }\n\n try {\n await track.applyConstraints({\n advanced: [{ torch: on } as MediaTrackConstraintSet],\n });\n } catch {\n throw new Error('Flash/torch is not supported on this device');\n }\n }\n\n /**\n * If the current camera lacks continuous autofocus (e.g. an ultrawide sensor\n * picked by facingMode: 'environment'), find a better camera with the same\n * facing mode and replace this.stream. Called before assigning to the video\n * element so the user never sees the wrong camera.\n */\n private async ensureBestCamera(): Promise<void> {\n if (this.facingMode !== 'environment' && this.facingMode !== 'user') {\n console.debug(\n '[QrScanner] ensureBestCamera: skipped (specific deviceId)',\n );\n return;\n }\n\n const track = this.getVideoTrack();\n if (!track) return;\n\n try {\n const capabilities = track.getCapabilities() as MediaTrackCapabilities & {\n focusMode?: string[];\n };\n if (\n !capabilities.focusMode ||\n capabilities.focusMode.includes('continuous')\n ) {\n // focusMode not reported (e.g. Safari/iOS) or has autofocus — skip.\n // Only enter the candidate loop when the browser explicitly reports\n // focusMode without 'continuous' (e.g. S24 + Brave ultrawide).\n console.debug(\n `[QrScanner] ensureBestCamera: skipped (focusMode: ${JSON.stringify(capabilities.focusMode)})`,\n );\n return;\n }\n console.debug(\n `[QrScanner] ensureBestCamera: current camera lacks autofocus (focusMode: ${JSON.stringify(capabilities.focusMode)})`,\n );\n } catch {\n return;\n }\n\n // Current camera lacks continuous autofocus.\n // Enumerate devices while stream is active (ensures deviceIds are available).\n const currentDeviceId = track.getSettings().deviceId;\n\n let devices: MediaDeviceInfo[];\n try {\n devices = await navigator.mediaDevices.enumerateDevices();\n } catch {\n return;\n }\n if (!Array.isArray(devices)) return;\n\n const candidates = devices.filter(\n (d) => d.kind === 'videoinput' && d.deviceId !== currentDeviceId,\n );\n console.debug(\n `[QrScanner] ensureBestCamera: testing ${candidates.length} candidate camera(s)`,\n );\n if (candidates.length === 0) return;\n\n // Stop current stream — mobile devices only allow one active camera\n this.stop();\n\n for (const candidate of candidates) {\n const t = performance.now();\n let candidateStream: MediaStream;\n try {\n candidateStream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: { exact: candidate.deviceId },\n width: this.resolution?.width ?? { ideal: 1920 },\n height: this.resolution?.height ?? { ideal: 1080 },\n },\n audio: false,\n });\n console.debug(\n `[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia ${(performance.now() - t).toFixed(0)}ms`,\n );\n } catch {\n console.debug(\n `[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia failed ${(performance.now() - t).toFixed(0)}ms`,\n );\n continue;\n }\n\n const candidateTrack = candidateStream.getVideoTracks()[0];\n if (!candidateTrack) {\n for (const t of candidateStream.getTracks()) t.stop();\n continue;\n }\n\n // Must match the desired facing mode\n const candidateSettings =\n candidateTrack.getSettings() as MediaTrackSettings & {\n facingMode?: string;\n };\n if (\n candidateSettings.facingMode &&\n candidateSettings.facingMode !== this.facingMode\n ) {\n for (const t of candidateStream.getTracks()) t.stop();\n continue;\n }\n\n // Check if this camera supports continuous autofocus\n try {\n const candidateCaps =\n candidateTrack.getCapabilities() as MediaTrackCapabilities & {\n focusMode?: string[];\n };\n if (candidateCaps.focusMode?.includes('continuous')) {\n this.stream = candidateStream;\n return;\n }\n } catch {\n // Can't check capabilities, skip\n }\n\n for (const t of candidateStream.getTracks()) t.stop();\n }\n\n // No better camera found — re-open the original\n try {\n this.stream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: currentDeviceId ? { exact: currentDeviceId } : undefined,\n width: this.resolution?.width ?? { ideal: 1920 },\n height: this.resolution?.height ?? { ideal: 1080 },\n },\n audio: false,\n });\n } catch {\n try {\n this.stream = await navigator.mediaDevices.getUserMedia(\n this.buildConstraints(),\n );\n } catch {\n // Could not recover camera\n }\n }\n }\n\n private getVideoTrack(): MediaStreamTrack | null {\n if (!this.stream) return null;\n const tracks = this.stream.getVideoTracks();\n return tracks[0] ?? null;\n }\n\n /**\n * Try getUserMedia with progressively simpler constraints.\n *\n * Some browsers (e.g. Brave on Samsung Galaxy S24) throw NotReadableError\n * when facingMode and resolution constraints are combined. Falling back to\n * fewer constraints lets us still open the camera on those browsers.\n */\n private async acquireStream(): Promise<MediaStream> {\n const labels: string[] = [];\n const attempts: MediaStreamConstraints[] = [];\n\n // If we've previously found a good camera for this facingMode, try it first\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n const cachedId = getCachedDeviceId(this.facingMode);\n if (cachedId) {\n labels.push('cached deviceId');\n const video: MediaTrackConstraints = {\n deviceId: { exact: cachedId },\n };\n if (this.resolution?.width) video.width = this.resolution.width;\n else video.width = { ideal: 1920 };\n if (this.resolution?.height) video.height = this.resolution.height;\n else video.height = { ideal: 1080 };\n attempts.push({ video, audio: false });\n }\n }\n\n // Standard fallback chain\n labels.push('full constraints', 'no resolution', 'bare minimum');\n attempts.push(\n // facingMode/deviceId + resolution\n this.buildConstraints(),\n // facingMode/deviceId only, no resolution\n this.buildConstraints(false),\n // Bare minimum\n { video: true, audio: false },\n );\n\n let lastError: unknown;\n for (let i = 0; i < attempts.length; i++) {\n const t = performance.now();\n try {\n const stream = await navigator.mediaDevices.getUserMedia(attempts[i]);\n console.debug(\n `[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms ✓`,\n );\n return stream;\n } catch (err) {\n console.debug(\n `[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms ✗ ${err instanceof DOMException ? err.name : err}`,\n );\n if (err instanceof DOMException) {\n if (err.name === 'NotAllowedError') {\n throw new CameraPermissionError();\n }\n if (err.name === 'NotFoundError') {\n throw new CameraNotFoundError();\n }\n // NotReadableError or OverconstrainedError — try next fallback\n lastError = err;\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n private buildConstraints(includeResolution = true): MediaStreamConstraints {\n const video: MediaTrackConstraints = {};\n\n if (includeResolution) {\n video.width = this.resolution?.width ?? { ideal: 1920 };\n video.height = this.resolution?.height ?? { ideal: 1080 };\n }\n\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n video.facingMode = this.facingMode;\n } else {\n video.deviceId = { exact: this.facingMode };\n }\n\n return { video, audio: false };\n }\n\n static async hasCamera(): Promise<boolean> {\n try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n return devices.some((d) => d.kind === 'videoinput');\n } catch {\n return false;\n }\n }\n\n static async listCameras(requestLabels = false): Promise<Camera[]> {\n if (requestLabels) {\n // Requesting labels requires a temporary stream to trigger the permission prompt\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: true,\n });\n for (const track of stream.getTracks()) {\n track.stop();\n }\n } catch {\n // Permission denied — fall through with empty labels\n }\n }\n\n const devices = await navigator.mediaDevices.enumerateDevices();\n return devices\n .filter((d) => d.kind === 'videoinput')\n .map((d) => ({\n id: d.deviceId,\n label: d.label || `Camera ${d.deviceId.slice(0, 8)}`,\n }));\n }\n}\n","import type { ScanRegion } from './types.js';\n\nexport interface FrameExtractorConfig {\n maxScansPerSecond: number;\n getScanRegion: () => ScanRegion;\n}\n\nexport class FrameExtractor {\n private video: HTMLVideoElement;\n private canvas: HTMLCanvasElement | OffscreenCanvas;\n private ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n private rafId: number | null = null;\n private running = false;\n private workerBusy = false;\n private lastScanTime = -Infinity;\n private minInterval: number;\n private getScanRegion: () => ScanRegion;\n private onFrame: ((imageData: ImageData) => void) | null = null;\n\n constructor(video: HTMLVideoElement, config: FrameExtractorConfig) {\n this.video = video;\n this.minInterval = 1000 / config.maxScansPerSecond;\n this.getScanRegion = config.getScanRegion;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n this.canvas = new OffscreenCanvas(1, 1);\n this.ctx = this.canvas.getContext('2d')! as OffscreenCanvasRenderingContext2D;\n } else {\n this.canvas = document.createElement('canvas');\n this.canvas.style.display = 'none';\n this.ctx = this.canvas.getContext('2d')!;\n }\n }\n\n start(onFrame: (imageData: ImageData) => void): void {\n if (this.running) return;\n this.running = true;\n this.onFrame = onFrame;\n this.rafId = requestAnimationFrame(this.tick);\n }\n\n stop(): void {\n this.running = false;\n this.onFrame = null;\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n }\n\n destroy(): void {\n this.stop();\n if (this.canvas instanceof HTMLCanvasElement && this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n }\n\n markWorkerIdle(): void {\n this.workerBusy = false;\n }\n\n markWorkerBusy(): void {\n this.workerBusy = true;\n }\n\n private tick = (): void => {\n if (!this.running) return;\n\n this.rafId = requestAnimationFrame(this.tick);\n\n // Skip if worker is still processing previous frame\n if (this.workerBusy) return;\n\n // Rate limiting\n const now = performance.now();\n if (now - this.lastScanTime < this.minInterval) return;\n\n // Skip if video isn't ready\n if (this.video.readyState < 2) return;\n\n this.lastScanTime = now;\n\n const region = this.getScanRegion();\n const sx = region.x ?? 0;\n const sy = region.y ?? 0;\n const sw = region.width ?? this.video.videoWidth;\n const sh = region.height ?? this.video.videoHeight;\n\n if (sw <= 0 || sh <= 0) return;\n\n this.canvas.width = sw;\n this.canvas.height = sh;\n\n this.ctx.drawImage(this.video, sx, sy, sw, sh, 0, 0, sw, sh);\n const imageData = this.ctx.getImageData(0, 0, sw, sh);\n\n this.workerBusy = true;\n this.onFrame?.(imageData);\n };\n}\n","import type { ScanRegion, Point } from './types.js';\n\n/**\n * Compute the actual rendered position and size of the video content\n * within the element, accounting for object-fit: cover.\n *\n * With object-fit: cover the video is scaled up to fill the element and\n * cropped. The rendered content is larger than the element, centered,\n * with negative offsets for the cropped portions.\n *\n * When object-fit is the default (fill), the rendered size equals the\n * element size and offsets are zero — so this is backwards-compatible.\n */\nfunction getRenderedVideoRect(video: HTMLVideoElement): {\n offsetX: number;\n offsetY: number;\n width: number;\n height: number;\n} {\n const elementWidth = video.clientWidth;\n const elementHeight = video.clientHeight;\n const videoWidth = video.videoWidth || 1;\n const videoHeight = video.videoHeight || 1;\n\n const objectFit = getComputedStyle(video).objectFit;\n\n if (objectFit === 'cover') {\n const scale = Math.max(\n elementWidth / videoWidth,\n elementHeight / videoHeight,\n );\n const renderedWidth = videoWidth * scale;\n const renderedHeight = videoHeight * scale;\n return {\n offsetX: (elementWidth - renderedWidth) / 2,\n offsetY: (elementHeight - renderedHeight) / 2,\n width: renderedWidth,\n height: renderedHeight,\n };\n }\n\n if (objectFit === 'contain') {\n const scale = Math.min(\n elementWidth / videoWidth,\n elementHeight / videoHeight,\n );\n const renderedWidth = videoWidth * scale;\n const renderedHeight = videoHeight * scale;\n return {\n offsetX: (elementWidth - renderedWidth) / 2,\n offsetY: (elementHeight - renderedHeight) / 2,\n width: renderedWidth,\n height: renderedHeight,\n };\n }\n\n // Default (fill / none / scale-down with no scaling needed): element dimensions\n return { offsetX: 0, offsetY: 0, width: elementWidth, height: elementHeight };\n}\n\nexport interface OverlayConfig {\n highlightScanRegion: boolean;\n highlightCodeOutline: boolean;\n customOverlay?: HTMLDivElement;\n}\n\nexport class ScanOverlay {\n private container: HTMLElement;\n private overlayEl: HTMLDivElement | null = null;\n private codeOutlineEl: SVGElement | null = null;\n private config: OverlayConfig;\n private video: HTMLVideoElement;\n\n constructor(video: HTMLVideoElement, config: OverlayConfig) {\n this.video = video;\n this.config = config;\n\n const parent = video.parentElement;\n if (!parent) {\n throw new Error(\n 'QrScanner: video element must have a parent element. ' +\n 'The parent should have position: relative.',\n );\n }\n this.container = parent;\n }\n\n setup(): void {\n if (this.config.customOverlay) {\n this.overlayEl = this.config.customOverlay;\n this.positionOverlay();\n return;\n }\n\n if (this.config.highlightScanRegion) {\n this.createScanRegionOverlay();\n }\n\n if (this.config.highlightCodeOutline) {\n this.createCodeOutline();\n }\n }\n\n updateScanRegion(region: ScanRegion): void {\n if (!this.overlayEl || this.config.customOverlay) return;\n this.positionOverlayToRegion(region);\n }\n\n updateCodeOutline(\n cornerPoints: Point[] | null,\n scanRegion?: ScanRegion,\n ): void {\n if (!this.codeOutlineEl) return;\n\n if (!cornerPoints || cornerPoints.length < 4) {\n this.codeOutlineEl.style.display = 'none';\n return;\n }\n\n this.codeOutlineEl.style.display = 'block';\n\n const polygon = this.codeOutlineEl.querySelector('polygon');\n if (!polygon) return;\n\n // Corner points are relative to the cropped scan region.\n // Add the scan region offset to get full video coordinates,\n // then scale to display coordinates (accounting for object-fit).\n const regionX = scanRegion?.x ?? 0;\n const regionY = scanRegion?.y ?? 0;\n const rendered = getRenderedVideoRect(this.video);\n const scaleX = rendered.width / this.video.videoWidth;\n const scaleY = rendered.height / this.video.videoHeight;\n\n const points = cornerPoints\n .map(\n (p) =>\n `${(p.x + regionX) * scaleX + rendered.offsetX},${(p.y + regionY) * scaleY + rendered.offsetY}`,\n )\n .join(' ');\n\n polygon.setAttribute('points', points);\n }\n\n destroy(): void {\n if (this.overlayEl && !this.config.customOverlay) {\n this.overlayEl.remove();\n }\n if (this.codeOutlineEl) {\n this.codeOutlineEl.remove();\n }\n this.overlayEl = null;\n this.codeOutlineEl = null;\n }\n\n private createScanRegionOverlay(): void {\n this.overlayEl = document.createElement('div');\n this.overlayEl.className = 'qr-scanner-region';\n\n // Overlay size: 3/4 of the smaller container dimension, centered.\n const cw = this.container.clientWidth;\n const ch = this.container.clientHeight;\n const size = Math.round((Math.min(cw, ch) * 3) / 4);\n\n Object.assign(this.overlayEl.style, {\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: `${size}px`,\n height: `${size}px`,\n border: '2px solid rgba(255, 255, 255, 0.5)',\n borderRadius: '8px',\n boxShadow: '0 0 0 9999px rgba(0, 0, 0, 0.5)',\n pointerEvents: 'none',\n zIndex: '10',\n });\n\n // Corner markers\n const corners = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];\n for (const corner of corners) {\n const marker = document.createElement('div');\n marker.className = `qr-scanner-corner qr-scanner-corner-${corner}`;\n\n const [vertical, horizontal] = corner.split('-');\n\n Object.assign(marker.style, {\n position: 'absolute',\n width: '24px',\n height: '24px',\n [vertical]: '-2px',\n [horizontal]: '-2px',\n [`border-${vertical}`]: '3px solid white',\n [`border-${horizontal}`]: '3px solid white',\n [`border-${vertical}-${horizontal}-radius`]: '8px',\n });\n\n this.overlayEl.appendChild(marker);\n }\n\n this.container.appendChild(this.overlayEl);\n }\n\n private createCodeOutline(): void {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('class', 'qr-scanner-code-outline');\n\n Object.assign(svg.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '11',\n display: 'none',\n });\n\n const polygon = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'polygon',\n );\n polygon.setAttribute('fill', 'none');\n polygon.setAttribute('stroke', '#00ff00');\n polygon.setAttribute('stroke-width', '3');\n polygon.setAttribute('stroke-linejoin', 'round');\n\n // Animated stroke\n const animate = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'animate',\n );\n animate.setAttribute('attributeName', 'stroke-opacity');\n animate.setAttribute('values', '1;0.5;1');\n animate.setAttribute('dur', '1.5s');\n animate.setAttribute('repeatCount', 'indefinite');\n polygon.appendChild(animate);\n\n svg.appendChild(polygon);\n this.container.appendChild(svg);\n this.codeOutlineEl = svg;\n }\n\n private positionOverlay(): void {\n if (!this.overlayEl) return;\n\n Object.assign(this.overlayEl.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '10',\n });\n }\n\n private positionOverlayToRegion(_region: ScanRegion): void {\n if (!this.overlayEl) return;\n\n // Keep the overlay at a container-relative centered size rather than\n // mapping scan region coordinates to display coordinates. With\n // object-fit: cover on a portrait phone with a landscape camera, the\n // mapped region extends beyond the container — fine once the camera is\n // visible but causes a jarring jump from the initial placeholder.\n // The overlay is a visual guide; the actual scan area (in the frame\n // extractor) is unaffected and may be larger than what's shown.\n const cw = this.container.clientWidth;\n const ch = this.container.clientHeight;\n const size = Math.round((Math.min(cw, ch) * 3) / 4);\n\n // Only update size — initial CSS centering (top: 50%, left: 50%,\n // transform: translate(-50%, -50%)) persists and handles re-centering.\n Object.assign(this.overlayEl.style, {\n width: `${size}px`,\n height: `${size}px`,\n });\n }\n}\n","import type { ScanRegion } from './types.js';\n\n/**\n * Calculate the default scan region: a centered square covering\n * 2/3 of the smaller video dimension.\n */\nexport function calculateDefaultScanRegion(video: HTMLVideoElement): ScanRegion {\n const videoWidth = video.videoWidth || video.width;\n const videoHeight = video.videoHeight || video.height;\n\n const smallerDimension = Math.min(videoWidth, videoHeight);\n const size = Math.round((smallerDimension * 2) / 3);\n\n return {\n x: Math.round((videoWidth - size) / 2),\n y: Math.round((videoHeight - size) / 2),\n width: size,\n height: size,\n };\n}\n","import { CameraManager } from './camera.js';\nimport { FrameExtractor } from './frame-extractor.js';\nimport { ScanOverlay } from './overlay.js';\nimport { calculateDefaultScanRegion } from './scan-region.js';\nimport type {\n ScannerOptions,\n ScanResult,\n ScanRegion,\n InversionMode,\n WorkerRequest,\n WorkerResponse,\n} from './types.js';\nimport type { ReaderOptions } from 'zxing-wasm/reader';\n\ntype OnDecodeCallback = (result: ScanResult) => void;\n\n/**\n * Custom worker URL override. When set, this URL is used instead of the\n * default bundler-resolved worker. Useful for CJS consumers or non-standard\n * bundler setups.\n */\nlet customWorkerUrl: string | URL | null = null;\n\nexport function setWorkerUrl(url: string | URL): void {\n customWorkerUrl = url;\n}\n\nfunction resolveWorkerUrl(): string | URL {\n if (customWorkerUrl) {\n return customWorkerUrl;\n }\n // Standard pattern: modern bundlers (Vite, webpack 5, Parcel, esbuild)\n // resolve `new URL('./file', import.meta.url)` at build time,\n // copying worker.js to the output directory and returning the correct URL.\n // Falls back gracefully for CJS builds where import.meta is unavailable.\n try {\n return new URL('./worker.js', import.meta.url);\n } catch {\n throw new Error(\n '@agicash/qr-scanner: Could not resolve worker URL. ' +\n 'Call QrScanner.setWorkerUrl() with the path to the worker script before creating a scanner. ' +\n 'Example: QrScanner.setWorkerUrl(\"/path/to/@agicash/qr-scanner/dist/worker.js\")',\n );\n }\n}\n\nexport class Scanner {\n private video: HTMLVideoElement;\n private onDecode: OnDecodeCallback;\n private options: ScannerOptions;\n private camera: CameraManager;\n private frameExtractor: FrameExtractor | null = null;\n private worker: Worker | null = null;\n private overlay: ScanOverlay | null = null;\n private active = false;\n private paused = false;\n private destroyed = false;\n\n constructor(\n video: HTMLVideoElement,\n onDecode: OnDecodeCallback,\n options: ScannerOptions = {},\n ) {\n this.video = video;\n this.onDecode = onDecode;\n this.options = options;\n\n this.camera = new CameraManager({\n preferredCamera: options.preferredCamera,\n cameraResolution: options.cameraResolution,\n });\n }\n\n async start(): Promise<void> {\n if (this.destroyed) {\n throw new Error('Scanner has been destroyed');\n }\n\n if (this.active && !this.paused) {\n return; // Already running\n }\n\n const t0 = performance.now();\n\n // Show overlay immediately (CSS-centered placeholder) so the UI looks\n // ready while the camera is still loading.\n if (\n !this.overlay &&\n (this.options.highlightScanRegion ||\n this.options.highlightCodeOutline ||\n this.options.overlay)\n ) {\n try {\n this.overlay = new ScanOverlay(this.video, {\n highlightScanRegion: this.options.highlightScanRegion ?? false,\n highlightCodeOutline: this.options.highlightCodeOutline ?? false,\n customOverlay: this.options.overlay,\n });\n this.overlay.setup();\n } catch {\n // Overlay setup failed (e.g., no parent element) — continue without overlay\n }\n }\n\n // Start camera\n await this.camera.start(this.video);\n console.debug(\n `[QrScanner] start: camera ready ${(performance.now() - t0).toFixed(0)}ms`,\n );\n\n // Now that video dimensions are known, position overlay exactly\n if (this.overlay) {\n this.overlay.updateScanRegion(this.getCurrentScanRegion());\n }\n\n // Create worker if needed\n if (!this.worker) {\n const tw = performance.now();\n this.worker = this.createWorker();\n console.debug(\n `[QrScanner] start: worker created ${(performance.now() - tw).toFixed(0)}ms`,\n );\n }\n\n // Create frame extractor if needed\n if (!this.frameExtractor) {\n this.frameExtractor = new FrameExtractor(this.video, {\n maxScansPerSecond: this.options.maxScansPerSecond ?? 15,\n getScanRegion: () => this.getCurrentScanRegion(),\n });\n }\n\n // Start frame extraction loop\n this.frameExtractor.start((imageData) => {\n this.sendToWorker(imageData);\n });\n\n this.active = true;\n this.paused = false;\n\n console.debug(\n `[QrScanner] start: total ${(performance.now() - t0).toFixed(0)}ms`,\n );\n }\n\n stop(): void {\n this.frameExtractor?.stop();\n this.camera.stop();\n this.video.srcObject = null;\n this.active = false;\n this.paused = false;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.stop();\n this.frameExtractor?.destroy();\n this.frameExtractor = null;\n this.overlay?.destroy();\n this.overlay = null;\n this.worker?.terminate();\n this.worker = null;\n this.destroyed = true;\n }\n\n async pause(stopStreamImmediately = true): Promise<boolean> {\n if (!this.active) return false;\n\n this.frameExtractor?.stop();\n this.paused = true;\n\n if (stopStreamImmediately) {\n this.camera.stop();\n this.video.srcObject = null;\n }\n\n return true;\n }\n\n async setCamera(facingModeOrDeviceId: string): Promise<void> {\n const wasActive = this.active && !this.paused;\n if (wasActive) {\n this.frameExtractor?.stop();\n }\n\n await this.camera.setCamera(facingModeOrDeviceId, this.video);\n\n if (wasActive) {\n this.frameExtractor?.start((imageData) => {\n this.sendToWorker(imageData);\n });\n }\n }\n\n async hasFlash(): Promise<boolean> {\n return this.camera.hasFlash();\n }\n\n isFlashOn(): boolean {\n return this.camera.isFlashOn();\n }\n\n async toggleFlash(): Promise<void> {\n return this.camera.toggleFlash();\n }\n\n async turnFlashOn(): Promise<void> {\n return this.camera.turnFlashOn();\n }\n\n async turnFlashOff(): Promise<void> {\n return this.camera.turnFlashOff();\n }\n\n setInversionMode(mode: InversionMode): void {\n if (!this.worker) return;\n\n const options: Partial<ReaderOptions> = {};\n switch (mode) {\n case 'original':\n options.tryInvert = false;\n break;\n case 'invert':\n options.tryInvert = true;\n break;\n case 'both':\n options.tryInvert = true;\n break;\n }\n\n const msg: WorkerRequest = { type: 'configure', options };\n this.worker.postMessage(msg);\n }\n\n isActive(): boolean {\n return this.active;\n }\n\n isPaused(): boolean {\n return this.paused;\n }\n\n isDestroyed(): boolean {\n return this.destroyed;\n }\n\n private getCurrentScanRegion(): ScanRegion {\n if (this.options.calculateScanRegion) {\n return this.options.calculateScanRegion(this.video);\n }\n return calculateDefaultScanRegion(this.video);\n }\n\n private createWorker(): Worker {\n const workerUrl = resolveWorkerUrl();\n const worker = new Worker(workerUrl, { type: 'module' });\n\n // Configure with custom decoder options\n if (this.options.decoderOptions) {\n const msg: WorkerRequest = {\n type: 'configure',\n options: this.options.decoderOptions,\n };\n worker.postMessage(msg);\n }\n\n worker.onmessage = (e: MessageEvent<WorkerResponse>) => {\n this.handleWorkerMessage(e.data);\n };\n\n worker.onerror = (err) => {\n console.error('QR Scanner worker error:', err);\n this.frameExtractor?.markWorkerIdle();\n };\n\n return worker;\n }\n\n private handleWorkerMessage(response: WorkerResponse): void {\n this.frameExtractor?.markWorkerIdle();\n\n if (response.type === 'ready') {\n return;\n }\n\n if (response.type === 'error') {\n this.options.onDecodeError?.(response.message);\n return;\n }\n\n if (response.type === 'result') {\n if (response.results.length > 0) {\n const result = response.results[0];\n this.onDecode(result);\n\n // Update overlay\n if (this.overlay) {\n const region = this.getCurrentScanRegion();\n this.overlay.updateScanRegion(region);\n this.overlay.updateCodeOutline(result.cornerPoints, region);\n }\n } else {\n this.options.onDecodeError?.('No QR code found');\n\n // Hide code outline when no QR found\n if (this.overlay) {\n this.overlay.updateCodeOutline(null);\n }\n }\n }\n }\n\n private sendToWorker(imageData: ImageData): void {\n if (!this.worker) return;\n\n const msg: WorkerRequest = { type: 'decode', imageData };\n this.worker.postMessage(msg, [imageData.data.buffer]);\n }\n}\n","import { readBarcodes, type ReaderOptions } from 'zxing-wasm/reader';\nimport type { ScanResult, ScanRegion, Point } from './types.js';\nimport { loadImageData } from './utils.js';\n\nconst defaultReaderOptions: ReaderOptions = {\n formats: ['QRCode'],\n tryHarder: true,\n tryInvert: true,\n tryRotate: true,\n tryDenoise: false,\n tryDownscale: true,\n maxNumberOfSymbols: 1,\n};\n\nfunction mapPosition(position: {\n topLeft: Point;\n topRight: Point;\n bottomLeft: Point;\n bottomRight: Point;\n}): Point[] {\n return [\n position.topLeft,\n position.topRight,\n position.bottomRight,\n position.bottomLeft,\n ];\n}\n\n/** Input types that zxing-wasm can handle directly (no canvas needed). */\ntype DirectInput = Blob | ArrayBuffer | Uint8Array | ImageData;\n\n/** Input types that need canvas-based pixel extraction. */\ntype CanvasInput = HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap;\n\nfunction isDirectInput(source: unknown): source is DirectInput {\n return (\n source instanceof Blob ||\n source instanceof ArrayBuffer ||\n source instanceof Uint8Array ||\n (typeof ImageData !== 'undefined' && source instanceof ImageData)\n );\n}\n\n/**\n * Scan a single image for QR codes. Does not require a camera or video stream.\n */\nexport async function scanImage(\n source:\n | CanvasInput\n | DirectInput\n | File\n | URL\n | string,\n options?: {\n scanRegion?: ScanRegion | null;\n canvas?: HTMLCanvasElement | null;\n decoderOptions?: Partial<ReaderOptions>;\n },\n): Promise<ScanResult> {\n const readerOptions: ReaderOptions = {\n ...defaultReaderOptions,\n ...options?.decoderOptions,\n formats: ['QRCode'],\n };\n\n let input: DirectInput;\n if (isDirectInput(source)) {\n input = source;\n } else if (typeof source === 'string' || source instanceof URL) {\n // URL string - fetch and pass as ArrayBuffer\n const url = source instanceof URL ? source.href : source;\n const response = await fetch(url);\n input = await response.arrayBuffer();\n } else {\n // Canvas-based sources - extract ImageData\n input = await loadImageData(source, options?.scanRegion, options?.canvas);\n }\n\n const results = await readBarcodes(input, readerOptions);\n const valid = results.filter((r) => r.isValid);\n\n if (valid.length === 0) {\n throw new Error('No QR code found in the image');\n }\n\n const first = valid[0];\n return {\n data: first.text,\n cornerPoints: mapPosition(first.position),\n };\n}\n","import type { ScanRegion } from './types.js';\n\n/**\n * Load an image source into an ImageData object, optionally cropping to a scan region.\n */\nexport async function loadImageData(\n source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | File | Blob | URL | string,\n scanRegion?: ScanRegion | null,\n canvas?: HTMLCanvasElement | null,\n): Promise<ImageData> {\n const img = await resolveImageSource(source);\n\n const sx = scanRegion?.x ?? 0;\n const sy = scanRegion?.y ?? 0;\n const sw = scanRegion?.width ?? (img.width - sx);\n const sh = scanRegion?.height ?? (img.height - sy);\n\n let drawCanvas: HTMLCanvasElement | OffscreenCanvas;\n let ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n\n if (canvas) {\n drawCanvas = canvas;\n canvas.width = sw;\n canvas.height = sh;\n ctx = canvas.getContext('2d')!;\n } else if (typeof OffscreenCanvas !== 'undefined') {\n drawCanvas = new OffscreenCanvas(sw, sh);\n ctx = drawCanvas.getContext('2d')! as OffscreenCanvasRenderingContext2D;\n } else {\n drawCanvas = document.createElement('canvas');\n drawCanvas.width = sw;\n drawCanvas.height = sh;\n ctx = drawCanvas.getContext('2d')!;\n }\n\n ctx.drawImage(img as CanvasImageSource, sx, sy, sw, sh, 0, 0, sw, sh);\n return ctx.getImageData(0, 0, sw, sh);\n}\n\nasync function resolveImageSource(\n source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | File | Blob | URL | string,\n): Promise<HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap> {\n if (source instanceof HTMLImageElement || source instanceof HTMLCanvasElement || source instanceof ImageBitmap) {\n return source;\n }\n\n if (typeof OffscreenCanvas !== 'undefined' && source instanceof OffscreenCanvas) {\n return source;\n }\n\n if (source instanceof File || source instanceof Blob) {\n return createImageBitmapFromBlob(source);\n }\n\n // URL or string\n const url = source instanceof URL ? source.href : source as string;\n const response = await fetch(url);\n const blob = await response.blob();\n return createImageBitmapFromBlob(blob);\n}\n\nasync function createImageBitmapFromBlob(blob: Blob): Promise<ImageBitmap> {\n if (typeof createImageBitmap !== 'undefined') {\n return createImageBitmap(blob);\n }\n // Fallback for environments without createImageBitmap\n const url = URL.createObjectURL(blob);\n try {\n const img = new Image();\n img.src = url;\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error('Failed to load image'));\n });\n return img as unknown as ImageBitmap;\n } finally {\n URL.revokeObjectURL(url);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YACE,UAAU,uEACV;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,sBAAN,cAAkC,MAAM;AAAA,EAC7C,YACE,UAAU,2DACV;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAM,mBAAmB;AAEzB,SAAS,kBAAkB,YAAmC;AAC5D,MAAI;AACF,WAAO,aAAa,QAAQ,GAAG,gBAAgB,GAAG,UAAU,EAAE;AAAA,EAChE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,kBAAkB,YAAoB,UAAwB;AACrE,MAAI;AACF,iBAAa,QAAQ,GAAG,gBAAgB,GAAG,UAAU,IAAI,QAAQ;AAAA,EACnE,QAAQ;AAAA,EAER;AACF;AAUO,IAAM,gBAAN,MAAoB;AAAA,EAKzB,YAAY,SAAuB,CAAC,GAAG;AAJvC,SAAQ,SAA6B;AAKnC,SAAK,aAAa,OAAO,mBAAmB;AAC5C,SAAK,aAAa,OAAO;AAAA,EAC3B;AAAA,EAEA,MAAM,MAAM,OAA+C;AACzD,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,YAAY,IAAI;AAE3B,SAAK,SAAS,MAAM,KAAK,cAAc;AACvC,UAAM,KAAK,YAAY,IAAI;AAC3B,YAAQ,MAAM,+BAA+B,KAAK,IAAI,QAAQ,CAAC,CAAC,IAAI;AAKpE,UAAM,KAAK,iBAAiB;AAC5B,UAAM,KAAK,YAAY,IAAI;AAC3B,YAAQ,MAAM,kCAAkC,KAAK,IAAI,QAAQ,CAAC,CAAC,IAAI;AAEvE,UAAM,YAAY,KAAK;AACvB,UAAM,aAAa,eAAe,MAAM;AACxC,UAAM,MAAM,KAAK;AACjB,UAAM,KAAK,YAAY,IAAI;AAC3B,YAAQ,MAAM,4BAA4B,KAAK,IAAI,QAAQ,CAAC,CAAC,IAAI;AACjE,YAAQ,MAAM,oCAAoC,KAAK,IAAI,QAAQ,CAAC,CAAC,IAAI;AAGzE,QAAI,KAAK,eAAe,iBAAiB,KAAK,eAAe,QAAQ;AACnE,YAAM,gBAAgB,KAAK,cAAc,GAAG,YAAY,EAAE;AAC1D,UAAI,eAAe;AACjB,0BAAkB,KAAK,YAAY,aAAa;AAAA,MAClD;AAAA,IACF;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,OAAa;AACX,QAAI,KAAK,QAAQ;AACf,iBAAW,SAAS,KAAK,OAAO,UAAU,GAAG;AAC3C,cAAM,KAAK;AAAA,MACb;AACA,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,MAAM,UACJ,sBACA,OACe;AACf,SAAK,KAAK;AACV,SAAK,aAAa;AAClB,UAAM,KAAK,MAAM,KAAK;AAAA,EACxB;AAAA,EAEA,YAAgC;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,WAA6B;AACjC,UAAM,QAAQ,KAAK,cAAc;AACjC,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI;AACF,YAAM,eAAe,MAAM,gBAAgB;AAG3C,aAAO,aAAa,UAAU;AAAA,IAChC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,YAAqB;AACnB,UAAM,QAAQ,KAAK,cAAc;AACjC,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,WAAW,MAAM,YAAY;AAGnC,WAAO,SAAS,UAAU;AAAA,EAC5B;AAAA,EAEA,MAAM,cAA6B;AACjC,QAAI,KAAK,UAAU,GAAG;AACpB,YAAM,KAAK,aAAa;AAAA,IAC1B,OAAO;AACL,YAAM,KAAK,YAAY;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,MAAM,cAA6B;AACjC,UAAM,KAAK,SAAS,IAAI;AAAA,EAC1B;AAAA,EAEA,MAAM,eAA8B;AAClC,UAAM,KAAK,SAAS,KAAK;AAAA,EAC3B;AAAA,EAEA,MAAc,SAAS,IAA4B;AACjD,UAAM,QAAQ,KAAK,cAAc;AACjC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,QAAI;AACF,YAAM,MAAM,iBAAiB;AAAA,QAC3B,UAAU,CAAC,EAAE,OAAO,GAAG,CAA4B;AAAA,MACrD,CAAC;AAAA,IACH,QAAQ;AACN,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,mBAAkC;AAC9C,QAAI,KAAK,eAAe,iBAAiB,KAAK,eAAe,QAAQ;AACnE,cAAQ;AAAA,QACN;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,cAAc;AACjC,QAAI,CAAC,MAAO;AAEZ,QAAI;AACF,YAAM,eAAe,MAAM,gBAAgB;AAG3C,UACE,CAAC,aAAa,aACd,aAAa,UAAU,SAAS,YAAY,GAC5C;AAIA,gBAAQ;AAAA,UACN,qDAAqD,KAAK,UAAU,aAAa,SAAS,CAAC;AAAA,QAC7F;AACA;AAAA,MACF;AACA,cAAQ;AAAA,QACN,4EAA4E,KAAK,UAAU,aAAa,SAAS,CAAC;AAAA,MACpH;AAAA,IACF,QAAQ;AACN;AAAA,IACF;AAIA,UAAM,kBAAkB,MAAM,YAAY,EAAE;AAE5C,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,UAAU,aAAa,iBAAiB;AAAA,IAC1D,QAAQ;AACN;AAAA,IACF;AACA,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG;AAE7B,UAAM,aAAa,QAAQ;AAAA,MACzB,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,aAAa;AAAA,IACnD;AACA,YAAQ;AAAA,MACN,yCAAyC,WAAW,MAAM;AAAA,IAC5D;AACA,QAAI,WAAW,WAAW,EAAG;AAG7B,SAAK,KAAK;AAEV,eAAW,aAAa,YAAY;AAClC,YAAM,IAAI,YAAY,IAAI;AAC1B,UAAI;AACJ,UAAI;AACF,0BAAkB,MAAM,UAAU,aAAa,aAAa;AAAA,UAC1D,OAAO;AAAA,YACL,UAAU,EAAE,OAAO,UAAU,SAAS;AAAA,YACtC,OAAO,KAAK,YAAY,SAAS,EAAE,OAAO,KAAK;AAAA,YAC/C,QAAQ,KAAK,YAAY,UAAU,EAAE,OAAO,KAAK;AAAA,UACnD;AAAA,UACA,OAAO;AAAA,QACT,CAAC;AACD,gBAAQ;AAAA,UACN,2CAA2C,UAAU,SAAS,UAAU,SAAS,MAAM,GAAG,CAAC,CAAC,mBAAmB,YAAY,IAAI,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,QAClJ;AAAA,MACF,QAAQ;AACN,gBAAQ;AAAA,UACN,2CAA2C,UAAU,SAAS,UAAU,SAAS,MAAM,GAAG,CAAC,CAAC,0BAA0B,YAAY,IAAI,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,QACzJ;AACA;AAAA,MACF;AAEA,YAAM,iBAAiB,gBAAgB,eAAe,EAAE,CAAC;AACzD,UAAI,CAAC,gBAAgB;AACnB,mBAAWA,MAAK,gBAAgB,UAAU,EAAG,CAAAA,GAAE,KAAK;AACpD;AAAA,MACF;AAGA,YAAM,oBACJ,eAAe,YAAY;AAG7B,UACE,kBAAkB,cAClB,kBAAkB,eAAe,KAAK,YACtC;AACA,mBAAWA,MAAK,gBAAgB,UAAU,EAAG,CAAAA,GAAE,KAAK;AACpD;AAAA,MACF;AAGA,UAAI;AACF,cAAM,gBACJ,eAAe,gBAAgB;AAGjC,YAAI,cAAc,WAAW,SAAS,YAAY,GAAG;AACnD,eAAK,SAAS;AACd;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,iBAAWA,MAAK,gBAAgB,UAAU,EAAG,CAAAA,GAAE,KAAK;AAAA,IACtD;AAGA,QAAI;AACF,WAAK,SAAS,MAAM,UAAU,aAAa,aAAa;AAAA,QACtD,OAAO;AAAA,UACL,UAAU,kBAAkB,EAAE,OAAO,gBAAgB,IAAI;AAAA,UACzD,OAAO,KAAK,YAAY,SAAS,EAAE,OAAO,KAAK;AAAA,UAC/C,QAAQ,KAAK,YAAY,UAAU,EAAE,OAAO,KAAK;AAAA,QACnD;AAAA,QACA,OAAO;AAAA,MACT,CAAC;AAAA,IACH,QAAQ;AACN,UAAI;AACF,aAAK,SAAS,MAAM,UAAU,aAAa;AAAA,UACzC,KAAK,iBAAiB;AAAA,QACxB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,gBAAyC;AAC/C,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,UAAM,SAAS,KAAK,OAAO,eAAe;AAC1C,WAAO,OAAO,CAAC,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,gBAAsC;AAClD,UAAM,SAAmB,CAAC;AAC1B,UAAM,WAAqC,CAAC;AAG5C,QAAI,KAAK,eAAe,iBAAiB,KAAK,eAAe,QAAQ;AACnE,YAAM,WAAW,kBAAkB,KAAK,UAAU;AAClD,UAAI,UAAU;AACZ,eAAO,KAAK,iBAAiB;AAC7B,cAAM,QAA+B;AAAA,UACnC,UAAU,EAAE,OAAO,SAAS;AAAA,QAC9B;AACA,YAAI,KAAK,YAAY,MAAO,OAAM,QAAQ,KAAK,WAAW;AAAA,YACrD,OAAM,QAAQ,EAAE,OAAO,KAAK;AACjC,YAAI,KAAK,YAAY,OAAQ,OAAM,SAAS,KAAK,WAAW;AAAA,YACvD,OAAM,SAAS,EAAE,OAAO,KAAK;AAClC,iBAAS,KAAK,EAAE,OAAO,OAAO,MAAM,CAAC;AAAA,MACvC;AAAA,IACF;AAGA,WAAO,KAAK,oBAAoB,iBAAiB,cAAc;AAC/D,aAAS;AAAA;AAAA,MAEP,KAAK,iBAAiB;AAAA;AAAA,MAEtB,KAAK,iBAAiB,KAAK;AAAA;AAAA,MAE3B,EAAE,OAAO,MAAM,OAAO,MAAM;AAAA,IAC9B;AAEA,QAAI;AACJ,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,YAAM,IAAI,YAAY,IAAI;AAC1B,UAAI;AACF,cAAM,SAAS,MAAM,UAAU,aAAa,aAAa,SAAS,CAAC,CAAC;AACpE,gBAAQ;AAAA,UACN,4BAA4B,OAAO,CAAC,CAAC,OAAO,YAAY,IAAI,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,QAC/E;AACA,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,gBAAQ;AAAA,UACN,4BAA4B,OAAO,CAAC,CAAC,OAAO,YAAY,IAAI,IAAI,GAAG,QAAQ,CAAC,CAAC,aAAQ,eAAe,eAAe,IAAI,OAAO,GAAG;AAAA,QACnI;AACA,YAAI,eAAe,cAAc;AAC/B,cAAI,IAAI,SAAS,mBAAmB;AAClC,kBAAM,IAAI,sBAAsB;AAAA,UAClC;AACA,cAAI,IAAI,SAAS,iBAAiB;AAChC,kBAAM,IAAI,oBAAoB;AAAA,UAChC;AAEA,sBAAY;AACZ;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM;AAAA,EACR;AAAA,EAEQ,iBAAiB,oBAAoB,MAA8B;AACzE,UAAM,QAA+B,CAAC;AAEtC,QAAI,mBAAmB;AACrB,YAAM,QAAQ,KAAK,YAAY,SAAS,EAAE,OAAO,KAAK;AACtD,YAAM,SAAS,KAAK,YAAY,UAAU,EAAE,OAAO,KAAK;AAAA,IAC1D;AAEA,QAAI,KAAK,eAAe,iBAAiB,KAAK,eAAe,QAAQ;AACnE,YAAM,aAAa,KAAK;AAAA,IAC1B,OAAO;AACL,YAAM,WAAW,EAAE,OAAO,KAAK,WAAW;AAAA,IAC5C;AAEA,WAAO,EAAE,OAAO,OAAO,MAAM;AAAA,EAC/B;AAAA,EAEA,aAAa,YAA8B;AACzC,QAAI;AACF,YAAM,UAAU,MAAM,UAAU,aAAa,iBAAiB;AAC9D,aAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,YAAY;AAAA,IACpD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,aAAa,YAAY,gBAAgB,OAA0B;AACjE,QAAI,eAAe;AAEjB,UAAI;AACF,cAAM,SAAS,MAAM,UAAU,aAAa,aAAa;AAAA,UACvD,OAAO;AAAA,QACT,CAAC;AACD,mBAAW,SAAS,OAAO,UAAU,GAAG;AACtC,gBAAM,KAAK;AAAA,QACb;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,UAAU,MAAM,UAAU,aAAa,iBAAiB;AAC9D,WAAO,QACJ,OAAO,CAAC,MAAM,EAAE,SAAS,YAAY,EACrC,IAAI,CAAC,OAAO;AAAA,MACX,IAAI,EAAE;AAAA,MACN,OAAO,EAAE,SAAS,UAAU,EAAE,SAAS,MAAM,GAAG,CAAC,CAAC;AAAA,IACpD,EAAE;AAAA,EACN;AACF;;;AC5aO,IAAM,iBAAN,MAAqB;AAAA,EAY1B,YAAY,OAAyB,QAA8B;AARnE,SAAQ,QAAuB;AAC/B,SAAQ,UAAU;AAClB,SAAQ,aAAa;AACrB,SAAQ,eAAe;AAGvB,SAAQ,UAAmD;AAgD3D,SAAQ,OAAO,MAAY;AACzB,UAAI,CAAC,KAAK,QAAS;AAEnB,WAAK,QAAQ,sBAAsB,KAAK,IAAI;AAG5C,UAAI,KAAK,WAAY;AAGrB,YAAM,MAAM,YAAY,IAAI;AAC5B,UAAI,MAAM,KAAK,eAAe,KAAK,YAAa;AAGhD,UAAI,KAAK,MAAM,aAAa,EAAG;AAE/B,WAAK,eAAe;AAEpB,YAAM,SAAS,KAAK,cAAc;AAClC,YAAM,KAAK,OAAO,KAAK;AACvB,YAAM,KAAK,OAAO,KAAK;AACvB,YAAM,KAAK,OAAO,SAAS,KAAK,MAAM;AACtC,YAAM,KAAK,OAAO,UAAU,KAAK,MAAM;AAEvC,UAAI,MAAM,KAAK,MAAM,EAAG;AAExB,WAAK,OAAO,QAAQ;AACpB,WAAK,OAAO,SAAS;AAErB,WAAK,IAAI,UAAU,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,IAAI,EAAE;AAC3D,YAAM,YAAY,KAAK,IAAI,aAAa,GAAG,GAAG,IAAI,EAAE;AAEpD,WAAK,aAAa;AAClB,WAAK,UAAU,SAAS;AAAA,IAC1B;AA9EE,SAAK,QAAQ;AACb,SAAK,cAAc,MAAO,OAAO;AACjC,SAAK,gBAAgB,OAAO;AAE5B,QAAI,OAAO,oBAAoB,aAAa;AAC1C,WAAK,SAAS,IAAI,gBAAgB,GAAG,CAAC;AACtC,WAAK,MAAM,KAAK,OAAO,WAAW,IAAI;AAAA,IACxC,OAAO;AACL,WAAK,SAAS,SAAS,cAAc,QAAQ;AAC7C,WAAK,OAAO,MAAM,UAAU;AAC5B,WAAK,MAAM,KAAK,OAAO,WAAW,IAAI;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,MAAM,SAA+C;AACnD,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AACf,SAAK,UAAU;AACf,SAAK,QAAQ,sBAAsB,KAAK,IAAI;AAAA,EAC9C;AAAA,EAEA,OAAa;AACX,SAAK,UAAU;AACf,SAAK,UAAU;AACf,QAAI,KAAK,UAAU,MAAM;AACvB,2BAAqB,KAAK,KAAK;AAC/B,WAAK,QAAQ;AAAA,IACf;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,KAAK;AACV,QAAI,KAAK,kBAAkB,qBAAqB,KAAK,OAAO,YAAY;AACtE,WAAK,OAAO,WAAW,YAAY,KAAK,MAAM;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,iBAAuB;AACrB,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,iBAAuB;AACrB,SAAK,aAAa;AAAA,EACpB;AAoCF;;;ACtFA,SAAS,qBAAqB,OAK5B;AACA,QAAM,eAAe,MAAM;AAC3B,QAAM,gBAAgB,MAAM;AAC5B,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,cAAc,MAAM,eAAe;AAEzC,QAAM,YAAY,iBAAiB,KAAK,EAAE;AAE1C,MAAI,cAAc,SAAS;AACzB,UAAM,QAAQ,KAAK;AAAA,MACjB,eAAe;AAAA,MACf,gBAAgB;AAAA,IAClB;AACA,UAAM,gBAAgB,aAAa;AACnC,UAAM,iBAAiB,cAAc;AACrC,WAAO;AAAA,MACL,UAAU,eAAe,iBAAiB;AAAA,MAC1C,UAAU,gBAAgB,kBAAkB;AAAA,MAC5C,OAAO;AAAA,MACP,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,cAAc,WAAW;AAC3B,UAAM,QAAQ,KAAK;AAAA,MACjB,eAAe;AAAA,MACf,gBAAgB;AAAA,IAClB;AACA,UAAM,gBAAgB,aAAa;AACnC,UAAM,iBAAiB,cAAc;AACrC,WAAO;AAAA,MACL,UAAU,eAAe,iBAAiB;AAAA,MAC1C,UAAU,gBAAgB,kBAAkB;AAAA,MAC5C,OAAO;AAAA,MACP,QAAQ;AAAA,IACV;AAAA,EACF;AAGA,SAAO,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,cAAc,QAAQ,cAAc;AAC9E;AAQO,IAAM,cAAN,MAAkB;AAAA,EAOvB,YAAY,OAAyB,QAAuB;AAL5D,SAAQ,YAAmC;AAC3C,SAAQ,gBAAmC;AAKzC,SAAK,QAAQ;AACb,SAAK,SAAS;AAEd,UAAM,SAAS,MAAM;AACrB,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,OAAO,eAAe;AAC7B,WAAK,YAAY,KAAK,OAAO;AAC7B,WAAK,gBAAgB;AACrB;AAAA,IACF;AAEA,QAAI,KAAK,OAAO,qBAAqB;AACnC,WAAK,wBAAwB;AAAA,IAC/B;AAEA,QAAI,KAAK,OAAO,sBAAsB;AACpC,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,iBAAiB,QAA0B;AACzC,QAAI,CAAC,KAAK,aAAa,KAAK,OAAO,cAAe;AAClD,SAAK,wBAAwB,MAAM;AAAA,EACrC;AAAA,EAEA,kBACE,cACA,YACM;AACN,QAAI,CAAC,KAAK,cAAe;AAEzB,QAAI,CAAC,gBAAgB,aAAa,SAAS,GAAG;AAC5C,WAAK,cAAc,MAAM,UAAU;AACnC;AAAA,IACF;AAEA,SAAK,cAAc,MAAM,UAAU;AAEnC,UAAM,UAAU,KAAK,cAAc,cAAc,SAAS;AAC1D,QAAI,CAAC,QAAS;AAKd,UAAM,UAAU,YAAY,KAAK;AACjC,UAAM,UAAU,YAAY,KAAK;AACjC,UAAM,WAAW,qBAAqB,KAAK,KAAK;AAChD,UAAM,SAAS,SAAS,QAAQ,KAAK,MAAM;AAC3C,UAAM,SAAS,SAAS,SAAS,KAAK,MAAM;AAE5C,UAAM,SAAS,aACZ;AAAA,MACC,CAAC,MACC,IAAI,EAAE,IAAI,WAAW,SAAS,SAAS,OAAO,KAAK,EAAE,IAAI,WAAW,SAAS,SAAS,OAAO;AAAA,IACjG,EACC,KAAK,GAAG;AAEX,YAAQ,aAAa,UAAU,MAAM;AAAA,EACvC;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,aAAa,CAAC,KAAK,OAAO,eAAe;AAChD,WAAK,UAAU,OAAO;AAAA,IACxB;AACA,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,OAAO;AAAA,IAC5B;AACA,SAAK,YAAY;AACjB,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,0BAAgC;AACtC,SAAK,YAAY,SAAS,cAAc,KAAK;AAC7C,SAAK,UAAU,YAAY;AAG3B,UAAM,KAAK,KAAK,UAAU;AAC1B,UAAM,KAAK,KAAK,UAAU;AAC1B,UAAM,OAAO,KAAK,MAAO,KAAK,IAAI,IAAI,EAAE,IAAI,IAAK,CAAC;AAElD,WAAO,OAAO,KAAK,UAAU,OAAO;AAAA,MAClC,UAAU;AAAA,MACV,KAAK;AAAA,MACL,MAAM;AAAA,MACN,WAAW;AAAA,MACX,OAAO,GAAG,IAAI;AAAA,MACd,QAAQ,GAAG,IAAI;AAAA,MACf,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,WAAW;AAAA,MACX,eAAe;AAAA,MACf,QAAQ;AAAA,IACV,CAAC;AAGD,UAAM,UAAU,CAAC,YAAY,aAAa,eAAe,cAAc;AACvE,eAAW,UAAU,SAAS;AAC5B,YAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,aAAO,YAAY,uCAAuC,MAAM;AAEhE,YAAM,CAAC,UAAU,UAAU,IAAI,OAAO,MAAM,GAAG;AAE/C,aAAO,OAAO,OAAO,OAAO;AAAA,QAC1B,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,CAAC,QAAQ,GAAG;AAAA,QACZ,CAAC,UAAU,GAAG;AAAA,QACd,CAAC,UAAU,QAAQ,EAAE,GAAG;AAAA,QACxB,CAAC,UAAU,UAAU,EAAE,GAAG;AAAA,QAC1B,CAAC,UAAU,QAAQ,IAAI,UAAU,SAAS,GAAG;AAAA,MAC/C,CAAC;AAED,WAAK,UAAU,YAAY,MAAM;AAAA,IACnC;AAEA,SAAK,UAAU,YAAY,KAAK,SAAS;AAAA,EAC3C;AAAA,EAEQ,oBAA0B;AAChC,UAAM,MAAM,SAAS,gBAAgB,8BAA8B,KAAK;AACxE,QAAI,aAAa,SAAS,yBAAyB;AAEnD,WAAO,OAAO,IAAI,OAAO;AAAA,MACvB,UAAU;AAAA,MACV,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAED,UAAM,UAAU,SAAS;AAAA,MACvB;AAAA,MACA;AAAA,IACF;AACA,YAAQ,aAAa,QAAQ,MAAM;AACnC,YAAQ,aAAa,UAAU,SAAS;AACxC,YAAQ,aAAa,gBAAgB,GAAG;AACxC,YAAQ,aAAa,mBAAmB,OAAO;AAG/C,UAAM,UAAU,SAAS;AAAA,MACvB;AAAA,MACA;AAAA,IACF;AACA,YAAQ,aAAa,iBAAiB,gBAAgB;AACtD,YAAQ,aAAa,UAAU,SAAS;AACxC,YAAQ,aAAa,OAAO,MAAM;AAClC,YAAQ,aAAa,eAAe,YAAY;AAChD,YAAQ,YAAY,OAAO;AAE3B,QAAI,YAAY,OAAO;AACvB,SAAK,UAAU,YAAY,GAAG;AAC9B,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,CAAC,KAAK,UAAW;AAErB,WAAO,OAAO,KAAK,UAAU,OAAO;AAAA,MAClC,UAAU;AAAA,MACV,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEQ,wBAAwB,SAA2B;AACzD,QAAI,CAAC,KAAK,UAAW;AASrB,UAAM,KAAK,KAAK,UAAU;AAC1B,UAAM,KAAK,KAAK,UAAU;AAC1B,UAAM,OAAO,KAAK,MAAO,KAAK,IAAI,IAAI,EAAE,IAAI,IAAK,CAAC;AAIlD,WAAO,OAAO,KAAK,UAAU,OAAO;AAAA,MAClC,OAAO,GAAG,IAAI;AAAA,MACd,QAAQ,GAAG,IAAI;AAAA,IACjB,CAAC;AAAA,EACH;AACF;;;AC/QO,SAAS,2BAA2B,OAAqC;AAC9E,QAAM,aAAa,MAAM,cAAc,MAAM;AAC7C,QAAM,cAAc,MAAM,eAAe,MAAM;AAE/C,QAAM,mBAAmB,KAAK,IAAI,YAAY,WAAW;AACzD,QAAM,OAAO,KAAK,MAAO,mBAAmB,IAAK,CAAC;AAElD,SAAO;AAAA,IACL,GAAG,KAAK,OAAO,aAAa,QAAQ,CAAC;AAAA,IACrC,GAAG,KAAK,OAAO,cAAc,QAAQ,CAAC;AAAA,IACtC,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AACF;;;ACnBA;AAqBA,IAAI,kBAAuC;AAEpC,SAAS,aAAa,KAAyB;AACpD,oBAAkB;AACpB;AAEA,SAAS,mBAAiC;AACxC,MAAI,iBAAiB;AACnB,WAAO;AAAA,EACT;AAKA,MAAI;AACF,WAAO,IAAI,IAAI,eAAe,YAAY,GAAG;AAAA,EAC/C,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AACF;AAEO,IAAM,UAAN,MAAc;AAAA,EAYnB,YACE,OACA,UACA,UAA0B,CAAC,GAC3B;AAXF,SAAQ,iBAAwC;AAChD,SAAQ,SAAwB;AAChC,SAAQ,UAA8B;AACtC,SAAQ,SAAS;AACjB,SAAQ,SAAS;AACjB,SAAQ,YAAY;AAOlB,SAAK,QAAQ;AACb,SAAK,WAAW;AAChB,SAAK,UAAU;AAEf,SAAK,SAAS,IAAI,cAAc;AAAA,MAC9B,iBAAiB,QAAQ;AAAA,MACzB,kBAAkB,QAAQ;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,WAAW;AAClB,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC9C;AAEA,QAAI,KAAK,UAAU,CAAC,KAAK,QAAQ;AAC/B;AAAA,IACF;AAEA,UAAM,KAAK,YAAY,IAAI;AAI3B,QACE,CAAC,KAAK,YACL,KAAK,QAAQ,uBACZ,KAAK,QAAQ,wBACb,KAAK,QAAQ,UACf;AACA,UAAI;AACF,aAAK,UAAU,IAAI,YAAY,KAAK,OAAO;AAAA,UACzC,qBAAqB,KAAK,QAAQ,uBAAuB;AAAA,UACzD,sBAAsB,KAAK,QAAQ,wBAAwB;AAAA,UAC3D,eAAe,KAAK,QAAQ;AAAA,QAC9B,CAAC;AACD,aAAK,QAAQ,MAAM;AAAA,MACrB,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,UAAM,KAAK,OAAO,MAAM,KAAK,KAAK;AAClC,YAAQ;AAAA,MACN,oCAAoC,YAAY,IAAI,IAAI,IAAI,QAAQ,CAAC,CAAC;AAAA,IACxE;AAGA,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,iBAAiB,KAAK,qBAAqB,CAAC;AAAA,IAC3D;AAGA,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,KAAK,YAAY,IAAI;AAC3B,WAAK,SAAS,KAAK,aAAa;AAChC,cAAQ;AAAA,QACN,sCAAsC,YAAY,IAAI,IAAI,IAAI,QAAQ,CAAC,CAAC;AAAA,MAC1E;AAAA,IACF;AAGA,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,iBAAiB,IAAI,eAAe,KAAK,OAAO;AAAA,QACnD,mBAAmB,KAAK,QAAQ,qBAAqB;AAAA,QACrD,eAAe,MAAM,KAAK,qBAAqB;AAAA,MACjD,CAAC;AAAA,IACH;AAGA,SAAK,eAAe,MAAM,CAAC,cAAc;AACvC,WAAK,aAAa,SAAS;AAAA,IAC7B,CAAC;AAED,SAAK,SAAS;AACd,SAAK,SAAS;AAEd,YAAQ;AAAA,MACN,6BAA6B,YAAY,IAAI,IAAI,IAAI,QAAQ,CAAC,CAAC;AAAA,IACjE;AAAA,EACF;AAAA,EAEA,OAAa;AACX,SAAK,gBAAgB,KAAK;AAC1B,SAAK,OAAO,KAAK;AACjB,SAAK,MAAM,YAAY;AACvB,SAAK,SAAS;AACd,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,UAAW;AACpB,SAAK,KAAK;AACV,SAAK,gBAAgB,QAAQ;AAC7B,SAAK,iBAAiB;AACtB,SAAK,SAAS,QAAQ;AACtB,SAAK,UAAU;AACf,SAAK,QAAQ,UAAU;AACvB,SAAK,SAAS;AACd,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,MAAM,wBAAwB,MAAwB;AAC1D,QAAI,CAAC,KAAK,OAAQ,QAAO;AAEzB,SAAK,gBAAgB,KAAK;AAC1B,SAAK,SAAS;AAEd,QAAI,uBAAuB;AACzB,WAAK,OAAO,KAAK;AACjB,WAAK,MAAM,YAAY;AAAA,IACzB;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,sBAA6C;AAC3D,UAAM,YAAY,KAAK,UAAU,CAAC,KAAK;AACvC,QAAI,WAAW;AACb,WAAK,gBAAgB,KAAK;AAAA,IAC5B;AAEA,UAAM,KAAK,OAAO,UAAU,sBAAsB,KAAK,KAAK;AAE5D,QAAI,WAAW;AACb,WAAK,gBAAgB,MAAM,CAAC,cAAc;AACxC,aAAK,aAAa,SAAS;AAAA,MAC7B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,WAA6B;AACjC,WAAO,KAAK,OAAO,SAAS;AAAA,EAC9B;AAAA,EAEA,YAAqB;AACnB,WAAO,KAAK,OAAO,UAAU;AAAA,EAC/B;AAAA,EAEA,MAAM,cAA6B;AACjC,WAAO,KAAK,OAAO,YAAY;AAAA,EACjC;AAAA,EAEA,MAAM,cAA6B;AACjC,WAAO,KAAK,OAAO,YAAY;AAAA,EACjC;AAAA,EAEA,MAAM,eAA8B;AAClC,WAAO,KAAK,OAAO,aAAa;AAAA,EAClC;AAAA,EAEA,iBAAiB,MAA2B;AAC1C,QAAI,CAAC,KAAK,OAAQ;AAElB,UAAM,UAAkC,CAAC;AACzC,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,gBAAQ,YAAY;AACpB;AAAA,MACF,KAAK;AACH,gBAAQ,YAAY;AACpB;AAAA,MACF,KAAK;AACH,gBAAQ,YAAY;AACpB;AAAA,IACJ;AAEA,UAAM,MAAqB,EAAE,MAAM,aAAa,QAAQ;AACxD,SAAK,OAAO,YAAY,GAAG;AAAA,EAC7B;AAAA,EAEA,WAAoB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAoB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,uBAAmC;AACzC,QAAI,KAAK,QAAQ,qBAAqB;AACpC,aAAO,KAAK,QAAQ,oBAAoB,KAAK,KAAK;AAAA,IACpD;AACA,WAAO,2BAA2B,KAAK,KAAK;AAAA,EAC9C;AAAA,EAEQ,eAAuB;AAC7B,UAAM,YAAY,iBAAiB;AACnC,UAAM,SAAS,IAAI,OAAO,WAAW,EAAE,MAAM,SAAS,CAAC;AAGvD,QAAI,KAAK,QAAQ,gBAAgB;AAC/B,YAAM,MAAqB;AAAA,QACzB,MAAM;AAAA,QACN,SAAS,KAAK,QAAQ;AAAA,MACxB;AACA,aAAO,YAAY,GAAG;AAAA,IACxB;AAEA,WAAO,YAAY,CAAC,MAAoC;AACtD,WAAK,oBAAoB,EAAE,IAAI;AAAA,IACjC;AAEA,WAAO,UAAU,CAAC,QAAQ;AACxB,cAAQ,MAAM,4BAA4B,GAAG;AAC7C,WAAK,gBAAgB,eAAe;AAAA,IACtC;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,oBAAoB,UAAgC;AAC1D,SAAK,gBAAgB,eAAe;AAEpC,QAAI,SAAS,SAAS,SAAS;AAC7B;AAAA,IACF;AAEA,QAAI,SAAS,SAAS,SAAS;AAC7B,WAAK,QAAQ,gBAAgB,SAAS,OAAO;AAC7C;AAAA,IACF;AAEA,QAAI,SAAS,SAAS,UAAU;AAC9B,UAAI,SAAS,QAAQ,SAAS,GAAG;AAC/B,cAAM,SAAS,SAAS,QAAQ,CAAC;AACjC,aAAK,SAAS,MAAM;AAGpB,YAAI,KAAK,SAAS;AAChB,gBAAM,SAAS,KAAK,qBAAqB;AACzC,eAAK,QAAQ,iBAAiB,MAAM;AACpC,eAAK,QAAQ,kBAAkB,OAAO,cAAc,MAAM;AAAA,QAC5D;AAAA,MACF,OAAO;AACL,aAAK,QAAQ,gBAAgB,kBAAkB;AAG/C,YAAI,KAAK,SAAS;AAChB,eAAK,QAAQ,kBAAkB,IAAI;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa,WAA4B;AAC/C,QAAI,CAAC,KAAK,OAAQ;AAElB,UAAM,MAAqB,EAAE,MAAM,UAAU,UAAU;AACvD,SAAK,OAAO,YAAY,KAAK,CAAC,UAAU,KAAK,MAAM,CAAC;AAAA,EACtD;AACF;;;AC9TA,oBAAiD;;;ACKjD,eAAsB,cACpB,QACA,YACA,QACoB;AACpB,QAAM,MAAM,MAAM,mBAAmB,MAAM;AAE3C,QAAM,KAAK,YAAY,KAAK;AAC5B,QAAM,KAAK,YAAY,KAAK;AAC5B,QAAM,KAAK,YAAY,SAAU,IAAI,QAAQ;AAC7C,QAAM,KAAK,YAAY,UAAW,IAAI,SAAS;AAE/C,MAAI;AACJ,MAAI;AAEJ,MAAI,QAAQ;AACV,iBAAa;AACb,WAAO,QAAQ;AACf,WAAO,SAAS;AAChB,UAAM,OAAO,WAAW,IAAI;AAAA,EAC9B,WAAW,OAAO,oBAAoB,aAAa;AACjD,iBAAa,IAAI,gBAAgB,IAAI,EAAE;AACvC,UAAM,WAAW,WAAW,IAAI;AAAA,EAClC,OAAO;AACL,iBAAa,SAAS,cAAc,QAAQ;AAC5C,eAAW,QAAQ;AACnB,eAAW,SAAS;AACpB,UAAM,WAAW,WAAW,IAAI;AAAA,EAClC;AAEA,MAAI,UAAU,KAA0B,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,IAAI,EAAE;AACpE,SAAO,IAAI,aAAa,GAAG,GAAG,IAAI,EAAE;AACtC;AAEA,eAAe,mBACb,QAC+E;AAC/E,MAAI,kBAAkB,oBAAoB,kBAAkB,qBAAqB,kBAAkB,aAAa;AAC9G,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,oBAAoB,eAAe,kBAAkB,iBAAiB;AAC/E,WAAO;AAAA,EACT;AAEA,MAAI,kBAAkB,QAAQ,kBAAkB,MAAM;AACpD,WAAO,0BAA0B,MAAM;AAAA,EACzC;AAGA,QAAM,MAAM,kBAAkB,MAAM,OAAO,OAAO;AAClD,QAAM,WAAW,MAAM,MAAM,GAAG;AAChC,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,SAAO,0BAA0B,IAAI;AACvC;AAEA,eAAe,0BAA0B,MAAkC;AACzE,MAAI,OAAO,sBAAsB,aAAa;AAC5C,WAAO,kBAAkB,IAAI;AAAA,EAC/B;AAEA,QAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,MAAI;AACF,UAAM,MAAM,IAAI,MAAM;AACtB,QAAI,MAAM;AACV,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAI,SAAS,MAAM,QAAQ;AAC3B,UAAI,UAAU,MAAM,OAAO,IAAI,MAAM,sBAAsB,CAAC;AAAA,IAC9D,CAAC;AACD,WAAO;AAAA,EACT,UAAE;AACA,QAAI,gBAAgB,GAAG;AAAA,EACzB;AACF;;;AD1EA,IAAM,uBAAsC;AAAA,EAC1C,SAAS,CAAC,QAAQ;AAAA,EAClB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,oBAAoB;AACtB;AAEA,SAAS,YAAY,UAKT;AACV,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AACF;AAQA,SAAS,cAAc,QAAwC;AAC7D,SACE,kBAAkB,QAClB,kBAAkB,eAClB,kBAAkB,cACjB,OAAO,cAAc,eAAe,kBAAkB;AAE3D;AAKA,eAAsB,UACpB,QAMA,SAKqB;AACrB,QAAM,gBAA+B;AAAA,IACnC,GAAG;AAAA,IACH,GAAG,SAAS;AAAA,IACZ,SAAS,CAAC,QAAQ;AAAA,EACpB;AAEA,MAAI;AACJ,MAAI,cAAc,MAAM,GAAG;AACzB,YAAQ;AAAA,EACV,WAAW,OAAO,WAAW,YAAY,kBAAkB,KAAK;AAE9D,UAAM,MAAM,kBAAkB,MAAM,OAAO,OAAO;AAClD,UAAM,WAAW,MAAM,MAAM,GAAG;AAChC,YAAQ,MAAM,SAAS,YAAY;AAAA,EACrC,OAAO;AAEL,YAAQ,MAAM,cAAc,QAAQ,SAAS,YAAY,SAAS,MAAM;AAAA,EAC1E;AAEA,QAAM,UAAU,UAAM,4BAAa,OAAO,aAAa;AACvD,QAAM,QAAQ,QAAQ,OAAO,CAAC,MAAM,EAAE,OAAO;AAE7C,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AAEA,QAAM,QAAQ,MAAM,CAAC;AACrB,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,cAAc,YAAY,MAAM,QAAQ;AAAA,EAC1C;AACF;;;ANnFA,IAAAC,iBAAwC;AA6BxC,IAAM,YAAN,MAAgB;AAAA,EAGd,YACE,cACA,UACA,UAA0B,CAAC,GAC3B;AACA,SAAK,UAAU,IAAI,QAAQ,cAAc,UAAU,OAAO;AAAA,EAC5D;AAAA;AAAA,EAGA,MAAM,QAAuB;AAC3B,WAAO,KAAK,QAAQ,MAAM;AAAA,EAC5B;AAAA;AAAA,EAGA,OAAa;AACX,SAAK,QAAQ,KAAK;AAAA,EACpB;AAAA;AAAA,EAGA,UAAgB;AACd,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA;AAAA,EAGA,MAAM,MAAM,uBAAmD;AAC7D,WAAO,KAAK,QAAQ,MAAM,qBAAqB;AAAA,EACjD;AAAA;AAAA,EAGA,MAAM,UAAU,sBAA4D;AAC1E,WAAO,KAAK,QAAQ,UAAU,oBAAoB;AAAA,EACpD;AAAA;AAAA,EAGA,MAAM,WAA6B;AACjC,WAAO,KAAK,QAAQ,SAAS;AAAA,EAC/B;AAAA;AAAA,EAGA,YAAqB;AACnB,WAAO,KAAK,QAAQ,UAAU;AAAA,EAChC;AAAA;AAAA,EAGA,MAAM,cAA6B;AACjC,WAAO,KAAK,QAAQ,YAAY;AAAA,EAClC;AAAA;AAAA,EAGA,MAAM,cAA6B;AACjC,WAAO,KAAK,QAAQ,YAAY;AAAA,EAClC;AAAA;AAAA,EAGA,MAAM,eAA8B;AAClC,WAAO,KAAK,QAAQ,aAAa;AAAA,EACnC;AAAA;AAAA,EAGA,iBAAiB,MAA2B;AAC1C,SAAK,QAAQ,iBAAiB,IAAI;AAAA,EACpC;AAAA;AAAA;AAAA,EAKA,OAAO,YAA8B;AACnC,WAAO,cAAc,UAAU;AAAA,EACjC;AAAA;AAAA,EAGA,OAAO,YAAY,eAA4C;AAC7D,WAAO,cAAc,YAAY,aAAa;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,UAAyB;AAEpC,UAAM,QAAQ,IAAI,kBAAkB,CAAC,KAAK,KAAK,KAAK,GAAG,CAAC;AACxD,UAAM,MAAM,IAAI,UAAU,OAAO,GAAG,CAAC;AACrC,QAAI;AACF,YAAM,UAAU,GAAG;AAAA,IACrB,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,cAAc,WAA4C;AAC/D,gDAAwB,SAAS;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO,aAAa,KAAyB;AAC3C,iBAAa,GAAG;AAAA,EAClB;AAAA;AAAA,EAGA,OAAO,UACL,QAYA,SAKqB;AACrB,WAAO,UAAU,QAAQ,OAAO;AAAA,EAClC;AACF;AAEA,IAAO,gBAAQ;","names":["t","import_reader"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/debug.ts","../src/camera.ts","../src/frame-extractor.ts","../src/overlay.ts","../src/scan-region.ts","../src/scanner.ts","../src/scan-image.ts","../src/utils.ts"],"sourcesContent":["import { Scanner, setWorkerUrl } from './scanner.js';\nimport {\n CameraManager,\n CameraNotFoundError,\n CameraPermissionError,\n} from './camera.js';\nimport { setDebug } from './debug.js';\nimport { scanImage } from './scan-image.js';\nimport { setZXingModuleOverrides } from 'zxing-wasm/reader';\nimport type {\n ScanResult,\n ScanRegion,\n ScannerOptions,\n Camera,\n Point,\n FacingMode,\n DeviceId,\n InversionMode,\n} from './types.js';\nimport type { ReaderOptions } from 'zxing-wasm/reader';\n\nexport { CameraNotFoundError, CameraPermissionError };\n\nexport type {\n ScanResult,\n ScanRegion,\n ScannerOptions,\n Camera,\n Point,\n FacingMode,\n DeviceId,\n InversionMode,\n};\n\n/**\n * High-performance QR code scanner for the web, powered by ZXing-C++ WebAssembly.\n */\nclass QrScanner {\n private scanner: Scanner;\n\n constructor(\n videoElement: HTMLVideoElement,\n onDecode: (result: ScanResult) => void,\n options: ScannerOptions = {},\n ) {\n this.scanner = new Scanner(videoElement, onDecode, options);\n }\n\n /** Start camera and begin scanning. Resolves when camera is ready. */\n async start(): Promise<void> {\n return this.scanner.start();\n }\n\n /** Stop scanning and release the camera stream. */\n stop(): void {\n this.scanner.stop();\n }\n\n /** Stop scanning, release camera, terminate worker, clean up DOM. */\n destroy(): void {\n this.scanner.destroy();\n }\n\n /** Pause scanning. If stopStreamImmediately is false, camera stays on. */\n async pause(stopStreamImmediately?: boolean): Promise<boolean> {\n return this.scanner.pause(stopStreamImmediately);\n }\n\n /** Switch to a different camera by facing mode or device ID. */\n async setCamera(facingModeOrDeviceId: FacingMode | DeviceId): Promise<void> {\n return this.scanner.setCamera(facingModeOrDeviceId);\n }\n\n /** Check if the current camera supports flash/torch. */\n async hasFlash(): Promise<boolean> {\n return this.scanner.hasFlash();\n }\n\n /** Whether flash is currently on. */\n isFlashOn(): boolean {\n return this.scanner.isFlashOn();\n }\n\n /** Toggle flash on/off. */\n async toggleFlash(): Promise<void> {\n return this.scanner.toggleFlash();\n }\n\n /** Turn flash on. */\n async turnFlashOn(): Promise<void> {\n return this.scanner.turnFlashOn();\n }\n\n /** Turn flash off. */\n async turnFlashOff(): Promise<void> {\n return this.scanner.turnFlashOff();\n }\n\n /** Set the inversion mode for detecting inverted QR codes. */\n setInversionMode(mode: InversionMode): void {\n this.scanner.setInversionMode(mode);\n }\n\n // --- Static methods ---\n\n /** Check if the device has at least one camera. */\n static hasCamera(): Promise<boolean> {\n return CameraManager.hasCamera();\n }\n\n /** List available cameras. Pass true to request labels (triggers permission prompt). */\n static listCameras(requestLabels?: boolean): Promise<Camera[]> {\n return CameraManager.listCameras(requestLabels);\n }\n\n /**\n * Pre-load the WASM binary so it's ready when the scanner starts.\n * Call this early (e.g., on app init) to avoid delay on first scan.\n */\n static async preload(): Promise<void> {\n // Trigger WASM loading by doing a minimal scan\n const pixel = new Uint8ClampedArray([255, 255, 255, 255]);\n const img = new ImageData(pixel, 1, 1);\n try {\n await scanImage(img);\n } catch {\n // Expected — no QR code in a 1x1 image. The point was to load WASM.\n }\n }\n\n /**\n * Configure WASM loading. Call before creating any scanner instance.\n * @example\n * QrScanner.configureWasm({ locateFile: (filename) => `/wasm/${filename}` });\n */\n static configureWasm(overrides: Partial<EmscriptenModule>): void {\n setZXingModuleOverrides(overrides);\n }\n\n /**\n * Set a custom URL for the worker script. Call before creating any scanner.\n * Needed for CJS consumers or non-standard bundler setups.\n * By default, the worker URL is resolved via `new URL('./worker.js', import.meta.url)`,\n * which works with Vite, webpack 5, Parcel, and other modern bundlers.\n * @example\n * QrScanner.setWorkerUrl('/assets/qr-scanner-worker.js');\n */\n static setWorkerUrl(url: string | URL): void {\n setWorkerUrl(url);\n }\n\n /**\n * Enable or disable debug logging (performance timings, camera selection).\n * Off by default. Useful for diagnosing camera issues in the browser console.\n * @example\n * QrScanner.setDebug(true);\n */\n static setDebug(enabled: boolean): void {\n setDebug(enabled);\n }\n\n /** Scan a single image (not a video stream). */\n static scanImage(\n source:\n | HTMLImageElement\n | HTMLCanvasElement\n | OffscreenCanvas\n | ImageBitmap\n | ImageData\n | Blob\n | ArrayBuffer\n | Uint8Array\n | File\n | URL\n | string,\n options?: {\n scanRegion?: ScanRegion | null;\n canvas?: HTMLCanvasElement | null;\n decoderOptions?: Partial<ReaderOptions>;\n },\n ): Promise<ScanResult> {\n return scanImage(source, options);\n }\n}\n\nexport default QrScanner;\n","let enabled = false;\n\nexport function setDebug(on: boolean): void {\n enabled = on;\n}\n\nexport function debug(...args: unknown[]): void {\n if (enabled) console.debug(...args);\n}\n","import { debug } from './debug.js';\nimport type { FacingMode, DeviceId, Camera } from './types.js';\n\nexport class CameraPermissionError extends Error {\n constructor(\n message = 'Camera access denied. Please grant camera permission and try again.',\n ) {\n super(message);\n this.name = 'CameraPermissionError';\n }\n}\n\nexport class CameraNotFoundError extends Error {\n constructor(\n message = 'No camera found. Please connect a camera and try again.',\n ) {\n super(message);\n this.name = 'CameraNotFoundError';\n }\n}\n\nconst CACHE_KEY_PREFIX = '@agicash/qr-scanner:camera:';\n\nfunction getCachedDeviceId(facingMode: string): string | null {\n try {\n return localStorage.getItem(`${CACHE_KEY_PREFIX}${facingMode}`);\n } catch {\n return null;\n }\n}\n\nfunction setCachedDeviceId(facingMode: string, deviceId: string): void {\n try {\n localStorage.setItem(`${CACHE_KEY_PREFIX}${facingMode}`, deviceId);\n } catch {\n // localStorage unavailable or full — ignore\n }\n}\n\nexport interface CameraConfig {\n preferredCamera?: FacingMode | DeviceId;\n cameraResolution?: {\n width?: MediaTrackConstraintSet['width'];\n height?: MediaTrackConstraintSet['height'];\n };\n}\n\nexport class CameraManager {\n private stream: MediaStream | null = null;\n private facingMode: FacingMode | DeviceId;\n private resolution: CameraConfig['cameraResolution'];\n\n constructor(config: CameraConfig = {}) {\n this.facingMode = config.preferredCamera ?? 'environment';\n this.resolution = config.cameraResolution;\n }\n\n async start(video: HTMLVideoElement): Promise<MediaStream> {\n if (this.stream) {\n return this.stream;\n }\n\n const t0 = performance.now();\n\n this.stream = await this.acquireStream();\n const t1 = performance.now();\n debug(`[QrScanner] acquireStream: ${(t1 - t0).toFixed(0)}ms`);\n\n // On some devices (e.g. Samsung S24 + Brave), facingMode: 'environment'\n // picks an ultrawide camera that lacks autofocus. Check and switch to a\n // better camera BEFORE showing on screen to avoid visible flicker.\n await this.ensureBestCamera();\n const t2 = performance.now();\n debug(`[QrScanner] ensureBestCamera: ${(t2 - t1).toFixed(0)}ms`);\n\n video.srcObject = this.stream;\n video.setAttribute('playsinline', 'true');\n await video.play();\n const t3 = performance.now();\n debug(`[QrScanner] video.play: ${(t3 - t2).toFixed(0)}ms`);\n debug(`[QrScanner] camera.start total: ${(t3 - t0).toFixed(0)}ms`);\n\n // Cache the final camera so subsequent starts skip ensureBestCamera\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n const finalDeviceId = this.getVideoTrack()?.getSettings().deviceId;\n if (finalDeviceId) {\n setCachedDeviceId(this.facingMode, finalDeviceId);\n }\n }\n\n return this.stream;\n }\n\n stop(): void {\n if (this.stream) {\n for (const track of this.stream.getTracks()) {\n track.stop();\n }\n this.stream = null;\n }\n }\n\n async setCamera(\n facingModeOrDeviceId: FacingMode | DeviceId,\n video: HTMLVideoElement,\n ): Promise<void> {\n this.stop();\n this.facingMode = facingModeOrDeviceId;\n await this.start(video);\n }\n\n getStream(): MediaStream | null {\n return this.stream;\n }\n\n async hasFlash(): Promise<boolean> {\n const track = this.getVideoTrack();\n if (!track) return false;\n\n try {\n const capabilities = track.getCapabilities() as MediaTrackCapabilities & {\n torch?: boolean;\n };\n return capabilities.torch === true;\n } catch {\n return false;\n }\n }\n\n isFlashOn(): boolean {\n const track = this.getVideoTrack();\n if (!track) return false;\n\n const settings = track.getSettings() as MediaTrackSettings & {\n torch?: boolean;\n };\n return settings.torch === true;\n }\n\n async toggleFlash(): Promise<void> {\n if (this.isFlashOn()) {\n await this.turnFlashOff();\n } else {\n await this.turnFlashOn();\n }\n }\n\n async turnFlashOn(): Promise<void> {\n await this.setTorch(true);\n }\n\n async turnFlashOff(): Promise<void> {\n await this.setTorch(false);\n }\n\n private async setTorch(on: boolean): Promise<void> {\n const track = this.getVideoTrack();\n if (!track) {\n throw new Error('No active camera stream');\n }\n\n try {\n await track.applyConstraints({\n advanced: [{ torch: on } as MediaTrackConstraintSet],\n });\n } catch {\n throw new Error('Flash/torch is not supported on this device');\n }\n }\n\n /**\n * If the current camera lacks continuous autofocus (e.g. an ultrawide sensor\n * picked by facingMode: 'environment'), find a better camera with the same\n * facing mode and replace this.stream. Called before assigning to the video\n * element so the user never sees the wrong camera.\n */\n private async ensureBestCamera(): Promise<void> {\n if (this.facingMode !== 'environment' && this.facingMode !== 'user') {\n debug('[QrScanner] ensureBestCamera: skipped (specific deviceId)');\n return;\n }\n\n const track = this.getVideoTrack();\n if (!track) return;\n\n try {\n const capabilities = track.getCapabilities() as MediaTrackCapabilities & {\n focusMode?: string[];\n };\n if (\n !capabilities.focusMode ||\n capabilities.focusMode.includes('continuous')\n ) {\n // focusMode not reported (e.g. Safari/iOS) or has autofocus — skip.\n // Only enter the candidate loop when the browser explicitly reports\n // focusMode without 'continuous' (e.g. S24 + Brave ultrawide).\n debug(\n `[QrScanner] ensureBestCamera: skipped (focusMode: ${JSON.stringify(capabilities.focusMode)})`,\n );\n return;\n }\n debug(\n `[QrScanner] ensureBestCamera: current camera lacks autofocus (focusMode: ${JSON.stringify(capabilities.focusMode)})`,\n );\n } catch {\n return;\n }\n\n // Current camera lacks continuous autofocus.\n // Enumerate devices while stream is active (ensures deviceIds are available).\n const currentDeviceId = track.getSettings().deviceId;\n\n let devices: MediaDeviceInfo[];\n try {\n devices = await navigator.mediaDevices.enumerateDevices();\n } catch {\n return;\n }\n if (!Array.isArray(devices)) return;\n\n const candidates = devices.filter(\n (d) => d.kind === 'videoinput' && d.deviceId !== currentDeviceId,\n );\n debug(\n `[QrScanner] ensureBestCamera: testing ${candidates.length} candidate camera(s)`,\n );\n if (candidates.length === 0) return;\n\n // Stop current stream — mobile devices only allow one active camera\n this.stop();\n\n for (const candidate of candidates) {\n const t = performance.now();\n let candidateStream: MediaStream;\n try {\n candidateStream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: { exact: candidate.deviceId },\n width: this.resolution?.width ?? { ideal: 1920 },\n height: this.resolution?.height ?? { ideal: 1080 },\n },\n audio: false,\n });\n debug(\n `[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia ${(performance.now() - t).toFixed(0)}ms`,\n );\n } catch {\n debug(\n `[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia failed ${(performance.now() - t).toFixed(0)}ms`,\n );\n continue;\n }\n\n const candidateTrack = candidateStream.getVideoTracks()[0];\n if (!candidateTrack) {\n for (const t of candidateStream.getTracks()) t.stop();\n continue;\n }\n\n // Must match the desired facing mode\n const candidateSettings =\n candidateTrack.getSettings() as MediaTrackSettings & {\n facingMode?: string;\n };\n if (\n candidateSettings.facingMode &&\n candidateSettings.facingMode !== this.facingMode\n ) {\n for (const t of candidateStream.getTracks()) t.stop();\n continue;\n }\n\n // Check if this camera supports continuous autofocus\n try {\n const candidateCaps =\n candidateTrack.getCapabilities() as MediaTrackCapabilities & {\n focusMode?: string[];\n };\n if (candidateCaps.focusMode?.includes('continuous')) {\n this.stream = candidateStream;\n return;\n }\n } catch {\n // Can't check capabilities, skip\n }\n\n for (const t of candidateStream.getTracks()) t.stop();\n }\n\n // No better camera found — re-open the original\n try {\n this.stream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: currentDeviceId ? { exact: currentDeviceId } : undefined,\n width: this.resolution?.width ?? { ideal: 1920 },\n height: this.resolution?.height ?? { ideal: 1080 },\n },\n audio: false,\n });\n } catch {\n try {\n this.stream = await navigator.mediaDevices.getUserMedia(\n this.buildConstraints(),\n );\n } catch {\n // Could not recover camera\n }\n }\n }\n\n private getVideoTrack(): MediaStreamTrack | null {\n if (!this.stream) return null;\n const tracks = this.stream.getVideoTracks();\n return tracks[0] ?? null;\n }\n\n /**\n * Try getUserMedia with progressively simpler constraints.\n *\n * Some browsers (e.g. Brave on Samsung Galaxy S24) throw NotReadableError\n * when facingMode and resolution constraints are combined. Falling back to\n * fewer constraints lets us still open the camera on those browsers.\n */\n private async acquireStream(): Promise<MediaStream> {\n const labels: string[] = [];\n const attempts: MediaStreamConstraints[] = [];\n\n // If we've previously found a good camera for this facingMode, try it first\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n const cachedId = getCachedDeviceId(this.facingMode);\n if (cachedId) {\n labels.push('cached deviceId');\n const video: MediaTrackConstraints = {\n deviceId: { exact: cachedId },\n };\n if (this.resolution?.width) video.width = this.resolution.width;\n else video.width = { ideal: 1920 };\n if (this.resolution?.height) video.height = this.resolution.height;\n else video.height = { ideal: 1080 };\n attempts.push({ video, audio: false });\n }\n }\n\n // Standard fallback chain\n labels.push('full constraints', 'no resolution', 'bare minimum');\n attempts.push(\n // facingMode/deviceId + resolution\n this.buildConstraints(),\n // facingMode/deviceId only, no resolution\n this.buildConstraints(false),\n // Bare minimum\n { video: true, audio: false },\n );\n\n let lastError: unknown;\n for (let i = 0; i < attempts.length; i++) {\n const t = performance.now();\n try {\n const stream = await navigator.mediaDevices.getUserMedia(attempts[i]);\n debug(\n `[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms ✓`,\n );\n return stream;\n } catch (err) {\n debug(\n `[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms ✗ ${err instanceof DOMException ? err.name : err}`,\n );\n if (err instanceof DOMException) {\n if (err.name === 'NotAllowedError') {\n throw new CameraPermissionError();\n }\n if (err.name === 'NotFoundError') {\n throw new CameraNotFoundError();\n }\n // NotReadableError or OverconstrainedError — try next fallback\n lastError = err;\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n private buildConstraints(includeResolution = true): MediaStreamConstraints {\n const video: MediaTrackConstraints = {};\n\n if (includeResolution) {\n video.width = this.resolution?.width ?? { ideal: 1920 };\n video.height = this.resolution?.height ?? { ideal: 1080 };\n }\n\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n video.facingMode = this.facingMode;\n } else {\n video.deviceId = { exact: this.facingMode };\n }\n\n return { video, audio: false };\n }\n\n static async hasCamera(): Promise<boolean> {\n try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n return devices.some((d) => d.kind === 'videoinput');\n } catch {\n return false;\n }\n }\n\n static async listCameras(requestLabels = false): Promise<Camera[]> {\n if (requestLabels) {\n // Requesting labels requires a temporary stream to trigger the permission prompt\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: true,\n });\n for (const track of stream.getTracks()) {\n track.stop();\n }\n } catch {\n // Permission denied — fall through with empty labels\n }\n }\n\n const devices = await navigator.mediaDevices.enumerateDevices();\n return devices\n .filter((d) => d.kind === 'videoinput')\n .map((d) => ({\n id: d.deviceId,\n label: d.label || `Camera ${d.deviceId.slice(0, 8)}`,\n }));\n }\n}\n","import type { ScanRegion } from './types.js';\n\nexport interface FrameExtractorConfig {\n maxScansPerSecond: number;\n getScanRegion: () => ScanRegion;\n}\n\nexport class FrameExtractor {\n private video: HTMLVideoElement;\n private canvas: HTMLCanvasElement | OffscreenCanvas;\n private ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n private rafId: number | null = null;\n private running = false;\n private workerBusy = false;\n private lastScanTime = -Infinity;\n private minInterval: number;\n private getScanRegion: () => ScanRegion;\n private onFrame: ((imageData: ImageData) => void) | null = null;\n\n constructor(video: HTMLVideoElement, config: FrameExtractorConfig) {\n this.video = video;\n this.minInterval = 1000 / config.maxScansPerSecond;\n this.getScanRegion = config.getScanRegion;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n this.canvas = new OffscreenCanvas(1, 1);\n this.ctx = this.canvas.getContext('2d')! as OffscreenCanvasRenderingContext2D;\n } else {\n this.canvas = document.createElement('canvas');\n this.canvas.style.display = 'none';\n this.ctx = this.canvas.getContext('2d')!;\n }\n }\n\n start(onFrame: (imageData: ImageData) => void): void {\n if (this.running) return;\n this.running = true;\n this.onFrame = onFrame;\n this.rafId = requestAnimationFrame(this.tick);\n }\n\n stop(): void {\n this.running = false;\n this.onFrame = null;\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n }\n\n destroy(): void {\n this.stop();\n if (this.canvas instanceof HTMLCanvasElement && this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n }\n\n markWorkerIdle(): void {\n this.workerBusy = false;\n }\n\n markWorkerBusy(): void {\n this.workerBusy = true;\n }\n\n private tick = (): void => {\n if (!this.running) return;\n\n this.rafId = requestAnimationFrame(this.tick);\n\n // Skip if worker is still processing previous frame\n if (this.workerBusy) return;\n\n // Rate limiting\n const now = performance.now();\n if (now - this.lastScanTime < this.minInterval) return;\n\n // Skip if video isn't ready\n if (this.video.readyState < 2) return;\n\n this.lastScanTime = now;\n\n const region = this.getScanRegion();\n const sx = region.x ?? 0;\n const sy = region.y ?? 0;\n const sw = region.width ?? this.video.videoWidth;\n const sh = region.height ?? this.video.videoHeight;\n\n if (sw <= 0 || sh <= 0) return;\n\n this.canvas.width = sw;\n this.canvas.height = sh;\n\n this.ctx.drawImage(this.video, sx, sy, sw, sh, 0, 0, sw, sh);\n const imageData = this.ctx.getImageData(0, 0, sw, sh);\n\n this.workerBusy = true;\n this.onFrame?.(imageData);\n };\n}\n","import type { ScanRegion, Point } from './types.js';\n\n/**\n * Compute the actual rendered position and size of the video content\n * within the element, accounting for object-fit: cover.\n *\n * With object-fit: cover the video is scaled up to fill the element and\n * cropped. The rendered content is larger than the element, centered,\n * with negative offsets for the cropped portions.\n *\n * When object-fit is the default (fill), the rendered size equals the\n * element size and offsets are zero — so this is backwards-compatible.\n */\nfunction getRenderedVideoRect(video: HTMLVideoElement): {\n offsetX: number;\n offsetY: number;\n width: number;\n height: number;\n} {\n const elementWidth = video.clientWidth;\n const elementHeight = video.clientHeight;\n const videoWidth = video.videoWidth || 1;\n const videoHeight = video.videoHeight || 1;\n\n const objectFit = getComputedStyle(video).objectFit;\n\n if (objectFit === 'cover') {\n const scale = Math.max(\n elementWidth / videoWidth,\n elementHeight / videoHeight,\n );\n const renderedWidth = videoWidth * scale;\n const renderedHeight = videoHeight * scale;\n return {\n offsetX: (elementWidth - renderedWidth) / 2,\n offsetY: (elementHeight - renderedHeight) / 2,\n width: renderedWidth,\n height: renderedHeight,\n };\n }\n\n if (objectFit === 'contain') {\n const scale = Math.min(\n elementWidth / videoWidth,\n elementHeight / videoHeight,\n );\n const renderedWidth = videoWidth * scale;\n const renderedHeight = videoHeight * scale;\n return {\n offsetX: (elementWidth - renderedWidth) / 2,\n offsetY: (elementHeight - renderedHeight) / 2,\n width: renderedWidth,\n height: renderedHeight,\n };\n }\n\n // Default (fill / none / scale-down with no scaling needed): element dimensions\n return { offsetX: 0, offsetY: 0, width: elementWidth, height: elementHeight };\n}\n\nexport interface OverlayConfig {\n highlightScanRegion: boolean;\n highlightCodeOutline: boolean;\n customOverlay?: HTMLDivElement;\n}\n\nexport class ScanOverlay {\n private container: HTMLElement;\n private overlayEl: HTMLDivElement | null = null;\n private codeOutlineEl: SVGElement | null = null;\n private config: OverlayConfig;\n private video: HTMLVideoElement;\n\n constructor(video: HTMLVideoElement, config: OverlayConfig) {\n this.video = video;\n this.config = config;\n\n const parent = video.parentElement;\n if (!parent) {\n throw new Error(\n 'QrScanner: video element must have a parent element. ' +\n 'The parent should have position: relative.',\n );\n }\n this.container = parent;\n }\n\n setup(): void {\n if (this.config.customOverlay) {\n this.overlayEl = this.config.customOverlay;\n this.positionOverlay();\n return;\n }\n\n if (this.config.highlightScanRegion) {\n this.createScanRegionOverlay();\n }\n\n if (this.config.highlightCodeOutline) {\n this.createCodeOutline();\n }\n }\n\n updateScanRegion(region: ScanRegion): void {\n if (!this.overlayEl || this.config.customOverlay) return;\n this.positionOverlayToRegion(region);\n }\n\n updateCodeOutline(\n cornerPoints: Point[] | null,\n scanRegion?: ScanRegion,\n ): void {\n if (!this.codeOutlineEl) return;\n\n if (!cornerPoints || cornerPoints.length < 4) {\n this.codeOutlineEl.style.display = 'none';\n return;\n }\n\n this.codeOutlineEl.style.display = 'block';\n\n const polygon = this.codeOutlineEl.querySelector('polygon');\n if (!polygon) return;\n\n // Corner points are relative to the cropped scan region.\n // Add the scan region offset to get full video coordinates,\n // then scale to display coordinates (accounting for object-fit).\n const regionX = scanRegion?.x ?? 0;\n const regionY = scanRegion?.y ?? 0;\n const rendered = getRenderedVideoRect(this.video);\n const scaleX = rendered.width / this.video.videoWidth;\n const scaleY = rendered.height / this.video.videoHeight;\n\n const points = cornerPoints\n .map(\n (p) =>\n `${(p.x + regionX) * scaleX + rendered.offsetX},${(p.y + regionY) * scaleY + rendered.offsetY}`,\n )\n .join(' ');\n\n polygon.setAttribute('points', points);\n }\n\n destroy(): void {\n if (this.overlayEl && !this.config.customOverlay) {\n this.overlayEl.remove();\n }\n if (this.codeOutlineEl) {\n this.codeOutlineEl.remove();\n }\n this.overlayEl = null;\n this.codeOutlineEl = null;\n }\n\n private createScanRegionOverlay(): void {\n this.overlayEl = document.createElement('div');\n this.overlayEl.className = 'qr-scanner-region';\n\n // Overlay size: 3/4 of the smaller container dimension, centered.\n const cw = this.container.clientWidth;\n const ch = this.container.clientHeight;\n const size = Math.round((Math.min(cw, ch) * 3) / 4);\n\n Object.assign(this.overlayEl.style, {\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: `${size}px`,\n height: `${size}px`,\n border: '2px solid rgba(255, 255, 255, 0.5)',\n borderRadius: '8px',\n boxShadow: '0 0 0 9999px rgba(0, 0, 0, 0.5)',\n pointerEvents: 'none',\n zIndex: '10',\n });\n\n // Corner markers\n const corners = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];\n for (const corner of corners) {\n const marker = document.createElement('div');\n marker.className = `qr-scanner-corner qr-scanner-corner-${corner}`;\n\n const [vertical, horizontal] = corner.split('-');\n\n Object.assign(marker.style, {\n position: 'absolute',\n width: '24px',\n height: '24px',\n [vertical]: '-2px',\n [horizontal]: '-2px',\n [`border-${vertical}`]: '3px solid white',\n [`border-${horizontal}`]: '3px solid white',\n [`border-${vertical}-${horizontal}-radius`]: '8px',\n });\n\n this.overlayEl.appendChild(marker);\n }\n\n this.container.appendChild(this.overlayEl);\n }\n\n private createCodeOutline(): void {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('class', 'qr-scanner-code-outline');\n\n Object.assign(svg.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '11',\n display: 'none',\n });\n\n const polygon = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'polygon',\n );\n polygon.setAttribute('fill', 'none');\n polygon.setAttribute('stroke', '#00ff00');\n polygon.setAttribute('stroke-width', '3');\n polygon.setAttribute('stroke-linejoin', 'round');\n\n // Animated stroke\n const animate = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'animate',\n );\n animate.setAttribute('attributeName', 'stroke-opacity');\n animate.setAttribute('values', '1;0.5;1');\n animate.setAttribute('dur', '1.5s');\n animate.setAttribute('repeatCount', 'indefinite');\n polygon.appendChild(animate);\n\n svg.appendChild(polygon);\n this.container.appendChild(svg);\n this.codeOutlineEl = svg;\n }\n\n private positionOverlay(): void {\n if (!this.overlayEl) return;\n\n Object.assign(this.overlayEl.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '10',\n });\n }\n\n private positionOverlayToRegion(_region: ScanRegion): void {\n if (!this.overlayEl) return;\n\n // Keep the overlay at a container-relative centered size rather than\n // mapping scan region coordinates to display coordinates. With\n // object-fit: cover on a portrait phone with a landscape camera, the\n // mapped region extends beyond the container — fine once the camera is\n // visible but causes a jarring jump from the initial placeholder.\n // The overlay is a visual guide; the actual scan area (in the frame\n // extractor) is unaffected and may be larger than what's shown.\n const cw = this.container.clientWidth;\n const ch = this.container.clientHeight;\n const size = Math.round((Math.min(cw, ch) * 3) / 4);\n\n // Only update size — initial CSS centering (top: 50%, left: 50%,\n // transform: translate(-50%, -50%)) persists and handles re-centering.\n Object.assign(this.overlayEl.style, {\n width: `${size}px`,\n height: `${size}px`,\n });\n }\n}\n","import type { ScanRegion } from './types.js';\n\n/**\n * Calculate the default scan region: a centered square covering\n * 2/3 of the smaller video dimension.\n */\nexport function calculateDefaultScanRegion(video: HTMLVideoElement): ScanRegion {\n const videoWidth = video.videoWidth || video.width;\n const videoHeight = video.videoHeight || video.height;\n\n const smallerDimension = Math.min(videoWidth, videoHeight);\n const size = Math.round((smallerDimension * 2) / 3);\n\n return {\n x: Math.round((videoWidth - size) / 2),\n y: Math.round((videoHeight - size) / 2),\n width: size,\n height: size,\n };\n}\n","import { CameraManager } from './camera.js';\nimport { debug } from './debug.js';\nimport { FrameExtractor } from './frame-extractor.js';\nimport { ScanOverlay } from './overlay.js';\nimport { calculateDefaultScanRegion } from './scan-region.js';\nimport type {\n ScannerOptions,\n ScanResult,\n ScanRegion,\n InversionMode,\n WorkerRequest,\n WorkerResponse,\n} from './types.js';\nimport type { ReaderOptions } from 'zxing-wasm/reader';\n\ntype OnDecodeCallback = (result: ScanResult) => void;\n\n/**\n * Custom worker URL override. When set, this URL is used instead of the\n * default bundler-resolved worker. Useful for CJS consumers or non-standard\n * bundler setups.\n */\nlet customWorkerUrl: string | URL | null = null;\n\nexport function setWorkerUrl(url: string | URL): void {\n customWorkerUrl = url;\n}\n\nfunction resolveWorkerUrl(): string | URL {\n if (customWorkerUrl) {\n return customWorkerUrl;\n }\n // Standard pattern: modern bundlers (Vite, webpack 5, Parcel, esbuild)\n // resolve `new URL('./file', import.meta.url)` at build time,\n // copying worker.js to the output directory and returning the correct URL.\n // Falls back gracefully for CJS builds where import.meta is unavailable.\n try {\n return new URL('./worker.js', import.meta.url);\n } catch {\n throw new Error(\n '@agicash/qr-scanner: Could not resolve worker URL. ' +\n 'Call QrScanner.setWorkerUrl() with the path to the worker script before creating a scanner. ' +\n 'Example: QrScanner.setWorkerUrl(\"/path/to/@agicash/qr-scanner/dist/worker.js\")',\n );\n }\n}\n\nexport class Scanner {\n private video: HTMLVideoElement;\n private onDecode: OnDecodeCallback;\n private options: ScannerOptions;\n private camera: CameraManager;\n private frameExtractor: FrameExtractor | null = null;\n private worker: Worker | null = null;\n private overlay: ScanOverlay | null = null;\n private active = false;\n private paused = false;\n private destroyed = false;\n\n constructor(\n video: HTMLVideoElement,\n onDecode: OnDecodeCallback,\n options: ScannerOptions = {},\n ) {\n this.video = video;\n this.onDecode = onDecode;\n this.options = options;\n\n this.camera = new CameraManager({\n preferredCamera: options.preferredCamera,\n cameraResolution: options.cameraResolution,\n });\n }\n\n async start(): Promise<void> {\n if (this.destroyed) {\n throw new Error('Scanner has been destroyed');\n }\n\n if (this.active && !this.paused) {\n return; // Already running\n }\n\n const t0 = performance.now();\n\n // Show overlay immediately (CSS-centered placeholder) so the UI looks\n // ready while the camera is still loading.\n if (\n !this.overlay &&\n (this.options.highlightScanRegion ||\n this.options.highlightCodeOutline ||\n this.options.overlay)\n ) {\n try {\n this.overlay = new ScanOverlay(this.video, {\n highlightScanRegion: this.options.highlightScanRegion ?? false,\n highlightCodeOutline: this.options.highlightCodeOutline ?? false,\n customOverlay: this.options.overlay,\n });\n this.overlay.setup();\n } catch {\n // Overlay setup failed (e.g., no parent element) — continue without overlay\n }\n }\n\n // Start camera\n await this.camera.start(this.video);\n debug(\n `[QrScanner] start: camera ready ${(performance.now() - t0).toFixed(0)}ms`,\n );\n\n // Now that video dimensions are known, position overlay exactly\n if (this.overlay) {\n this.overlay.updateScanRegion(this.getCurrentScanRegion());\n }\n\n // Create worker if needed\n if (!this.worker) {\n const tw = performance.now();\n this.worker = this.createWorker();\n debug(\n `[QrScanner] start: worker created ${(performance.now() - tw).toFixed(0)}ms`,\n );\n }\n\n // Create frame extractor if needed\n if (!this.frameExtractor) {\n this.frameExtractor = new FrameExtractor(this.video, {\n maxScansPerSecond: this.options.maxScansPerSecond ?? 15,\n getScanRegion: () => this.getCurrentScanRegion(),\n });\n }\n\n // Start frame extraction loop\n this.frameExtractor.start((imageData) => {\n this.sendToWorker(imageData);\n });\n\n this.active = true;\n this.paused = false;\n\n debug(`[QrScanner] start: total ${(performance.now() - t0).toFixed(0)}ms`);\n }\n\n stop(): void {\n this.frameExtractor?.stop();\n this.camera.stop();\n this.video.srcObject = null;\n this.active = false;\n this.paused = false;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.stop();\n this.frameExtractor?.destroy();\n this.frameExtractor = null;\n this.overlay?.destroy();\n this.overlay = null;\n this.worker?.terminate();\n this.worker = null;\n this.destroyed = true;\n }\n\n async pause(stopStreamImmediately = true): Promise<boolean> {\n if (!this.active) return false;\n\n this.frameExtractor?.stop();\n this.paused = true;\n\n if (stopStreamImmediately) {\n this.camera.stop();\n this.video.srcObject = null;\n }\n\n return true;\n }\n\n async setCamera(facingModeOrDeviceId: string): Promise<void> {\n const wasActive = this.active && !this.paused;\n if (wasActive) {\n this.frameExtractor?.stop();\n }\n\n await this.camera.setCamera(facingModeOrDeviceId, this.video);\n\n if (wasActive) {\n this.frameExtractor?.start((imageData) => {\n this.sendToWorker(imageData);\n });\n }\n }\n\n async hasFlash(): Promise<boolean> {\n return this.camera.hasFlash();\n }\n\n isFlashOn(): boolean {\n return this.camera.isFlashOn();\n }\n\n async toggleFlash(): Promise<void> {\n return this.camera.toggleFlash();\n }\n\n async turnFlashOn(): Promise<void> {\n return this.camera.turnFlashOn();\n }\n\n async turnFlashOff(): Promise<void> {\n return this.camera.turnFlashOff();\n }\n\n setInversionMode(mode: InversionMode): void {\n if (!this.worker) return;\n\n const options: Partial<ReaderOptions> = {};\n switch (mode) {\n case 'original':\n options.tryInvert = false;\n break;\n case 'invert':\n options.tryInvert = true;\n break;\n case 'both':\n options.tryInvert = true;\n break;\n }\n\n const msg: WorkerRequest = { type: 'configure', options };\n this.worker.postMessage(msg);\n }\n\n isActive(): boolean {\n return this.active;\n }\n\n isPaused(): boolean {\n return this.paused;\n }\n\n isDestroyed(): boolean {\n return this.destroyed;\n }\n\n private getCurrentScanRegion(): ScanRegion {\n if (this.options.calculateScanRegion) {\n return this.options.calculateScanRegion(this.video);\n }\n return calculateDefaultScanRegion(this.video);\n }\n\n private createWorker(): Worker {\n const workerUrl = resolveWorkerUrl();\n const worker = new Worker(workerUrl, { type: 'module' });\n\n // Configure with custom decoder options\n if (this.options.decoderOptions) {\n const msg: WorkerRequest = {\n type: 'configure',\n options: this.options.decoderOptions,\n };\n worker.postMessage(msg);\n }\n\n worker.onmessage = (e: MessageEvent<WorkerResponse>) => {\n this.handleWorkerMessage(e.data);\n };\n\n worker.onerror = (err) => {\n console.error('QR Scanner worker error:', err);\n this.frameExtractor?.markWorkerIdle();\n };\n\n return worker;\n }\n\n private handleWorkerMessage(response: WorkerResponse): void {\n this.frameExtractor?.markWorkerIdle();\n\n if (response.type === 'ready') {\n return;\n }\n\n if (response.type === 'error') {\n this.options.onDecodeError?.(response.message);\n return;\n }\n\n if (response.type === 'result') {\n if (response.results.length > 0) {\n const result = response.results[0];\n this.onDecode(result);\n\n // Update overlay\n if (this.overlay) {\n const region = this.getCurrentScanRegion();\n this.overlay.updateScanRegion(region);\n this.overlay.updateCodeOutline(result.cornerPoints, region);\n }\n } else {\n this.options.onDecodeError?.('No QR code found');\n\n // Hide code outline when no QR found\n if (this.overlay) {\n this.overlay.updateCodeOutline(null);\n }\n }\n }\n }\n\n private sendToWorker(imageData: ImageData): void {\n if (!this.worker) return;\n\n const msg: WorkerRequest = { type: 'decode', imageData };\n this.worker.postMessage(msg, [imageData.data.buffer]);\n }\n}\n","import { readBarcodes, type ReaderOptions } from 'zxing-wasm/reader';\nimport type { ScanResult, ScanRegion, Point } from './types.js';\nimport { loadImageData } from './utils.js';\n\nconst defaultReaderOptions: ReaderOptions = {\n formats: ['QRCode'],\n tryHarder: true,\n tryInvert: true,\n tryRotate: true,\n tryDenoise: false,\n tryDownscale: true,\n maxNumberOfSymbols: 1,\n};\n\nfunction mapPosition(position: {\n topLeft: Point;\n topRight: Point;\n bottomLeft: Point;\n bottomRight: Point;\n}): Point[] {\n return [\n position.topLeft,\n position.topRight,\n position.bottomRight,\n position.bottomLeft,\n ];\n}\n\n/** Input types that zxing-wasm can handle directly (no canvas needed). */\ntype DirectInput = Blob | ArrayBuffer | Uint8Array | ImageData;\n\n/** Input types that need canvas-based pixel extraction. */\ntype CanvasInput = HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap;\n\nfunction isDirectInput(source: unknown): source is DirectInput {\n return (\n source instanceof Blob ||\n source instanceof ArrayBuffer ||\n source instanceof Uint8Array ||\n (typeof ImageData !== 'undefined' && source instanceof ImageData)\n );\n}\n\n/**\n * Scan a single image for QR codes. Does not require a camera or video stream.\n */\nexport async function scanImage(\n source:\n | CanvasInput\n | DirectInput\n | File\n | URL\n | string,\n options?: {\n scanRegion?: ScanRegion | null;\n canvas?: HTMLCanvasElement | null;\n decoderOptions?: Partial<ReaderOptions>;\n },\n): Promise<ScanResult> {\n const readerOptions: ReaderOptions = {\n ...defaultReaderOptions,\n ...options?.decoderOptions,\n formats: ['QRCode'],\n };\n\n let input: DirectInput;\n if (isDirectInput(source)) {\n input = source;\n } else if (typeof source === 'string' || source instanceof URL) {\n // URL string - fetch and pass as ArrayBuffer\n const url = source instanceof URL ? source.href : source;\n const response = await fetch(url);\n input = await response.arrayBuffer();\n } else {\n // Canvas-based sources - extract ImageData\n input = await loadImageData(source, options?.scanRegion, options?.canvas);\n }\n\n const results = await readBarcodes(input, readerOptions);\n const valid = results.filter((r) => r.isValid);\n\n if (valid.length === 0) {\n throw new Error('No QR code found in the image');\n }\n\n const first = valid[0];\n return {\n data: first.text,\n cornerPoints: mapPosition(first.position),\n };\n}\n","import type { ScanRegion } from './types.js';\n\n/**\n * Load an image source into an ImageData object, optionally cropping to a scan region.\n */\nexport async function loadImageData(\n source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | File | Blob | URL | string,\n scanRegion?: ScanRegion | null,\n canvas?: HTMLCanvasElement | null,\n): Promise<ImageData> {\n const img = await resolveImageSource(source);\n\n const sx = scanRegion?.x ?? 0;\n const sy = scanRegion?.y ?? 0;\n const sw = scanRegion?.width ?? (img.width - sx);\n const sh = scanRegion?.height ?? (img.height - sy);\n\n let drawCanvas: HTMLCanvasElement | OffscreenCanvas;\n let ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n\n if (canvas) {\n drawCanvas = canvas;\n canvas.width = sw;\n canvas.height = sh;\n ctx = canvas.getContext('2d')!;\n } else if (typeof OffscreenCanvas !== 'undefined') {\n drawCanvas = new OffscreenCanvas(sw, sh);\n ctx = drawCanvas.getContext('2d')! as OffscreenCanvasRenderingContext2D;\n } else {\n drawCanvas = document.createElement('canvas');\n drawCanvas.width = sw;\n drawCanvas.height = sh;\n ctx = drawCanvas.getContext('2d')!;\n }\n\n ctx.drawImage(img as CanvasImageSource, sx, sy, sw, sh, 0, 0, sw, sh);\n return ctx.getImageData(0, 0, sw, sh);\n}\n\nasync function resolveImageSource(\n source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | File | Blob | URL | string,\n): Promise<HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap> {\n if (source instanceof HTMLImageElement || source instanceof HTMLCanvasElement || source instanceof ImageBitmap) {\n return source;\n }\n\n if (typeof OffscreenCanvas !== 'undefined' && source instanceof OffscreenCanvas) {\n return source;\n }\n\n if (source instanceof File || source instanceof Blob) {\n return createImageBitmapFromBlob(source);\n }\n\n // URL or string\n const url = source instanceof URL ? source.href : source as string;\n const response = await fetch(url);\n const blob = await response.blob();\n return createImageBitmapFromBlob(blob);\n}\n\nasync function createImageBitmapFromBlob(blob: Blob): Promise<ImageBitmap> {\n if (typeof createImageBitmap !== 'undefined') {\n return createImageBitmap(blob);\n }\n // Fallback for environments without createImageBitmap\n const url = URL.createObjectURL(blob);\n try {\n const img = new Image();\n img.src = url;\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error('Failed to load image'));\n });\n return img as unknown as ImageBitmap;\n } finally {\n URL.revokeObjectURL(url);\n }\n}\n"],"mappings":"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","names":["t","import_reader","enabled"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -95,6 +95,13 @@ declare class QrScanner {
|
|
|
95
95
|
* QrScanner.setWorkerUrl('/assets/qr-scanner-worker.js');
|
|
96
96
|
*/
|
|
97
97
|
static setWorkerUrl(url: string | URL): void;
|
|
98
|
+
/**
|
|
99
|
+
* Enable or disable debug logging (performance timings, camera selection).
|
|
100
|
+
* Off by default. Useful for diagnosing camera issues in the browser console.
|
|
101
|
+
* @example
|
|
102
|
+
* QrScanner.setDebug(true);
|
|
103
|
+
*/
|
|
104
|
+
static setDebug(enabled: boolean): void;
|
|
98
105
|
/** Scan a single image (not a video stream). */
|
|
99
106
|
static scanImage(source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | ImageData | Blob | ArrayBuffer | Uint8Array | File | URL | string, options?: {
|
|
100
107
|
scanRegion?: ScanRegion | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -95,6 +95,13 @@ declare class QrScanner {
|
|
|
95
95
|
* QrScanner.setWorkerUrl('/assets/qr-scanner-worker.js');
|
|
96
96
|
*/
|
|
97
97
|
static setWorkerUrl(url: string | URL): void;
|
|
98
|
+
/**
|
|
99
|
+
* Enable or disable debug logging (performance timings, camera selection).
|
|
100
|
+
* Off by default. Useful for diagnosing camera issues in the browser console.
|
|
101
|
+
* @example
|
|
102
|
+
* QrScanner.setDebug(true);
|
|
103
|
+
*/
|
|
104
|
+
static setDebug(enabled: boolean): void;
|
|
98
105
|
/** Scan a single image (not a video stream). */
|
|
99
106
|
static scanImage(source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | ImageData | Blob | ArrayBuffer | Uint8Array | File | URL | string, options?: {
|
|
100
107
|
scanRegion?: ScanRegion | null;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// src/debug.ts
|
|
2
|
+
var enabled = false;
|
|
3
|
+
function setDebug(on) {
|
|
4
|
+
enabled = on;
|
|
5
|
+
}
|
|
6
|
+
function debug(...args) {
|
|
7
|
+
if (enabled) console.debug(...args);
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
// src/camera.ts
|
|
2
11
|
var CameraPermissionError = class extends Error {
|
|
3
12
|
constructor(message = "Camera access denied. Please grant camera permission and try again.") {
|
|
@@ -38,16 +47,16 @@ var CameraManager = class {
|
|
|
38
47
|
const t0 = performance.now();
|
|
39
48
|
this.stream = await this.acquireStream();
|
|
40
49
|
const t1 = performance.now();
|
|
41
|
-
|
|
50
|
+
debug(`[QrScanner] acquireStream: ${(t1 - t0).toFixed(0)}ms`);
|
|
42
51
|
await this.ensureBestCamera();
|
|
43
52
|
const t2 = performance.now();
|
|
44
|
-
|
|
53
|
+
debug(`[QrScanner] ensureBestCamera: ${(t2 - t1).toFixed(0)}ms`);
|
|
45
54
|
video.srcObject = this.stream;
|
|
46
55
|
video.setAttribute("playsinline", "true");
|
|
47
56
|
await video.play();
|
|
48
57
|
const t3 = performance.now();
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
debug(`[QrScanner] video.play: ${(t3 - t2).toFixed(0)}ms`);
|
|
59
|
+
debug(`[QrScanner] camera.start total: ${(t3 - t0).toFixed(0)}ms`);
|
|
51
60
|
if (this.facingMode === "environment" || this.facingMode === "user") {
|
|
52
61
|
const finalDeviceId = this.getVideoTrack()?.getSettings().deviceId;
|
|
53
62
|
if (finalDeviceId) {
|
|
@@ -122,9 +131,7 @@ var CameraManager = class {
|
|
|
122
131
|
*/
|
|
123
132
|
async ensureBestCamera() {
|
|
124
133
|
if (this.facingMode !== "environment" && this.facingMode !== "user") {
|
|
125
|
-
|
|
126
|
-
"[QrScanner] ensureBestCamera: skipped (specific deviceId)"
|
|
127
|
-
);
|
|
134
|
+
debug("[QrScanner] ensureBestCamera: skipped (specific deviceId)");
|
|
128
135
|
return;
|
|
129
136
|
}
|
|
130
137
|
const track = this.getVideoTrack();
|
|
@@ -132,12 +139,12 @@ var CameraManager = class {
|
|
|
132
139
|
try {
|
|
133
140
|
const capabilities = track.getCapabilities();
|
|
134
141
|
if (!capabilities.focusMode || capabilities.focusMode.includes("continuous")) {
|
|
135
|
-
|
|
142
|
+
debug(
|
|
136
143
|
`[QrScanner] ensureBestCamera: skipped (focusMode: ${JSON.stringify(capabilities.focusMode)})`
|
|
137
144
|
);
|
|
138
145
|
return;
|
|
139
146
|
}
|
|
140
|
-
|
|
147
|
+
debug(
|
|
141
148
|
`[QrScanner] ensureBestCamera: current camera lacks autofocus (focusMode: ${JSON.stringify(capabilities.focusMode)})`
|
|
142
149
|
);
|
|
143
150
|
} catch {
|
|
@@ -154,7 +161,7 @@ var CameraManager = class {
|
|
|
154
161
|
const candidates = devices.filter(
|
|
155
162
|
(d) => d.kind === "videoinput" && d.deviceId !== currentDeviceId
|
|
156
163
|
);
|
|
157
|
-
|
|
164
|
+
debug(
|
|
158
165
|
`[QrScanner] ensureBestCamera: testing ${candidates.length} candidate camera(s)`
|
|
159
166
|
);
|
|
160
167
|
if (candidates.length === 0) return;
|
|
@@ -171,11 +178,11 @@ var CameraManager = class {
|
|
|
171
178
|
},
|
|
172
179
|
audio: false
|
|
173
180
|
});
|
|
174
|
-
|
|
181
|
+
debug(
|
|
175
182
|
`[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia ${(performance.now() - t).toFixed(0)}ms`
|
|
176
183
|
);
|
|
177
184
|
} catch {
|
|
178
|
-
|
|
185
|
+
debug(
|
|
179
186
|
`[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia failed ${(performance.now() - t).toFixed(0)}ms`
|
|
180
187
|
);
|
|
181
188
|
continue;
|
|
@@ -261,12 +268,12 @@ var CameraManager = class {
|
|
|
261
268
|
const t = performance.now();
|
|
262
269
|
try {
|
|
263
270
|
const stream = await navigator.mediaDevices.getUserMedia(attempts[i]);
|
|
264
|
-
|
|
271
|
+
debug(
|
|
265
272
|
`[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms \u2713`
|
|
266
273
|
);
|
|
267
274
|
return stream;
|
|
268
275
|
} catch (err) {
|
|
269
|
-
|
|
276
|
+
debug(
|
|
270
277
|
`[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms \u2717 ${err instanceof DOMException ? err.name : err}`
|
|
271
278
|
);
|
|
272
279
|
if (err instanceof DOMException) {
|
|
@@ -654,7 +661,7 @@ var Scanner = class {
|
|
|
654
661
|
}
|
|
655
662
|
}
|
|
656
663
|
await this.camera.start(this.video);
|
|
657
|
-
|
|
664
|
+
debug(
|
|
658
665
|
`[QrScanner] start: camera ready ${(performance.now() - t0).toFixed(0)}ms`
|
|
659
666
|
);
|
|
660
667
|
if (this.overlay) {
|
|
@@ -663,7 +670,7 @@ var Scanner = class {
|
|
|
663
670
|
if (!this.worker) {
|
|
664
671
|
const tw = performance.now();
|
|
665
672
|
this.worker = this.createWorker();
|
|
666
|
-
|
|
673
|
+
debug(
|
|
667
674
|
`[QrScanner] start: worker created ${(performance.now() - tw).toFixed(0)}ms`
|
|
668
675
|
);
|
|
669
676
|
}
|
|
@@ -678,9 +685,7 @@ var Scanner = class {
|
|
|
678
685
|
});
|
|
679
686
|
this.active = true;
|
|
680
687
|
this.paused = false;
|
|
681
|
-
|
|
682
|
-
`[QrScanner] start: total ${(performance.now() - t0).toFixed(0)}ms`
|
|
683
|
-
);
|
|
688
|
+
debug(`[QrScanner] start: total ${(performance.now() - t0).toFixed(0)}ms`);
|
|
684
689
|
}
|
|
685
690
|
stop() {
|
|
686
691
|
this.frameExtractor?.stop();
|
|
@@ -1022,6 +1027,15 @@ var QrScanner = class {
|
|
|
1022
1027
|
static setWorkerUrl(url) {
|
|
1023
1028
|
setWorkerUrl(url);
|
|
1024
1029
|
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Enable or disable debug logging (performance timings, camera selection).
|
|
1032
|
+
* Off by default. Useful for diagnosing camera issues in the browser console.
|
|
1033
|
+
* @example
|
|
1034
|
+
* QrScanner.setDebug(true);
|
|
1035
|
+
*/
|
|
1036
|
+
static setDebug(enabled2) {
|
|
1037
|
+
setDebug(enabled2);
|
|
1038
|
+
}
|
|
1025
1039
|
/** Scan a single image (not a video stream). */
|
|
1026
1040
|
static scanImage(source, options) {
|
|
1027
1041
|
return scanImage(source, options);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/camera.ts","../src/frame-extractor.ts","../src/overlay.ts","../src/scan-region.ts","../src/scanner.ts","../src/scan-image.ts","../src/utils.ts","../src/index.ts"],"sourcesContent":["import type { FacingMode, DeviceId, Camera } from './types.js';\n\nexport class CameraPermissionError extends Error {\n constructor(\n message = 'Camera access denied. Please grant camera permission and try again.',\n ) {\n super(message);\n this.name = 'CameraPermissionError';\n }\n}\n\nexport class CameraNotFoundError extends Error {\n constructor(\n message = 'No camera found. Please connect a camera and try again.',\n ) {\n super(message);\n this.name = 'CameraNotFoundError';\n }\n}\n\nconst CACHE_KEY_PREFIX = '@agicash/qr-scanner:camera:';\n\nfunction getCachedDeviceId(facingMode: string): string | null {\n try {\n return localStorage.getItem(`${CACHE_KEY_PREFIX}${facingMode}`);\n } catch {\n return null;\n }\n}\n\nfunction setCachedDeviceId(facingMode: string, deviceId: string): void {\n try {\n localStorage.setItem(`${CACHE_KEY_PREFIX}${facingMode}`, deviceId);\n } catch {\n // localStorage unavailable or full — ignore\n }\n}\n\nexport interface CameraConfig {\n preferredCamera?: FacingMode | DeviceId;\n cameraResolution?: {\n width?: MediaTrackConstraintSet['width'];\n height?: MediaTrackConstraintSet['height'];\n };\n}\n\nexport class CameraManager {\n private stream: MediaStream | null = null;\n private facingMode: FacingMode | DeviceId;\n private resolution: CameraConfig['cameraResolution'];\n\n constructor(config: CameraConfig = {}) {\n this.facingMode = config.preferredCamera ?? 'environment';\n this.resolution = config.cameraResolution;\n }\n\n async start(video: HTMLVideoElement): Promise<MediaStream> {\n if (this.stream) {\n return this.stream;\n }\n\n const t0 = performance.now();\n\n this.stream = await this.acquireStream();\n const t1 = performance.now();\n console.debug(`[QrScanner] acquireStream: ${(t1 - t0).toFixed(0)}ms`);\n\n // On some devices (e.g. Samsung S24 + Brave), facingMode: 'environment'\n // picks an ultrawide camera that lacks autofocus. Check and switch to a\n // better camera BEFORE showing on screen to avoid visible flicker.\n await this.ensureBestCamera();\n const t2 = performance.now();\n console.debug(`[QrScanner] ensureBestCamera: ${(t2 - t1).toFixed(0)}ms`);\n\n video.srcObject = this.stream;\n video.setAttribute('playsinline', 'true');\n await video.play();\n const t3 = performance.now();\n console.debug(`[QrScanner] video.play: ${(t3 - t2).toFixed(0)}ms`);\n console.debug(`[QrScanner] camera.start total: ${(t3 - t0).toFixed(0)}ms`);\n\n // Cache the final camera so subsequent starts skip ensureBestCamera\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n const finalDeviceId = this.getVideoTrack()?.getSettings().deviceId;\n if (finalDeviceId) {\n setCachedDeviceId(this.facingMode, finalDeviceId);\n }\n }\n\n return this.stream;\n }\n\n stop(): void {\n if (this.stream) {\n for (const track of this.stream.getTracks()) {\n track.stop();\n }\n this.stream = null;\n }\n }\n\n async setCamera(\n facingModeOrDeviceId: FacingMode | DeviceId,\n video: HTMLVideoElement,\n ): Promise<void> {\n this.stop();\n this.facingMode = facingModeOrDeviceId;\n await this.start(video);\n }\n\n getStream(): MediaStream | null {\n return this.stream;\n }\n\n async hasFlash(): Promise<boolean> {\n const track = this.getVideoTrack();\n if (!track) return false;\n\n try {\n const capabilities = track.getCapabilities() as MediaTrackCapabilities & {\n torch?: boolean;\n };\n return capabilities.torch === true;\n } catch {\n return false;\n }\n }\n\n isFlashOn(): boolean {\n const track = this.getVideoTrack();\n if (!track) return false;\n\n const settings = track.getSettings() as MediaTrackSettings & {\n torch?: boolean;\n };\n return settings.torch === true;\n }\n\n async toggleFlash(): Promise<void> {\n if (this.isFlashOn()) {\n await this.turnFlashOff();\n } else {\n await this.turnFlashOn();\n }\n }\n\n async turnFlashOn(): Promise<void> {\n await this.setTorch(true);\n }\n\n async turnFlashOff(): Promise<void> {\n await this.setTorch(false);\n }\n\n private async setTorch(on: boolean): Promise<void> {\n const track = this.getVideoTrack();\n if (!track) {\n throw new Error('No active camera stream');\n }\n\n try {\n await track.applyConstraints({\n advanced: [{ torch: on } as MediaTrackConstraintSet],\n });\n } catch {\n throw new Error('Flash/torch is not supported on this device');\n }\n }\n\n /**\n * If the current camera lacks continuous autofocus (e.g. an ultrawide sensor\n * picked by facingMode: 'environment'), find a better camera with the same\n * facing mode and replace this.stream. Called before assigning to the video\n * element so the user never sees the wrong camera.\n */\n private async ensureBestCamera(): Promise<void> {\n if (this.facingMode !== 'environment' && this.facingMode !== 'user') {\n console.debug(\n '[QrScanner] ensureBestCamera: skipped (specific deviceId)',\n );\n return;\n }\n\n const track = this.getVideoTrack();\n if (!track) return;\n\n try {\n const capabilities = track.getCapabilities() as MediaTrackCapabilities & {\n focusMode?: string[];\n };\n if (\n !capabilities.focusMode ||\n capabilities.focusMode.includes('continuous')\n ) {\n // focusMode not reported (e.g. Safari/iOS) or has autofocus — skip.\n // Only enter the candidate loop when the browser explicitly reports\n // focusMode without 'continuous' (e.g. S24 + Brave ultrawide).\n console.debug(\n `[QrScanner] ensureBestCamera: skipped (focusMode: ${JSON.stringify(capabilities.focusMode)})`,\n );\n return;\n }\n console.debug(\n `[QrScanner] ensureBestCamera: current camera lacks autofocus (focusMode: ${JSON.stringify(capabilities.focusMode)})`,\n );\n } catch {\n return;\n }\n\n // Current camera lacks continuous autofocus.\n // Enumerate devices while stream is active (ensures deviceIds are available).\n const currentDeviceId = track.getSettings().deviceId;\n\n let devices: MediaDeviceInfo[];\n try {\n devices = await navigator.mediaDevices.enumerateDevices();\n } catch {\n return;\n }\n if (!Array.isArray(devices)) return;\n\n const candidates = devices.filter(\n (d) => d.kind === 'videoinput' && d.deviceId !== currentDeviceId,\n );\n console.debug(\n `[QrScanner] ensureBestCamera: testing ${candidates.length} candidate camera(s)`,\n );\n if (candidates.length === 0) return;\n\n // Stop current stream — mobile devices only allow one active camera\n this.stop();\n\n for (const candidate of candidates) {\n const t = performance.now();\n let candidateStream: MediaStream;\n try {\n candidateStream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: { exact: candidate.deviceId },\n width: this.resolution?.width ?? { ideal: 1920 },\n height: this.resolution?.height ?? { ideal: 1080 },\n },\n audio: false,\n });\n console.debug(\n `[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia ${(performance.now() - t).toFixed(0)}ms`,\n );\n } catch {\n console.debug(\n `[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia failed ${(performance.now() - t).toFixed(0)}ms`,\n );\n continue;\n }\n\n const candidateTrack = candidateStream.getVideoTracks()[0];\n if (!candidateTrack) {\n for (const t of candidateStream.getTracks()) t.stop();\n continue;\n }\n\n // Must match the desired facing mode\n const candidateSettings =\n candidateTrack.getSettings() as MediaTrackSettings & {\n facingMode?: string;\n };\n if (\n candidateSettings.facingMode &&\n candidateSettings.facingMode !== this.facingMode\n ) {\n for (const t of candidateStream.getTracks()) t.stop();\n continue;\n }\n\n // Check if this camera supports continuous autofocus\n try {\n const candidateCaps =\n candidateTrack.getCapabilities() as MediaTrackCapabilities & {\n focusMode?: string[];\n };\n if (candidateCaps.focusMode?.includes('continuous')) {\n this.stream = candidateStream;\n return;\n }\n } catch {\n // Can't check capabilities, skip\n }\n\n for (const t of candidateStream.getTracks()) t.stop();\n }\n\n // No better camera found — re-open the original\n try {\n this.stream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: currentDeviceId ? { exact: currentDeviceId } : undefined,\n width: this.resolution?.width ?? { ideal: 1920 },\n height: this.resolution?.height ?? { ideal: 1080 },\n },\n audio: false,\n });\n } catch {\n try {\n this.stream = await navigator.mediaDevices.getUserMedia(\n this.buildConstraints(),\n );\n } catch {\n // Could not recover camera\n }\n }\n }\n\n private getVideoTrack(): MediaStreamTrack | null {\n if (!this.stream) return null;\n const tracks = this.stream.getVideoTracks();\n return tracks[0] ?? null;\n }\n\n /**\n * Try getUserMedia with progressively simpler constraints.\n *\n * Some browsers (e.g. Brave on Samsung Galaxy S24) throw NotReadableError\n * when facingMode and resolution constraints are combined. Falling back to\n * fewer constraints lets us still open the camera on those browsers.\n */\n private async acquireStream(): Promise<MediaStream> {\n const labels: string[] = [];\n const attempts: MediaStreamConstraints[] = [];\n\n // If we've previously found a good camera for this facingMode, try it first\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n const cachedId = getCachedDeviceId(this.facingMode);\n if (cachedId) {\n labels.push('cached deviceId');\n const video: MediaTrackConstraints = {\n deviceId: { exact: cachedId },\n };\n if (this.resolution?.width) video.width = this.resolution.width;\n else video.width = { ideal: 1920 };\n if (this.resolution?.height) video.height = this.resolution.height;\n else video.height = { ideal: 1080 };\n attempts.push({ video, audio: false });\n }\n }\n\n // Standard fallback chain\n labels.push('full constraints', 'no resolution', 'bare minimum');\n attempts.push(\n // facingMode/deviceId + resolution\n this.buildConstraints(),\n // facingMode/deviceId only, no resolution\n this.buildConstraints(false),\n // Bare minimum\n { video: true, audio: false },\n );\n\n let lastError: unknown;\n for (let i = 0; i < attempts.length; i++) {\n const t = performance.now();\n try {\n const stream = await navigator.mediaDevices.getUserMedia(attempts[i]);\n console.debug(\n `[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms ✓`,\n );\n return stream;\n } catch (err) {\n console.debug(\n `[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms ✗ ${err instanceof DOMException ? err.name : err}`,\n );\n if (err instanceof DOMException) {\n if (err.name === 'NotAllowedError') {\n throw new CameraPermissionError();\n }\n if (err.name === 'NotFoundError') {\n throw new CameraNotFoundError();\n }\n // NotReadableError or OverconstrainedError — try next fallback\n lastError = err;\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n private buildConstraints(includeResolution = true): MediaStreamConstraints {\n const video: MediaTrackConstraints = {};\n\n if (includeResolution) {\n video.width = this.resolution?.width ?? { ideal: 1920 };\n video.height = this.resolution?.height ?? { ideal: 1080 };\n }\n\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n video.facingMode = this.facingMode;\n } else {\n video.deviceId = { exact: this.facingMode };\n }\n\n return { video, audio: false };\n }\n\n static async hasCamera(): Promise<boolean> {\n try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n return devices.some((d) => d.kind === 'videoinput');\n } catch {\n return false;\n }\n }\n\n static async listCameras(requestLabels = false): Promise<Camera[]> {\n if (requestLabels) {\n // Requesting labels requires a temporary stream to trigger the permission prompt\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: true,\n });\n for (const track of stream.getTracks()) {\n track.stop();\n }\n } catch {\n // Permission denied — fall through with empty labels\n }\n }\n\n const devices = await navigator.mediaDevices.enumerateDevices();\n return devices\n .filter((d) => d.kind === 'videoinput')\n .map((d) => ({\n id: d.deviceId,\n label: d.label || `Camera ${d.deviceId.slice(0, 8)}`,\n }));\n }\n}\n","import type { ScanRegion } from './types.js';\n\nexport interface FrameExtractorConfig {\n maxScansPerSecond: number;\n getScanRegion: () => ScanRegion;\n}\n\nexport class FrameExtractor {\n private video: HTMLVideoElement;\n private canvas: HTMLCanvasElement | OffscreenCanvas;\n private ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n private rafId: number | null = null;\n private running = false;\n private workerBusy = false;\n private lastScanTime = -Infinity;\n private minInterval: number;\n private getScanRegion: () => ScanRegion;\n private onFrame: ((imageData: ImageData) => void) | null = null;\n\n constructor(video: HTMLVideoElement, config: FrameExtractorConfig) {\n this.video = video;\n this.minInterval = 1000 / config.maxScansPerSecond;\n this.getScanRegion = config.getScanRegion;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n this.canvas = new OffscreenCanvas(1, 1);\n this.ctx = this.canvas.getContext('2d')! as OffscreenCanvasRenderingContext2D;\n } else {\n this.canvas = document.createElement('canvas');\n this.canvas.style.display = 'none';\n this.ctx = this.canvas.getContext('2d')!;\n }\n }\n\n start(onFrame: (imageData: ImageData) => void): void {\n if (this.running) return;\n this.running = true;\n this.onFrame = onFrame;\n this.rafId = requestAnimationFrame(this.tick);\n }\n\n stop(): void {\n this.running = false;\n this.onFrame = null;\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n }\n\n destroy(): void {\n this.stop();\n if (this.canvas instanceof HTMLCanvasElement && this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n }\n\n markWorkerIdle(): void {\n this.workerBusy = false;\n }\n\n markWorkerBusy(): void {\n this.workerBusy = true;\n }\n\n private tick = (): void => {\n if (!this.running) return;\n\n this.rafId = requestAnimationFrame(this.tick);\n\n // Skip if worker is still processing previous frame\n if (this.workerBusy) return;\n\n // Rate limiting\n const now = performance.now();\n if (now - this.lastScanTime < this.minInterval) return;\n\n // Skip if video isn't ready\n if (this.video.readyState < 2) return;\n\n this.lastScanTime = now;\n\n const region = this.getScanRegion();\n const sx = region.x ?? 0;\n const sy = region.y ?? 0;\n const sw = region.width ?? this.video.videoWidth;\n const sh = region.height ?? this.video.videoHeight;\n\n if (sw <= 0 || sh <= 0) return;\n\n this.canvas.width = sw;\n this.canvas.height = sh;\n\n this.ctx.drawImage(this.video, sx, sy, sw, sh, 0, 0, sw, sh);\n const imageData = this.ctx.getImageData(0, 0, sw, sh);\n\n this.workerBusy = true;\n this.onFrame?.(imageData);\n };\n}\n","import type { ScanRegion, Point } from './types.js';\n\n/**\n * Compute the actual rendered position and size of the video content\n * within the element, accounting for object-fit: cover.\n *\n * With object-fit: cover the video is scaled up to fill the element and\n * cropped. The rendered content is larger than the element, centered,\n * with negative offsets for the cropped portions.\n *\n * When object-fit is the default (fill), the rendered size equals the\n * element size and offsets are zero — so this is backwards-compatible.\n */\nfunction getRenderedVideoRect(video: HTMLVideoElement): {\n offsetX: number;\n offsetY: number;\n width: number;\n height: number;\n} {\n const elementWidth = video.clientWidth;\n const elementHeight = video.clientHeight;\n const videoWidth = video.videoWidth || 1;\n const videoHeight = video.videoHeight || 1;\n\n const objectFit = getComputedStyle(video).objectFit;\n\n if (objectFit === 'cover') {\n const scale = Math.max(\n elementWidth / videoWidth,\n elementHeight / videoHeight,\n );\n const renderedWidth = videoWidth * scale;\n const renderedHeight = videoHeight * scale;\n return {\n offsetX: (elementWidth - renderedWidth) / 2,\n offsetY: (elementHeight - renderedHeight) / 2,\n width: renderedWidth,\n height: renderedHeight,\n };\n }\n\n if (objectFit === 'contain') {\n const scale = Math.min(\n elementWidth / videoWidth,\n elementHeight / videoHeight,\n );\n const renderedWidth = videoWidth * scale;\n const renderedHeight = videoHeight * scale;\n return {\n offsetX: (elementWidth - renderedWidth) / 2,\n offsetY: (elementHeight - renderedHeight) / 2,\n width: renderedWidth,\n height: renderedHeight,\n };\n }\n\n // Default (fill / none / scale-down with no scaling needed): element dimensions\n return { offsetX: 0, offsetY: 0, width: elementWidth, height: elementHeight };\n}\n\nexport interface OverlayConfig {\n highlightScanRegion: boolean;\n highlightCodeOutline: boolean;\n customOverlay?: HTMLDivElement;\n}\n\nexport class ScanOverlay {\n private container: HTMLElement;\n private overlayEl: HTMLDivElement | null = null;\n private codeOutlineEl: SVGElement | null = null;\n private config: OverlayConfig;\n private video: HTMLVideoElement;\n\n constructor(video: HTMLVideoElement, config: OverlayConfig) {\n this.video = video;\n this.config = config;\n\n const parent = video.parentElement;\n if (!parent) {\n throw new Error(\n 'QrScanner: video element must have a parent element. ' +\n 'The parent should have position: relative.',\n );\n }\n this.container = parent;\n }\n\n setup(): void {\n if (this.config.customOverlay) {\n this.overlayEl = this.config.customOverlay;\n this.positionOverlay();\n return;\n }\n\n if (this.config.highlightScanRegion) {\n this.createScanRegionOverlay();\n }\n\n if (this.config.highlightCodeOutline) {\n this.createCodeOutline();\n }\n }\n\n updateScanRegion(region: ScanRegion): void {\n if (!this.overlayEl || this.config.customOverlay) return;\n this.positionOverlayToRegion(region);\n }\n\n updateCodeOutline(\n cornerPoints: Point[] | null,\n scanRegion?: ScanRegion,\n ): void {\n if (!this.codeOutlineEl) return;\n\n if (!cornerPoints || cornerPoints.length < 4) {\n this.codeOutlineEl.style.display = 'none';\n return;\n }\n\n this.codeOutlineEl.style.display = 'block';\n\n const polygon = this.codeOutlineEl.querySelector('polygon');\n if (!polygon) return;\n\n // Corner points are relative to the cropped scan region.\n // Add the scan region offset to get full video coordinates,\n // then scale to display coordinates (accounting for object-fit).\n const regionX = scanRegion?.x ?? 0;\n const regionY = scanRegion?.y ?? 0;\n const rendered = getRenderedVideoRect(this.video);\n const scaleX = rendered.width / this.video.videoWidth;\n const scaleY = rendered.height / this.video.videoHeight;\n\n const points = cornerPoints\n .map(\n (p) =>\n `${(p.x + regionX) * scaleX + rendered.offsetX},${(p.y + regionY) * scaleY + rendered.offsetY}`,\n )\n .join(' ');\n\n polygon.setAttribute('points', points);\n }\n\n destroy(): void {\n if (this.overlayEl && !this.config.customOverlay) {\n this.overlayEl.remove();\n }\n if (this.codeOutlineEl) {\n this.codeOutlineEl.remove();\n }\n this.overlayEl = null;\n this.codeOutlineEl = null;\n }\n\n private createScanRegionOverlay(): void {\n this.overlayEl = document.createElement('div');\n this.overlayEl.className = 'qr-scanner-region';\n\n // Overlay size: 3/4 of the smaller container dimension, centered.\n const cw = this.container.clientWidth;\n const ch = this.container.clientHeight;\n const size = Math.round((Math.min(cw, ch) * 3) / 4);\n\n Object.assign(this.overlayEl.style, {\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: `${size}px`,\n height: `${size}px`,\n border: '2px solid rgba(255, 255, 255, 0.5)',\n borderRadius: '8px',\n boxShadow: '0 0 0 9999px rgba(0, 0, 0, 0.5)',\n pointerEvents: 'none',\n zIndex: '10',\n });\n\n // Corner markers\n const corners = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];\n for (const corner of corners) {\n const marker = document.createElement('div');\n marker.className = `qr-scanner-corner qr-scanner-corner-${corner}`;\n\n const [vertical, horizontal] = corner.split('-');\n\n Object.assign(marker.style, {\n position: 'absolute',\n width: '24px',\n height: '24px',\n [vertical]: '-2px',\n [horizontal]: '-2px',\n [`border-${vertical}`]: '3px solid white',\n [`border-${horizontal}`]: '3px solid white',\n [`border-${vertical}-${horizontal}-radius`]: '8px',\n });\n\n this.overlayEl.appendChild(marker);\n }\n\n this.container.appendChild(this.overlayEl);\n }\n\n private createCodeOutline(): void {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('class', 'qr-scanner-code-outline');\n\n Object.assign(svg.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '11',\n display: 'none',\n });\n\n const polygon = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'polygon',\n );\n polygon.setAttribute('fill', 'none');\n polygon.setAttribute('stroke', '#00ff00');\n polygon.setAttribute('stroke-width', '3');\n polygon.setAttribute('stroke-linejoin', 'round');\n\n // Animated stroke\n const animate = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'animate',\n );\n animate.setAttribute('attributeName', 'stroke-opacity');\n animate.setAttribute('values', '1;0.5;1');\n animate.setAttribute('dur', '1.5s');\n animate.setAttribute('repeatCount', 'indefinite');\n polygon.appendChild(animate);\n\n svg.appendChild(polygon);\n this.container.appendChild(svg);\n this.codeOutlineEl = svg;\n }\n\n private positionOverlay(): void {\n if (!this.overlayEl) return;\n\n Object.assign(this.overlayEl.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '10',\n });\n }\n\n private positionOverlayToRegion(_region: ScanRegion): void {\n if (!this.overlayEl) return;\n\n // Keep the overlay at a container-relative centered size rather than\n // mapping scan region coordinates to display coordinates. With\n // object-fit: cover on a portrait phone with a landscape camera, the\n // mapped region extends beyond the container — fine once the camera is\n // visible but causes a jarring jump from the initial placeholder.\n // The overlay is a visual guide; the actual scan area (in the frame\n // extractor) is unaffected and may be larger than what's shown.\n const cw = this.container.clientWidth;\n const ch = this.container.clientHeight;\n const size = Math.round((Math.min(cw, ch) * 3) / 4);\n\n // Only update size — initial CSS centering (top: 50%, left: 50%,\n // transform: translate(-50%, -50%)) persists and handles re-centering.\n Object.assign(this.overlayEl.style, {\n width: `${size}px`,\n height: `${size}px`,\n });\n }\n}\n","import type { ScanRegion } from './types.js';\n\n/**\n * Calculate the default scan region: a centered square covering\n * 2/3 of the smaller video dimension.\n */\nexport function calculateDefaultScanRegion(video: HTMLVideoElement): ScanRegion {\n const videoWidth = video.videoWidth || video.width;\n const videoHeight = video.videoHeight || video.height;\n\n const smallerDimension = Math.min(videoWidth, videoHeight);\n const size = Math.round((smallerDimension * 2) / 3);\n\n return {\n x: Math.round((videoWidth - size) / 2),\n y: Math.round((videoHeight - size) / 2),\n width: size,\n height: size,\n };\n}\n","import { CameraManager } from './camera.js';\nimport { FrameExtractor } from './frame-extractor.js';\nimport { ScanOverlay } from './overlay.js';\nimport { calculateDefaultScanRegion } from './scan-region.js';\nimport type {\n ScannerOptions,\n ScanResult,\n ScanRegion,\n InversionMode,\n WorkerRequest,\n WorkerResponse,\n} from './types.js';\nimport type { ReaderOptions } from 'zxing-wasm/reader';\n\ntype OnDecodeCallback = (result: ScanResult) => void;\n\n/**\n * Custom worker URL override. When set, this URL is used instead of the\n * default bundler-resolved worker. Useful for CJS consumers or non-standard\n * bundler setups.\n */\nlet customWorkerUrl: string | URL | null = null;\n\nexport function setWorkerUrl(url: string | URL): void {\n customWorkerUrl = url;\n}\n\nfunction resolveWorkerUrl(): string | URL {\n if (customWorkerUrl) {\n return customWorkerUrl;\n }\n // Standard pattern: modern bundlers (Vite, webpack 5, Parcel, esbuild)\n // resolve `new URL('./file', import.meta.url)` at build time,\n // copying worker.js to the output directory and returning the correct URL.\n // Falls back gracefully for CJS builds where import.meta is unavailable.\n try {\n return new URL('./worker.js', import.meta.url);\n } catch {\n throw new Error(\n '@agicash/qr-scanner: Could not resolve worker URL. ' +\n 'Call QrScanner.setWorkerUrl() with the path to the worker script before creating a scanner. ' +\n 'Example: QrScanner.setWorkerUrl(\"/path/to/@agicash/qr-scanner/dist/worker.js\")',\n );\n }\n}\n\nexport class Scanner {\n private video: HTMLVideoElement;\n private onDecode: OnDecodeCallback;\n private options: ScannerOptions;\n private camera: CameraManager;\n private frameExtractor: FrameExtractor | null = null;\n private worker: Worker | null = null;\n private overlay: ScanOverlay | null = null;\n private active = false;\n private paused = false;\n private destroyed = false;\n\n constructor(\n video: HTMLVideoElement,\n onDecode: OnDecodeCallback,\n options: ScannerOptions = {},\n ) {\n this.video = video;\n this.onDecode = onDecode;\n this.options = options;\n\n this.camera = new CameraManager({\n preferredCamera: options.preferredCamera,\n cameraResolution: options.cameraResolution,\n });\n }\n\n async start(): Promise<void> {\n if (this.destroyed) {\n throw new Error('Scanner has been destroyed');\n }\n\n if (this.active && !this.paused) {\n return; // Already running\n }\n\n const t0 = performance.now();\n\n // Show overlay immediately (CSS-centered placeholder) so the UI looks\n // ready while the camera is still loading.\n if (\n !this.overlay &&\n (this.options.highlightScanRegion ||\n this.options.highlightCodeOutline ||\n this.options.overlay)\n ) {\n try {\n this.overlay = new ScanOverlay(this.video, {\n highlightScanRegion: this.options.highlightScanRegion ?? false,\n highlightCodeOutline: this.options.highlightCodeOutline ?? false,\n customOverlay: this.options.overlay,\n });\n this.overlay.setup();\n } catch {\n // Overlay setup failed (e.g., no parent element) — continue without overlay\n }\n }\n\n // Start camera\n await this.camera.start(this.video);\n console.debug(\n `[QrScanner] start: camera ready ${(performance.now() - t0).toFixed(0)}ms`,\n );\n\n // Now that video dimensions are known, position overlay exactly\n if (this.overlay) {\n this.overlay.updateScanRegion(this.getCurrentScanRegion());\n }\n\n // Create worker if needed\n if (!this.worker) {\n const tw = performance.now();\n this.worker = this.createWorker();\n console.debug(\n `[QrScanner] start: worker created ${(performance.now() - tw).toFixed(0)}ms`,\n );\n }\n\n // Create frame extractor if needed\n if (!this.frameExtractor) {\n this.frameExtractor = new FrameExtractor(this.video, {\n maxScansPerSecond: this.options.maxScansPerSecond ?? 15,\n getScanRegion: () => this.getCurrentScanRegion(),\n });\n }\n\n // Start frame extraction loop\n this.frameExtractor.start((imageData) => {\n this.sendToWorker(imageData);\n });\n\n this.active = true;\n this.paused = false;\n\n console.debug(\n `[QrScanner] start: total ${(performance.now() - t0).toFixed(0)}ms`,\n );\n }\n\n stop(): void {\n this.frameExtractor?.stop();\n this.camera.stop();\n this.video.srcObject = null;\n this.active = false;\n this.paused = false;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.stop();\n this.frameExtractor?.destroy();\n this.frameExtractor = null;\n this.overlay?.destroy();\n this.overlay = null;\n this.worker?.terminate();\n this.worker = null;\n this.destroyed = true;\n }\n\n async pause(stopStreamImmediately = true): Promise<boolean> {\n if (!this.active) return false;\n\n this.frameExtractor?.stop();\n this.paused = true;\n\n if (stopStreamImmediately) {\n this.camera.stop();\n this.video.srcObject = null;\n }\n\n return true;\n }\n\n async setCamera(facingModeOrDeviceId: string): Promise<void> {\n const wasActive = this.active && !this.paused;\n if (wasActive) {\n this.frameExtractor?.stop();\n }\n\n await this.camera.setCamera(facingModeOrDeviceId, this.video);\n\n if (wasActive) {\n this.frameExtractor?.start((imageData) => {\n this.sendToWorker(imageData);\n });\n }\n }\n\n async hasFlash(): Promise<boolean> {\n return this.camera.hasFlash();\n }\n\n isFlashOn(): boolean {\n return this.camera.isFlashOn();\n }\n\n async toggleFlash(): Promise<void> {\n return this.camera.toggleFlash();\n }\n\n async turnFlashOn(): Promise<void> {\n return this.camera.turnFlashOn();\n }\n\n async turnFlashOff(): Promise<void> {\n return this.camera.turnFlashOff();\n }\n\n setInversionMode(mode: InversionMode): void {\n if (!this.worker) return;\n\n const options: Partial<ReaderOptions> = {};\n switch (mode) {\n case 'original':\n options.tryInvert = false;\n break;\n case 'invert':\n options.tryInvert = true;\n break;\n case 'both':\n options.tryInvert = true;\n break;\n }\n\n const msg: WorkerRequest = { type: 'configure', options };\n this.worker.postMessage(msg);\n }\n\n isActive(): boolean {\n return this.active;\n }\n\n isPaused(): boolean {\n return this.paused;\n }\n\n isDestroyed(): boolean {\n return this.destroyed;\n }\n\n private getCurrentScanRegion(): ScanRegion {\n if (this.options.calculateScanRegion) {\n return this.options.calculateScanRegion(this.video);\n }\n return calculateDefaultScanRegion(this.video);\n }\n\n private createWorker(): Worker {\n const workerUrl = resolveWorkerUrl();\n const worker = new Worker(workerUrl, { type: 'module' });\n\n // Configure with custom decoder options\n if (this.options.decoderOptions) {\n const msg: WorkerRequest = {\n type: 'configure',\n options: this.options.decoderOptions,\n };\n worker.postMessage(msg);\n }\n\n worker.onmessage = (e: MessageEvent<WorkerResponse>) => {\n this.handleWorkerMessage(e.data);\n };\n\n worker.onerror = (err) => {\n console.error('QR Scanner worker error:', err);\n this.frameExtractor?.markWorkerIdle();\n };\n\n return worker;\n }\n\n private handleWorkerMessage(response: WorkerResponse): void {\n this.frameExtractor?.markWorkerIdle();\n\n if (response.type === 'ready') {\n return;\n }\n\n if (response.type === 'error') {\n this.options.onDecodeError?.(response.message);\n return;\n }\n\n if (response.type === 'result') {\n if (response.results.length > 0) {\n const result = response.results[0];\n this.onDecode(result);\n\n // Update overlay\n if (this.overlay) {\n const region = this.getCurrentScanRegion();\n this.overlay.updateScanRegion(region);\n this.overlay.updateCodeOutline(result.cornerPoints, region);\n }\n } else {\n this.options.onDecodeError?.('No QR code found');\n\n // Hide code outline when no QR found\n if (this.overlay) {\n this.overlay.updateCodeOutline(null);\n }\n }\n }\n }\n\n private sendToWorker(imageData: ImageData): void {\n if (!this.worker) return;\n\n const msg: WorkerRequest = { type: 'decode', imageData };\n this.worker.postMessage(msg, [imageData.data.buffer]);\n }\n}\n","import { readBarcodes, type ReaderOptions } from 'zxing-wasm/reader';\nimport type { ScanResult, ScanRegion, Point } from './types.js';\nimport { loadImageData } from './utils.js';\n\nconst defaultReaderOptions: ReaderOptions = {\n formats: ['QRCode'],\n tryHarder: true,\n tryInvert: true,\n tryRotate: true,\n tryDenoise: false,\n tryDownscale: true,\n maxNumberOfSymbols: 1,\n};\n\nfunction mapPosition(position: {\n topLeft: Point;\n topRight: Point;\n bottomLeft: Point;\n bottomRight: Point;\n}): Point[] {\n return [\n position.topLeft,\n position.topRight,\n position.bottomRight,\n position.bottomLeft,\n ];\n}\n\n/** Input types that zxing-wasm can handle directly (no canvas needed). */\ntype DirectInput = Blob | ArrayBuffer | Uint8Array | ImageData;\n\n/** Input types that need canvas-based pixel extraction. */\ntype CanvasInput = HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap;\n\nfunction isDirectInput(source: unknown): source is DirectInput {\n return (\n source instanceof Blob ||\n source instanceof ArrayBuffer ||\n source instanceof Uint8Array ||\n (typeof ImageData !== 'undefined' && source instanceof ImageData)\n );\n}\n\n/**\n * Scan a single image for QR codes. Does not require a camera or video stream.\n */\nexport async function scanImage(\n source:\n | CanvasInput\n | DirectInput\n | File\n | URL\n | string,\n options?: {\n scanRegion?: ScanRegion | null;\n canvas?: HTMLCanvasElement | null;\n decoderOptions?: Partial<ReaderOptions>;\n },\n): Promise<ScanResult> {\n const readerOptions: ReaderOptions = {\n ...defaultReaderOptions,\n ...options?.decoderOptions,\n formats: ['QRCode'],\n };\n\n let input: DirectInput;\n if (isDirectInput(source)) {\n input = source;\n } else if (typeof source === 'string' || source instanceof URL) {\n // URL string - fetch and pass as ArrayBuffer\n const url = source instanceof URL ? source.href : source;\n const response = await fetch(url);\n input = await response.arrayBuffer();\n } else {\n // Canvas-based sources - extract ImageData\n input = await loadImageData(source, options?.scanRegion, options?.canvas);\n }\n\n const results = await readBarcodes(input, readerOptions);\n const valid = results.filter((r) => r.isValid);\n\n if (valid.length === 0) {\n throw new Error('No QR code found in the image');\n }\n\n const first = valid[0];\n return {\n data: first.text,\n cornerPoints: mapPosition(first.position),\n };\n}\n","import type { ScanRegion } from './types.js';\n\n/**\n * Load an image source into an ImageData object, optionally cropping to a scan region.\n */\nexport async function loadImageData(\n source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | File | Blob | URL | string,\n scanRegion?: ScanRegion | null,\n canvas?: HTMLCanvasElement | null,\n): Promise<ImageData> {\n const img = await resolveImageSource(source);\n\n const sx = scanRegion?.x ?? 0;\n const sy = scanRegion?.y ?? 0;\n const sw = scanRegion?.width ?? (img.width - sx);\n const sh = scanRegion?.height ?? (img.height - sy);\n\n let drawCanvas: HTMLCanvasElement | OffscreenCanvas;\n let ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n\n if (canvas) {\n drawCanvas = canvas;\n canvas.width = sw;\n canvas.height = sh;\n ctx = canvas.getContext('2d')!;\n } else if (typeof OffscreenCanvas !== 'undefined') {\n drawCanvas = new OffscreenCanvas(sw, sh);\n ctx = drawCanvas.getContext('2d')! as OffscreenCanvasRenderingContext2D;\n } else {\n drawCanvas = document.createElement('canvas');\n drawCanvas.width = sw;\n drawCanvas.height = sh;\n ctx = drawCanvas.getContext('2d')!;\n }\n\n ctx.drawImage(img as CanvasImageSource, sx, sy, sw, sh, 0, 0, sw, sh);\n return ctx.getImageData(0, 0, sw, sh);\n}\n\nasync function resolveImageSource(\n source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | File | Blob | URL | string,\n): Promise<HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap> {\n if (source instanceof HTMLImageElement || source instanceof HTMLCanvasElement || source instanceof ImageBitmap) {\n return source;\n }\n\n if (typeof OffscreenCanvas !== 'undefined' && source instanceof OffscreenCanvas) {\n return source;\n }\n\n if (source instanceof File || source instanceof Blob) {\n return createImageBitmapFromBlob(source);\n }\n\n // URL or string\n const url = source instanceof URL ? source.href : source as string;\n const response = await fetch(url);\n const blob = await response.blob();\n return createImageBitmapFromBlob(blob);\n}\n\nasync function createImageBitmapFromBlob(blob: Blob): Promise<ImageBitmap> {\n if (typeof createImageBitmap !== 'undefined') {\n return createImageBitmap(blob);\n }\n // Fallback for environments without createImageBitmap\n const url = URL.createObjectURL(blob);\n try {\n const img = new Image();\n img.src = url;\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error('Failed to load image'));\n });\n return img as unknown as ImageBitmap;\n } finally {\n URL.revokeObjectURL(url);\n }\n}\n","import { Scanner, setWorkerUrl } from './scanner.js';\nimport {\n CameraManager,\n CameraNotFoundError,\n CameraPermissionError,\n} from './camera.js';\nimport { scanImage } from './scan-image.js';\nimport { setZXingModuleOverrides } from 'zxing-wasm/reader';\nimport type {\n ScanResult,\n ScanRegion,\n ScannerOptions,\n Camera,\n Point,\n FacingMode,\n DeviceId,\n InversionMode,\n} from './types.js';\nimport type { ReaderOptions } from 'zxing-wasm/reader';\n\nexport { CameraNotFoundError, CameraPermissionError };\n\nexport type {\n ScanResult,\n ScanRegion,\n ScannerOptions,\n Camera,\n Point,\n FacingMode,\n DeviceId,\n InversionMode,\n};\n\n/**\n * High-performance QR code scanner for the web, powered by ZXing-C++ WebAssembly.\n */\nclass QrScanner {\n private scanner: Scanner;\n\n constructor(\n videoElement: HTMLVideoElement,\n onDecode: (result: ScanResult) => void,\n options: ScannerOptions = {},\n ) {\n this.scanner = new Scanner(videoElement, onDecode, options);\n }\n\n /** Start camera and begin scanning. Resolves when camera is ready. */\n async start(): Promise<void> {\n return this.scanner.start();\n }\n\n /** Stop scanning and release the camera stream. */\n stop(): void {\n this.scanner.stop();\n }\n\n /** Stop scanning, release camera, terminate worker, clean up DOM. */\n destroy(): void {\n this.scanner.destroy();\n }\n\n /** Pause scanning. If stopStreamImmediately is false, camera stays on. */\n async pause(stopStreamImmediately?: boolean): Promise<boolean> {\n return this.scanner.pause(stopStreamImmediately);\n }\n\n /** Switch to a different camera by facing mode or device ID. */\n async setCamera(facingModeOrDeviceId: FacingMode | DeviceId): Promise<void> {\n return this.scanner.setCamera(facingModeOrDeviceId);\n }\n\n /** Check if the current camera supports flash/torch. */\n async hasFlash(): Promise<boolean> {\n return this.scanner.hasFlash();\n }\n\n /** Whether flash is currently on. */\n isFlashOn(): boolean {\n return this.scanner.isFlashOn();\n }\n\n /** Toggle flash on/off. */\n async toggleFlash(): Promise<void> {\n return this.scanner.toggleFlash();\n }\n\n /** Turn flash on. */\n async turnFlashOn(): Promise<void> {\n return this.scanner.turnFlashOn();\n }\n\n /** Turn flash off. */\n async turnFlashOff(): Promise<void> {\n return this.scanner.turnFlashOff();\n }\n\n /** Set the inversion mode for detecting inverted QR codes. */\n setInversionMode(mode: InversionMode): void {\n this.scanner.setInversionMode(mode);\n }\n\n // --- Static methods ---\n\n /** Check if the device has at least one camera. */\n static hasCamera(): Promise<boolean> {\n return CameraManager.hasCamera();\n }\n\n /** List available cameras. Pass true to request labels (triggers permission prompt). */\n static listCameras(requestLabels?: boolean): Promise<Camera[]> {\n return CameraManager.listCameras(requestLabels);\n }\n\n /**\n * Pre-load the WASM binary so it's ready when the scanner starts.\n * Call this early (e.g., on app init) to avoid delay on first scan.\n */\n static async preload(): Promise<void> {\n // Trigger WASM loading by doing a minimal scan\n const pixel = new Uint8ClampedArray([255, 255, 255, 255]);\n const img = new ImageData(pixel, 1, 1);\n try {\n await scanImage(img);\n } catch {\n // Expected — no QR code in a 1x1 image. The point was to load WASM.\n }\n }\n\n /**\n * Configure WASM loading. Call before creating any scanner instance.\n * @example\n * QrScanner.configureWasm({ locateFile: (filename) => `/wasm/${filename}` });\n */\n static configureWasm(overrides: Partial<EmscriptenModule>): void {\n setZXingModuleOverrides(overrides);\n }\n\n /**\n * Set a custom URL for the worker script. Call before creating any scanner.\n * Needed for CJS consumers or non-standard bundler setups.\n * By default, the worker URL is resolved via `new URL('./worker.js', import.meta.url)`,\n * which works with Vite, webpack 5, Parcel, and other modern bundlers.\n * @example\n * QrScanner.setWorkerUrl('/assets/qr-scanner-worker.js');\n */\n static setWorkerUrl(url: string | URL): void {\n setWorkerUrl(url);\n }\n\n /** Scan a single image (not a video stream). */\n static scanImage(\n source:\n | HTMLImageElement\n | HTMLCanvasElement\n | OffscreenCanvas\n | ImageBitmap\n | ImageData\n | Blob\n | ArrayBuffer\n | Uint8Array\n | File\n | URL\n | string,\n options?: {\n scanRegion?: ScanRegion | null;\n canvas?: HTMLCanvasElement | null;\n decoderOptions?: Partial<ReaderOptions>;\n },\n ): Promise<ScanResult> {\n return scanImage(source, options);\n }\n}\n\nexport default QrScanner;\n"],"mappings":"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","names":["t"]}
|
|
1
|
+
{"version":3,"sources":["../src/debug.ts","../src/camera.ts","../src/frame-extractor.ts","../src/overlay.ts","../src/scan-region.ts","../src/scanner.ts","../src/scan-image.ts","../src/utils.ts","../src/index.ts"],"sourcesContent":["let enabled = false;\n\nexport function setDebug(on: boolean): void {\n enabled = on;\n}\n\nexport function debug(...args: unknown[]): void {\n if (enabled) console.debug(...args);\n}\n","import { debug } from './debug.js';\nimport type { FacingMode, DeviceId, Camera } from './types.js';\n\nexport class CameraPermissionError extends Error {\n constructor(\n message = 'Camera access denied. Please grant camera permission and try again.',\n ) {\n super(message);\n this.name = 'CameraPermissionError';\n }\n}\n\nexport class CameraNotFoundError extends Error {\n constructor(\n message = 'No camera found. Please connect a camera and try again.',\n ) {\n super(message);\n this.name = 'CameraNotFoundError';\n }\n}\n\nconst CACHE_KEY_PREFIX = '@agicash/qr-scanner:camera:';\n\nfunction getCachedDeviceId(facingMode: string): string | null {\n try {\n return localStorage.getItem(`${CACHE_KEY_PREFIX}${facingMode}`);\n } catch {\n return null;\n }\n}\n\nfunction setCachedDeviceId(facingMode: string, deviceId: string): void {\n try {\n localStorage.setItem(`${CACHE_KEY_PREFIX}${facingMode}`, deviceId);\n } catch {\n // localStorage unavailable or full — ignore\n }\n}\n\nexport interface CameraConfig {\n preferredCamera?: FacingMode | DeviceId;\n cameraResolution?: {\n width?: MediaTrackConstraintSet['width'];\n height?: MediaTrackConstraintSet['height'];\n };\n}\n\nexport class CameraManager {\n private stream: MediaStream | null = null;\n private facingMode: FacingMode | DeviceId;\n private resolution: CameraConfig['cameraResolution'];\n\n constructor(config: CameraConfig = {}) {\n this.facingMode = config.preferredCamera ?? 'environment';\n this.resolution = config.cameraResolution;\n }\n\n async start(video: HTMLVideoElement): Promise<MediaStream> {\n if (this.stream) {\n return this.stream;\n }\n\n const t0 = performance.now();\n\n this.stream = await this.acquireStream();\n const t1 = performance.now();\n debug(`[QrScanner] acquireStream: ${(t1 - t0).toFixed(0)}ms`);\n\n // On some devices (e.g. Samsung S24 + Brave), facingMode: 'environment'\n // picks an ultrawide camera that lacks autofocus. Check and switch to a\n // better camera BEFORE showing on screen to avoid visible flicker.\n await this.ensureBestCamera();\n const t2 = performance.now();\n debug(`[QrScanner] ensureBestCamera: ${(t2 - t1).toFixed(0)}ms`);\n\n video.srcObject = this.stream;\n video.setAttribute('playsinline', 'true');\n await video.play();\n const t3 = performance.now();\n debug(`[QrScanner] video.play: ${(t3 - t2).toFixed(0)}ms`);\n debug(`[QrScanner] camera.start total: ${(t3 - t0).toFixed(0)}ms`);\n\n // Cache the final camera so subsequent starts skip ensureBestCamera\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n const finalDeviceId = this.getVideoTrack()?.getSettings().deviceId;\n if (finalDeviceId) {\n setCachedDeviceId(this.facingMode, finalDeviceId);\n }\n }\n\n return this.stream;\n }\n\n stop(): void {\n if (this.stream) {\n for (const track of this.stream.getTracks()) {\n track.stop();\n }\n this.stream = null;\n }\n }\n\n async setCamera(\n facingModeOrDeviceId: FacingMode | DeviceId,\n video: HTMLVideoElement,\n ): Promise<void> {\n this.stop();\n this.facingMode = facingModeOrDeviceId;\n await this.start(video);\n }\n\n getStream(): MediaStream | null {\n return this.stream;\n }\n\n async hasFlash(): Promise<boolean> {\n const track = this.getVideoTrack();\n if (!track) return false;\n\n try {\n const capabilities = track.getCapabilities() as MediaTrackCapabilities & {\n torch?: boolean;\n };\n return capabilities.torch === true;\n } catch {\n return false;\n }\n }\n\n isFlashOn(): boolean {\n const track = this.getVideoTrack();\n if (!track) return false;\n\n const settings = track.getSettings() as MediaTrackSettings & {\n torch?: boolean;\n };\n return settings.torch === true;\n }\n\n async toggleFlash(): Promise<void> {\n if (this.isFlashOn()) {\n await this.turnFlashOff();\n } else {\n await this.turnFlashOn();\n }\n }\n\n async turnFlashOn(): Promise<void> {\n await this.setTorch(true);\n }\n\n async turnFlashOff(): Promise<void> {\n await this.setTorch(false);\n }\n\n private async setTorch(on: boolean): Promise<void> {\n const track = this.getVideoTrack();\n if (!track) {\n throw new Error('No active camera stream');\n }\n\n try {\n await track.applyConstraints({\n advanced: [{ torch: on } as MediaTrackConstraintSet],\n });\n } catch {\n throw new Error('Flash/torch is not supported on this device');\n }\n }\n\n /**\n * If the current camera lacks continuous autofocus (e.g. an ultrawide sensor\n * picked by facingMode: 'environment'), find a better camera with the same\n * facing mode and replace this.stream. Called before assigning to the video\n * element so the user never sees the wrong camera.\n */\n private async ensureBestCamera(): Promise<void> {\n if (this.facingMode !== 'environment' && this.facingMode !== 'user') {\n debug('[QrScanner] ensureBestCamera: skipped (specific deviceId)');\n return;\n }\n\n const track = this.getVideoTrack();\n if (!track) return;\n\n try {\n const capabilities = track.getCapabilities() as MediaTrackCapabilities & {\n focusMode?: string[];\n };\n if (\n !capabilities.focusMode ||\n capabilities.focusMode.includes('continuous')\n ) {\n // focusMode not reported (e.g. Safari/iOS) or has autofocus — skip.\n // Only enter the candidate loop when the browser explicitly reports\n // focusMode without 'continuous' (e.g. S24 + Brave ultrawide).\n debug(\n `[QrScanner] ensureBestCamera: skipped (focusMode: ${JSON.stringify(capabilities.focusMode)})`,\n );\n return;\n }\n debug(\n `[QrScanner] ensureBestCamera: current camera lacks autofocus (focusMode: ${JSON.stringify(capabilities.focusMode)})`,\n );\n } catch {\n return;\n }\n\n // Current camera lacks continuous autofocus.\n // Enumerate devices while stream is active (ensures deviceIds are available).\n const currentDeviceId = track.getSettings().deviceId;\n\n let devices: MediaDeviceInfo[];\n try {\n devices = await navigator.mediaDevices.enumerateDevices();\n } catch {\n return;\n }\n if (!Array.isArray(devices)) return;\n\n const candidates = devices.filter(\n (d) => d.kind === 'videoinput' && d.deviceId !== currentDeviceId,\n );\n debug(\n `[QrScanner] ensureBestCamera: testing ${candidates.length} candidate camera(s)`,\n );\n if (candidates.length === 0) return;\n\n // Stop current stream — mobile devices only allow one active camera\n this.stop();\n\n for (const candidate of candidates) {\n const t = performance.now();\n let candidateStream: MediaStream;\n try {\n candidateStream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: { exact: candidate.deviceId },\n width: this.resolution?.width ?? { ideal: 1920 },\n height: this.resolution?.height ?? { ideal: 1080 },\n },\n audio: false,\n });\n debug(\n `[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia ${(performance.now() - t).toFixed(0)}ms`,\n );\n } catch {\n debug(\n `[QrScanner] ensureBestCamera: candidate ${candidate.label || candidate.deviceId.slice(0, 8)}: getUserMedia failed ${(performance.now() - t).toFixed(0)}ms`,\n );\n continue;\n }\n\n const candidateTrack = candidateStream.getVideoTracks()[0];\n if (!candidateTrack) {\n for (const t of candidateStream.getTracks()) t.stop();\n continue;\n }\n\n // Must match the desired facing mode\n const candidateSettings =\n candidateTrack.getSettings() as MediaTrackSettings & {\n facingMode?: string;\n };\n if (\n candidateSettings.facingMode &&\n candidateSettings.facingMode !== this.facingMode\n ) {\n for (const t of candidateStream.getTracks()) t.stop();\n continue;\n }\n\n // Check if this camera supports continuous autofocus\n try {\n const candidateCaps =\n candidateTrack.getCapabilities() as MediaTrackCapabilities & {\n focusMode?: string[];\n };\n if (candidateCaps.focusMode?.includes('continuous')) {\n this.stream = candidateStream;\n return;\n }\n } catch {\n // Can't check capabilities, skip\n }\n\n for (const t of candidateStream.getTracks()) t.stop();\n }\n\n // No better camera found — re-open the original\n try {\n this.stream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: currentDeviceId ? { exact: currentDeviceId } : undefined,\n width: this.resolution?.width ?? { ideal: 1920 },\n height: this.resolution?.height ?? { ideal: 1080 },\n },\n audio: false,\n });\n } catch {\n try {\n this.stream = await navigator.mediaDevices.getUserMedia(\n this.buildConstraints(),\n );\n } catch {\n // Could not recover camera\n }\n }\n }\n\n private getVideoTrack(): MediaStreamTrack | null {\n if (!this.stream) return null;\n const tracks = this.stream.getVideoTracks();\n return tracks[0] ?? null;\n }\n\n /**\n * Try getUserMedia with progressively simpler constraints.\n *\n * Some browsers (e.g. Brave on Samsung Galaxy S24) throw NotReadableError\n * when facingMode and resolution constraints are combined. Falling back to\n * fewer constraints lets us still open the camera on those browsers.\n */\n private async acquireStream(): Promise<MediaStream> {\n const labels: string[] = [];\n const attempts: MediaStreamConstraints[] = [];\n\n // If we've previously found a good camera for this facingMode, try it first\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n const cachedId = getCachedDeviceId(this.facingMode);\n if (cachedId) {\n labels.push('cached deviceId');\n const video: MediaTrackConstraints = {\n deviceId: { exact: cachedId },\n };\n if (this.resolution?.width) video.width = this.resolution.width;\n else video.width = { ideal: 1920 };\n if (this.resolution?.height) video.height = this.resolution.height;\n else video.height = { ideal: 1080 };\n attempts.push({ video, audio: false });\n }\n }\n\n // Standard fallback chain\n labels.push('full constraints', 'no resolution', 'bare minimum');\n attempts.push(\n // facingMode/deviceId + resolution\n this.buildConstraints(),\n // facingMode/deviceId only, no resolution\n this.buildConstraints(false),\n // Bare minimum\n { video: true, audio: false },\n );\n\n let lastError: unknown;\n for (let i = 0; i < attempts.length; i++) {\n const t = performance.now();\n try {\n const stream = await navigator.mediaDevices.getUserMedia(attempts[i]);\n debug(\n `[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms ✓`,\n );\n return stream;\n } catch (err) {\n debug(\n `[QrScanner] getUserMedia(${labels[i]}): ${(performance.now() - t).toFixed(0)}ms ✗ ${err instanceof DOMException ? err.name : err}`,\n );\n if (err instanceof DOMException) {\n if (err.name === 'NotAllowedError') {\n throw new CameraPermissionError();\n }\n if (err.name === 'NotFoundError') {\n throw new CameraNotFoundError();\n }\n // NotReadableError or OverconstrainedError — try next fallback\n lastError = err;\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n private buildConstraints(includeResolution = true): MediaStreamConstraints {\n const video: MediaTrackConstraints = {};\n\n if (includeResolution) {\n video.width = this.resolution?.width ?? { ideal: 1920 };\n video.height = this.resolution?.height ?? { ideal: 1080 };\n }\n\n if (this.facingMode === 'environment' || this.facingMode === 'user') {\n video.facingMode = this.facingMode;\n } else {\n video.deviceId = { exact: this.facingMode };\n }\n\n return { video, audio: false };\n }\n\n static async hasCamera(): Promise<boolean> {\n try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n return devices.some((d) => d.kind === 'videoinput');\n } catch {\n return false;\n }\n }\n\n static async listCameras(requestLabels = false): Promise<Camera[]> {\n if (requestLabels) {\n // Requesting labels requires a temporary stream to trigger the permission prompt\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: true,\n });\n for (const track of stream.getTracks()) {\n track.stop();\n }\n } catch {\n // Permission denied — fall through with empty labels\n }\n }\n\n const devices = await navigator.mediaDevices.enumerateDevices();\n return devices\n .filter((d) => d.kind === 'videoinput')\n .map((d) => ({\n id: d.deviceId,\n label: d.label || `Camera ${d.deviceId.slice(0, 8)}`,\n }));\n }\n}\n","import type { ScanRegion } from './types.js';\n\nexport interface FrameExtractorConfig {\n maxScansPerSecond: number;\n getScanRegion: () => ScanRegion;\n}\n\nexport class FrameExtractor {\n private video: HTMLVideoElement;\n private canvas: HTMLCanvasElement | OffscreenCanvas;\n private ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n private rafId: number | null = null;\n private running = false;\n private workerBusy = false;\n private lastScanTime = -Infinity;\n private minInterval: number;\n private getScanRegion: () => ScanRegion;\n private onFrame: ((imageData: ImageData) => void) | null = null;\n\n constructor(video: HTMLVideoElement, config: FrameExtractorConfig) {\n this.video = video;\n this.minInterval = 1000 / config.maxScansPerSecond;\n this.getScanRegion = config.getScanRegion;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n this.canvas = new OffscreenCanvas(1, 1);\n this.ctx = this.canvas.getContext('2d')! as OffscreenCanvasRenderingContext2D;\n } else {\n this.canvas = document.createElement('canvas');\n this.canvas.style.display = 'none';\n this.ctx = this.canvas.getContext('2d')!;\n }\n }\n\n start(onFrame: (imageData: ImageData) => void): void {\n if (this.running) return;\n this.running = true;\n this.onFrame = onFrame;\n this.rafId = requestAnimationFrame(this.tick);\n }\n\n stop(): void {\n this.running = false;\n this.onFrame = null;\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n }\n\n destroy(): void {\n this.stop();\n if (this.canvas instanceof HTMLCanvasElement && this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n }\n\n markWorkerIdle(): void {\n this.workerBusy = false;\n }\n\n markWorkerBusy(): void {\n this.workerBusy = true;\n }\n\n private tick = (): void => {\n if (!this.running) return;\n\n this.rafId = requestAnimationFrame(this.tick);\n\n // Skip if worker is still processing previous frame\n if (this.workerBusy) return;\n\n // Rate limiting\n const now = performance.now();\n if (now - this.lastScanTime < this.minInterval) return;\n\n // Skip if video isn't ready\n if (this.video.readyState < 2) return;\n\n this.lastScanTime = now;\n\n const region = this.getScanRegion();\n const sx = region.x ?? 0;\n const sy = region.y ?? 0;\n const sw = region.width ?? this.video.videoWidth;\n const sh = region.height ?? this.video.videoHeight;\n\n if (sw <= 0 || sh <= 0) return;\n\n this.canvas.width = sw;\n this.canvas.height = sh;\n\n this.ctx.drawImage(this.video, sx, sy, sw, sh, 0, 0, sw, sh);\n const imageData = this.ctx.getImageData(0, 0, sw, sh);\n\n this.workerBusy = true;\n this.onFrame?.(imageData);\n };\n}\n","import type { ScanRegion, Point } from './types.js';\n\n/**\n * Compute the actual rendered position and size of the video content\n * within the element, accounting for object-fit: cover.\n *\n * With object-fit: cover the video is scaled up to fill the element and\n * cropped. The rendered content is larger than the element, centered,\n * with negative offsets for the cropped portions.\n *\n * When object-fit is the default (fill), the rendered size equals the\n * element size and offsets are zero — so this is backwards-compatible.\n */\nfunction getRenderedVideoRect(video: HTMLVideoElement): {\n offsetX: number;\n offsetY: number;\n width: number;\n height: number;\n} {\n const elementWidth = video.clientWidth;\n const elementHeight = video.clientHeight;\n const videoWidth = video.videoWidth || 1;\n const videoHeight = video.videoHeight || 1;\n\n const objectFit = getComputedStyle(video).objectFit;\n\n if (objectFit === 'cover') {\n const scale = Math.max(\n elementWidth / videoWidth,\n elementHeight / videoHeight,\n );\n const renderedWidth = videoWidth * scale;\n const renderedHeight = videoHeight * scale;\n return {\n offsetX: (elementWidth - renderedWidth) / 2,\n offsetY: (elementHeight - renderedHeight) / 2,\n width: renderedWidth,\n height: renderedHeight,\n };\n }\n\n if (objectFit === 'contain') {\n const scale = Math.min(\n elementWidth / videoWidth,\n elementHeight / videoHeight,\n );\n const renderedWidth = videoWidth * scale;\n const renderedHeight = videoHeight * scale;\n return {\n offsetX: (elementWidth - renderedWidth) / 2,\n offsetY: (elementHeight - renderedHeight) / 2,\n width: renderedWidth,\n height: renderedHeight,\n };\n }\n\n // Default (fill / none / scale-down with no scaling needed): element dimensions\n return { offsetX: 0, offsetY: 0, width: elementWidth, height: elementHeight };\n}\n\nexport interface OverlayConfig {\n highlightScanRegion: boolean;\n highlightCodeOutline: boolean;\n customOverlay?: HTMLDivElement;\n}\n\nexport class ScanOverlay {\n private container: HTMLElement;\n private overlayEl: HTMLDivElement | null = null;\n private codeOutlineEl: SVGElement | null = null;\n private config: OverlayConfig;\n private video: HTMLVideoElement;\n\n constructor(video: HTMLVideoElement, config: OverlayConfig) {\n this.video = video;\n this.config = config;\n\n const parent = video.parentElement;\n if (!parent) {\n throw new Error(\n 'QrScanner: video element must have a parent element. ' +\n 'The parent should have position: relative.',\n );\n }\n this.container = parent;\n }\n\n setup(): void {\n if (this.config.customOverlay) {\n this.overlayEl = this.config.customOverlay;\n this.positionOverlay();\n return;\n }\n\n if (this.config.highlightScanRegion) {\n this.createScanRegionOverlay();\n }\n\n if (this.config.highlightCodeOutline) {\n this.createCodeOutline();\n }\n }\n\n updateScanRegion(region: ScanRegion): void {\n if (!this.overlayEl || this.config.customOverlay) return;\n this.positionOverlayToRegion(region);\n }\n\n updateCodeOutline(\n cornerPoints: Point[] | null,\n scanRegion?: ScanRegion,\n ): void {\n if (!this.codeOutlineEl) return;\n\n if (!cornerPoints || cornerPoints.length < 4) {\n this.codeOutlineEl.style.display = 'none';\n return;\n }\n\n this.codeOutlineEl.style.display = 'block';\n\n const polygon = this.codeOutlineEl.querySelector('polygon');\n if (!polygon) return;\n\n // Corner points are relative to the cropped scan region.\n // Add the scan region offset to get full video coordinates,\n // then scale to display coordinates (accounting for object-fit).\n const regionX = scanRegion?.x ?? 0;\n const regionY = scanRegion?.y ?? 0;\n const rendered = getRenderedVideoRect(this.video);\n const scaleX = rendered.width / this.video.videoWidth;\n const scaleY = rendered.height / this.video.videoHeight;\n\n const points = cornerPoints\n .map(\n (p) =>\n `${(p.x + regionX) * scaleX + rendered.offsetX},${(p.y + regionY) * scaleY + rendered.offsetY}`,\n )\n .join(' ');\n\n polygon.setAttribute('points', points);\n }\n\n destroy(): void {\n if (this.overlayEl && !this.config.customOverlay) {\n this.overlayEl.remove();\n }\n if (this.codeOutlineEl) {\n this.codeOutlineEl.remove();\n }\n this.overlayEl = null;\n this.codeOutlineEl = null;\n }\n\n private createScanRegionOverlay(): void {\n this.overlayEl = document.createElement('div');\n this.overlayEl.className = 'qr-scanner-region';\n\n // Overlay size: 3/4 of the smaller container dimension, centered.\n const cw = this.container.clientWidth;\n const ch = this.container.clientHeight;\n const size = Math.round((Math.min(cw, ch) * 3) / 4);\n\n Object.assign(this.overlayEl.style, {\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: `${size}px`,\n height: `${size}px`,\n border: '2px solid rgba(255, 255, 255, 0.5)',\n borderRadius: '8px',\n boxShadow: '0 0 0 9999px rgba(0, 0, 0, 0.5)',\n pointerEvents: 'none',\n zIndex: '10',\n });\n\n // Corner markers\n const corners = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];\n for (const corner of corners) {\n const marker = document.createElement('div');\n marker.className = `qr-scanner-corner qr-scanner-corner-${corner}`;\n\n const [vertical, horizontal] = corner.split('-');\n\n Object.assign(marker.style, {\n position: 'absolute',\n width: '24px',\n height: '24px',\n [vertical]: '-2px',\n [horizontal]: '-2px',\n [`border-${vertical}`]: '3px solid white',\n [`border-${horizontal}`]: '3px solid white',\n [`border-${vertical}-${horizontal}-radius`]: '8px',\n });\n\n this.overlayEl.appendChild(marker);\n }\n\n this.container.appendChild(this.overlayEl);\n }\n\n private createCodeOutline(): void {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('class', 'qr-scanner-code-outline');\n\n Object.assign(svg.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '11',\n display: 'none',\n });\n\n const polygon = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'polygon',\n );\n polygon.setAttribute('fill', 'none');\n polygon.setAttribute('stroke', '#00ff00');\n polygon.setAttribute('stroke-width', '3');\n polygon.setAttribute('stroke-linejoin', 'round');\n\n // Animated stroke\n const animate = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'animate',\n );\n animate.setAttribute('attributeName', 'stroke-opacity');\n animate.setAttribute('values', '1;0.5;1');\n animate.setAttribute('dur', '1.5s');\n animate.setAttribute('repeatCount', 'indefinite');\n polygon.appendChild(animate);\n\n svg.appendChild(polygon);\n this.container.appendChild(svg);\n this.codeOutlineEl = svg;\n }\n\n private positionOverlay(): void {\n if (!this.overlayEl) return;\n\n Object.assign(this.overlayEl.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '10',\n });\n }\n\n private positionOverlayToRegion(_region: ScanRegion): void {\n if (!this.overlayEl) return;\n\n // Keep the overlay at a container-relative centered size rather than\n // mapping scan region coordinates to display coordinates. With\n // object-fit: cover on a portrait phone with a landscape camera, the\n // mapped region extends beyond the container — fine once the camera is\n // visible but causes a jarring jump from the initial placeholder.\n // The overlay is a visual guide; the actual scan area (in the frame\n // extractor) is unaffected and may be larger than what's shown.\n const cw = this.container.clientWidth;\n const ch = this.container.clientHeight;\n const size = Math.round((Math.min(cw, ch) * 3) / 4);\n\n // Only update size — initial CSS centering (top: 50%, left: 50%,\n // transform: translate(-50%, -50%)) persists and handles re-centering.\n Object.assign(this.overlayEl.style, {\n width: `${size}px`,\n height: `${size}px`,\n });\n }\n}\n","import type { ScanRegion } from './types.js';\n\n/**\n * Calculate the default scan region: a centered square covering\n * 2/3 of the smaller video dimension.\n */\nexport function calculateDefaultScanRegion(video: HTMLVideoElement): ScanRegion {\n const videoWidth = video.videoWidth || video.width;\n const videoHeight = video.videoHeight || video.height;\n\n const smallerDimension = Math.min(videoWidth, videoHeight);\n const size = Math.round((smallerDimension * 2) / 3);\n\n return {\n x: Math.round((videoWidth - size) / 2),\n y: Math.round((videoHeight - size) / 2),\n width: size,\n height: size,\n };\n}\n","import { CameraManager } from './camera.js';\nimport { debug } from './debug.js';\nimport { FrameExtractor } from './frame-extractor.js';\nimport { ScanOverlay } from './overlay.js';\nimport { calculateDefaultScanRegion } from './scan-region.js';\nimport type {\n ScannerOptions,\n ScanResult,\n ScanRegion,\n InversionMode,\n WorkerRequest,\n WorkerResponse,\n} from './types.js';\nimport type { ReaderOptions } from 'zxing-wasm/reader';\n\ntype OnDecodeCallback = (result: ScanResult) => void;\n\n/**\n * Custom worker URL override. When set, this URL is used instead of the\n * default bundler-resolved worker. Useful for CJS consumers or non-standard\n * bundler setups.\n */\nlet customWorkerUrl: string | URL | null = null;\n\nexport function setWorkerUrl(url: string | URL): void {\n customWorkerUrl = url;\n}\n\nfunction resolveWorkerUrl(): string | URL {\n if (customWorkerUrl) {\n return customWorkerUrl;\n }\n // Standard pattern: modern bundlers (Vite, webpack 5, Parcel, esbuild)\n // resolve `new URL('./file', import.meta.url)` at build time,\n // copying worker.js to the output directory and returning the correct URL.\n // Falls back gracefully for CJS builds where import.meta is unavailable.\n try {\n return new URL('./worker.js', import.meta.url);\n } catch {\n throw new Error(\n '@agicash/qr-scanner: Could not resolve worker URL. ' +\n 'Call QrScanner.setWorkerUrl() with the path to the worker script before creating a scanner. ' +\n 'Example: QrScanner.setWorkerUrl(\"/path/to/@agicash/qr-scanner/dist/worker.js\")',\n );\n }\n}\n\nexport class Scanner {\n private video: HTMLVideoElement;\n private onDecode: OnDecodeCallback;\n private options: ScannerOptions;\n private camera: CameraManager;\n private frameExtractor: FrameExtractor | null = null;\n private worker: Worker | null = null;\n private overlay: ScanOverlay | null = null;\n private active = false;\n private paused = false;\n private destroyed = false;\n\n constructor(\n video: HTMLVideoElement,\n onDecode: OnDecodeCallback,\n options: ScannerOptions = {},\n ) {\n this.video = video;\n this.onDecode = onDecode;\n this.options = options;\n\n this.camera = new CameraManager({\n preferredCamera: options.preferredCamera,\n cameraResolution: options.cameraResolution,\n });\n }\n\n async start(): Promise<void> {\n if (this.destroyed) {\n throw new Error('Scanner has been destroyed');\n }\n\n if (this.active && !this.paused) {\n return; // Already running\n }\n\n const t0 = performance.now();\n\n // Show overlay immediately (CSS-centered placeholder) so the UI looks\n // ready while the camera is still loading.\n if (\n !this.overlay &&\n (this.options.highlightScanRegion ||\n this.options.highlightCodeOutline ||\n this.options.overlay)\n ) {\n try {\n this.overlay = new ScanOverlay(this.video, {\n highlightScanRegion: this.options.highlightScanRegion ?? false,\n highlightCodeOutline: this.options.highlightCodeOutline ?? false,\n customOverlay: this.options.overlay,\n });\n this.overlay.setup();\n } catch {\n // Overlay setup failed (e.g., no parent element) — continue without overlay\n }\n }\n\n // Start camera\n await this.camera.start(this.video);\n debug(\n `[QrScanner] start: camera ready ${(performance.now() - t0).toFixed(0)}ms`,\n );\n\n // Now that video dimensions are known, position overlay exactly\n if (this.overlay) {\n this.overlay.updateScanRegion(this.getCurrentScanRegion());\n }\n\n // Create worker if needed\n if (!this.worker) {\n const tw = performance.now();\n this.worker = this.createWorker();\n debug(\n `[QrScanner] start: worker created ${(performance.now() - tw).toFixed(0)}ms`,\n );\n }\n\n // Create frame extractor if needed\n if (!this.frameExtractor) {\n this.frameExtractor = new FrameExtractor(this.video, {\n maxScansPerSecond: this.options.maxScansPerSecond ?? 15,\n getScanRegion: () => this.getCurrentScanRegion(),\n });\n }\n\n // Start frame extraction loop\n this.frameExtractor.start((imageData) => {\n this.sendToWorker(imageData);\n });\n\n this.active = true;\n this.paused = false;\n\n debug(`[QrScanner] start: total ${(performance.now() - t0).toFixed(0)}ms`);\n }\n\n stop(): void {\n this.frameExtractor?.stop();\n this.camera.stop();\n this.video.srcObject = null;\n this.active = false;\n this.paused = false;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.stop();\n this.frameExtractor?.destroy();\n this.frameExtractor = null;\n this.overlay?.destroy();\n this.overlay = null;\n this.worker?.terminate();\n this.worker = null;\n this.destroyed = true;\n }\n\n async pause(stopStreamImmediately = true): Promise<boolean> {\n if (!this.active) return false;\n\n this.frameExtractor?.stop();\n this.paused = true;\n\n if (stopStreamImmediately) {\n this.camera.stop();\n this.video.srcObject = null;\n }\n\n return true;\n }\n\n async setCamera(facingModeOrDeviceId: string): Promise<void> {\n const wasActive = this.active && !this.paused;\n if (wasActive) {\n this.frameExtractor?.stop();\n }\n\n await this.camera.setCamera(facingModeOrDeviceId, this.video);\n\n if (wasActive) {\n this.frameExtractor?.start((imageData) => {\n this.sendToWorker(imageData);\n });\n }\n }\n\n async hasFlash(): Promise<boolean> {\n return this.camera.hasFlash();\n }\n\n isFlashOn(): boolean {\n return this.camera.isFlashOn();\n }\n\n async toggleFlash(): Promise<void> {\n return this.camera.toggleFlash();\n }\n\n async turnFlashOn(): Promise<void> {\n return this.camera.turnFlashOn();\n }\n\n async turnFlashOff(): Promise<void> {\n return this.camera.turnFlashOff();\n }\n\n setInversionMode(mode: InversionMode): void {\n if (!this.worker) return;\n\n const options: Partial<ReaderOptions> = {};\n switch (mode) {\n case 'original':\n options.tryInvert = false;\n break;\n case 'invert':\n options.tryInvert = true;\n break;\n case 'both':\n options.tryInvert = true;\n break;\n }\n\n const msg: WorkerRequest = { type: 'configure', options };\n this.worker.postMessage(msg);\n }\n\n isActive(): boolean {\n return this.active;\n }\n\n isPaused(): boolean {\n return this.paused;\n }\n\n isDestroyed(): boolean {\n return this.destroyed;\n }\n\n private getCurrentScanRegion(): ScanRegion {\n if (this.options.calculateScanRegion) {\n return this.options.calculateScanRegion(this.video);\n }\n return calculateDefaultScanRegion(this.video);\n }\n\n private createWorker(): Worker {\n const workerUrl = resolveWorkerUrl();\n const worker = new Worker(workerUrl, { type: 'module' });\n\n // Configure with custom decoder options\n if (this.options.decoderOptions) {\n const msg: WorkerRequest = {\n type: 'configure',\n options: this.options.decoderOptions,\n };\n worker.postMessage(msg);\n }\n\n worker.onmessage = (e: MessageEvent<WorkerResponse>) => {\n this.handleWorkerMessage(e.data);\n };\n\n worker.onerror = (err) => {\n console.error('QR Scanner worker error:', err);\n this.frameExtractor?.markWorkerIdle();\n };\n\n return worker;\n }\n\n private handleWorkerMessage(response: WorkerResponse): void {\n this.frameExtractor?.markWorkerIdle();\n\n if (response.type === 'ready') {\n return;\n }\n\n if (response.type === 'error') {\n this.options.onDecodeError?.(response.message);\n return;\n }\n\n if (response.type === 'result') {\n if (response.results.length > 0) {\n const result = response.results[0];\n this.onDecode(result);\n\n // Update overlay\n if (this.overlay) {\n const region = this.getCurrentScanRegion();\n this.overlay.updateScanRegion(region);\n this.overlay.updateCodeOutline(result.cornerPoints, region);\n }\n } else {\n this.options.onDecodeError?.('No QR code found');\n\n // Hide code outline when no QR found\n if (this.overlay) {\n this.overlay.updateCodeOutline(null);\n }\n }\n }\n }\n\n private sendToWorker(imageData: ImageData): void {\n if (!this.worker) return;\n\n const msg: WorkerRequest = { type: 'decode', imageData };\n this.worker.postMessage(msg, [imageData.data.buffer]);\n }\n}\n","import { readBarcodes, type ReaderOptions } from 'zxing-wasm/reader';\nimport type { ScanResult, ScanRegion, Point } from './types.js';\nimport { loadImageData } from './utils.js';\n\nconst defaultReaderOptions: ReaderOptions = {\n formats: ['QRCode'],\n tryHarder: true,\n tryInvert: true,\n tryRotate: true,\n tryDenoise: false,\n tryDownscale: true,\n maxNumberOfSymbols: 1,\n};\n\nfunction mapPosition(position: {\n topLeft: Point;\n topRight: Point;\n bottomLeft: Point;\n bottomRight: Point;\n}): Point[] {\n return [\n position.topLeft,\n position.topRight,\n position.bottomRight,\n position.bottomLeft,\n ];\n}\n\n/** Input types that zxing-wasm can handle directly (no canvas needed). */\ntype DirectInput = Blob | ArrayBuffer | Uint8Array | ImageData;\n\n/** Input types that need canvas-based pixel extraction. */\ntype CanvasInput = HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap;\n\nfunction isDirectInput(source: unknown): source is DirectInput {\n return (\n source instanceof Blob ||\n source instanceof ArrayBuffer ||\n source instanceof Uint8Array ||\n (typeof ImageData !== 'undefined' && source instanceof ImageData)\n );\n}\n\n/**\n * Scan a single image for QR codes. Does not require a camera or video stream.\n */\nexport async function scanImage(\n source:\n | CanvasInput\n | DirectInput\n | File\n | URL\n | string,\n options?: {\n scanRegion?: ScanRegion | null;\n canvas?: HTMLCanvasElement | null;\n decoderOptions?: Partial<ReaderOptions>;\n },\n): Promise<ScanResult> {\n const readerOptions: ReaderOptions = {\n ...defaultReaderOptions,\n ...options?.decoderOptions,\n formats: ['QRCode'],\n };\n\n let input: DirectInput;\n if (isDirectInput(source)) {\n input = source;\n } else if (typeof source === 'string' || source instanceof URL) {\n // URL string - fetch and pass as ArrayBuffer\n const url = source instanceof URL ? source.href : source;\n const response = await fetch(url);\n input = await response.arrayBuffer();\n } else {\n // Canvas-based sources - extract ImageData\n input = await loadImageData(source, options?.scanRegion, options?.canvas);\n }\n\n const results = await readBarcodes(input, readerOptions);\n const valid = results.filter((r) => r.isValid);\n\n if (valid.length === 0) {\n throw new Error('No QR code found in the image');\n }\n\n const first = valid[0];\n return {\n data: first.text,\n cornerPoints: mapPosition(first.position),\n };\n}\n","import type { ScanRegion } from './types.js';\n\n/**\n * Load an image source into an ImageData object, optionally cropping to a scan region.\n */\nexport async function loadImageData(\n source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | File | Blob | URL | string,\n scanRegion?: ScanRegion | null,\n canvas?: HTMLCanvasElement | null,\n): Promise<ImageData> {\n const img = await resolveImageSource(source);\n\n const sx = scanRegion?.x ?? 0;\n const sy = scanRegion?.y ?? 0;\n const sw = scanRegion?.width ?? (img.width - sx);\n const sh = scanRegion?.height ?? (img.height - sy);\n\n let drawCanvas: HTMLCanvasElement | OffscreenCanvas;\n let ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n\n if (canvas) {\n drawCanvas = canvas;\n canvas.width = sw;\n canvas.height = sh;\n ctx = canvas.getContext('2d')!;\n } else if (typeof OffscreenCanvas !== 'undefined') {\n drawCanvas = new OffscreenCanvas(sw, sh);\n ctx = drawCanvas.getContext('2d')! as OffscreenCanvasRenderingContext2D;\n } else {\n drawCanvas = document.createElement('canvas');\n drawCanvas.width = sw;\n drawCanvas.height = sh;\n ctx = drawCanvas.getContext('2d')!;\n }\n\n ctx.drawImage(img as CanvasImageSource, sx, sy, sw, sh, 0, 0, sw, sh);\n return ctx.getImageData(0, 0, sw, sh);\n}\n\nasync function resolveImageSource(\n source: HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | File | Blob | URL | string,\n): Promise<HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap> {\n if (source instanceof HTMLImageElement || source instanceof HTMLCanvasElement || source instanceof ImageBitmap) {\n return source;\n }\n\n if (typeof OffscreenCanvas !== 'undefined' && source instanceof OffscreenCanvas) {\n return source;\n }\n\n if (source instanceof File || source instanceof Blob) {\n return createImageBitmapFromBlob(source);\n }\n\n // URL or string\n const url = source instanceof URL ? source.href : source as string;\n const response = await fetch(url);\n const blob = await response.blob();\n return createImageBitmapFromBlob(blob);\n}\n\nasync function createImageBitmapFromBlob(blob: Blob): Promise<ImageBitmap> {\n if (typeof createImageBitmap !== 'undefined') {\n return createImageBitmap(blob);\n }\n // Fallback for environments without createImageBitmap\n const url = URL.createObjectURL(blob);\n try {\n const img = new Image();\n img.src = url;\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error('Failed to load image'));\n });\n return img as unknown as ImageBitmap;\n } finally {\n URL.revokeObjectURL(url);\n }\n}\n","import { Scanner, setWorkerUrl } from './scanner.js';\nimport {\n CameraManager,\n CameraNotFoundError,\n CameraPermissionError,\n} from './camera.js';\nimport { setDebug } from './debug.js';\nimport { scanImage } from './scan-image.js';\nimport { setZXingModuleOverrides } from 'zxing-wasm/reader';\nimport type {\n ScanResult,\n ScanRegion,\n ScannerOptions,\n Camera,\n Point,\n FacingMode,\n DeviceId,\n InversionMode,\n} from './types.js';\nimport type { ReaderOptions } from 'zxing-wasm/reader';\n\nexport { CameraNotFoundError, CameraPermissionError };\n\nexport type {\n ScanResult,\n ScanRegion,\n ScannerOptions,\n Camera,\n Point,\n FacingMode,\n DeviceId,\n InversionMode,\n};\n\n/**\n * High-performance QR code scanner for the web, powered by ZXing-C++ WebAssembly.\n */\nclass QrScanner {\n private scanner: Scanner;\n\n constructor(\n videoElement: HTMLVideoElement,\n onDecode: (result: ScanResult) => void,\n options: ScannerOptions = {},\n ) {\n this.scanner = new Scanner(videoElement, onDecode, options);\n }\n\n /** Start camera and begin scanning. Resolves when camera is ready. */\n async start(): Promise<void> {\n return this.scanner.start();\n }\n\n /** Stop scanning and release the camera stream. */\n stop(): void {\n this.scanner.stop();\n }\n\n /** Stop scanning, release camera, terminate worker, clean up DOM. */\n destroy(): void {\n this.scanner.destroy();\n }\n\n /** Pause scanning. If stopStreamImmediately is false, camera stays on. */\n async pause(stopStreamImmediately?: boolean): Promise<boolean> {\n return this.scanner.pause(stopStreamImmediately);\n }\n\n /** Switch to a different camera by facing mode or device ID. */\n async setCamera(facingModeOrDeviceId: FacingMode | DeviceId): Promise<void> {\n return this.scanner.setCamera(facingModeOrDeviceId);\n }\n\n /** Check if the current camera supports flash/torch. */\n async hasFlash(): Promise<boolean> {\n return this.scanner.hasFlash();\n }\n\n /** Whether flash is currently on. */\n isFlashOn(): boolean {\n return this.scanner.isFlashOn();\n }\n\n /** Toggle flash on/off. */\n async toggleFlash(): Promise<void> {\n return this.scanner.toggleFlash();\n }\n\n /** Turn flash on. */\n async turnFlashOn(): Promise<void> {\n return this.scanner.turnFlashOn();\n }\n\n /** Turn flash off. */\n async turnFlashOff(): Promise<void> {\n return this.scanner.turnFlashOff();\n }\n\n /** Set the inversion mode for detecting inverted QR codes. */\n setInversionMode(mode: InversionMode): void {\n this.scanner.setInversionMode(mode);\n }\n\n // --- Static methods ---\n\n /** Check if the device has at least one camera. */\n static hasCamera(): Promise<boolean> {\n return CameraManager.hasCamera();\n }\n\n /** List available cameras. Pass true to request labels (triggers permission prompt). */\n static listCameras(requestLabels?: boolean): Promise<Camera[]> {\n return CameraManager.listCameras(requestLabels);\n }\n\n /**\n * Pre-load the WASM binary so it's ready when the scanner starts.\n * Call this early (e.g., on app init) to avoid delay on first scan.\n */\n static async preload(): Promise<void> {\n // Trigger WASM loading by doing a minimal scan\n const pixel = new Uint8ClampedArray([255, 255, 255, 255]);\n const img = new ImageData(pixel, 1, 1);\n try {\n await scanImage(img);\n } catch {\n // Expected — no QR code in a 1x1 image. The point was to load WASM.\n }\n }\n\n /**\n * Configure WASM loading. Call before creating any scanner instance.\n * @example\n * QrScanner.configureWasm({ locateFile: (filename) => `/wasm/${filename}` });\n */\n static configureWasm(overrides: Partial<EmscriptenModule>): void {\n setZXingModuleOverrides(overrides);\n }\n\n /**\n * Set a custom URL for the worker script. Call before creating any scanner.\n * Needed for CJS consumers or non-standard bundler setups.\n * By default, the worker URL is resolved via `new URL('./worker.js', import.meta.url)`,\n * which works with Vite, webpack 5, Parcel, and other modern bundlers.\n * @example\n * QrScanner.setWorkerUrl('/assets/qr-scanner-worker.js');\n */\n static setWorkerUrl(url: string | URL): void {\n setWorkerUrl(url);\n }\n\n /**\n * Enable or disable debug logging (performance timings, camera selection).\n * Off by default. Useful for diagnosing camera issues in the browser console.\n * @example\n * QrScanner.setDebug(true);\n */\n static setDebug(enabled: boolean): void {\n setDebug(enabled);\n }\n\n /** Scan a single image (not a video stream). */\n static scanImage(\n source:\n | HTMLImageElement\n | HTMLCanvasElement\n | OffscreenCanvas\n | ImageBitmap\n | ImageData\n | Blob\n | ArrayBuffer\n | Uint8Array\n | File\n | URL\n | string,\n options?: {\n scanRegion?: ScanRegion | null;\n canvas?: HTMLCanvasElement | null;\n decoderOptions?: Partial<ReaderOptions>;\n },\n ): Promise<ScanResult> {\n return scanImage(source, options);\n }\n}\n\nexport default QrScanner;\n"],"mappings":"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","names":["t","enabled"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agicash/qr-scanner",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "High-performance QR code scanner for the web, powered by ZXing-C++ WebAssembly",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -19,9 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"./dist/worker.js": "./dist/worker.js"
|
|
21
21
|
},
|
|
22
|
-
"files": [
|
|
23
|
-
"dist"
|
|
24
|
-
],
|
|
22
|
+
"files": ["dist"],
|
|
25
23
|
"scripts": {
|
|
26
24
|
"build": "tsup",
|
|
27
25
|
"test": "vitest run",
|
|
@@ -42,6 +40,10 @@
|
|
|
42
40
|
],
|
|
43
41
|
"author": "",
|
|
44
42
|
"license": "MIT",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/MakePrisms/qr-scanner"
|
|
46
|
+
},
|
|
45
47
|
"dependencies": {
|
|
46
48
|
"zxing-wasm": "2.2.4"
|
|
47
49
|
},
|