@sekyro/web 0.1.0-rc.6 → 0.1.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +3 -3
  3. package/README.md +4 -4
  4. package/dist/chunk-B45J4KC3.js +1 -0
  5. package/dist/chunk-BMA36W2W.js +1 -0
  6. package/dist/chunk-FPXL63KZ.js +1 -0
  7. package/dist/chunk-IYUOYINS.js +1 -0
  8. package/dist/chunk-P7ECRN47.js +1 -0
  9. package/dist/chunk-SXZCL5NO.js +1 -0
  10. package/dist/chunk-YOB4ZTYN.js +1 -0
  11. package/dist/chunk-YQBK6OIM.js +1 -0
  12. package/dist/client/index.cjs +1 -357
  13. package/dist/client/index.d.cts +2 -2
  14. package/dist/client/index.d.ts +2 -2
  15. package/dist/client/index.js +1 -15
  16. package/dist/core/index.cjs +1 -1639
  17. package/dist/core/index.js +1 -139
  18. package/dist/core/v3/detect-worker.cjs +1 -392
  19. package/dist/core/v3/detect-worker.js +1 -13
  20. package/dist/{create-verification-BKc9NFQj.d.cts → create-verification-C2JhOO6Y.d.cts} +94 -16
  21. package/dist/{create-verification-DjcMZHAQ.d.ts → create-verification-CGazwtAh.d.ts} +94 -16
  22. package/dist/detector-scanic-VQFFXKTL.js +1 -0
  23. package/dist/{hosted-client-DJXq_CB9.d.ts → hosted-client-kBeq-mnJ.d.cts} +164 -11
  24. package/dist/{hosted-client-DJXq_CB9.d.cts → hosted-client-kBeq-mnJ.d.ts} +164 -11
  25. package/dist/index.cjs +1 -3030
  26. package/dist/index.d.cts +2 -2
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.js +1 -85
  29. package/dist/internal/index.cjs +1 -4439
  30. package/dist/internal/index.d.cts +10 -7
  31. package/dist/internal/index.d.ts +10 -7
  32. package/dist/internal/index.js +1 -657
  33. package/dist/popup/index.cjs +1 -76
  34. package/dist/popup/index.js +1 -11
  35. package/dist/scanic-ml-stub-KW7IZHUT.js +1 -0
  36. package/package.json +5 -8
  37. package/sbom.cdx.json +195 -0
  38. package/dist/chunk-MWNFSNMP.js +0 -52
  39. package/dist/chunk-MWNFSNMP.js.map +0 -1
  40. package/dist/chunk-NILNKLK6.js +0 -50
  41. package/dist/chunk-NILNKLK6.js.map +0 -1
  42. package/dist/chunk-NWF46H7K.js +0 -359
  43. package/dist/chunk-NWF46H7K.js.map +0 -1
  44. package/dist/chunk-R3SJQHYU.js +0 -1173
  45. package/dist/chunk-R3SJQHYU.js.map +0 -1
  46. package/dist/chunk-TG5IE552.js +0 -1128
  47. package/dist/chunk-TG5IE552.js.map +0 -1
  48. package/dist/chunk-WY6U7AIK.js +0 -193
  49. package/dist/chunk-WY6U7AIK.js.map +0 -1
  50. package/dist/chunk-YVFF4Q4G.js +0 -327
  51. package/dist/chunk-YVFF4Q4G.js.map +0 -1
  52. package/dist/client/index.cjs.map +0 -1
  53. package/dist/client/index.js.map +0 -1
  54. package/dist/core/index.cjs.map +0 -1
  55. package/dist/core/index.js.map +0 -1
  56. package/dist/core/v3/detect-worker.cjs.map +0 -1
  57. package/dist/core/v3/detect-worker.js.map +0 -1
  58. package/dist/detector-scanic-4C6IEW2K.js +0 -787
  59. package/dist/detector-scanic-4C6IEW2K.js.map +0 -1
  60. package/dist/index.cjs.map +0 -1
  61. package/dist/index.js.map +0 -1
  62. package/dist/internal/index.cjs.map +0 -1
  63. package/dist/internal/index.js.map +0 -1
  64. package/dist/popup/index.cjs.map +0 -1
  65. package/dist/popup/index.js.map +0 -1
  66. package/dist/scanic-ml-stub-S2OZ6HEF.js +0 -10
  67. package/dist/scanic-ml-stub-S2OZ6HEF.js.map +0 -1
@@ -1,4439 +1 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
- };
11
- var __export = (target, all) => {
12
- for (var name in all)
13
- __defProp(target, name, { get: all[name], enumerable: true });
14
- };
15
- var __copyProps = (to, from, except, desc) => {
16
- if (from && typeof from === "object" || typeof from === "function") {
17
- for (let key of __getOwnPropNames(from))
18
- if (!__hasOwnProp.call(to, key) && key !== except)
19
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
- }
21
- return to;
22
- };
23
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
- // If the importer is in node compatibility mode or this is not an ESM
25
- // file that has been converted to a CommonJS file using a Babel-
26
- // compatible transform (i.e. "__esModule" has not been set), then set
27
- // "default" to the CommonJS "module.exports" for node compatibility.
28
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
- mod
30
- ));
31
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
-
33
- // src/core/doc/doc-catalog.ts
34
- function aspectBand(format) {
35
- return ASPECT_BANDS[format];
36
- }
37
- var ASPECT_BANDS, MR_DOC_CATALOG;
38
- var init_doc_catalog = __esm({
39
- "src/core/doc/doc-catalog.ts"() {
40
- "use strict";
41
- ASPECT_BANDS = {
42
- "ID-1": { center: 1.586, tolerance: 0.15 },
43
- "ID-3": { center: 1.42, tolerance: 0.2 }
44
- };
45
- MR_DOC_CATALOG = [
46
- {
47
- docType: "carte_identite",
48
- format: "ID-1",
49
- sides: ["recto", "verso"],
50
- mrz: "td1",
51
- // verso; carries the NNI with ICAO check digits (findings §6)
52
- portraitSide: "recto",
53
- aspectRatio: 1.586,
54
- identifierSource: "mrz"
55
- },
56
- {
57
- docType: "passport",
58
- format: "ID-3",
59
- sides: ["single"],
60
- mrz: "td3",
61
- portraitSide: "single",
62
- // data page
63
- aspectRatio: 1.42,
64
- identifierSource: "mrz"
65
- }
66
- ];
67
- }
68
- });
69
-
70
- // src/core/v3/frame-quality.ts
71
- function lumaAt(data, index) {
72
- return 0.299 * (data[index] ?? 0) + 0.587 * (data[index + 1] ?? 0) + 0.114 * (data[index + 2] ?? 0);
73
- }
74
- function meanLuma(image) {
75
- const { data, width, height } = image;
76
- const pixels = width * height;
77
- if (pixels === 0) return 0;
78
- let sum = 0;
79
- for (let i2 = 0; i2 < pixels; i2 += 1) sum += lumaAt(data, i2 * 4);
80
- return sum / pixels;
81
- }
82
- function sharpness(image) {
83
- const { data, width, height } = image;
84
- if (width < 3 || height < 3) return 0;
85
- const gray = new Float32Array(width * height);
86
- for (let i2 = 0; i2 < gray.length; i2 += 1) gray[i2] = lumaAt(data, i2 * 4);
87
- let sum = 0;
88
- let sumSquares = 0;
89
- let count = 0;
90
- for (let y2 = 1; y2 < height - 1; y2 += 1) {
91
- for (let x = 1; x < width - 1; x += 1) {
92
- const i2 = y2 * width + x;
93
- const response = (gray[i2 - width] ?? 0) + (gray[i2 - 1] ?? 0) + (gray[i2 + 1] ?? 0) + (gray[i2 + width] ?? 0) - 4 * (gray[i2] ?? 0);
94
- sum += response;
95
- sumSquares += response * response;
96
- count += 1;
97
- }
98
- }
99
- if (count === 0) return 0;
100
- const mean = sum / count;
101
- const variance = sumSquares / count - mean * mean;
102
- return Math.min(1, Math.max(0, variance) / SHARP_REF);
103
- }
104
- function exposure(image) {
105
- const mean = meanLuma(image);
106
- const [low, high] = EXPOSURE_BAND;
107
- const distance = mean < low ? low - mean : mean > high ? mean - high : 0;
108
- return Math.max(0, 1 - distance / EXPOSURE_FALLOFF);
109
- }
110
- var SHARP_REF, EXPOSURE_BAND, EXPOSURE_FALLOFF;
111
- var init_frame_quality = __esm({
112
- "src/core/v3/frame-quality.ts"() {
113
- "use strict";
114
- SHARP_REF = 180;
115
- EXPOSURE_BAND = [100, 190];
116
- EXPOSURE_FALLOFF = 64;
117
- }
118
- });
119
-
120
- // src/core/doc/doc-gate-v1.ts
121
- function quadAreaFrac(quad, frameWidth, frameHeight) {
122
- const pts = [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft];
123
- let doubled = 0;
124
- for (let i2 = 0; i2 < 4; i2++) {
125
- const a2 = pts[i2];
126
- const b = pts[(i2 + 1) % 4];
127
- doubled += a2.x * b.y - b.x * a2.y;
128
- }
129
- const frameArea = frameWidth * frameHeight;
130
- return frameArea > 0 ? Math.abs(doubled / 2) / frameArea : 0;
131
- }
132
- function quadIou(a2, b) {
133
- const boxA = bbox(a2);
134
- const boxB = bbox(b);
135
- const x1 = Math.max(boxA.x1, boxB.x1);
136
- const y1 = Math.max(boxA.y1, boxB.y1);
137
- const x2 = Math.min(boxA.x2, boxB.x2);
138
- const y2 = Math.min(boxA.y2, boxB.y2);
139
- const inter = Math.max(0, x2 - x1) * Math.max(0, y2 - y1);
140
- const areaA = (boxA.x2 - boxA.x1) * (boxA.y2 - boxA.y1);
141
- const areaB = (boxB.x2 - boxB.x1) * (boxB.y2 - boxB.y1);
142
- const union = areaA + areaB - inter;
143
- return union > 0 ? inter / union : 0;
144
- }
145
- function quadBounds(quad) {
146
- const box = bbox(quad);
147
- return { width: box.x2 - box.x1, height: box.y2 - box.y1 };
148
- }
149
- function bbox(quad) {
150
- const pts = [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft];
151
- return {
152
- x1: Math.min(...pts.map((p2) => p2.x)),
153
- y1: Math.min(...pts.map((p2) => p2.y)),
154
- x2: Math.max(...pts.map((p2) => p2.x)),
155
- y2: Math.max(...pts.map((p2) => p2.y))
156
- };
157
- }
158
- function quadAspect(quad) {
159
- const top = Math.hypot(quad.topRight.x - quad.topLeft.x, quad.topRight.y - quad.topLeft.y);
160
- const bottom = Math.hypot(
161
- quad.bottomRight.x - quad.bottomLeft.x,
162
- quad.bottomRight.y - quad.bottomLeft.y
163
- );
164
- const left = Math.hypot(quad.bottomLeft.x - quad.topLeft.x, quad.bottomLeft.y - quad.topLeft.y);
165
- const right = Math.hypot(
166
- quad.bottomRight.x - quad.topRight.x,
167
- quad.bottomRight.y - quad.topRight.y
168
- );
169
- const horizontal = (top + bottom) / 2;
170
- const vertical = (left + right) / 2;
171
- if (horizontal <= 0 || vertical <= 0) return 0;
172
- return Math.max(horizontal, vertical) / Math.min(horizontal, vertical);
173
- }
174
- var DOC_DETECT_WIDTH, DOC_GATE_V1_DEFAULTS, clamp01, DocGateV1;
175
- var init_doc_gate_v1 = __esm({
176
- "src/core/doc/doc-gate-v1.ts"() {
177
- "use strict";
178
- init_frame_quality();
179
- init_doc_catalog();
180
- DOC_DETECT_WIDTH = 480;
181
- DOC_GATE_V1_DEFAULTS = Object.freeze({
182
- MIN_AREA_FRAC: 0.15,
183
- EDGE_CLIP_MARGIN_PX: 4,
184
- STABLE_TICKS: 3,
185
- IOU_STABLE_MIN: 0.85,
186
- RISE_PER_S: 0.9,
187
- FALL_PER_S: 0.25,
188
- GUIDE_EXPOSURE: 0.6,
189
- GUIDE_SHARPNESS: 0.35,
190
- ID3_BAND_MIN_WIDTH_FRAC: 0.55,
191
- ID3_BAND_ASPECT_MIN: 4,
192
- ID3_BAND_ASPECT_MAX: 40
193
- });
194
- clamp01 = (value) => Math.min(1, Math.max(0, value));
195
- DocGateV1 = class {
196
- constructor(format, overrides = {}) {
197
- this.p = 0;
198
- this.lastTickAt = null;
199
- this.lastQuad = null;
200
- this.streak = 0;
201
- this.format = format;
202
- this.t = { ...DOC_GATE_V1_DEFAULTS, ...overrides };
203
- }
204
- reset() {
205
- this.p = 0;
206
- this.lastTickAt = null;
207
- this.lastQuad = null;
208
- this.streak = 0;
209
- }
210
- tick(input) {
211
- const { quad, quality, timestampMs } = input;
212
- const dtSeconds = this.lastTickAt === null ? 0 : Math.max(0, (timestampMs - this.lastTickAt) / 1e3);
213
- this.lastTickAt = timestampMs;
214
- let geometryKey = null;
215
- if (quad === null) {
216
- geometryKey = "dcv1.no_doc";
217
- } else if (this.format === "ID-3") {
218
- const box = quadBounds(quad);
219
- const aspect = box.height > 0 ? box.width / box.height : 0;
220
- if (box.width < this.t.ID3_BAND_MIN_WIDTH_FRAC * input.frameWidth) {
221
- geometryKey = "dcv1.come_closer";
222
- } else if (this.edgeClipped(quad, input.frameWidth, input.frameHeight)) {
223
- geometryKey = "dcv1.fit_document";
224
- } else if (aspect < this.t.ID3_BAND_ASPECT_MIN || aspect > this.t.ID3_BAND_ASPECT_MAX) {
225
- geometryKey = "dcv1.wrong_shape";
226
- }
227
- } else if (quadAreaFrac(quad, input.frameWidth, input.frameHeight) < this.t.MIN_AREA_FRAC) {
228
- geometryKey = "dcv1.come_closer";
229
- } else if (this.edgeClipped(quad, input.frameWidth, input.frameHeight)) {
230
- geometryKey = "dcv1.fit_document";
231
- } else {
232
- const band = aspectBand(this.format);
233
- const aspect = quadAspect(quad);
234
- if (Math.abs(aspect - band.center) > band.tolerance) geometryKey = "dcv1.wrong_shape";
235
- }
236
- const plausible = geometryKey === null;
237
- const exposureOk = clamp01(quality.exposure) >= this.t.GUIDE_EXPOSURE;
238
- const sharpnessOk = clamp01(quality.sharpness) >= this.t.GUIDE_SHARPNESS;
239
- const qualityOk = exposureOk && sharpnessOk;
240
- if (plausible && qualityOk && quad !== null) {
241
- const held = this.lastQuad === null || quadIou(quad, this.lastQuad) >= this.t.IOU_STABLE_MIN;
242
- this.streak = held ? this.streak + 1 : 1;
243
- } else {
244
- this.streak = 0;
245
- }
246
- this.lastQuad = quad;
247
- const good = plausible && qualityOk;
248
- this.p = clamp01(this.p + (good ? this.t.RISE_PER_S : -this.t.FALL_PER_S) * dtSeconds);
249
- const ready = good && this.streak >= this.t.STABLE_TICKS;
250
- let guidanceKey;
251
- if (geometryKey !== null) {
252
- guidanceKey = geometryKey;
253
- } else if (!exposureOk) {
254
- const bandMid = (EXPOSURE_BAND[0] + EXPOSURE_BAND[1]) / 2;
255
- guidanceKey = quality.meanLuma < bandMid ? "dcv1.more_light" : "dcv1.too_bright";
256
- } else if (!sharpnessOk) {
257
- guidanceKey = "dcv1.steady";
258
- } else {
259
- guidanceKey = "dcv1.hold_still";
260
- }
261
- return { at: timestampMs, quad, plausible, p: this.p, guidanceKey, ready, stableTicks: this.streak };
262
- }
263
- edgeClipped(quad, frameWidth, frameHeight) {
264
- const margin = this.t.EDGE_CLIP_MARGIN_PX;
265
- const pts = [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft];
266
- return pts.some(
267
- (p2) => p2.x <= margin || p2.y <= margin || p2.x >= frameWidth - margin || p2.y >= frameHeight - margin
268
- );
269
- }
270
- };
271
- }
272
- });
273
-
274
- // scanic-ml-stub:scanic-ml-stub
275
- var scanic_ml_stub_exports = {};
276
- __export(scanic_ml_stub_exports, {
277
- default: () => scanic_ml_stub_default,
278
- initMlDetector: () => initMlDetector
279
- });
280
- function initMlDetector() {
281
- throw new Error("scanic ML detector is not vendored (classical pipeline only)");
282
- }
283
- var scanic_ml_stub_default;
284
- var init_scanic_ml_stub = __esm({
285
- "scanic-ml-stub:scanic-ml-stub"() {
286
- "use strict";
287
- scanic_ml_stub_default = {};
288
- }
289
- });
290
-
291
- // vendor/scanic/scanic.js
292
- function B(A2, B2 = {}) {
293
- const t2 = B2.width || Math.sqrt(A2.length), i2 = B2.height || A2.length / t2, E2 = void 0 !== B2.mode ? B2.mode : 1, e2 = void 0 !== B2.method ? B2.method : 2, o2 = B2.minArea || I, n2 = t2 + 2, a2 = i2 + 2, s2 = new Int32Array(n2 * a2);
294
- for (let I2 = 0; I2 < i2; I2++) for (let g2 = 0; g2 < t2; g2++) A2[I2 * t2 + g2] > 0 && (s2[(I2 + 1) * n2 + (g2 + 1)] = 1);
295
- const c2 = [];
296
- let r2 = 2;
297
- for (let I2 = 1; I2 <= i2; I2++) for (let A3 = 1; A3 <= t2; A3++) {
298
- const B3 = s2[I2 * n2 + A3], t3 = s2[I2 * n2 + (A3 - 1)];
299
- let i3 = null, o3 = false, h3 = -1;
300
- if (1 === B3 && 0 === t3 ? (o3 = true, i3 = { x: A3, y: I2 }, h3 = 2) : 0 === B3 && t3 >= 1 && -1 !== t3 && 1 === t3 && (o3 = false, i3 = { x: A3 - 1, y: I2 }, h3 = 6), i3) {
301
- if (0 === E2 && !o3) {
302
- s2[i3.y * n2 + i3.x] = -1;
303
- continue;
304
- }
305
- const A4 = r2++, I3 = C(s2, n2, a2, i3, h3, A4);
306
- if (I3 && I3.length > 0) {
307
- let B4 = I3;
308
- 2 === e2 && (B4 = Q(I3));
309
- const C2 = B4.map((A5) => ({ x: A5.x - 1, y: A5.y - 1 }));
310
- if (C2.length >= (2 === e2 ? 4 : g)) {
311
- const I4 = { id: A4, points: C2, isOuter: o3 };
312
- c2.push(I4);
313
- }
314
- } else 1 === s2[i3.y * n2 + i3.x] && (s2[i3.y * n2 + i3.x] = A4);
315
- }
316
- }
317
- c2.forEach((A3) => {
318
- A3.area = (function(A4) {
319
- let I2 = 0;
320
- const g2 = A4.length;
321
- if (g2 < 3) return 0;
322
- for (let B3 = 0; B3 < g2; B3++) {
323
- const C2 = (B3 + 1) % g2;
324
- I2 += A4[B3].x * A4[C2].y, I2 -= A4[C2].x * A4[B3].y;
325
- }
326
- return Math.abs(I2) / 2;
327
- })(A3.points), A3.boundingBox = (function(A4) {
328
- if (0 === A4.length) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };
329
- let I2 = A4[0].x, g2 = A4[0].y, B3 = A4[0].x, C2 = A4[0].y;
330
- for (let Q2 = 1; Q2 < A4.length; Q2++) {
331
- const t3 = A4[Q2];
332
- I2 = Math.min(I2, t3.x), g2 = Math.min(g2, t3.y), B3 = Math.max(B3, t3.x), C2 = Math.max(C2, t3.y);
333
- }
334
- return { minX: I2, minY: g2, maxX: B3, maxY: C2 };
335
- })(A3.points);
336
- });
337
- const h2 = c2.filter((A3) => A3.area >= o2);
338
- return h2.sort((A3, I2) => I2.area - A3.area), B2.debug && (B2.debug.labels = s2, B2.debug.rawContours = c2, B2.debug.finalContours = h2), h2;
339
- }
340
- function C(A2, I2, g2, B2, C2, Q2) {
341
- const t2 = [], i2 = /* @__PURE__ */ new Set();
342
- let E2 = B2.x, e2 = B2.y;
343
- const o2 = E2, n2 = e2;
344
- let a2 = -1;
345
- A2[n2 * I2 + o2] = Q2;
346
- let s2 = 0;
347
- const c2 = I2 * g2, r2 = [0, 1, 1, 1, 0, -1, -1, -1], h2 = [-1, -1, 0, 1, 1, 1, 0, -1];
348
- for (; s2++ < c2; ) {
349
- let B3;
350
- if (-1 === a2) {
351
- let Q3 = false;
352
- for (let t3 = 0; t3 < 8; t3++) {
353
- B3 = C2 + t3 & 7;
354
- const i3 = E2 + r2[B3], o3 = e2 + h2[B3];
355
- if (i3 >= 0 && i3 < I2 && o3 >= 0 && o3 < g2 && A2[o3 * I2 + i3] > 0) {
356
- Q3 = true;
357
- break;
358
- }
359
- }
360
- if (!Q3) return null;
361
- } else B3 = a2 + 2 & 7;
362
- let s3 = -1, c3 = -1;
363
- for (let C3 = 0; C3 < 8; C3++) {
364
- const Q3 = B3 + C3 & 7, t3 = E2 + r2[Q3], i3 = e2 + h2[Q3];
365
- if (t3 >= 0 && t3 < I2 && i3 >= 0 && i3 < g2 && A2[i3 * I2 + t3] > 0) {
366
- s3 = t3, c3 = i3, a2 = Q3 + 4 & 7;
367
- break;
368
- }
369
- }
370
- if (-1 === s3) {
371
- 0 === t2.length && t2.push({ x: E2, y: e2 });
372
- break;
373
- }
374
- const l2 = e2 * I2 + E2;
375
- if (i2.has(l2)) return t2;
376
- t2.push({ x: E2, y: e2 }), i2.add(l2);
377
- const y2 = c3 * I2 + s3;
378
- if (1 === A2[y2] && (A2[y2] = Q2), E2 = s3, e2 = c3, E2 === o2 && e2 === n2) break;
379
- }
380
- return s2 >= c2 ? null : t2;
381
- }
382
- function Q(A2) {
383
- const I2 = A2.length;
384
- if (I2 <= 2) return A2;
385
- const g2 = [], B2 = A2[I2 - 1], C2 = A2[0];
386
- let Q2 = B2, t2 = C2, i2 = A2[1], E2 = t2.x - Q2.x, e2 = t2.y - Q2.y, o2 = i2.x - t2.x, n2 = i2.y - t2.y;
387
- E2 * n2 !== e2 * o2 && g2.push(t2);
388
- for (let a2 = 1; a2 < I2 - 1; a2++) Q2 = A2[a2 - 1], t2 = A2[a2], i2 = A2[a2 + 1], E2 = t2.x - Q2.x, e2 = t2.y - Q2.y, o2 = i2.x - t2.x, n2 = i2.y - t2.y, E2 * n2 !== e2 * o2 && g2.push(t2);
389
- if (Q2 = A2[I2 - 2], t2 = B2, i2 = C2, E2 = t2.x - Q2.x, e2 = t2.y - Q2.y, o2 = i2.x - t2.x, n2 = i2.y - t2.y, E2 * n2 !== e2 * o2 && g2.push(t2), 0 === g2.length) {
390
- if (1 === I2) return [A2[0]];
391
- if (2 === I2) return A2;
392
- let g3 = 0, B3 = 1;
393
- const Q3 = C2.x, t3 = C2.y;
394
- for (let C3 = 1; C3 < I2; C3++) {
395
- const I3 = A2[C3], i3 = I3.x - Q3, E3 = I3.y - t3, e3 = i3 * i3 + E3 * E3;
396
- e3 > g3 && (g3 = e3, B3 = C3);
397
- }
398
- return [C2, A2[B3]];
399
- }
400
- return g2;
401
- }
402
- function t(A2, I2 = 1) {
403
- if (A2.length <= 2) return A2;
404
- let g2 = 0, B2 = 0;
405
- const C2 = A2[0], Q2 = A2[A2.length - 1];
406
- for (let t2 = 1; t2 < A2.length - 1; t2++) {
407
- const I3 = i(A2[t2], C2, Q2);
408
- I3 > g2 && (g2 = I3, B2 = t2);
409
- }
410
- if (g2 > I2) {
411
- const g3 = t(A2.slice(0, B2 + 1), I2), C3 = t(A2.slice(B2), I2);
412
- return g3.slice(0, -1).concat(C3);
413
- }
414
- return [C2, Q2];
415
- }
416
- function i(A2, I2, g2) {
417
- const B2 = g2.x - I2.x, C2 = g2.y - I2.y, Q2 = B2 * B2 + C2 * C2;
418
- if (0 === Q2) return Math.sqrt(Math.pow(A2.x - I2.x, 2) + Math.pow(A2.y - I2.y, 2));
419
- const t2 = ((A2.x - I2.x) * B2 + (A2.y - I2.y) * C2) / Q2;
420
- let i2, E2;
421
- t2 < 0 ? (i2 = I2.x, E2 = I2.y) : t2 > 1 ? (i2 = g2.x, E2 = g2.y) : (i2 = I2.x + t2 * B2, E2 = I2.y + t2 * C2);
422
- const e2 = A2.x - i2, o2 = A2.y - E2;
423
- return Math.sqrt(e2 * e2 + o2 * o2);
424
- }
425
- function E(A2, I2 = 0.02) {
426
- return t(A2, I2 * (function(A3) {
427
- let I3 = 0;
428
- const g2 = A3.length;
429
- if (g2 < 2) return 0;
430
- for (let B2 = 0; B2 < g2; B2++) {
431
- const C2 = (B2 + 1) % g2, Q2 = A3[B2].x - A3[C2].x, t2 = A3[B2].y - A3[C2].y;
432
- I3 += Math.sqrt(Q2 * Q2 + t2 * t2);
433
- }
434
- return I3;
435
- })(A2));
436
- }
437
- function e(A2, I2) {
438
- return Math.hypot(I2.x - A2.x, I2.y - A2.y);
439
- }
440
- function o(A2) {
441
- let I2 = 0, g2 = 0;
442
- for (const B2 of A2) I2 += B2.x, g2 += B2.y;
443
- return { x: I2 / A2.length, y: g2 / A2.length };
444
- }
445
- function n(A2, I2 = {}) {
446
- if (!A2 || !A2.points || A2.points.length < 4) return null;
447
- const g2 = I2.epsilon || 0.02, B2 = (function(A3, I3) {
448
- if (!A3 || A3.length < 4) return null;
449
- const g3 = [I3, 1.3 * I3, 1.6 * I3, 2 * I3], B3 = /* @__PURE__ */ new Set();
450
- for (const C3 of g3) {
451
- const I4 = Math.min(0.12, C3), g4 = I4.toFixed(4);
452
- if (B3.has(g4)) continue;
453
- B3.add(g4);
454
- const Q2 = a(E(A3, I4));
455
- if (Q2 && 4 === Q2.length) return Q2;
456
- }
457
- return null;
458
- })(A2.points, g2);
459
- let C2;
460
- return B2 && 4 === B2.length ? C2 = (function(A3) {
461
- if (4 !== A3.length) return null;
462
- const I3 = o(A3), g3 = [...A3].sort((A4, g4) => Math.atan2(A4.y - I3.y, A4.x - I3.x) - Math.atan2(g4.y - I3.y, g4.x - I3.x));
463
- let B3 = 1 / 0, C3 = 0;
464
- for (let t2 = 0; t2 < 4; t2++) {
465
- const A4 = g3[t2].x + g3[t2].y;
466
- A4 < B3 && (B3 = A4, C3 = t2);
467
- }
468
- const Q2 = [g3[C3], g3[(C3 + 1) % 4], g3[(C3 + 2) % 4], g3[(C3 + 3) % 4]];
469
- return { topLeft: Q2[0], topRight: Q2[1], bottomRight: Q2[2], bottomLeft: Q2[3] };
470
- })(B2) : (C2 = (function(A3) {
471
- if (!A3 || A3.length < 4) return null;
472
- const I3 = o(A3);
473
- let g3 = null, B3 = null, C3 = null, Q2 = null, t2 = 0, i2 = 0, E2 = 0, n2 = 0;
474
- for (const o2 of A3) {
475
- const A4 = e(o2, I3);
476
- o2.x < I3.x && o2.y < I3.y ? A4 > t2 && (g3 = o2, t2 = A4) : o2.x > I3.x && o2.y < I3.y ? A4 > i2 && (B3 = o2, i2 = A4) : o2.x > I3.x && o2.y > I3.y ? A4 > E2 && (C3 = o2, E2 = A4) : o2.x < I3.x && o2.y > I3.y && A4 > n2 && (Q2 = o2, n2 = A4);
477
- }
478
- return g3 && B3 && C3 && Q2 ? { topLeft: g3, topRight: B3, bottomRight: C3, bottomLeft: Q2 } : null;
479
- })(A2.points), C2 && C2.topLeft && C2.topRight && C2.bottomRight && C2.bottomLeft || (C2 = (function(A3) {
480
- if (!A3 || 0 === A3.length) return null;
481
- let I3 = A3[0], g3 = A3[0], B3 = A3[0], C3 = A3[0], Q2 = I3.x + I3.y, t2 = g3.x - g3.y, i2 = B3.x + B3.y, E2 = C3.x - C3.y;
482
- for (let e2 = 1; e2 < A3.length; e2++) {
483
- const o2 = A3[e2], n2 = o2.x + o2.y, a2 = o2.x - o2.y;
484
- n2 < Q2 && (Q2 = n2, I3 = o2), n2 > i2 && (i2 = n2, B3 = o2), a2 > t2 && (t2 = a2, g3 = o2), a2 < E2 && (E2 = a2, C3 = o2);
485
- }
486
- return { topLeft: I3, topRight: g3, bottomRight: B3, bottomLeft: C3 };
487
- })(A2.points))), C2 && C2.topLeft && C2.topRight && C2.bottomRight && C2.bottomLeft ? C2 : null;
488
- }
489
- function a(A2) {
490
- if (!A2 || A2.length < 4) return null;
491
- if (4 === A2.length) return A2;
492
- if (A2.length > 8) return null;
493
- let I2 = (function(A3, I3) {
494
- if (!A3 || 0 === A3.length) return [];
495
- const g2 = [];
496
- for (const B2 of A3) (0 === g2.length || e(B2, g2[g2.length - 1]) > I3) && g2.push(B2);
497
- g2.length > 2 && e(g2[0], g2[g2.length - 1]) <= I3 && g2.pop();
498
- return g2;
499
- })(A2, 6);
500
- return 4 === I2.length ? I2 : (I2.length, null);
501
- }
502
- function c() {
503
- return null !== s && 0 !== s.byteLength || (s = new Uint8Array(A.memory.buffer)), s;
504
- }
505
- function h(A2, I2) {
506
- const g2 = I2(1 * A2.length, 1) >>> 0;
507
- return c().set(A2, g2 / 1), r = A2.length, g2;
508
- }
509
- function l(A2, I2) {
510
- return A2 >>>= 0, c().subarray(A2 / 1, A2 / 1 + I2);
511
- }
512
- function D() {
513
- return null !== y && 0 !== y.byteLength || (y = new Float32Array(A.memory.buffer)), y;
514
- }
515
- function w(I2, g2, B2, C2, Q2) {
516
- const t2 = (function(A2, I3) {
517
- const g3 = I3(4 * A2.length, 4) >>> 0;
518
- return D().set(A2, g3 / 4), r = A2.length, g3;
519
- })(I2, A.__wbindgen_malloc), i2 = r, E2 = A.hysteresis_thresholding(t2, i2, g2, B2, C2, Q2);
520
- var e2 = l(E2[0], E2[1]).slice();
521
- return A.__wbindgen_free(E2[0], 1 * E2[1], 1), e2;
522
- }
523
- function f(I2, g2) {
524
- const B2 = g2(2 * I2.length, 2) >>> 0;
525
- return (null !== d && 0 !== d.byteLength || (d = new Uint16Array(A.memory.buffer)), d).set(I2, B2 / 2), r = I2.length, B2;
526
- }
527
- function u(I2, g2, B2, C2, Q2) {
528
- const t2 = f(I2, A.__wbindgen_malloc), i2 = r, E2 = f(g2, A.__wbindgen_malloc), e2 = r, o2 = A.non_maximum_suppression(t2, i2, E2, e2, B2, C2, Q2);
529
- var n2, a2, s2 = (n2 = o2[0], a2 = o2[1], n2 >>>= 0, D().subarray(n2 / 4, n2 / 4 + a2)).slice();
530
- return A.__wbindgen_free(o2[0], 4 * o2[1], 4), s2;
531
- }
532
- async function m(I2) {
533
- if (void 0 !== A) return A;
534
- if (void 0 !== I2 && Object.getPrototypeOf(I2) === Object.prototype && ({ module_or_path: I2 } = I2), void 0 === I2) throw new Error("scanic: WASM module bytes must be passed to init().");
535
- const g2 = (function() {
536
- const I3 = { wbg: {} };
537
- return I3.wbg.__wbindgen_init_externref_table = function() {
538
- const I4 = A.__wbindgen_export_0, g3 = I4.grow(4);
539
- I4.set(0, void 0), I4.set(g3 + 0, void 0), I4.set(g3 + 1, null), I4.set(g3 + 2, true), I4.set(g3 + 3, false);
540
- }, I3;
541
- })();
542
- ("string" == typeof I2 || "function" == typeof Request && I2 instanceof Request || "function" == typeof URL && I2 instanceof URL) && (I2 = fetch(I2));
543
- const { instance: B2, module: C2 } = await (async function(A2, I3) {
544
- if ("function" == typeof Response && A2 instanceof Response) {
545
- if ("function" == typeof WebAssembly.instantiateStreaming) try {
546
- return await WebAssembly.instantiateStreaming(A2, I3);
547
- } catch (g3) {
548
- if ("application/wasm" == A2.headers.get("Content-Type")) throw g3;
549
- }
550
- const B3 = await A2.arrayBuffer();
551
- return await WebAssembly.instantiate(B3, I3);
552
- }
553
- {
554
- const g3 = await WebAssembly.instantiate(A2, I3);
555
- return g3 instanceof WebAssembly.Instance ? { instance: g3, module: A2 } : g3;
556
- }
557
- })(await I2, g2);
558
- return (function(I3, g3) {
559
- return A = I3.exports, m.__wbindgen_wasm_module = g3, y = null, d = null, s = null, A.__wbindgen_start(), A;
560
- })(B2, C2);
561
- }
562
- function F(A2) {
563
- if ("function" == typeof atob) {
564
- const I2 = atob(A2), g2 = new Uint8Array(I2.length);
565
- for (let A3 = 0; A3 < I2.length; A3++) g2[A3] = I2.charCodeAt(A3);
566
- return g2;
567
- }
568
- return Uint8Array.from(Buffer.from(A2, "base64"));
569
- }
570
- async function J() {
571
- if (!(function() {
572
- if (null !== p) return p;
573
- let A2 = false;
574
- if ("object" == typeof WebAssembly && "function" == typeof WebAssembly.validate) {
575
- const I2 = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65, 0, 253, 15, 253, 98, 11]), g2 = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 111, 3, 2, 1, 0, 10, 6, 1, 4, 0, 208, 111, 11]);
576
- try {
577
- A2 = WebAssembly.validate(I2) && WebAssembly.validate(g2);
578
- } catch {
579
- A2 = false;
580
- }
581
- }
582
- return p = A2, A2;
583
- })()) throw new Error("scanic: WebAssembly features required by the WASM module (reference-types, SIMD) are unavailable in this engine; using the JavaScript fallback.");
584
- return await m({ module_or_path: F("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JAAgAiABIAJqIgFLBEBBAEEAEC0ACyADQQRqIAAoAgAiAiAAKAIEQQggASACQQF0IgIgASACSxsiASABQQhNGyIBQQFBARARIAMoAgRBAUYEQCADKAIIIAMoAgwQLQALIAMoAgghAiAAIAE2AgAgACACNgIEIANBEGokAAt5AQF/IwBBIGsiAiQAAn8gACgCAEGAgICAeEcEQCABIAAoAgQgACgCCBAwDAELIAJBEGogACgCDCgCACIAQQhqKQIANwMAIAJBGGogAEEQaikCADcDACACIAApAgA3AwggASgCACABKAIEIAJBCGoQBwsgAkEgaiQAC2kBA38jAEEQayIBJAAgAUEEaiAAKAIAIgIgACgCBEEEIAJBAXQiAiACQQRNGyICQQRBBBARIAEoAgRBAUYEQCABKAIIIAEoAgwQLQALIAEoAgghAyAAIAI2AgAgACADNgIEIAFBEGokAAtpAQN/IwBBEGsiASQAIAFBBGogACgCACICIAAoAgRBBCACQQF0IgIgAkEETRsiAkEEQQgQESABKAIEQQFGBEAgASgCCCABKAIMEC0ACyABKAIIIQMgACACNgIAIAAgAzYCBCABQRBqJAALaQEDfyMAQRBrIgEkACABQQRqIAAoAgAiAiAAKAIEQQQgAkEBdCICIAJBBE0bIgJBAkECEBEgASgCBEEBRgRAIAEoAgggASgCDBAtAAsgASgCCCEDIAAgAjYCACAAIAM2AgQgAUEQaiQACxIAIwBBMGsiACQAIABBMGokAAtoAgF/AX4jAEEwayIDJAAgAyABNgIEIAMgADYCACADQQI2AgwgA0Hkl8AANgIIIANCAjcCFCADQoCAgIAwIgQgA62ENwMoIAMgBCADQQRqrYQ3AyAgAyADQSBqNgIQIANBCGogAhAmAAtHAQF/IAAoAgAgACgCCCIDayACSQRAIAAgAyACEBIgACgCCCEDCyACBEAgACgCBCADaiABIAL8CgAACyAAIAIgA2o2AghBAAtEAQJ/IAEoAgQhAiABKAIAIQNBCEEEEDUiAUUEQEEEQQgQOQALIAEgAjYCBCABIAM2AgAgAEHcksAANgIEIAAgATYCAAvGAgACQCAAIAJNBEAgACABTSABIAJLcg0BIwBBMGsiAiQAIAIgATYCBCACIAA2AgAgAkECNgIMIAJB2JbAADYCCCACQgI3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IAAAABwAEAAMAAAAEgAAABcAAAAcABAADAAAABcAAAAZAAAAHAAQAAwAAAAUAAAAGQAAABwAEAAMAAAAUQAAAB4AAAAcABAADAAAAFIAAAAeAAAATGF6eSBpbnN0YW5jZSBoYXMgcHJldmlvdXNseSBiZWVuIHBvaXNvbmVkAAA8CBAAKgAAAEgBEABaAAAACAMAABkAAAByZWVudHJhbnQgaW5pdAAAgAgQAA4AAABIARAAWgAAAHoCAAANAAAAfP2LMlfmV/kC30S/40jnr21dy9YsUOtjeEGmV3Ebi7ltZW1vcnkgYWxsb2NhdGlvbiBvZiAgYnl0ZXMgZmFpbGVkAADICBAAFQAAAN0IEAANAAAALwEQABgAAABkAQAACQAAAAQAAAAMAAAABAAAAAUAAAAGAAAABwAAAAAAAAAIAAAABAAAAAgAAAAJAAAACgAAAAsAAAAMAAAAEAAAAAQAAAANAAAADgAAAA8AAAAQAAAAAAAAAAgAAAAEAAAAEQAAAGFzc2VydGlvbiBmYWlsZWQ6IHBzaXplID49IHNpemUgKyBtaW5fb3ZlcmhlYWQAAAQBEAAqAAAAsQQAAAkAAABhc3NlcnRpb24gZmFpbGVkOiBwc2l6ZSA8PSBzaXplICsgbWF4X292ZXJoZWFkAAAEARAAKgAAALcEAAANAAAABAAAAAwAAAAEAAAAEgAAAGNhcGFjaXR5IG92ZXJmbG93AAAA/AkQABEAAADjABAAIAAAABwAAAAFAAAAMDAwMTAyMDMwNDA1MDYwNzA4MDkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjEyMjIzMjQyNTI2MjcyODI5MzAzMTMyMzMzNDM1MzYzNzM4Mzk0MDQxNDI0MzQ0NDU0NjQ3NDg0OTUwNTE1MjUzNTQ1NTU2NTc1ODU5NjA2MTYyNjM2NDY1NjY2NzY4Njk3MDcxNzI3Mzc0NzU3Njc3Nzg3OTgwODE4MjgzODQ4NTg2ODc4ODg5OTA5MTkyOTM5NDk1OTY5Nzk4OTlyYW5nZSBlbmQgaW5kZXggIG91dCBvZiByYW5nZSBmb3Igc2xpY2Ugb2YgbGVuZ3RoIAAA8AoQABAAAAAACxAAIgAAAHNsaWNlIGluZGV4IHN0YXJ0cyBhdCAgYnV0IGVuZHMgYXQgADQLEAAWAAAASgsQAA0AAAByYW5nZSBzdGFydCBpbmRleCAAAGgLEAASAAAAAAsQACIAAABhdHRlbXB0IHRvIGRpdmlkZSBieSB6ZXJvAAAAjAsQABkAAABpbmRleCBvdXQgb2YgYm91bmRzOiB0aGUgbGVuIGlzICBidXQgdGhlIGluZGV4IGlzIAAAsAsQACAAAADQCxAAEgAAAAAAAD8AAAC/AEGUmMAACwEBAHwJcHJvZHVjZXJzAghsYW5ndWFnZQEEUnVzdAAMcHJvY2Vzc2VkLWJ5AwVydXN0Yx0xLjkyLjAgKGRlZDVjMDZjZiAyMDI1LTEyLTA4KQZ3YWxydXMGMC4yMy4zDHdhc20tYmluZGdlbhMwLjIuMTAwICgyNDA1ZWMyYjQpAHQPdGFyZ2V0X2ZlYXR1cmVzBysPbXV0YWJsZS1nbG9iYWxzKxNub250cmFwcGluZy1mcHRvaW50KwdzaW1kMTI4KwtidWxrLW1lbW9yeSsIc2lnbi1leHQrD3JlZmVyZW5jZS10eXBlcysKbXVsdGl2YWx1ZQ==") });
585
- }
586
- function G() {
587
- return N || (N = J().catch((A2) => {
588
- throw N = null, A2;
589
- })), N;
590
- }
591
- function k(A2, I2, g2, B2 = 5, C2 = 0) {
592
- 0 === C2 && (C2 = 0.3 * (0.5 * (B2 - 1) - 1) + 0.8);
593
- const Q2 = Math.floor(B2 / 2), t2 = (function(A3, I3) {
594
- const g3 = new Float32Array(A3), B3 = Math.floor(A3 / 2);
595
- let C3 = 0;
596
- for (let Q3 = 0; Q3 < A3; Q3++) {
597
- const A4 = Q3 - B3;
598
- g3[Q3] = Math.exp(-A4 * A4 / (2 * I3 * I3)), C3 += g3[Q3];
599
- }
600
- for (let Q3 = 0; Q3 < A3; Q3++) g3[Q3] /= C3;
601
- return g3;
602
- })(B2, C2), i2 = new Uint8ClampedArray(I2 * g2), E2 = new Uint8ClampedArray(I2 * g2);
603
- for (let e2 = 0; e2 < g2; e2++) {
604
- const g3 = e2 * I2;
605
- for (let B3 = 0; B3 < I2; B3++) {
606
- let C3 = 0;
607
- for (let i3 = -Q2; i3 <= Q2; i3++) {
608
- C3 += A2[g3 + Math.min(I2 - 1, Math.max(0, B3 + i3))] * t2[Q2 + i3];
609
- }
610
- i2[g3 + B3] = C3;
611
- }
612
- }
613
- for (let e2 = 0; e2 < I2; e2++) for (let A3 = 0; A3 < g2; A3++) {
614
- let B3 = 0;
615
- for (let C3 = -Q2; C3 <= Q2; C3++) {
616
- B3 += i2[Math.min(g2 - 1, Math.max(0, A3 + C3)) * I2 + e2] * t2[Q2 + C3];
617
- }
618
- E2[A3 * I2 + e2] = Math.round(B3);
619
- }
620
- return E2;
621
- }
622
- function S(A2, I2, g2, B2, C2) {
623
- const Q2 = new Uint8Array(I2 * g2), t2 = [];
624
- for (let e2 = 1; e2 < g2 - 1; e2++) for (let g3 = 1; g3 < I2 - 1; g3++) {
625
- const i3 = e2 * I2 + g3, E3 = A2[i3];
626
- E3 >= C2 ? (Q2[i3] = 2, t2.push({ x: g3, y: e2 })) : Q2[i3] = E3 >= B2 ? 0 : 1;
627
- }
628
- for (let e2 = 0; e2 < I2; e2++) Q2[e2] = 1, Q2[(g2 - 1) * I2 + e2] = 1;
629
- for (let e2 = 1; e2 < g2 - 1; e2++) Q2[e2 * I2] = 1, Q2[e2 * I2 + I2 - 1] = 1;
630
- const i2 = [-1, 0, 1, -1, 1, -1, 0, 1], E2 = [-1, -1, -1, 0, 0, 1, 1, 1];
631
- for (; t2.length > 0; ) {
632
- const { x: A3, y: g3 } = t2.pop();
633
- for (let B3 = 0; B3 < 8; B3++) {
634
- const C3 = A3 + i2[B3], e2 = g3 + E2[B3], o2 = e2 * I2 + C3;
635
- 0 === Q2[o2] && (Q2[o2] = 2, t2.push({ x: C3, y: e2 }));
636
- }
637
- }
638
- return Q2;
639
- }
640
- async function M(I2, g2 = {}) {
641
- const B2 = !(!g2.debug || g2.debug._timingsOnly), C2 = [], Q2 = performance.now();
642
- let t2, i2, E2;
643
- if (g2.skipGrayscale || false) t2 = g2.width, i2 = g2.height, E2 = I2, B2 && (g2.debug.grayscale = E2);
644
- else {
645
- t2 = I2.width, i2 = I2.height;
646
- let A2 = performance.now();
647
- E2 = (function(A3) {
648
- const { width: I3, height: g3, data: B3 } = A3, C3 = new Uint8ClampedArray(I3 * g3);
649
- for (let Q4 = 0, t3 = 0; Q4 < B3.length; Q4 += 4, t3++) C3[t3] = 54 * B3[Q4] + 183 * B3[Q4 + 1] + 19 * B3[Q4 + 2] >> 8;
650
- return C3;
651
- })(I2);
652
- let Q3 = performance.now();
653
- C2.push({ step: "Grayscale", ms: (Q3 - A2).toFixed(2) }), B2 && (g2.debug.grayscale = E2);
654
- }
655
- let e2 = void 0 !== g2.lowThreshold ? g2.lowThreshold : null, o2 = void 0 !== g2.highThreshold ? g2.highThreshold : null;
656
- if (null === e2 || null === o2) {
657
- const A2 = 1024, I3 = new Uint32Array(A2);
658
- let g3 = 0;
659
- for (let e3 = 1; e3 < i2 - 1; e3++) for (let B4 = 1; B4 < t2 - 1; B4++) {
660
- const C4 = e3 * t2 + B4, Q4 = -E2[C4 - t2 - 1] + E2[C4 - t2 + 1] - 2 * E2[C4 - 1] + 2 * E2[C4 + 1] - E2[C4 + t2 - 1] + E2[C4 + t2 + 1], i3 = -E2[C4 - t2 - 1] - 2 * E2[C4 - t2] - E2[C4 - t2 + 1] + E2[C4 + t2 - 1] + 2 * E2[C4 + t2] + E2[C4 + t2 + 1];
661
- let o3 = Math.abs(Q4) + Math.abs(i3);
662
- o3 >= A2 && (o3 = A2 - 1), o3 > 0 && (I3[o3]++, g3++);
663
- }
664
- const B3 = Math.round(0.7 * g3);
665
- let C3 = 0, Q3 = 75;
666
- for (let t3 = 1; t3 < A2; t3++) if (C3 += I3[t3], C3 >= B3) {
667
- Q3 = t3;
668
- break;
669
- }
670
- null === e2 && (e2 = Math.max(5, Math.round(0.5 * Q3))), null === o2 && (o2 = Math.min(500, Math.round(1.5 * Q3)));
671
- }
672
- const n2 = g2.kernelSize || 5, a2 = g2.sigma || 0, s2 = void 0 !== g2.L2gradient && g2.L2gradient, c2 = void 0 === g2.applyDilation || g2.applyDilation, y2 = g2.dilationKernelSize || 5, D2 = void 0 !== g2.useWasmHysteresis && g2.useWasmHysteresis, d2 = void 0 !== g2.useWasmFullCanny && g2.useWasmFullCanny;
673
- if (e2 >= o2 && ([e2, o2] = [o2, e2]), d2) try {
674
- await G();
675
- const I3 = performance.now(), D3 = new Uint8ClampedArray((function(I4, g3, B3, C3, Q3, t3, i3, E3, e3, o3) {
676
- const n3 = h(I4, A.__wbindgen_malloc), a3 = r, s3 = A.canny_edge_detector_full(n3, a3, g3, B3, C3, Q3, t3, i3, E3, e3, o3);
677
- var c3 = l(s3[0], s3[1]).slice();
678
- return A.__wbindgen_free(s3[0], 1 * s3[1], 1), c3;
679
- })(E2, t2, i2, e2, o2, n2, a2, s2, c2, y2)), w2 = (performance.now() - I3).toFixed(2);
680
- C2.push({ step: "Edge Processing (WASM)", ms: w2 }), B2 && (g2.debug.finalEdges = D3), g2.debug ? g2.debug.timings = C2 : g2.debug = { timings: C2 };
681
- const d3 = performance.now();
682
- return C2.unshift({ step: "Edge Detection Total", ms: (d3 - Q2).toFixed(2) }), D3;
683
- } catch (Y) {
684
- if (!R) {
685
- R = true;
686
- Y instanceof Error ? Y.message : String(Y);
687
- }
688
- }
689
- let f2, m2, N2, p2, F2, J2;
690
- f2 = performance.now();
691
- try {
692
- await G(), N2 = (function(I3, g3, B3, C3, Q3) {
693
- const t3 = h(I3, A.__wbindgen_malloc), i3 = r, E3 = A.blur(t3, i3, g3, B3, C3, Q3);
694
- var e3 = l(E3[0], E3[1]).slice();
695
- return A.__wbindgen_free(E3[0], 1 * E3[1], 1), e3;
696
- })(E2, t2, i2, n2, a2);
697
- } catch {
698
- N2 = k(E2, t2, i2, n2, a2);
699
- }
700
- m2 = performance.now(), C2.push({ step: "Gaussian Blur", ms: (m2 - f2).toFixed(2) }), B2 && (g2.debug.blurred = N2), f2 = performance.now();
701
- {
702
- const A2 = (function(A3, I3, g3) {
703
- const B3 = new Int16Array(I3 * g3), C3 = new Int16Array(I3 * g3);
704
- for (let Q3 = 1; Q3 < g3 - 1; Q3++) {
705
- const g4 = Q3 * I3, t3 = (Q3 - 1) * I3, i3 = (Q3 + 1) * I3;
706
- for (let Q4 = 1; Q4 < I3 - 1; Q4++) {
707
- const I4 = g4 + Q4, E3 = A3[t3 + Q4 - 1], e3 = A3[t3 + Q4], o3 = A3[t3 + Q4 + 1], n3 = A3[g4 + Q4 - 1], a3 = A3[g4 + Q4 + 1], s3 = A3[i3 + Q4 - 1], c3 = A3[i3 + Q4], r2 = A3[i3 + Q4 + 1], h2 = o3 - E3 + 2 * (a3 - n3) + (r2 - s3), l2 = s3 + 2 * c3 + r2 - (E3 + 2 * e3 + o3);
708
- B3[I4] = h2, C3[I4] = l2;
709
- }
710
- }
711
- return { dx: B3, dy: C3 };
712
- })(N2, t2, i2);
713
- p2 = A2.dx, F2 = A2.dy;
714
- }
715
- m2 = performance.now(), C2.push({ step: "Gradients", ms: (m2 - f2).toFixed(2) }), f2 = performance.now();
716
- try {
717
- await G(), J2 = await u(p2, F2, t2, i2, s2);
718
- } catch {
719
- J2 = (function(A2, I3, g3, B3, C3) {
720
- const Q3 = new Float32Array(g3 * B3), t3 = new Float32Array(g3 * B3);
721
- for (let i3 = 0; i3 < A2.length; i3++) {
722
- const g4 = A2[i3], B4 = I3[i3];
723
- Q3[i3] = C3 ? Math.sqrt(g4 * g4 + B4 * B4) : Math.abs(g4) + Math.abs(B4);
724
- }
725
- for (let i3 = 1; i3 < B3 - 1; i3++) for (let B4 = 1; B4 < g3 - 1; B4++) {
726
- const C4 = i3 * g3 + B4, E3 = Q3[C4];
727
- if (0 === E3) {
728
- t3[C4] = 0;
729
- continue;
730
- }
731
- const e3 = A2[C4], o3 = I3[C4];
732
- let n3 = 0, a3 = 0;
733
- const s3 = Math.abs(e3), c3 = Math.abs(o3);
734
- if (c3 > 2.4142 * s3) n3 = Q3[C4 - g3], a3 = Q3[C4 + g3];
735
- else if (s3 > 2.4142 * c3) n3 = Q3[C4 - 1], a3 = Q3[C4 + 1];
736
- else {
737
- const A3 = (e3 ^ o3) < 0 ? -1 : 1;
738
- o3 > 0 ? (n3 = Q3[(i3 - 1) * g3 + (B4 - A3)], a3 = Q3[(i3 + 1) * g3 + (B4 + A3)]) : (n3 = Q3[(i3 + 1) * g3 + (B4 - A3)], a3 = Q3[(i3 - 1) * g3 + (B4 + A3)]), e3 > 0 && o3 > 0 || e3 < 0 && o3 < 0 ? (n3 = Q3[(i3 - 1) * g3 + (B4 + 1)], a3 = Q3[(i3 + 1) * g3 + (B4 - 1)]) : (n3 = Q3[(i3 - 1) * g3 + (B4 - 1)], a3 = Q3[(i3 + 1) * g3 + (B4 + 1)]);
739
- }
740
- t3[C4] = E3 >= n3 && E3 >= a3 ? E3 : 0;
741
- }
742
- return t3;
743
- })(p2, F2, t2, i2, s2);
744
- }
745
- m2 = performance.now(), C2.push({ step: "Non-Max Suppression", ms: (m2 - f2).toFixed(2) }), f2 = performance.now();
746
- const M2 = s2 ? e2 * e2 : e2, b = s2 ? o2 * o2 : o2;
747
- let L;
748
- if (D2) try {
749
- await G(), L = w(J2, t2, i2, M2, b);
750
- } catch (q) {
751
- L = S(J2, t2, i2, M2, b);
752
- }
753
- else L = S(J2, t2, i2, M2, b);
754
- m2 = performance.now(), C2.push({ step: "Hysteresis", ms: (m2 - f2).toFixed(2) }), f2 = performance.now();
755
- const x = new Uint8ClampedArray(t2 * i2);
756
- for (let A2 = 0; A2 < L.length; A2++) x[A2] = 2 === L[A2] ? 255 : 0;
757
- m2 = performance.now(), C2.push({ step: "Binary Image", ms: (m2 - f2).toFixed(2) }), f2 = performance.now();
758
- let U = x;
759
- if (c2) try {
760
- await G(), U = (function(I3, g3, B3, C3) {
761
- const Q3 = h(I3, A.__wbindgen_malloc), t3 = r, i3 = A.dilate(Q3, t3, g3, B3, C3);
762
- var E3 = l(i3[0], i3[1]).slice();
763
- return A.__wbindgen_free(i3[0], 1 * i3[1], 1), E3;
764
- })(x, t2, i2, y2);
765
- } catch {
766
- U = (function(A2, I3, g3, B3 = 5) {
767
- const C3 = Math.floor(B3 / 2), Q3 = new Uint8ClampedArray(I3 * g3), t3 = new Uint8ClampedArray(I3 * g3);
768
- for (let i3 = 0; i3 < g3; i3++) {
769
- const g4 = i3 * I3;
770
- for (let B4 = 0; B4 < I3; B4++) {
771
- let t4 = 0;
772
- for (let Q4 = -C3; Q4 <= C3; Q4++) {
773
- const C4 = B4 + Q4;
774
- if (C4 >= 0 && C4 < I3) {
775
- const I4 = A2[g4 + C4];
776
- I4 > t4 && (t4 = I4);
777
- }
778
- }
779
- Q3[g4 + B4] = t4;
780
- }
781
- }
782
- for (let i3 = 0; i3 < I3; i3++) for (let A3 = 0; A3 < g3; A3++) {
783
- let B4 = 0;
784
- for (let t4 = -C3; t4 <= C3; t4++) {
785
- const C4 = A3 + t4;
786
- if (C4 >= 0 && C4 < g3) {
787
- const A4 = Q3[C4 * I3 + i3];
788
- A4 > B4 && (B4 = A4);
789
- }
790
- }
791
- t3[A3 * I3 + i3] = B4;
792
- }
793
- return t3;
794
- })(x, t2, i2, y2);
795
- }
796
- if (m2 = performance.now(), C2.push({ step: "Dilation", ms: (m2 - f2).toFixed(2) }), B2) {
797
- g2.debug.dx = p2, g2.debug.dy = F2;
798
- const A2 = new Float32Array(t2 * i2);
799
- for (let I3 = 0; I3 < p2.length; I3++) {
800
- const g3 = p2[I3], B3 = F2[I3];
801
- A2[I3] = s2 ? Math.sqrt(g3 * g3 + B3 * B3) : Math.abs(g3) + Math.abs(B3);
802
- }
803
- g2.debug.magnitude = A2, g2.debug.suppressed = J2, g2.debug.edgeMap = L, g2.debug.cannyEdges = x, g2.debug.finalEdges = U;
804
- }
805
- g2.debug ? g2.debug.timings = C2 : g2.debug || (g2.debug = { timings: C2 });
806
- const H = performance.now();
807
- return C2.unshift({ step: "Edge Detection Total", ms: (H - Q2).toFixed(2) }), U;
808
- }
809
- function Z(A2) {
810
- return A2 <= 0 ? 0 : A2 >= 1 ? 1 : A2;
811
- }
812
- function X(A2, I2) {
813
- return Math.hypot(A2.x - I2.x, A2.y - I2.y);
814
- }
815
- function V(A2) {
816
- return [X(A2.topLeft, A2.topRight), X(A2.topRight, A2.bottomRight), X(A2.bottomRight, A2.bottomLeft), X(A2.bottomLeft, A2.topLeft)];
817
- }
818
- function j(A2) {
819
- const I2 = (function(A3) {
820
- const I3 = [A3.topLeft, A3.topRight, A3.bottomRight, A3.bottomLeft], g3 = [];
821
- for (let B2 = 0; B2 < I3.length; B2++) {
822
- const A4 = I3[(B2 + I3.length - 1) % I3.length], C2 = I3[B2], Q2 = I3[(B2 + 1) % I3.length], t2 = A4.x - C2.x, i2 = A4.y - C2.y, E2 = Q2.x - C2.x, e2 = Q2.y - C2.y, o2 = t2 * E2 + i2 * e2, n2 = Math.max(1e-6, Math.hypot(t2, i2) * Math.hypot(E2, e2)), a2 = Math.max(-1, Math.min(1, o2 / n2));
823
- g3.push(180 * Math.acos(a2) / Math.PI);
824
- }
825
- return g3;
826
- })(A2);
827
- let g2 = 0;
828
- for (const B2 of I2) {
829
- g2 += Z(1 - Math.abs(B2 - 90) / 55);
830
- }
831
- return g2 / Math.max(1, I2.length);
832
- }
833
- function O(A2, I2) {
834
- const g2 = Number(I2.isValid) - Number(A2.isValid);
835
- if (0 !== g2) return g2;
836
- const B2 = I2.confidence - A2.confidence;
837
- if (!(Math.abs(B2) < 0.015) && 0 !== B2) return B2;
838
- const C2 = Math.abs((A2.approxCount ?? 99) - 4) - Math.abs((I2.approxCount ?? 99) - 4);
839
- if (0 !== C2) return C2;
840
- const Q2 = (I2.rightAngleScore ?? 0) - (A2.rightAngleScore ?? 0);
841
- if (Math.abs(Q2) > 1e-6) return Q2;
842
- const t2 = Math.abs(1 - (A2.contourFitRatio ?? 1)) - Math.abs(1 - (I2.contourFitRatio ?? 1));
843
- return Math.abs(t2) > 1e-6 ? t2 : B2 || I2.score - A2.score || I2.coverageRatio - A2.coverageRatio || I2.area - A2.area;
844
- }
845
- function z(A2, I2, g2, B2, C2 = {}) {
846
- const Q2 = C2.epsilon || 0.02, t2 = E(A2.points, Q2).length, i2 = n(A2, { epsilon: Q2 });
847
- if (!i2) return { contour: A2, corners: null, score: 0, confidence: 0, isValid: false, area: A2.area || 0, fillRatio: 0, coverageRatio: 0, cornersArea: 0, approxCount: t2, convex: false, edgeSupport: 0, aspectRatio: 1 / 0, minSide: 0, rightAngleScore: 0, oppositeSideConsistency: 0, contourFitRatio: 0, contourFitScore: 0 };
848
- const e2 = g2 * B2, o2 = A2.area || 0, a2 = A2.boundingBox || { minX: 0, minY: 0, maxX: 0, maxY: 0 }, s2 = o2 / Math.max(1, (a2.maxX - a2.minX + 1) * (a2.maxY - a2.minY + 1)), c2 = (function(A3) {
849
- if (!A3) return 0;
850
- const I3 = [A3.topLeft, A3.topRight, A3.bottomRight, A3.bottomLeft];
851
- let g3 = 0;
852
- for (let B3 = 0; B3 < I3.length; B3++) {
853
- const A4 = (B3 + 1) % I3.length;
854
- g3 += I3[B3].x * I3[A4].y - I3[A4].x * I3[B3].y;
855
- }
856
- return Math.abs(g3) / 2;
857
- })(i2), r2 = c2 / Math.max(1, e2), h2 = V(i2), l2 = Math.min(...h2), y2 = (h2[0] + h2[2]) / 2, D2 = (h2[1] + h2[3]) / 2, w2 = y2 > D2 ? y2 / Math.max(1e-6, D2) : D2 / Math.max(1e-6, y2), d2 = (function(A3) {
858
- const I3 = [A3.topLeft, A3.topRight, A3.bottomRight, A3.bottomLeft], g3 = [];
859
- for (let C3 = 0; C3 < I3.length; C3++) {
860
- const A4 = I3[C3], B4 = I3[(C3 + 1) % I3.length], Q3 = I3[(C3 + 2) % I3.length], t3 = (B4.x - A4.x) * (Q3.y - B4.y) - (B4.y - A4.y) * (Q3.x - B4.x);
861
- Math.abs(t3) < 1e-6 || g3.push(Math.sign(t3));
862
- }
863
- if (g3.length < 3) return false;
864
- const B3 = g3[0];
865
- return g3.every((A4) => A4 === B3);
866
- })(i2), f2 = (function(A3, I3, g3, B3) {
867
- if (!A3?.points || 0 === A3.points.length) return 0;
868
- const C3 = Math.max(1, Math.floor(A3.points.length / 240));
869
- let Q3 = 0, t3 = 0;
870
- for (let i3 = 0; i3 < A3.points.length; i3 += C3) {
871
- const C4 = A3.points[i3], E2 = Math.max(0, Math.min(g3 - 1, 0 | C4.x)), e3 = Math.max(0, Math.min(B3 - 1, 0 | C4.y));
872
- Q3++;
873
- let o3 = false;
874
- for (let A4 = -1; A4 <= 1 && !o3; A4++) {
875
- const C5 = e3 + A4;
876
- if (!(C5 < 0 || C5 >= B3)) for (let A5 = -1; A5 <= 1; A5++) {
877
- const B4 = E2 + A5;
878
- if (!(B4 < 0 || B4 >= g3) && I3[C5 * g3 + B4] > 0) {
879
- o3 = true;
880
- break;
881
- }
882
- }
883
- }
884
- o3 && t3++;
885
- }
886
- return 0 === Q3 ? 0 : t3 / Q3;
887
- })(A2, I2, g2, B2), u2 = j(i2), m2 = (function(A3) {
888
- const I3 = V(A3);
889
- return (Math.min(I3[0], I3[2]) / Math.max(1e-6, Math.max(I3[0], I3[2])) + Math.min(I3[1], I3[3]) / Math.max(1e-6, Math.max(I3[1], I3[3]))) / 2;
890
- })(i2), N2 = o2 / Math.max(1, c2), R2 = Z(1 - Math.abs(N2 - 1) / 0.55), p2 = 4 === t2 ? 1 : 5 === t2 ? 0.9 : 6 === t2 ? 0.7 : t2 <= 8 ? 0.5 : 0.28, F2 = Z(o2 / Math.max(1, 0.4 * e2)), J2 = Z((s2 - 0.08) / 0.72), G2 = Z((r2 - 0.03) / 0.82), k2 = void 0 !== C2.minDocumentSideRatio ? C2.minDocumentSideRatio : 0.06, S2 = void 0 !== C2.minDocumentCoverageRatio ? C2.minDocumentCoverageRatio : 0.04, M2 = void 0 !== C2.maxDocumentAspectRatio ? C2.maxDocumentAspectRatio : 8, b = void 0 !== C2.minDocumentFillRatio ? C2.minDocumentFillRatio : 0.07, L = void 0 !== C2.minContourFitRatio ? C2.minContourFitRatio : 0.11, x = void 0 !== C2.maxContourFitRatio ? C2.maxContourFitRatio : 1.2, U = void 0 !== C2.minRightAngleScore ? C2.minRightAngleScore : 0.42, H = void 0 !== C2.minOppositeSideConsistency ? C2.minOppositeSideConsistency : 0.3, Y = Math.min(g2, B2) * k2, q = (function(A3, I3 = 6) {
891
- const g3 = [A3?.topLeft, A3?.topRight, A3?.bottomRight, A3?.bottomLeft];
892
- if (g3.some((A4) => !A4 || !Number.isFinite(A4.x) || !Number.isFinite(A4.y))) return false;
893
- for (let B3 = 0; B3 < g3.length; B3++) for (let A4 = B3 + 1; A4 < g3.length; A4++) if (X(g3[B3], g3[A4]) < I3) return false;
894
- return true;
895
- })(i2) && d2 && l2 >= Y && r2 >= S2 && w2 <= M2 && s2 >= b && N2 >= L && N2 <= x && u2 >= U && m2 >= H, v = 0.22 * F2 + 0.14 * J2 + 0.15 * p2 + 0.08 * (d2 ? 1 : 0) + 0.08 * f2 + 0.13 * G2 + 0.1 * u2 + 0.05 * m2 + 0.05 * R2;
896
- return { contour: A2, corners: i2, score: v, confidence: q ? v : 0.33 * v, isValid: q, area: o2, fillRatio: s2, coverageRatio: r2, cornersArea: c2, approxCount: t2, convex: d2, edgeSupport: f2, aspectRatio: w2, minSide: l2, rightAngleScore: u2, oppositeSideConsistency: m2, contourFitRatio: N2, contourFitScore: R2 };
897
- }
898
- async function _(A2, I2, g2, C2, Q2 = {}) {
899
- const t2 = Q2.debug ? {} : { _timingsOnly: true }, i2 = [];
900
- t2 && !t2._timingsOnly && (t2.preprocessing = { scaledDimensions: { width: I2, height: g2 }, scaleFactor: C2, maxProcessingDimension: Q2.maxProcessingDimension || 800 });
901
- const E2 = (function(A3 = {}) {
902
- const I3 = A3.dilationKernelSize || 3, g3 = A3.dilationIterations || 1, B2 = void 0 === A3.applyDilation || A3.applyDilation, C3 = [{ name: "default", lowThreshold: A3.lowThreshold, highThreshold: A3.highThreshold, dilationKernelSize: I3, dilationIterations: g3, applyDilation: B2 }];
903
- if (false === A3.enableDetectionCascade) return C3;
904
- C3.push({ name: "connect-edges", lowThreshold: A3.lowThreshold, highThreshold: A3.highThreshold, dilationKernelSize: Math.max(I3, 5), dilationIterations: Math.max(g3, 2), applyDilation: true }), C3.push({ name: "no-dilation", lowThreshold: A3.lowThreshold, highThreshold: A3.highThreshold, dilationKernelSize: I3, dilationIterations: g3, applyDilation: false }), void 0 === A3.lowThreshold && void 0 === A3.highThreshold && C3.push({ name: "fixed-mid-thresholds", lowThreshold: 60, highThreshold: 180, dilationKernelSize: I3, dilationIterations: g3, applyDilation: B2 });
905
- const Q3 = [], t3 = /* @__PURE__ */ new Set();
906
- for (const i3 of C3) {
907
- const A4 = [i3.lowThreshold, i3.highThreshold, i3.dilationKernelSize, i3.dilationIterations, i3.applyDilation].join(":");
908
- t3.has(A4) || (t3.add(A4), Q3.push(i3));
909
- }
910
- return Q3;
911
- })(Q2), e2 = [], o2 = async (t3, E3) => {
912
- const e3 = t3.name || `pass-${E3 + 1}`, o3 = 0 === E3 ? "" : ` (${e3})`, n3 = Q2.debug ? {} : { _timingsOnly: true }, a3 = await M(A2, { width: I2, height: g2, lowThreshold: t3.lowThreshold, highThreshold: t3.highThreshold, dilationKernelSize: t3.dilationKernelSize, dilationIterations: t3.dilationIterations, applyDilation: t3.applyDilation, debug: n3, skipGrayscale: true, useWasmBlur: true, useWasmHysteresis: Q2.useWasmHysteresis, useWasmFullCanny: Q2.useWasmFullCanny });
913
- n3.timings && n3.timings.forEach((A3) => {
914
- "Edge Detection Total" !== A3.step && i2.push({ step: `${A3.step}${o3}`, ms: A3.ms });
915
- });
916
- let s3 = performance.now();
917
- const c3 = B(a3, { minArea: (Q2.minArea || 1e3) / (C2 * C2), width: I2, height: g2 });
918
- i2.push({ step: `Find Contours${o3}`, ms: (performance.now() - s3).toFixed(2) }), s3 = performance.now();
919
- const { best: r3, candidates: h3 } = (function(A3, I3, g3, B2, C3 = {}) {
920
- const Q3 = C3.maxCandidateContours || 12, t4 = A3.slice(0, Q3).map((A4, Q4) => ({ rankByArea: Q4, ...z(A4, I3, g3, B2, C3) })).sort(O);
921
- return { best: t4[0] || null, candidates: t4 };
922
- })(c3, a3, I2, g2, Q2);
923
- return i2.push({ step: `Corner Detection${o3}`, ms: (performance.now() - s3).toFixed(2) }), { name: e3, params: { lowThreshold: t3.lowThreshold, highThreshold: t3.highThreshold, dilationKernelSize: t3.dilationKernelSize, dilationIterations: t3.dilationIterations, applyDilation: t3.applyDilation }, contours: c3, best: r3, candidates: h3 };
924
- }, n2 = await o2(E2[0], 0);
925
- if (e2.push(n2), (function(A3, I3 = {}) {
926
- if (false === I3.enableDetectionCascade) return false;
927
- if (!A3 || !A3.corners) return true;
928
- const g3 = void 0 !== I3.minCascadeTriggerConfidence ? I3.minCascadeTriggerConfidence : 0.68;
929
- return !A3.isValid || A3.confidence < g3 || A3.approxCount > 5 || A3.rightAngleScore < 0.55 || A3.contourFitRatio < 0.14;
930
- })(n2.best, Q2)) for (let B2 = 1; B2 < E2.length; B2++) e2.push(await o2(E2[B2], B2));
931
- const a2 = [];
932
- for (const B2 of e2) for (const A3 of B2.candidates) a2.push({ ...A3, passName: B2.name, passParams: B2.params });
933
- a2.sort(O);
934
- const s2 = a2[0] || null, c2 = a2;
935
- if (!s2 || !s2.corners) return { success: false, message: "No document detected", debug: t2._timingsOnly ? null : t2, timings: i2 };
936
- t2 && !t2._timingsOnly && (t2.passes = e2.map((A3) => ({ name: A3.name, params: A3.params, contourCount: A3.contours.length, bestCandidate: A3.best ? { score: A3.best.score, confidence: A3.best.confidence, isValid: A3.best.isValid, approxCount: A3.best.approxCount, coverageRatio: A3.best.coverageRatio, fillRatio: A3.best.fillRatio, rightAngleScore: A3.best.rightAngleScore, contourFitRatio: A3.best.contourFitRatio } : null })), t2.candidates = c2.map((A3) => ({ passName: A3.passName, rankByArea: A3.rankByArea, area: A3.area, fillRatio: A3.fillRatio, coverageRatio: A3.coverageRatio, cornersArea: A3.cornersArea, approxCount: A3.approxCount, convex: A3.convex, edgeSupport: A3.edgeSupport, aspectRatio: A3.aspectRatio, minSide: A3.minSide, rightAngleScore: A3.rightAngleScore, oppositeSideConsistency: A3.oppositeSideConsistency, contourFitRatio: A3.contourFitRatio, contourFitScore: A3.contourFitScore, score: A3.score, confidence: A3.confidence, isValid: A3.isValid })), t2.selectedCandidate = c2[0] ? { passName: c2[0].passName, rankByArea: c2[0].rankByArea, area: c2[0].area, fillRatio: c2[0].fillRatio, coverageRatio: c2[0].coverageRatio, approxCount: c2[0].approxCount, edgeSupport: c2[0].edgeSupport, aspectRatio: c2[0].aspectRatio, minSide: c2[0].minSide, rightAngleScore: c2[0].rightAngleScore, oppositeSideConsistency: c2[0].oppositeSideConsistency, contourFitRatio: c2[0].contourFitRatio, score: c2[0].score, confidence: c2[0].confidence, isValid: c2[0].isValid } : null);
937
- const r2 = s2.corners, h2 = s2.contour;
938
- let l2 = r2;
939
- return 1 !== C2 && (l2 = { topLeft: { x: r2.topLeft.x * C2, y: r2.topLeft.y * C2 }, topRight: { x: r2.topRight.x * C2, y: r2.topRight.y * C2 }, bottomRight: { x: r2.bottomRight.x * C2, y: r2.bottomRight.y * C2 }, bottomLeft: { x: r2.bottomLeft.x * C2, y: r2.bottomLeft.y * C2 } }), { success: true, contour: h2, corners: l2, confidence: s2.confidence, debug: t2._timingsOnly ? null : t2, timings: i2 };
940
- }
941
- function $(A2, I2, g2) {
942
- const { topLeft: B2, topRight: C2, bottomRight: Q2, bottomLeft: t2 } = g2, i2 = Math.hypot(Q2.x - t2.x, Q2.y - t2.y), E2 = Math.hypot(C2.x - B2.x, C2.y - B2.y), e2 = Math.round(Math.max(i2, E2)), o2 = Math.hypot(C2.x - Q2.x, C2.y - Q2.y), n2 = Math.hypot(B2.x - t2.x, B2.y - t2.y), a2 = Math.round(Math.max(o2, n2));
943
- A2.canvas.width = e2, A2.canvas.height = a2, (function(A3, I3, g3, B3, C3) {
944
- const Q3 = I3 && "number" == typeof I3.width && "number" == typeof I3.height && I3.data, t3 = I3.width || I3.naturalWidth, i3 = I3.height || I3.naturalHeight, E3 = document.createElement("canvas");
945
- E3.width = t3, E3.height = i3;
946
- const e3 = E3.getContext("2d", { willReadFrequently: true });
947
- Q3 ? e3.putImageData(I3, 0, 0) : e3.drawImage(I3, 0, 0, t3, i3);
948
- const o3 = e3.getImageData(0, 0, t3, i3).data, n3 = (function(A4) {
949
- const I4 = A4[0][0], g4 = A4[0][1], B4 = A4[0][2], C4 = A4[1][0], Q4 = A4[1][1], t4 = A4[1][2], i4 = A4[2][0], E4 = A4[2][1], e4 = A4[2][2], o4 = Q4 * e4 - t4 * E4, n4 = -(C4 * e4 - t4 * i4), a4 = C4 * E4 - Q4 * i4, s3 = -(g4 * e4 - B4 * E4), c3 = I4 * e4 - B4 * i4, r3 = -(I4 * E4 - g4 * i4), h3 = g4 * t4 - B4 * Q4, l3 = -(I4 * t4 - B4 * C4), y3 = I4 * Q4 - g4 * C4, D3 = I4 * o4 + g4 * n4 + B4 * a4;
950
- if (0 === D3) throw new Error("Singular matrix");
951
- return [[o4 / D3, s3 / D3, h3 / D3], [n4 / D3, c3 / D3, l3 / D3], [a4 / D3, r3 / D3, y3 / D3]];
952
- })(g3), a3 = n3[0][0], s2 = n3[0][1], c2 = n3[0][2], r2 = n3[1][0], h2 = n3[1][1], l2 = n3[1][2], y2 = n3[2][0], D2 = n3[2][1], w2 = n3[2][2], d2 = A3.createImageData(B3, C3), f2 = d2.data, u2 = t3 - 1, m2 = i3 - 1;
953
- for (let N2 = 0; N2 < C3; N2++) {
954
- const A4 = s2 * N2 + c2, I4 = h2 * N2 + l2, g4 = D2 * N2 + w2;
955
- for (let C4 = 0; C4 < B3; C4++) {
956
- const Q4 = 1 / (y2 * C4 + g4), i4 = (a3 * C4 + A4) * Q4, E4 = (r2 * C4 + I4) * Q4, e4 = i4 < 0 ? 0 : i4 > u2 ? u2 : i4, n4 = E4 < 0 ? 0 : E4 > m2 ? m2 : E4, s3 = 0 | e4, c3 = 0 | n4, h3 = s3 < u2 ? s3 + 1 : s3, l3 = c3 < m2 ? c3 + 1 : c3, D3 = e4 - s3, w3 = n4 - c3, d3 = 1 - D3, R2 = 1 - w3, p2 = d3 * R2, F2 = D3 * R2, J2 = d3 * w3, G2 = D3 * w3, k2 = c3 * t3 + s3 << 2, S2 = c3 * t3 + h3 << 2, M2 = l3 * t3 + s3 << 2, b = l3 * t3 + h3 << 2, L = N2 * B3 + C4 << 2;
957
- f2[L] = o3[k2] * p2 + o3[S2] * F2 + o3[M2] * J2 + o3[b] * G2 + 0.5 | 0, f2[L + 1] = o3[k2 + 1] * p2 + o3[S2 + 1] * F2 + o3[M2 + 1] * J2 + o3[b + 1] * G2 + 0.5 | 0, f2[L + 2] = o3[k2 + 2] * p2 + o3[S2 + 2] * F2 + o3[M2 + 2] * J2 + o3[b + 2] * G2 + 0.5 | 0, f2[L + 3] = 255;
958
- }
959
- }
960
- A3.putImageData(d2, 0, 0);
961
- })(A2, I2, (function(A3, I3) {
962
- const g3 = (function(A4, I4) {
963
- const g4 = A4.length, B3 = A4[0].length, C3 = A4.map((A5) => A5.slice()), Q3 = I4.slice();
964
- for (let i3 = 0; i3 < B3; i3++) {
965
- let A5 = i3;
966
- for (let I5 = i3 + 1; I5 < g4; I5++) Math.abs(C3[I5][i3]) > Math.abs(C3[A5][i3]) && (A5 = I5);
967
- [C3[i3], C3[A5]] = [C3[A5], C3[i3]], [Q3[i3], Q3[A5]] = [Q3[A5], Q3[i3]];
968
- for (let I5 = i3 + 1; I5 < g4; I5++) {
969
- const A6 = C3[I5][i3] / C3[i3][i3];
970
- for (let g5 = i3; g5 < B3; g5++) C3[I5][g5] -= A6 * C3[i3][g5];
971
- Q3[I5] -= A6 * Q3[i3];
972
- }
973
- }
974
- const t3 = new Array(B3);
975
- for (let i3 = B3 - 1; i3 >= 0; i3--) {
976
- let A5 = Q3[i3];
977
- for (let I5 = i3 + 1; I5 < B3; I5++) A5 -= C3[i3][I5] * t3[I5];
978
- t3[i3] = A5 / C3[i3][i3];
979
- }
980
- return t3;
981
- })((function(A4) {
982
- const g4 = [];
983
- for (let B3 = 0; B3 < 4; B3++) {
984
- const [C3, Q3] = A4[B3];
985
- g4.push([C3, Q3, 1, 0, 0, 0, -C3 * I3[B3][0], -Q3 * I3[B3][0]]), g4.push([0, 0, 0, C3, Q3, 1, -C3 * I3[B3][1], -Q3 * I3[B3][1]]);
986
- }
987
- return g4;
988
- })(A3), [I3[0][0], I3[0][1], I3[1][0], I3[1][1], I3[2][0], I3[2][1], I3[3][0], I3[3][1]]);
989
- return [[g3[0], g3[1], g3[2]], [g3[3], g3[4], g3[5]], [g3[6], g3[7], 1]];
990
- })([[B2.x, B2.y], [C2.x, C2.y], [Q2.x, Q2.y], [t2.x, t2.y]], [[0, 0], [e2 - 1, 0], [e2 - 1, a2 - 1], [0, a2 - 1]]), e2, a2);
991
- }
992
- async function IA(A2, I2 = {}) {
993
- const g2 = [], B2 = performance.now(), C2 = I2.mode || "detect", Q2 = I2.output || "canvas", t2 = I2.maxProcessingDimension || 800;
994
- let i2, E2, e2, o2;
995
- if ("ml" === (I2.detector || "classical")) {
996
- E2 = performance.now();
997
- const { detectDocumentMl: B3 } = await Promise.resolve().then(() => (init_scanic_ml_stub(), scanic_ml_stub_exports));
998
- i2 = await B3(A2, I2.ml || {}), g2.push({ step: "ML Detection Total", ms: (performance.now() - E2).toFixed(2) }), i2.timings && i2.timings.forEach((A3) => g2.push(A3));
999
- } else {
1000
- E2 = performance.now();
1001
- const { grayscaleData: B3, scaleFactor: C3, scaledDimensions: Q3 } = await (async function(A3, I3 = 800) {
1002
- let g3, B4;
1003
- const C4 = A3 && "number" == typeof A3.width && "number" == typeof A3.height && A3.data;
1004
- if (C4) g3 = A3.width, B4 = A3.height;
1005
- else {
1006
- if (!A3) throw new Error("No image provided");
1007
- g3 = A3.width || A3.naturalWidth, B4 = A3.height || A3.naturalHeight;
1008
- }
1009
- const Q4 = Math.max(g3, B4);
1010
- let t3, i3, E3;
1011
- if (Q4 <= I3) t3 = g3, i3 = B4, E3 = 1;
1012
- else {
1013
- const A4 = I3 / Q4;
1014
- t3 = Math.round(g3 * A4), i3 = Math.round(B4 * A4), E3 = 1 / A4;
1015
- }
1016
- const e3 = "undefined" != typeof OffscreenCanvas, o3 = e3 ? new OffscreenCanvas(t3, i3) : document.createElement("canvas");
1017
- e3 || (o3.width = t3, o3.height = i3);
1018
- const n3 = o3.getContext("2d", { willReadFrequently: true });
1019
- if (n3.imageSmoothingEnabled = true, n3.imageSmoothingQuality = "medium", C4) {
1020
- const I4 = e3 ? new OffscreenCanvas(g3, B4) : document.createElement("canvas");
1021
- e3 || (I4.width = g3, I4.height = B4), I4.getContext("2d").putImageData(A3, 0, 0), n3.drawImage(I4, 0, 0, g3, B4, 0, 0, t3, i3);
1022
- } else n3.drawImage(A3, 0, 0, g3, B4, 0, 0, t3, i3);
1023
- const a2 = n3.getImageData(0, 0, t3, i3), s2 = a2.data, c2 = new Uint8ClampedArray(t3 * i3);
1024
- for (let r2 = 0, h2 = 0; r2 < s2.length; r2 += 4, h2++) {
1025
- const A4 = 54 * s2[r2] + 183 * s2[r2 + 1] + 19 * s2[r2 + 2] >> 8;
1026
- c2[h2] = A4, s2[r2] = s2[r2 + 1] = s2[r2 + 2] = A4;
1027
- }
1028
- return { grayscaleData: c2, imageData: a2, scaleFactor: E3, originalDimensions: { width: g3, height: B4 }, scaledDimensions: { width: t3, height: i3 } };
1029
- })(A2, t2);
1030
- g2.push({ step: "Image Prep + Scale + Gray", ms: (performance.now() - E2).toFixed(2) }), i2 = await _(B3, Q3.width, Q3.height, C3, I2), i2.timings && i2.timings.forEach((A3) => g2.push(A3));
1031
- }
1032
- if (!i2.success) {
1033
- const A3 = performance.now();
1034
- return g2.unshift({ step: "Total", ms: (A3 - B2).toFixed(2) }), { output: null, corners: null, contour: null, confidence: i2.confidence || null, score: i2.score ?? null, debug: i2.debug, success: false, message: i2.message || "No document detected", timings: g2 };
1035
- }
1036
- "detect" === C2 ? o2 = null : "extract" === C2 && (E2 = performance.now(), e2 = document.createElement("canvas"), $(e2.getContext("2d"), A2, i2.corners), g2.push({ step: "Perspective Transform", ms: (performance.now() - E2).toFixed(2) })), "detect" !== C2 && e2 && (E2 = performance.now(), o2 = "canvas" === Q2 ? e2 : "imagedata" === Q2 ? e2.getContext("2d").getImageData(0, 0, e2.width, e2.height) : "dataurl" === Q2 ? e2.toDataURL() : e2, g2.push({ step: "Output Conversion", ms: (performance.now() - E2).toFixed(2) }));
1037
- const n2 = performance.now();
1038
- return g2.unshift({ step: "Total", ms: (n2 - B2).toFixed(2) }), { output: o2, corners: i2.corners, contour: i2.contour ?? null, confidence: i2.confidence || null, score: i2.score ?? null, debug: i2.debug, success: true, message: "Document detected", timings: g2 };
1039
- }
1040
- var A, I, g, s, r, y, d, N, R, p;
1041
- var init_scanic = __esm({
1042
- "vendor/scanic/scanic.js"() {
1043
- "use strict";
1044
- I = 1e3;
1045
- g = 10;
1046
- s = null;
1047
- r = 0;
1048
- y = null;
1049
- d = null;
1050
- N = null;
1051
- R = false;
1052
- p = null;
1053
- }
1054
- });
1055
-
1056
- // src/core/doc/detector-scanic.ts
1057
- var detector_scanic_exports = {};
1058
- __export(detector_scanic_exports, {
1059
- DOC_DETECT_MIN_CONFIDENCE: () => DOC_DETECT_MIN_CONFIDENCE,
1060
- DOC_DETECT_WIDTH: () => DOC_DETECT_WIDTH,
1061
- SCANIC_VERSION: () => SCANIC_VERSION,
1062
- detectQuad: () => detectQuad
1063
- });
1064
- async function detectQuad(image) {
1065
- const result = await IA(image, {
1066
- mode: "detect",
1067
- detector: "classical",
1068
- maxProcessingDimension: DOC_DETECT_WIDTH
1069
- });
1070
- if (!result.success || result.corners === null) return null;
1071
- if (typeof result.confidence === "number" && result.confidence < DOC_DETECT_MIN_CONFIDENCE) {
1072
- return null;
1073
- }
1074
- return result.corners;
1075
- }
1076
- var SCANIC_VERSION, DOC_DETECT_MIN_CONFIDENCE;
1077
- var init_detector_scanic = __esm({
1078
- "src/core/doc/detector-scanic.ts"() {
1079
- "use strict";
1080
- init_scanic();
1081
- init_doc_gate_v1();
1082
- SCANIC_VERSION = "1.5.0";
1083
- DOC_DETECT_MIN_CONFIDENCE = 0.35;
1084
- }
1085
- });
1086
-
1087
- // src/internal/index.ts
1088
- var internal_exports = {};
1089
- __export(internal_exports, {
1090
- ASPECT_BANDS: () => ASPECT_BANDS,
1091
- AttestationError: () => AttestationError,
1092
- CAPTURE_CANDIDATE_SPACING_MS: () => CAPTURE_CANDIDATE_SPACING_MS,
1093
- CAPTURE_EXTRA_CANDIDATES: () => CAPTURE_EXTRA_CANDIDATES,
1094
- CENTERED_FACTOR: () => CENTERED_FACTOR,
1095
- CIRCLE_RADIUS_FACTOR: () => CIRCLE_RADIUS_FACTOR,
1096
- CLIP_MIME_ALLOWLIST: () => CLIP_MIME_ALLOWLIST,
1097
- CaptureSessionDoc: () => CaptureSessionDoc,
1098
- DOC_ANALYSIS_DEFAULTS: () => DOC_ANALYSIS_DEFAULTS,
1099
- DOC_CADENCE_HZ: () => DOC_CADENCE_HZ,
1100
- DOC_DETECT_WIDTH: () => DOC_DETECT_WIDTH,
1101
- DOC_FEEDBACK_STATES: () => DOC_FEEDBACK_STATES,
1102
- DOC_GATE_V1_DEFAULTS: () => DOC_GATE_V1_DEFAULTS,
1103
- DocFeedbackAggregator: () => DocFeedbackAggregator,
1104
- DocGateV1: () => DocGateV1,
1105
- IN_CIRCLE_FACTOR: () => IN_CIRCLE_FACTOR,
1106
- MRZ_BAND_DEFAULTS: () => MRZ_BAND_DEFAULTS,
1107
- MR_DOC_CATALOG: () => MR_DOC_CATALOG,
1108
- PRELOAD_BLAZE_INIT_TIMEOUT_MS: () => PRELOAD_BLAZE_INIT_TIMEOUT_MS,
1109
- PRELOAD_BUDGET_MS: () => PRELOAD_BUDGET_MS,
1110
- PROCESSING_POLL_DELAY_MS: () => PROCESSING_POLL_DELAY_MS,
1111
- PROCESSING_POLL_MAX: () => PROCESSING_POLL_MAX,
1112
- REGISTRY_RETRY_DELAY_MS: () => REGISTRY_RETRY_DELAY_MS,
1113
- RETRYABLE_REASONS: () => RETRYABLE_REASONS,
1114
- TRANSPORT_REPLAY_ATTEMPTS: () => TRANSPORT_REPLAY_ATTEMPTS,
1115
- TRANSPORT_REPLAY_DELAY_MS: () => TRANSPORT_REPLAY_DELAY_MS,
1116
- TURNSTILE_EXECUTE_TIMEOUT_MS: () => TURNSTILE_EXECUTE_TIMEOUT_MS,
1117
- TURNSTILE_SCRIPT_SRC: () => TURNSTILE_SCRIPT_SRC,
1118
- analyzeDocFrame: () => analyzeDocFrame,
1119
- aspectBand: () => aspectBand,
1120
- createLivenessCaptureInternal: () => createLivenessCaptureInternal,
1121
- createVerificationInternal: () => createVerificationInternal,
1122
- detectMrzBand: () => detectMrzBand,
1123
- executeTurnstile: () => executeTurnstile,
1124
- feedbackVoteOf: () => feedbackVoteOf,
1125
- frontierStep: () => frontierStep,
1126
- isExecutable: () => isExecutable,
1127
- isTerminalView: () => isTerminalView,
1128
- loadTurnstile: () => loadTurnstile,
1129
- mapEngineState: () => mapEngineState,
1130
- mapErrorKind: () => mapErrorKind,
1131
- mapGuidanceHint: () => mapGuidanceHint,
1132
- mapSessionResult: () => mapSessionResult,
1133
- mergeSessionView: () => mergeSessionView,
1134
- preloadedDetectorFactory: () => preloadedDetectorFactory,
1135
- quadAreaFrac: () => quadAreaFrac,
1136
- quadBounds: () => quadBounds,
1137
- quadIou: () => quadIou,
1138
- quadTiltRatio: () => quadTiltRatio,
1139
- randomUuid: () => randomUuid,
1140
- resetLivenessAssetsForTests: () => resetLivenessAssetsForTests,
1141
- resetTurnstileForTests: () => resetTurnstileForTests,
1142
- runLivenessFlow: () => runLivenessFlow,
1143
- runSubmission: () => runSubmission,
1144
- setPreloadLoaderForTests: () => setPreloadLoaderForTests,
1145
- specularFraction: () => specularFraction,
1146
- stepOf: () => stepOf,
1147
- warmDocDetector: () => warmDocDetector
1148
- });
1149
- module.exports = __toCommonJS(internal_exports);
1150
- init_doc_catalog();
1151
- init_doc_gate_v1();
1152
-
1153
- // src/core/doc/mrz-band.ts
1154
- var MRZ_BAND_DEFAULTS = Object.freeze({
1155
- EDGE_LUMA_DELTA: 40,
1156
- MIN_ROW_DENSITY: 0.08,
1157
- MIN_COLUMN_COVERAGE: 0.6,
1158
- MIN_WIDTH_FRAC: 0.55,
1159
- MIN_HEIGHT_FRAC: 0.02,
1160
- MAX_HEIGHT_FRAC: 0.16,
1161
- ROW_MERGE_GAP: 18
1162
- });
1163
- var COLUMN_BUCKETS = 12;
1164
- function detectMrzBand(frame, overrides = {}) {
1165
- const t2 = { ...MRZ_BAND_DEFAULTS, ...overrides };
1166
- const { data, width, height } = frame;
1167
- if (width < 32 || height < 32) return null;
1168
- const qualifies = new Array(height).fill(false);
1169
- const density = new Float32Array(height);
1170
- const minX = new Int32Array(height).fill(width);
1171
- const maxX = new Int32Array(height).fill(-1);
1172
- const bucketWidth = width / COLUMN_BUCKETS;
1173
- const buckets = new Array(COLUMN_BUCKETS);
1174
- for (let y2 = 0; y2 < height; y2++) {
1175
- let edges = 0;
1176
- buckets.fill(false);
1177
- const rowOffset = y2 * width * 4;
1178
- let previousLuma = 0.299 * (data[rowOffset] ?? 0) + 0.587 * (data[rowOffset + 1] ?? 0) + 0.114 * (data[rowOffset + 2] ?? 0);
1179
- for (let x = 1; x < width; x++) {
1180
- const i2 = rowOffset + x * 4;
1181
- const luma = 0.299 * (data[i2] ?? 0) + 0.587 * (data[i2 + 1] ?? 0) + 0.114 * (data[i2 + 2] ?? 0);
1182
- if (Math.abs(luma - previousLuma) >= t2.EDGE_LUMA_DELTA) {
1183
- edges += 1;
1184
- buckets[Math.min(COLUMN_BUCKETS - 1, Math.floor(x / bucketWidth))] = true;
1185
- if (x < minX[y2]) minX[y2] = x;
1186
- if (x > maxX[y2]) maxX[y2] = x;
1187
- }
1188
- previousLuma = luma;
1189
- }
1190
- density[y2] = edges / width;
1191
- const coverage = buckets.filter(Boolean).length / COLUMN_BUCKETS;
1192
- qualifies[y2] = density[y2] >= t2.MIN_ROW_DENSITY && coverage >= t2.MIN_COLUMN_COVERAGE && maxX[y2] - minX[y2] >= t2.MIN_WIDTH_FRAC * width;
1193
- }
1194
- let best = null;
1195
- let runTop = -1;
1196
- let lastQualifying = -1;
1197
- let runRows = 0;
1198
- const flush = (bottom) => {
1199
- if (runTop < 0) return;
1200
- const bandHeight = bottom - runTop + 1;
1201
- if (bandHeight >= t2.MIN_HEIGHT_FRAC * height && bandHeight <= t2.MAX_HEIGHT_FRAC * height && runRows >= 4 && // at least a few real stroke rows, not a lone edge
1202
- (best === null || runRows > best.rows)) {
1203
- best = { top: runTop, bottom, rows: runRows };
1204
- }
1205
- runTop = -1;
1206
- runRows = 0;
1207
- };
1208
- for (let y2 = 0; y2 < height; y2++) {
1209
- if (qualifies[y2]) {
1210
- if (runTop < 0) runTop = y2;
1211
- else if (y2 - lastQualifying > t2.ROW_MERGE_GAP) {
1212
- flush(lastQualifying);
1213
- runTop = y2;
1214
- }
1215
- lastQualifying = y2;
1216
- runRows += 1;
1217
- }
1218
- }
1219
- flush(lastQualifying);
1220
- if (best === null) return null;
1221
- const band = best;
1222
- let x1 = width;
1223
- let x2 = -1;
1224
- let densitySum = 0;
1225
- let densityRows = 0;
1226
- for (let y2 = band.top; y2 <= band.bottom; y2++) {
1227
- if (!qualifies[y2]) continue;
1228
- if (minX[y2] < x1) x1 = minX[y2];
1229
- if (maxX[y2] > x2) x2 = maxX[y2];
1230
- densitySum += density[y2];
1231
- densityRows += 1;
1232
- }
1233
- if (x2 - x1 < t2.MIN_WIDTH_FRAC * width) return null;
1234
- return {
1235
- x: x1,
1236
- y: band.top,
1237
- width: x2 - x1,
1238
- height: band.bottom - band.top + 1,
1239
- density: densityRows > 0 ? densitySum / densityRows : 0
1240
- };
1241
- }
1242
-
1243
- // src/core/doc/frame-analysis.ts
1244
- init_frame_quality();
1245
- init_doc_catalog();
1246
- init_doc_gate_v1();
1247
- var DOC_ANALYSIS_DEFAULTS = Object.freeze({
1248
- /** Doc area fraction above which the camera is too close (capture would crop). */
1249
- MAX_AREA_FRAC: 0.92,
1250
- /** Opposite-side length ratio beyond which the view is too oblique. */
1251
- TILT_MAX_SIDE_RATIO: 1.3,
1252
- /** Specular-pixel fraction at/above which the frame reads as glare. */
1253
- GLARE_MAX_SPECULAR_FRAC: 0.025
1254
- });
1255
- function specularFraction(crop) {
1256
- const { data, width, height } = crop;
1257
- const pixels = width * height;
1258
- if (pixels === 0) return 0;
1259
- let hot = 0;
1260
- for (let i2 = 0; i2 < pixels; i2++) {
1261
- const o2 = i2 * 4;
1262
- const luma = 0.299 * (data[o2] ?? 0) + 0.587 * (data[o2 + 1] ?? 0) + 0.114 * (data[o2 + 2] ?? 0);
1263
- if (luma >= 252) hot++;
1264
- }
1265
- return hot / pixels;
1266
- }
1267
- function quadTiltRatio(quad) {
1268
- const len = (a2, b) => Math.hypot(b.x - a2.x, b.y - a2.y);
1269
- const top = len(quad.topLeft, quad.topRight);
1270
- const bottom = len(quad.bottomLeft, quad.bottomRight);
1271
- const left = len(quad.topLeft, quad.bottomLeft);
1272
- const right = len(quad.topRight, quad.bottomRight);
1273
- const h2 = Math.max(top, bottom) / Math.max(1e-6, Math.min(top, bottom));
1274
- const v = Math.max(left, right) / Math.max(1e-6, Math.min(left, right));
1275
- return Math.max(h2, v);
1276
- }
1277
- function analyzeDocFrame(input) {
1278
- const t2 = { ...DOC_GATE_V1_DEFAULTS, ...input.thresholds };
1279
- const a2 = DOC_ANALYSIS_DEFAULTS;
1280
- const { quad, frameWidth, frameHeight, measures } = input;
1281
- const bandMode = input.format === "ID-3";
1282
- let framing = "ok";
1283
- if (quad === null) {
1284
- framing = "no_document";
1285
- } else if (bandMode) {
1286
- const bounds = quadBounds(quad);
1287
- const widthFrac = frameWidth > 0 ? bounds.width / frameWidth : 0;
1288
- const aspect = bounds.height > 0 ? bounds.width / bounds.height : 0;
1289
- if (widthFrac < t2.ID3_BAND_MIN_WIDTH_FRAC) framing = "too_far";
1290
- else if (edgeClipped(quad, frameWidth, frameHeight, t2.EDGE_CLIP_MARGIN_PX)) {
1291
- framing = "edge_clipped";
1292
- } else if (aspect < t2.ID3_BAND_ASPECT_MIN || aspect > t2.ID3_BAND_ASPECT_MAX) {
1293
- framing = "wrong_shape";
1294
- }
1295
- } else {
1296
- const areaFrac = quadAreaFrac(quad, frameWidth, frameHeight);
1297
- const band = aspectBand(input.format);
1298
- const bounds = quadBounds(quad);
1299
- const aspect = Math.max(bounds.width, bounds.height) / Math.max(1e-6, Math.min(bounds.width, bounds.height));
1300
- if (areaFrac < t2.MIN_AREA_FRAC) framing = "too_far";
1301
- else if (areaFrac > a2.MAX_AREA_FRAC) framing = "too_close";
1302
- else if (edgeClipped(quad, frameWidth, frameHeight, t2.EDGE_CLIP_MARGIN_PX)) {
1303
- framing = "edge_clipped";
1304
- } else if (Math.abs(aspect - band.center) > band.tolerance) framing = "wrong_shape";
1305
- else if (quadTiltRatio(quad) > a2.TILT_MAX_SIDE_RATIO) framing = "tilted";
1306
- }
1307
- const lighting = measures.exposure >= t2.GUIDE_EXPOSURE ? "ok" : measures.meanLuma < (EXPOSURE_BAND[0] + EXPOSURE_BAND[1]) / 2 ? "too_dark" : "too_bright";
1308
- const blur = measures.sharpness >= t2.GUIDE_SHARPNESS ? "ok" : "blurry";
1309
- const glare = measures.specularFraction >= a2.GLARE_MAX_SPECULAR_FRAC ? "glare" : "ok";
1310
- return {
1311
- framing,
1312
- lighting,
1313
- blur,
1314
- glare,
1315
- acceptable: framing === "ok" && lighting === "ok" && blur === "ok" && glare === "ok"
1316
- };
1317
- }
1318
- function edgeClipped(quad, frameWidth, frameHeight, margin) {
1319
- const pts = [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft];
1320
- return pts.some(
1321
- (p2) => p2.x <= margin || p2.y <= margin || p2.x >= frameWidth - margin || p2.y >= frameHeight - margin
1322
- );
1323
- }
1324
-
1325
- // src/core/doc/feedback-aggregator.ts
1326
- var DOC_FEEDBACK_STATES = Object.freeze({
1327
- sensing: { key: "sensing", reticle: "searching", minDurationMs: 900 },
1328
- too_far: { key: "too_far", reticle: "coaching", minDurationMs: 1400 },
1329
- too_close: { key: "too_close", reticle: "coaching", minDurationMs: 1400 },
1330
- edge_clipped: { key: "edge_clipped", reticle: "coaching", minDurationMs: 1400 },
1331
- wrong_shape: { key: "wrong_shape", reticle: "coaching", minDurationMs: 1400 },
1332
- tilted: { key: "tilted", reticle: "coaching", minDurationMs: 1400 },
1333
- too_dark: { key: "too_dark", reticle: "coaching", minDurationMs: 1400 },
1334
- too_bright: { key: "too_bright", reticle: "coaching", minDurationMs: 1400 },
1335
- blurry: { key: "blurry", reticle: "coaching", minDurationMs: 1400 },
1336
- glare: { key: "glare", reticle: "coaching", minDurationMs: 1400 },
1337
- hold_still: { key: "hold_still", reticle: "locking", minDurationMs: 900 },
1338
- processing: { key: "processing", reticle: "processing", minDurationMs: 800 },
1339
- side_captured: { key: "side_captured", reticle: "flip", minDurationMs: 2600 },
1340
- captured: { key: "captured", reticle: "done", minDurationMs: 800 }
1341
- });
1342
- function feedbackVoteOf(analysis) {
1343
- if (analysis.framing === "no_document") return "sensing";
1344
- if (analysis.framing === "too_far") return "too_far";
1345
- if (analysis.framing === "too_close") return "too_close";
1346
- if (analysis.framing === "edge_clipped") return "edge_clipped";
1347
- if (analysis.framing === "wrong_shape") return "wrong_shape";
1348
- if (analysis.framing === "tilted") return "tilted";
1349
- if (analysis.lighting === "too_dark") return "too_dark";
1350
- if (analysis.lighting === "too_bright") return "too_bright";
1351
- if (analysis.glare === "glare") return "glare";
1352
- if (analysis.blur === "blurry") return "blurry";
1353
- return "hold_still";
1354
- }
1355
- var DocFeedbackAggregator = class {
1356
- constructor(windowMs = 2600, decayPerSecond = 0.35) {
1357
- this.windowMs = windowMs;
1358
- this.decayPerSecond = decayPerSecond;
1359
- this.votes = [];
1360
- this.current = DOC_FEEDBACK_STATES.sensing;
1361
- this.currentSinceMs = null;
1362
- }
1363
- reset() {
1364
- this.votes = [];
1365
- this.current = DOC_FEEDBACK_STATES.sensing;
1366
- this.currentSinceMs = null;
1367
- }
1368
- /** Force a terminal/choreography state (capture fired, side flip, upload). */
1369
- force(key, nowMs) {
1370
- this.votes = [];
1371
- this.current = DOC_FEEDBACK_STATES[key];
1372
- this.currentSinceMs = nowMs;
1373
- return this.current;
1374
- }
1375
- /** Cast this frame's vote and return the (possibly held) winning state. */
1376
- tick(vote, nowMs) {
1377
- if (this.currentSinceMs === null) this.currentSinceMs = nowMs;
1378
- this.votes.push({ key: vote, atMs: nowMs });
1379
- this.votes = this.votes.filter((v) => nowMs - v.atMs <= this.windowMs);
1380
- if (nowMs - this.currentSinceMs < this.current.minDurationMs) return this.current;
1381
- const scores = /* @__PURE__ */ new Map();
1382
- for (const v of this.votes) {
1383
- const ageSeconds = (nowMs - v.atMs) / 1e3;
1384
- const weight = this.decayPerSecond ** ageSeconds;
1385
- scores.set(v.key, (scores.get(v.key) ?? 0) + weight);
1386
- }
1387
- let winner = this.current.key;
1388
- let best = -1;
1389
- for (const [key, score] of scores) {
1390
- if (score > best) {
1391
- best = score;
1392
- winner = key;
1393
- }
1394
- }
1395
- if (winner !== this.current.key) {
1396
- this.current = DOC_FEEDBACK_STATES[winner];
1397
- this.currentSinceMs = nowMs;
1398
- }
1399
- return this.current;
1400
- }
1401
- };
1402
-
1403
- // src/core/media.ts
1404
- var MIME_CANDIDATES = [
1405
- "video/mp4;codecs=avc1.42E01E,mp4a.40.2",
1406
- "video/mp4;codecs=avc1.42E01E",
1407
- "video/mp4",
1408
- "video/webm;codecs=vp9,opus",
1409
- "video/webm;codecs=vp9",
1410
- "video/webm;codecs=vp8,opus",
1411
- "video/webm;codecs=vp8",
1412
- "video/webm"
1413
- ];
1414
- function pickMimeType() {
1415
- const MR = globalThis.MediaRecorder;
1416
- if (!MR || typeof MR.isTypeSupported !== "function") return "";
1417
- return MIME_CANDIDATES.find((t2) => MR.isTypeSupported(t2)) ?? "";
1418
- }
1419
- var DEFAULT_CLIP_MIME = "video/webm";
1420
- function mapGetUserMediaError(err) {
1421
- if (err instanceof TypeError) return "insecure";
1422
- const name = err?.name ?? "";
1423
- switch (name) {
1424
- case "NotAllowedError":
1425
- case "PermissionDeniedError":
1426
- return "permission";
1427
- case "NotFoundError":
1428
- case "DevicesNotFoundError":
1429
- return "notfound";
1430
- case "NotReadableError":
1431
- case "TrackStartError":
1432
- return "inuse";
1433
- case "OverconstrainedError":
1434
- case "ConstraintNotSatisfiedError":
1435
- return "overconstrained";
1436
- default:
1437
- return "generic";
1438
- }
1439
- }
1440
- function cameraPreflight() {
1441
- const w2 = globalThis;
1442
- if (typeof w2.window !== "undefined" && w2.window.isSecureContext === false)
1443
- return "INSECURE_CONTEXT";
1444
- const md = w2.navigator?.mediaDevices;
1445
- if (!md || typeof md.getUserMedia !== "function") return "UNSUPPORTED";
1446
- return "OK";
1447
- }
1448
- function isMediaRecorderSupported() {
1449
- const MR = globalThis.MediaRecorder;
1450
- return typeof MR !== "undefined" && typeof MR.isTypeSupported === "function";
1451
- }
1452
- var MAX_CLIP_BYTES = 8 * 1024 * 1024;
1453
- function isClipTooLarge(blob) {
1454
- return blob.size > MAX_CLIP_BYTES;
1455
- }
1456
-
1457
- // src/core/v3/device-profile.ts
1458
- var DEVICE_PROFILES = Object.freeze({
1459
- LOW: Object.freeze({ cadenceHz: 5, inputWidth: 128, animations: "reduced" }),
1460
- MID: Object.freeze({ cadenceHz: 8, inputWidth: 160, animations: "full" }),
1461
- HIGH: Object.freeze({ cadenceHz: 10, inputWidth: 192, animations: "full" })
1462
- });
1463
- var SIMD_TEST_BYTES = new Uint8Array([
1464
- 0,
1465
- 97,
1466
- 115,
1467
- 109,
1468
- 1,
1469
- 0,
1470
- 0,
1471
- 0,
1472
- 1,
1473
- 5,
1474
- 1,
1475
- 96,
1476
- 0,
1477
- 1,
1478
- 123,
1479
- 3,
1480
- 2,
1481
- 1,
1482
- 0,
1483
- 10,
1484
- 10,
1485
- 1,
1486
- 8,
1487
- 0,
1488
- 65,
1489
- 0,
1490
- 253,
1491
- 15,
1492
- 253,
1493
- 98,
1494
- 11
1495
- ]);
1496
- function probeDevice() {
1497
- const nav = typeof navigator === "undefined" ? void 0 : navigator;
1498
- let simd = false;
1499
- try {
1500
- simd = typeof WebAssembly !== "undefined" && WebAssembly.validate(SIMD_TEST_BYTES);
1501
- } catch {
1502
- simd = false;
1503
- }
1504
- return {
1505
- cores: nav?.hardwareConcurrency ?? 2,
1506
- memGB: nav?.deviceMemory ?? null,
1507
- simd
1508
- };
1509
- }
1510
- function classifyDevice(probe) {
1511
- const memGB = probe.memGB ?? 4;
1512
- if (probe.cores < 4 || memGB < 3) return "LOW";
1513
- if (probe.cores >= 8 && memGB >= 6) return "HIGH";
1514
- return "MID";
1515
- }
1516
- var ORDER = ["LOW", "MID", "HIGH"];
1517
- var DeviceProfiler = class {
1518
- constructor(initial) {
1519
- this.samples = [];
1520
- this.adjusted = false;
1521
- this.current = initial;
1522
- }
1523
- get deviceClass() {
1524
- return this.current;
1525
- }
1526
- get profile() {
1527
- return DEVICE_PROFILES[this.current];
1528
- }
1529
- record(detectMs) {
1530
- if (this.adjusted || this.samples.length >= 10) return this.current;
1531
- this.samples.push(detectMs);
1532
- if (this.samples.length < 10) return this.current;
1533
- this.adjusted = true;
1534
- const mean = this.samples.reduce((sum, value) => sum + value, 0) / this.samples.length;
1535
- if (mean > 70) {
1536
- this.current = "LOW";
1537
- } else if (mean < 25) {
1538
- const index = ORDER.indexOf(this.current);
1539
- this.current = ORDER[Math.min(ORDER.length - 1, index + 1)] ?? this.current;
1540
- }
1541
- return this.current;
1542
- }
1543
- };
1544
-
1545
- // src/core/doc/capture-session-doc.ts
1546
- init_frame_quality();
1547
- init_doc_gate_v1();
1548
- var scanicDetect = null;
1549
- async function lazyScanicDetect(image) {
1550
- if (scanicDetect === null) {
1551
- const module_ = await Promise.resolve().then(() => (init_detector_scanic(), detector_scanic_exports));
1552
- scanicDetect = module_.detectQuad;
1553
- }
1554
- return scanicDetect(image);
1555
- }
1556
- async function mrzBandDetect(image) {
1557
- const band = detectMrzBand(image);
1558
- if (band === null) return null;
1559
- return {
1560
- topLeft: { x: band.x, y: band.y },
1561
- topRight: { x: band.x + band.width, y: band.y },
1562
- bottomRight: { x: band.x + band.width, y: band.y + band.height },
1563
- bottomLeft: { x: band.x, y: band.y + band.height }
1564
- };
1565
- }
1566
- function warmDocDetector() {
1567
- if (scanicDetect !== null) return;
1568
- void Promise.resolve().then(() => (init_detector_scanic(), detector_scanic_exports)).then((module_) => {
1569
- scanicDetect = module_.detectQuad;
1570
- }).catch(() => void 0);
1571
- }
1572
- var DOC_CADENCE_HZ = Object.freeze({
1573
- LOW: 3,
1574
- MID: 5,
1575
- HIGH: 6
1576
- });
1577
- var CaptureSessionDoc = class {
1578
- constructor(opts) {
1579
- this.handlers = /* @__PURE__ */ new Map();
1580
- this.stream = null;
1581
- this.timer = null;
1582
- this.state = "idle";
1583
- this.lastGuidance = null;
1584
- this.attempt = 0;
1585
- this.capturing = false;
1586
- this.feedback = new DocFeedbackAggregator();
1587
- this.lastFeedbackKey = null;
1588
- this.opts = opts;
1589
- this.gate = new DocGateV1(opts.format ?? "ID-1", opts.thresholds);
1590
- const deviceClass = opts.deviceClass ?? classifyDevice(probeDevice());
1591
- this.cadenceMs = 1e3 / DOC_CADENCE_HZ[deviceClass];
1592
- }
1593
- on(event, handler) {
1594
- let set = this.handlers.get(event);
1595
- if (!set) {
1596
- set = /* @__PURE__ */ new Set();
1597
- this.handlers.set(event, set);
1598
- }
1599
- set.add(handler);
1600
- return () => set?.delete(handler);
1601
- }
1602
- emit(event, payload) {
1603
- for (const handler of [...this.handlers.get(event) ?? []]) {
1604
- handler(payload);
1605
- }
1606
- }
1607
- async start() {
1608
- const attempt = ++this.attempt;
1609
- this.gate.reset();
1610
- this.feedback.reset();
1611
- this.lastFeedbackKey = null;
1612
- this.lastGuidance = null;
1613
- this.capturing = false;
1614
- this.setState("preflight");
1615
- try {
1616
- const getUserMedia = this.opts.getUserMedia ?? ((constraints) => navigator.mediaDevices.getUserMedia(constraints));
1617
- this.setState("acquiring");
1618
- this.stream = await getUserMedia({
1619
- audio: false,
1620
- video: {
1621
- facingMode: { ideal: "environment" },
1622
- width: { ideal: 1920 },
1623
- height: { ideal: 1080 }
1624
- }
1625
- });
1626
- if (attempt !== this.attempt) {
1627
- for (const track of this.stream.getTracks()) track.stop();
1628
- return;
1629
- }
1630
- this.opts.video.srcObject = this.stream;
1631
- await this.opts.video.play().catch(() => void 0);
1632
- this.setState("positioning");
1633
- this.scheduleTick(attempt);
1634
- } catch (err) {
1635
- const kind = mapGetUserMediaError(err);
1636
- this.setState("error");
1637
- this.emit("error", { kind, retryable: true });
1638
- }
1639
- }
1640
- /** Restart the gate for another side / a retake (same stream). */
1641
- rearm(side) {
1642
- if (side !== void 0) this.opts.side = side;
1643
- this.gate.reset();
1644
- this.feedback.reset();
1645
- this.lastFeedbackKey = null;
1646
- this.lastGuidance = null;
1647
- this.capturing = false;
1648
- if (this.state === "captured") {
1649
- this.setState("positioning");
1650
- this.scheduleTick(this.attempt);
1651
- }
1652
- }
1653
- destroy() {
1654
- this.attempt += 1;
1655
- if (this.timer !== null) (this.opts.clearTimer ?? clearTimeout)(this.timer);
1656
- this.timer = null;
1657
- if (this.stream) for (const track of this.stream.getTracks()) track.stop();
1658
- this.stream = null;
1659
- this.opts.video.srcObject = null;
1660
- }
1661
- setState(state) {
1662
- this.state = state;
1663
- this.emit("statechange", { state });
1664
- }
1665
- scheduleTick(attempt) {
1666
- const setTimer = this.opts.setTimer ?? setTimeout;
1667
- this.timer = setTimer(() => void this.tick(attempt), this.cadenceMs);
1668
- }
1669
- async tick(attempt) {
1670
- if (attempt !== this.attempt || this.state !== "positioning" || this.capturing) return;
1671
- const now = this.opts.now ?? (() => performance.now());
1672
- const grab = this.opts.grabDetectFrame ?? defaultGrabDetectFrame;
1673
- const detect = this.opts.detect ?? ((this.opts.format ?? "ID-1") === "ID-3" ? mrzBandDetect : lazyScanicDetect);
1674
- const frame = grab(this.opts.video, DOC_DETECT_WIDTH);
1675
- if (frame === null) {
1676
- this.scheduleTick(attempt);
1677
- return;
1678
- }
1679
- let quad = null;
1680
- try {
1681
- quad = await detect(frame);
1682
- } catch {
1683
- quad = null;
1684
- }
1685
- if (attempt !== this.attempt) return;
1686
- const crop = quad !== null ? cropQuadRegion(frame, quad) : frame;
1687
- const atMs = now();
1688
- const measures = {
1689
- sharpness: sharpness(crop),
1690
- exposure: exposure(crop),
1691
- meanLuma: meanLuma(crop),
1692
- specularFraction: specularFraction(crop)
1693
- };
1694
- const analysis = analyzeDocFrame({
1695
- format: this.opts.format ?? "ID-1",
1696
- quad,
1697
- frameWidth: frame.width,
1698
- frameHeight: frame.height,
1699
- measures,
1700
- ...this.opts.thresholds !== void 0 ? { thresholds: this.opts.thresholds } : {}
1701
- });
1702
- const tick = this.gate.tick({
1703
- timestampMs: atMs,
1704
- quad,
1705
- quality: measures,
1706
- frameWidth: frame.width,
1707
- frameHeight: frame.height
1708
- });
1709
- this.emit("checks", {
1710
- engine: "docv1",
1711
- p: tick.p,
1712
- plausible: tick.plausible,
1713
- stableTicks: tick.stableTicks,
1714
- quad: tick.quad,
1715
- frameWidth: frame.width,
1716
- frameHeight: frame.height,
1717
- analysis
1718
- });
1719
- const feedbackState = this.feedback.tick(feedbackVoteOf(analysis), atMs);
1720
- if (feedbackState.key !== this.lastFeedbackKey) {
1721
- this.lastFeedbackKey = feedbackState.key;
1722
- this.emit("feedback", feedbackState);
1723
- }
1724
- if (tick.guidanceKey !== this.lastGuidance) {
1725
- this.lastGuidance = tick.guidanceKey;
1726
- this.emit("guidance", { key: tick.guidanceKey });
1727
- }
1728
- if (tick.ready && quad !== null) {
1729
- const processing = this.feedback.force("processing", atMs);
1730
- this.lastFeedbackKey = processing.key;
1731
- this.emit("feedback", processing);
1732
- await this.fire(attempt, quad, {
1733
- width: frame.width,
1734
- height: frame.height,
1735
- tickSharpness: measures.sharpness
1736
- });
1737
- return;
1738
- }
1739
- this.scheduleTick(attempt);
1740
- }
1741
- /**
1742
- * BEST-FRAME capture window (capture-v2): the first ready tick captures a
1743
- * candidate immediately, then up to CAPTURE_EXTRA_CANDIDATES more stills are
1744
- * taken at CAPTURE_CANDIDATE_SPACING_MS while the user holds — each scored
1745
- * by the live detect-tick sharpness at its capture moment — and the SHARPEST
1746
- * wins. Beats first-acceptable-frame capture without decoding stills.
1747
- */
1748
- async fire(attempt, quad, detectSize) {
1749
- this.capturing = true;
1750
- const capture = this.opts.captureStill ?? defaultCaptureStill;
1751
- const grab = this.opts.grabDetectFrame ?? defaultGrabDetectFrame;
1752
- const setTimer = this.opts.setTimer ?? setTimeout;
1753
- const size = { width: detectSize.width, height: detectSize.height };
1754
- try {
1755
- let best = {
1756
- still: await capture(this.opts.video, quad, size),
1757
- sharpness: detectSize.tickSharpness
1758
- };
1759
- for (let i2 = 0; i2 < CAPTURE_EXTRA_CANDIDATES; i2++) {
1760
- await new Promise((resolve) => {
1761
- setTimer(() => resolve(), CAPTURE_CANDIDATE_SPACING_MS);
1762
- });
1763
- if (attempt !== this.attempt) return;
1764
- const frame = grab(this.opts.video, DOC_DETECT_WIDTH);
1765
- if (frame === null) continue;
1766
- const candidateSharpness = sharpness(cropQuadRegion(frame, quad));
1767
- if (candidateSharpness > best.sharpness * CAPTURE_IMPROVEMENT_MIN_RATIO) {
1768
- const still = await capture(this.opts.video, quad, size);
1769
- if (attempt !== this.attempt) return;
1770
- best = { still, sharpness: candidateSharpness };
1771
- }
1772
- }
1773
- if (attempt !== this.attempt) return;
1774
- this.setState("captured");
1775
- this.emit("artifacts", {
1776
- keyframe: best.still.blob,
1777
- previewDataUrl: best.still.previewDataUrl,
1778
- ...this.opts.side !== void 0 ? { side: this.opts.side } : {}
1779
- });
1780
- } catch {
1781
- if (attempt !== this.attempt) return;
1782
- this.capturing = false;
1783
- this.gate.reset();
1784
- this.scheduleTick(attempt);
1785
- }
1786
- }
1787
- };
1788
- var CAPTURE_EXTRA_CANDIDATES = 2;
1789
- var CAPTURE_CANDIDATE_SPACING_MS = 260;
1790
- var CAPTURE_IMPROVEMENT_MIN_RATIO = 1.08;
1791
- function defaultGrabDetectFrame(video, targetWidth) {
1792
- const vw = video.videoWidth;
1793
- const vh = video.videoHeight;
1794
- if (vw === 0 || vh === 0) return null;
1795
- const scale = Math.min(1, targetWidth / vw);
1796
- const width = Math.round(vw * scale);
1797
- const height = Math.round(vh * scale);
1798
- const canvas = document.createElement("canvas");
1799
- canvas.width = width;
1800
- canvas.height = height;
1801
- const context = canvas.getContext("2d", { willReadFrequently: true });
1802
- if (context === null) return null;
1803
- context.drawImage(video, 0, 0, width, height);
1804
- return context.getImageData(0, 0, width, height);
1805
- }
1806
- async function defaultCaptureStill(video, _quad, _detectSize) {
1807
- const canvas = document.createElement("canvas");
1808
- canvas.width = Math.max(1, video.videoWidth);
1809
- canvas.height = Math.max(1, video.videoHeight);
1810
- const context = canvas.getContext("2d");
1811
- if (context === null) throw new Error("2d context unavailable");
1812
- context.drawImage(video, 0, 0, canvas.width, canvas.height);
1813
- const blob = await new Promise((resolve, reject) => {
1814
- canvas.toBlob((b) => b ? resolve(b) : reject(new Error("toBlob failed")), "image/jpeg", 0.92);
1815
- });
1816
- return { blob, previewDataUrl: canvas.toDataURL("image/jpeg", 0.85) };
1817
- }
1818
- function cropQuadRegion(frame, quad) {
1819
- const xs = [quad.topLeft.x, quad.topRight.x, quad.bottomRight.x, quad.bottomLeft.x];
1820
- const ys = [quad.topLeft.y, quad.topRight.y, quad.bottomRight.y, quad.bottomLeft.y];
1821
- const x1 = Math.max(0, Math.floor(Math.min(...xs)));
1822
- const y1 = Math.max(0, Math.floor(Math.min(...ys)));
1823
- const x2 = Math.min(frame.width, Math.ceil(Math.max(...xs)));
1824
- const y2 = Math.min(frame.height, Math.ceil(Math.max(...ys)));
1825
- const width = Math.max(1, x2 - x1);
1826
- const height = Math.max(1, y2 - y1);
1827
- const data = new Uint8ClampedArray(width * height * 4);
1828
- for (let row = 0; row < height; row++) {
1829
- const src = ((y1 + row) * frame.width + x1) * 4;
1830
- data.set(frame.data.subarray(src, src + width * 4), row * width * 4);
1831
- }
1832
- return { data, width, height, colorSpace: frame.colorSpace };
1833
- }
1834
-
1835
- // src/core/capture-constraints.ts
1836
- function buildCaptureConstraints(isMobile, facingMode) {
1837
- void isMobile;
1838
- return {
1839
- video: {
1840
- width: { ideal: 1280, max: 1280 },
1841
- height: { ideal: 720, max: 720 },
1842
- facingMode,
1843
- frameRate: { ideal: 24, max: 30 }
1844
- },
1845
- audio: false
1846
- };
1847
- }
1848
- function detectIsMobile() {
1849
- if (typeof window === "undefined" || typeof navigator === "undefined") return false;
1850
- return window.innerWidth <= 768 || /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
1851
- String(navigator.userAgent ?? "")
1852
- );
1853
- }
1854
- var CIRCLE_RADIUS_FACTOR = 0.45;
1855
- var IN_CIRCLE_FACTOR = 0.9;
1856
- var CENTERED_FACTOR = 0.4;
1857
-
1858
- // src/core/clip-recorder.ts
1859
- var CLIP_MS = 2500;
1860
- var TIMESLICE_MS = 1e3;
1861
- var STOP_GRACE_MS = 1500;
1862
- var VIDEO_BPS = 25e5;
1863
- var ClipError = class extends Error {
1864
- constructor(kind, msg) {
1865
- super(msg ?? kind);
1866
- this.kind = kind;
1867
- }
1868
- };
1869
- var ClipRecorder = class {
1870
- constructor() {
1871
- this.recorder = null;
1872
- this.stream = null;
1873
- // own field so teardown can stop tracks (REVIEW FIX 8)
1874
- this.chunks = [];
1875
- this.bytes = 0;
1876
- this.hardStopTimer = null;
1877
- this.graceTimer = null;
1878
- this.settled = false;
1879
- }
1880
- clearTimers() {
1881
- if (this.hardStopTimer) clearTimeout(this.hardStopTimer);
1882
- if (this.graceTimer) clearTimeout(this.graceTimer);
1883
- this.hardStopTimer = null;
1884
- this.graceTimer = null;
1885
- }
1886
- /** Records CLIP_MS of the stream. Resolves with the clip blob + its container mime;
1887
- * rejects with ClipError. Behavior contract is the v1 hook's `start`, verbatim
1888
- * (iOS workarounds included).
1889
- *
1890
- * ONE RECORDING AT A TIME: chunk/byte/timer state is shared per instance, so a
1891
- * second record() while one is in flight rejects ClipError("generic") instead of
1892
- * corrupting the in-flight clip. (v2 guard — v1's hook was gated by its owning
1893
- * component; a class API invites reuse. Zero impact on clip bytes.)
1894
- *
1895
- * `onStopped` (optional) fires ONCE the moment the CLIP_MS recording window
1896
- * elapses (the hard-stop), BEFORE finalize — which on iOS can lag up to
1897
- * STOP_GRACE_MS while onstop flushes the last chunk. It lets the host freeze
1898
- * the display on the already-captured keyframe the instant recording ends,
1899
- * instead of waiting for the blob. PURE NOTIFICATION — it does not touch
1900
- * timers, chunks, or the finalize path, so it is calibration-neutral (no
1901
- * effect on clip bytes). Never fires on a rejected capture (error /
1902
- * cliptoolarge settle before the hard-stop and clear the timer). */
1903
- record(stream, onStopped) {
1904
- if (this.recorder && !this.settled) {
1905
- return Promise.reject(
1906
- new ClipError(
1907
- "generic",
1908
- "record() called while a recording is in flight \u2014 ClipRecorder handles one recording at a time"
1909
- )
1910
- );
1911
- }
1912
- this.recorder = null;
1913
- this.clearTimers();
1914
- this.chunks = [];
1915
- this.bytes = 0;
1916
- this.settled = false;
1917
- this.stream = stream;
1918
- const picked = pickMimeType();
1919
- return new Promise((resolve, reject) => {
1920
- let recorder;
1921
- try {
1922
- recorder = new MediaRecorder(
1923
- stream,
1924
- picked ? { mimeType: picked, videoBitsPerSecond: VIDEO_BPS } : { videoBitsPerSecond: VIDEO_BPS }
1925
- );
1926
- } catch {
1927
- try {
1928
- recorder = new MediaRecorder(stream);
1929
- } catch {
1930
- reject(new ClipError("unsupported"));
1931
- return;
1932
- }
1933
- }
1934
- this.recorder = recorder;
1935
- const settle = (fn) => {
1936
- if (this.settled) return;
1937
- this.settled = true;
1938
- this.clearTimers();
1939
- fn();
1940
- };
1941
- const finalize = () => settle(() => {
1942
- const type = recorder.mimeType || picked || DEFAULT_CLIP_MIME;
1943
- const blob = new Blob(this.chunks, { type });
1944
- if (isClipTooLarge(blob)) {
1945
- reject(new ClipError("cliptoolarge"));
1946
- return;
1947
- }
1948
- resolve({ blob, mimeType: type });
1949
- });
1950
- recorder.ondataavailable = (e2) => {
1951
- if (e2.data && e2.data.size) {
1952
- this.chunks.push(e2.data);
1953
- this.bytes += e2.data.size;
1954
- if (this.bytes > MAX_CLIP_BYTES) {
1955
- settle(() => {
1956
- try {
1957
- if (recorder.state !== "inactive") recorder.stop();
1958
- } catch {
1959
- }
1960
- reject(new ClipError("cliptoolarge"));
1961
- });
1962
- }
1963
- }
1964
- };
1965
- recorder.onstop = finalize;
1966
- recorder.onerror = () => settle(() => reject(new ClipError("generic")));
1967
- try {
1968
- recorder.start(TIMESLICE_MS);
1969
- } catch {
1970
- settle(() => reject(new ClipError("generic")));
1971
- return;
1972
- }
1973
- this.hardStopTimer = setTimeout(() => {
1974
- if (!this.settled) onStopped?.();
1975
- if (recorder.state !== "inactive") {
1976
- try {
1977
- recorder.stop();
1978
- } catch {
1979
- finalize();
1980
- }
1981
- this.graceTimer = setTimeout(finalize, STOP_GRACE_MS);
1982
- } else {
1983
- finalize();
1984
- }
1985
- }, CLIP_MS);
1986
- });
1987
- }
1988
- /** Idempotent teardown: stop recorder + ALL tracks (v1 `stopAndCleanup` + the unmount
1989
- * effect). Optional `stream` override mirrors v1's `stopAndCleanup(stream?)`.
1990
- *
1991
- * MID-RECORDING SEMANTICS (verbatim v1): calling stop() while a record() is in
1992
- * flight may LATER resolve the pending promise with a TRUNCATED clip (recorder.stop()
1993
- * fires onstop → finalize from whatever chunks arrived so far), or — because this
1994
- * method clears the hard-stop/grace timers — never settle it at all if onstop never
1995
- * fires (the iOS grace path has been torn down). Callers MUST NOT treat a resolution
1996
- * arriving after stop() as a full CLIP_MS clip, and must not await a record()
1997
- * promise past stop() without their own timeout. (Task 4's CaptureSession owns
1998
- * sequencing on top of this contract.) */
1999
- stop(stream) {
2000
- this.clearTimers();
2001
- const rec = this.recorder;
2002
- if (rec && rec.state !== "inactive") {
2003
- try {
2004
- rec.stop();
2005
- } catch {
2006
- }
2007
- }
2008
- this.recorder = null;
2009
- const s2 = stream ?? this.stream;
2010
- s2?.getTracks().forEach((t2) => t2.stop());
2011
- this.stream = null;
2012
- }
2013
- };
2014
-
2015
- // src/core/keyframe.ts
2016
- function captureMirroredKeyframe(video, canvas, quality = 0.92) {
2017
- return new Promise((resolve, reject) => {
2018
- const w2 = video.videoWidth;
2019
- const h2 = video.videoHeight;
2020
- if (!w2 || !h2) {
2021
- reject(new Error("video-not-ready"));
2022
- return;
2023
- }
2024
- const ctx = canvas.getContext("2d");
2025
- if (!ctx) {
2026
- reject(new Error("no-2d-context"));
2027
- return;
2028
- }
2029
- canvas.width = w2;
2030
- canvas.height = h2;
2031
- ctx.scale(-1, 1);
2032
- ctx.drawImage(video, -w2, 0);
2033
- canvas.toBlob(
2034
- (blob) => blob ? resolve(blob) : reject(new Error("empty-keyframe")),
2035
- "image/jpeg",
2036
- quality
2037
- );
2038
- });
2039
- }
2040
-
2041
- // src/core/v3/detector-blaze.ts
2042
- var BLAZE_INIT_TIMEOUT_MS = 1e4;
2043
- var BlazeDetector = class _BlazeDetector {
2044
- constructor(inner, fallbackReason) {
2045
- this.tier = "blaze";
2046
- this.inner = inner;
2047
- if (fallbackReason !== void 0) this.fallbackReason = fallbackReason;
2048
- }
2049
- static async create(assetBaseUrl, fallbackReason) {
2050
- const vision = await import("@mediapipe/tasks-vision");
2051
- const fileset = await vision.FilesetResolver.forVisionTasks(assetBaseUrl);
2052
- const inner = await vision.FaceDetector.createFromOptions(fileset, {
2053
- baseOptions: {
2054
- modelAssetPath: `${assetBaseUrl}/blaze_face_short_range.tflite`,
2055
- // CPU delegate — the iOS-Safari-safe path (see header). NEVER 'GPU'.
2056
- delegate: "CPU"
2057
- },
2058
- runningMode: "IMAGE"
2059
- });
2060
- return new _BlazeDetector(inner, fallbackReason);
2061
- }
2062
- async detect(source, sourceWidth, sourceHeight) {
2063
- let detections;
2064
- try {
2065
- detections = this.inner.detect(source).detections;
2066
- } catch {
2067
- return null;
2068
- }
2069
- const best = pickMostConfident(detections);
2070
- if (best?.boundingBox === void 0) return null;
2071
- const size = intrinsicSize(source);
2072
- const eyes = extractEyes(best.keypoints, size);
2073
- const observation = {
2074
- box: {
2075
- x: best.boundingBox.originX,
2076
- y: best.boundingBox.originY,
2077
- width: best.boundingBox.width,
2078
- height: best.boundingBox.height
2079
- },
2080
- ...eyes !== void 0 ? { eyes } : {},
2081
- score: best.categories[0]?.score ?? 0
2082
- };
2083
- return toStreamPixels(observation, source, sourceWidth, sourceHeight);
2084
- }
2085
- destroy() {
2086
- try {
2087
- this.inner.close();
2088
- } catch {
2089
- }
2090
- }
2091
- };
2092
- function pickMostConfident(detections) {
2093
- let best;
2094
- let bestScore = -1;
2095
- for (const detection of detections) {
2096
- const score = detection.categories[0]?.score ?? 0;
2097
- if (score > bestScore) {
2098
- best = detection;
2099
- bestScore = score;
2100
- }
2101
- }
2102
- return best;
2103
- }
2104
- function extractEyes(keypoints, size) {
2105
- const a2 = keypoints?.[0];
2106
- const b = keypoints?.[1];
2107
- if (a2 === void 0 || b === void 0) return void 0;
2108
- const toSource = (p2) => ({ x: p2.x * size.width, y: p2.y * size.height });
2109
- const [pa, pb] = [toSource(a2), toSource(b)];
2110
- return pa.x <= pb.x ? { left: pa, right: pb } : { left: pb, right: pa };
2111
- }
2112
-
2113
- // src/core/v3/detector-native.ts
2114
- function smokeSource() {
2115
- if (typeof OffscreenCanvas === "function") return new OffscreenCanvas(2, 2);
2116
- const canvas = document.createElement("canvas");
2117
- canvas.width = 2;
2118
- canvas.height = 2;
2119
- return canvas;
2120
- }
2121
- async function probeNativeDetector() {
2122
- const ctor = globalThis.FaceDetector;
2123
- if (typeof ctor !== "function") return { ok: false, reason: "unsupported" };
2124
- try {
2125
- const instance = new ctor({ fastMode: true, maxDetectedFaces: 1 });
2126
- await instance.detect(smokeSource());
2127
- return { ok: true, instance };
2128
- } catch (err) {
2129
- return { ok: false, reason: `smoke_failed:${err instanceof Error ? err.message : String(err)}` };
2130
- }
2131
- }
2132
- var NativeDetector = class {
2133
- constructor(inner, fallbackReason) {
2134
- this.tier = "native";
2135
- this.inner = inner;
2136
- if (fallbackReason !== void 0) this.fallbackReason = fallbackReason;
2137
- }
2138
- async detect(source, sourceWidth, sourceHeight) {
2139
- let faces;
2140
- try {
2141
- faces = await this.inner.detect(source);
2142
- } catch {
2143
- return null;
2144
- }
2145
- const face = faces[0];
2146
- if (face === void 0) return null;
2147
- const eyes = extractEyes2(face.landmarks);
2148
- const observation = {
2149
- box: {
2150
- x: face.boundingBox.x,
2151
- y: face.boundingBox.y,
2152
- width: face.boundingBox.width,
2153
- height: face.boundingBox.height
2154
- },
2155
- ...eyes !== void 0 ? { eyes } : {},
2156
- // The Shape Detection API exposes no confidence — the smoke-tested
2157
- // native tier treats any detection as confident.
2158
- score: 1
2159
- };
2160
- return toStreamPixels(observation, source, sourceWidth, sourceHeight);
2161
- }
2162
- destroy() {
2163
- }
2164
- };
2165
- function extractEyes2(landmarks) {
2166
- if (landmarks === void 0) return void 0;
2167
- const eyePoints = landmarks.filter((landmark) => landmark.type === "eye").map((landmark) => landmark.locations[0]).filter((point) => point !== void 0);
2168
- const [a2, b] = eyePoints;
2169
- if (a2 === void 0 || b === void 0) return void 0;
2170
- return a2.x <= b.x ? { left: a2, right: b } : { left: b, right: a2 };
2171
- }
2172
-
2173
- // src/core/v3/detector.ts
2174
- var DEFAULT_V3_ASSET_BASE_URL = "/models-v3";
2175
- var DEFAULT_TIER_ORDER = ["native", "blaze"];
2176
- var DetectorLadderError = class extends Error {
2177
- constructor(fallbackReason) {
2178
- super(`no detector tier available (${fallbackReason})`);
2179
- this.name = "DetectorLadderError";
2180
- this.fallbackReason = fallbackReason;
2181
- }
2182
- };
2183
- function intrinsicSize(source) {
2184
- const candidate = source;
2185
- if (typeof candidate.videoWidth === "number" && candidate.videoWidth > 0) {
2186
- return { width: candidate.videoWidth, height: candidate.videoHeight ?? 0 };
2187
- }
2188
- if (typeof candidate.naturalWidth === "number" && candidate.naturalWidth > 0) {
2189
- return { width: candidate.naturalWidth, height: candidate.naturalHeight ?? 0 };
2190
- }
2191
- const width = typeof candidate.width === "number" ? candidate.width : 0;
2192
- const height = typeof candidate.height === "number" ? candidate.height : 0;
2193
- return { width, height };
2194
- }
2195
- function toStreamPixels(observation, source, streamWidth, streamHeight) {
2196
- const size = intrinsicSize(source);
2197
- const scaleX = size.width > 0 ? streamWidth / size.width : 1;
2198
- const scaleY = size.height > 0 ? streamHeight / size.height : 1;
2199
- const scalePoint = (p2) => ({ x: p2.x * scaleX, y: p2.y * scaleY });
2200
- return {
2201
- box: {
2202
- x: observation.box.x * scaleX,
2203
- y: observation.box.y * scaleY,
2204
- width: observation.box.width * scaleX,
2205
- height: observation.box.height * scaleY
2206
- },
2207
- ...observation.eyes !== void 0 ? { eyes: { left: scalePoint(observation.eyes.left), right: scalePoint(observation.eyes.right) } } : {},
2208
- score: observation.score
2209
- };
2210
- }
2211
- function describeError(err) {
2212
- return err instanceof Error ? err.message : String(err);
2213
- }
2214
- async function createDetector(options) {
2215
- const order = options.preferred ?? DEFAULT_TIER_ORDER;
2216
- const reasons = [];
2217
- for (const tier of order) {
2218
- if (tier === "native") {
2219
- const probed = await probeNativeDetector();
2220
- if (probed.ok) {
2221
- return new NativeDetector(probed.instance, reasonOf(reasons));
2222
- }
2223
- reasons.push(`native:${probed.reason}`);
2224
- continue;
2225
- }
2226
- try {
2227
- return await withTimeout(
2228
- BlazeDetector.create(
2229
- options.v3AssetBaseUrl ?? DEFAULT_V3_ASSET_BASE_URL,
2230
- reasonOf(reasons)
2231
- ),
2232
- options.blazeInitTimeoutMs ?? BLAZE_INIT_TIMEOUT_MS
2233
- );
2234
- } catch (err) {
2235
- reasons.push(
2236
- err instanceof InitTimeoutError ? "blaze:blaze_init_timeout" : `blaze:${describeError(err)}`
2237
- );
2238
- }
2239
- }
2240
- throw new DetectorLadderError(reasonOf(reasons) ?? "no_tier_available");
2241
- }
2242
- function reasonOf(reasons) {
2243
- return reasons.length > 0 ? reasons.join("; ") : void 0;
2244
- }
2245
- var InitTimeoutError = class extends Error {
2246
- };
2247
- function withTimeout(promise, deadlineMs) {
2248
- return new Promise((resolvePromise, rejectPromise) => {
2249
- const timer = setTimeout(() => {
2250
- rejectPromise(new InitTimeoutError(`init exceeded ${deadlineMs}ms`));
2251
- promise.then(
2252
- (value) => value.destroy(),
2253
- () => void 0
2254
- );
2255
- }, deadlineMs);
2256
- promise.then(
2257
- (value) => {
2258
- clearTimeout(timer);
2259
- resolvePromise(value);
2260
- },
2261
- (err) => {
2262
- clearTimeout(timer);
2263
- rejectPromise(err);
2264
- }
2265
- );
2266
- });
2267
- }
2268
-
2269
- // src/core/v3/detect-worker.ts
2270
- var WORKER_PROTOCOL_VERSION = 1;
2271
- function workerOffloadSupported() {
2272
- return typeof OffscreenCanvas === "function" && typeof createImageBitmap === "function" && typeof Worker === "function";
2273
- }
2274
- function installWorkerDetectorHost(scope, deps = {}) {
2275
- const create = deps.createDetector ?? createDetector;
2276
- let detector = null;
2277
- scope.onmessage = (event) => {
2278
- const message = event.data;
2279
- if (message.v !== WORKER_PROTOCOL_VERSION) {
2280
- message.bitmap?.close?.();
2281
- return;
2282
- }
2283
- if (message.type === "init") {
2284
- void create(message.options).then((created) => {
2285
- detector = created;
2286
- const ready = {
2287
- v: WORKER_PROTOCOL_VERSION,
2288
- type: "ready",
2289
- tier: created.tier,
2290
- ...created.fallbackReason !== void 0 ? { fallbackReason: created.fallbackReason } : {}
2291
- };
2292
- scope.postMessage(ready);
2293
- });
2294
- return;
2295
- }
2296
- if (message.type === "detect") {
2297
- const respond = (observation) => {
2298
- const result = {
2299
- v: WORKER_PROTOCOL_VERSION,
2300
- type: "result",
2301
- id: message.id,
2302
- observation
2303
- };
2304
- scope.postMessage(result);
2305
- message.bitmap.close?.();
2306
- };
2307
- if (detector === null) {
2308
- respond(null);
2309
- return;
2310
- }
2311
- void detector.detect(message.bitmap, message.streamWidth, message.streamHeight).then(respond, () => respond(null));
2312
- }
2313
- };
2314
- }
2315
- if (typeof self !== "undefined" && typeof self.importScripts === "function") {
2316
- installWorkerDetectorHost(self);
2317
- }
2318
- var WorkerDetectorProxy = class _WorkerDetectorProxy {
2319
- constructor(worker, ready) {
2320
- this.pending = /* @__PURE__ */ new Map();
2321
- this.nextId = 1;
2322
- this.worker = worker;
2323
- this.tier = ready.tier;
2324
- if (ready.fallbackReason !== void 0) this.fallbackReason = ready.fallbackReason;
2325
- worker.addEventListener("message", (event) => {
2326
- const message = event.data;
2327
- if (message.v !== WORKER_PROTOCOL_VERSION || message.type !== "result") return;
2328
- const resolve = this.pending.get(message.id);
2329
- this.pending.delete(message.id);
2330
- resolve?.(message.observation);
2331
- });
2332
- }
2333
- static create(worker, options, readyTimeoutMs = 1e4) {
2334
- return new Promise((resolve, reject) => {
2335
- const timer = setTimeout(() => {
2336
- worker.removeEventListener("message", onReady);
2337
- worker.terminate();
2338
- reject(new Error(`worker detector not ready within ${readyTimeoutMs}ms`));
2339
- }, readyTimeoutMs);
2340
- const onReady = (event) => {
2341
- const message = event.data;
2342
- if (message.v !== WORKER_PROTOCOL_VERSION || message.type !== "ready") return;
2343
- clearTimeout(timer);
2344
- worker.removeEventListener("message", onReady);
2345
- resolve(new _WorkerDetectorProxy(worker, message));
2346
- };
2347
- worker.addEventListener("message", onReady);
2348
- const init = { v: WORKER_PROTOCOL_VERSION, type: "init", options };
2349
- worker.postMessage(init);
2350
- });
2351
- }
2352
- async detect(source, sourceWidth, sourceHeight) {
2353
- let bitmap;
2354
- try {
2355
- if (typeof ImageBitmap !== "undefined" && source instanceof ImageBitmap) {
2356
- bitmap = source;
2357
- } else if (typeof createImageBitmap === "function") {
2358
- bitmap = await createImageBitmap(source);
2359
- } else {
2360
- bitmap = source;
2361
- }
2362
- } catch {
2363
- return null;
2364
- }
2365
- const id = this.nextId;
2366
- this.nextId += 1;
2367
- return new Promise((resolve) => {
2368
- this.pending.set(id, resolve);
2369
- const message = {
2370
- v: WORKER_PROTOCOL_VERSION,
2371
- type: "detect",
2372
- id,
2373
- bitmap,
2374
- streamWidth: sourceWidth,
2375
- streamHeight: sourceHeight
2376
- };
2377
- this.worker.postMessage(message, [bitmap]);
2378
- });
2379
- }
2380
- destroy() {
2381
- for (const resolve of this.pending.values()) resolve(null);
2382
- this.pending.clear();
2383
- this.worker.terminate();
2384
- }
2385
- };
2386
-
2387
- // src/core/v3/detect-scheduler.ts
2388
- var STATS_WINDOW = 20;
2389
- var DetectScheduler = class {
2390
- constructor(options) {
2391
- this.timer = null;
2392
- this.frameCallbackId = null;
2393
- this.running = false;
2394
- this.busy = false;
2395
- this.lastRunAt = Number.NEGATIVE_INFINITY;
2396
- this.degradeCount = 0;
2397
- this.durations = [];
2398
- this.options = options;
2399
- this.periodMs = 1e3 / options.cadenceHz;
2400
- }
2401
- start() {
2402
- if (this.running) return;
2403
- this.running = true;
2404
- const video = this.options.video;
2405
- if (typeof video?.requestVideoFrameCallback === "function") {
2406
- const loop = () => {
2407
- if (!this.running) return;
2408
- this.frameCallbackId = video.requestVideoFrameCallback?.(() => {
2409
- this.frameCallbackId = null;
2410
- if (this.now() - this.lastRunAt >= this.periodMs) this.tick();
2411
- loop();
2412
- });
2413
- };
2414
- loop();
2415
- return;
2416
- }
2417
- this.timer = setInterval(() => this.tick(), this.periodMs);
2418
- }
2419
- stop() {
2420
- this.running = false;
2421
- if (this.timer !== null) {
2422
- clearInterval(this.timer);
2423
- this.timer = null;
2424
- }
2425
- if (this.frameCallbackId !== null) {
2426
- this.options.video?.cancelVideoFrameCallback?.(
2427
- this.frameCallbackId
2428
- );
2429
- this.frameCallbackId = null;
2430
- }
2431
- }
2432
- stats() {
2433
- const meanDetectMs = this.durations.length === 0 ? 0 : this.durations.reduce((sum, value) => sum + value, 0) / this.durations.length;
2434
- return { degradeCount: this.degradeCount, meanDetectMs };
2435
- }
2436
- now() {
2437
- return this.options.now?.() ?? performance.now();
2438
- }
2439
- tick() {
2440
- if (!this.running) return;
2441
- if (this.busy) {
2442
- this.degradeCount += 1;
2443
- return;
2444
- }
2445
- this.busy = true;
2446
- this.lastRunAt = this.now();
2447
- const startedAt = this.now();
2448
- this.options.run().catch(() => void 0).finally(() => {
2449
- this.busy = false;
2450
- this.durations.push(this.now() - startedAt);
2451
- if (this.durations.length > STATS_WINDOW) this.durations.shift();
2452
- });
2453
- }
2454
- };
2455
-
2456
- // src/core/v3/face-gate-v3.ts
2457
- init_frame_quality();
2458
- var V3_GATE_DEFAULTS = Object.freeze({
2459
- Q_GOOD: 0.6,
2460
- RISE_PER_S: 0.9,
2461
- FALL_PER_S: 0.25,
2462
- CENTER_FALLOFF_IOD_MULTIPLE: 1.35,
2463
- BOX_EYE_OFFSET_FACTOR: 0.12,
2464
- IOD_BOX_PROXY_FACTOR: 0.42,
2465
- SIZE_IDEAL_MIN: 0.12,
2466
- SIZE_IDEAL_MAX: 0.3,
2467
- SIZE_HARD_MIN: 0.08,
2468
- SIZE_HARD_MAX: 0.45,
2469
- ROLL_MAX_DEG: 25,
2470
- MOTION_VELOCITY_IOD_PER_S: 0.5,
2471
- MOTION_TAU_S: 0.4,
2472
- MOTION_DEADBAND_IOD_PER_S: 0.1,
2473
- READY_WINDOW_MS: 500,
2474
- // (READY_MEAN_Q, the former 0.75 window MEAN, is gone — 2026-10-17 field
2475
- // bug: a steady q anywhere in [Q_GOOD, 0.75) saturated p at 1, passed every
2476
- // guide ("hold still") and could never reach the mean, so the ring sat full
2477
- // and green with nothing recording. Readiness now checks the window against
2478
- // Q_GOOD, which keeps the one-flaky-tick forgiveness and the second-bad-tick
2479
- // block without a dead band above the rise threshold.)
2480
- GUIDE_SIZE: 0.6,
2481
- GUIDE_CENTERING: 0.6,
2482
- GUIDE_POSE: 0.6,
2483
- GUIDE_EXPOSURE: 0.6,
2484
- GUIDE_SHARPNESS: 0.35,
2485
- GUIDE_MOTION: 0.5
2486
- });
2487
- var clamp012 = (value) => Math.min(1, Math.max(0, value));
2488
- var FaceGateV3 = class {
2489
- constructor(overrides = {}) {
2490
- this.p = 0;
2491
- this.lastTickAt = null;
2492
- this.lastCenter = null;
2493
- this.velocityEma = 0;
2494
- this.qWindow = [];
2495
- /** Which side of the ideal band the last size measurement fell on. */
2496
- this.lastSizeDirection = "ideal";
2497
- this.t = { ...V3_GATE_DEFAULTS, ...overrides };
2498
- }
2499
- reset() {
2500
- this.p = 0;
2501
- this.lastTickAt = null;
2502
- this.lastCenter = null;
2503
- this.velocityEma = 0;
2504
- this.qWindow = [];
2505
- this.lastSizeDirection = "ideal";
2506
- }
2507
- tick(input) {
2508
- const { observation, quality, timestampMs } = input;
2509
- const dtSeconds = this.lastTickAt === null ? 0 : Math.max(0, (timestampMs - this.lastTickAt) / 1e3);
2510
- this.lastTickAt = timestampMs;
2511
- const factors = {
2512
- presence: 0,
2513
- centering: 0,
2514
- size: 0,
2515
- pose: 0,
2516
- sharpness: clamp012(quality.sharpness),
2517
- exposure: clamp012(quality.exposure),
2518
- motion: 1
2519
- };
2520
- if (observation !== null) {
2521
- factors.presence = 1;
2522
- const geometry = this.geometryOf(observation, input);
2523
- factors.centering = geometry.centering;
2524
- factors.size = geometry.size;
2525
- factors.pose = geometry.pose;
2526
- factors.motion = this.motionOf(
2527
- geometry.center,
2528
- geometry.iod,
2529
- timestampMs
2530
- );
2531
- } else {
2532
- this.lastCenter = null;
2533
- this.velocityEma = 0;
2534
- }
2535
- const q = Math.min(
2536
- factors.presence,
2537
- factors.centering,
2538
- factors.size,
2539
- factors.pose,
2540
- factors.sharpness,
2541
- factors.exposure,
2542
- factors.motion
2543
- );
2544
- this.p = clamp012(
2545
- this.p + (q >= this.t.Q_GOOD ? this.t.RISE_PER_S * q : -this.t.FALL_PER_S * (1 - q)) * dtSeconds
2546
- );
2547
- this.qWindow.push({ at: timestampMs, q });
2548
- this.qWindow = this.qWindow.filter(
2549
- (entry) => entry.at >= timestampMs - this.t.READY_WINDOW_MS
2550
- );
2551
- let windowSamples = this.qWindow.map((entry) => entry.q);
2552
- if (windowSamples.length >= 3) {
2553
- const worst = Math.min(...windowSamples);
2554
- const worstIndex = windowSamples.indexOf(worst);
2555
- windowSamples = windowSamples.filter((_2, index) => index !== worstIndex);
2556
- }
2557
- const ready = this.p >= 1 && windowSamples.every((sample) => sample >= this.t.Q_GOOD);
2558
- return {
2559
- at: timestampMs,
2560
- q,
2561
- p: this.p,
2562
- factors,
2563
- guidanceKey: this.guidanceOf(factors, quality, q),
2564
- ready,
2565
- accepted: q >= this.t.Q_GOOD
2566
- };
2567
- }
2568
- geometryOf(observation, input) {
2569
- const { box, eyes } = observation;
2570
- const frameCenter = { x: input.frameWidth / 2, y: input.frameHeight / 2 };
2571
- const shortSide = Math.min(input.frameWidth, input.frameHeight);
2572
- const center = eyes !== void 0 ? {
2573
- x: (eyes.left.x + eyes.right.x) / 2,
2574
- y: (eyes.left.y + eyes.right.y) / 2
2575
- } : {
2576
- x: box.x + box.width / 2,
2577
- y: box.y + box.height / 2 - this.t.BOX_EYE_OFFSET_FACTOR * box.height
2578
- };
2579
- const iod = eyes !== void 0 ? Math.hypot(eyes.right.x - eyes.left.x, eyes.right.y - eyes.left.y) : this.t.IOD_BOX_PROXY_FACTOR * box.width;
2580
- const distance = Math.hypot(
2581
- center.x - frameCenter.x,
2582
- center.y - frameCenter.y
2583
- );
2584
- const centering = iod <= 0 ? 0 : 1 - clamp012(distance / (this.t.CENTER_FALLOFF_IOD_MULTIPLE * iod));
2585
- const ratio = shortSide > 0 ? iod / shortSide : 0;
2586
- this.lastSizeDirection = ratio < this.t.SIZE_IDEAL_MIN ? "far" : ratio > this.t.SIZE_IDEAL_MAX ? "close" : "ideal";
2587
- let size;
2588
- if (ratio < this.t.SIZE_HARD_MIN || ratio > this.t.SIZE_HARD_MAX) {
2589
- size = 0;
2590
- } else if (ratio < this.t.SIZE_IDEAL_MIN) {
2591
- size = (ratio - this.t.SIZE_HARD_MIN) / (this.t.SIZE_IDEAL_MIN - this.t.SIZE_HARD_MIN);
2592
- } else if (ratio > this.t.SIZE_IDEAL_MAX) {
2593
- size = (this.t.SIZE_HARD_MAX - ratio) / (this.t.SIZE_HARD_MAX - this.t.SIZE_IDEAL_MAX);
2594
- } else {
2595
- size = 1;
2596
- }
2597
- let pose = 1;
2598
- if (eyes !== void 0) {
2599
- const rollDeg = Math.abs(
2600
- Math.atan2(eyes.right.y - eyes.left.y, eyes.right.x - eyes.left.x)
2601
- ) * 180 / Math.PI;
2602
- pose = 1 - clamp012(rollDeg / this.t.ROLL_MAX_DEG);
2603
- }
2604
- return { center, iod, centering, size, pose };
2605
- }
2606
- motionOf(center, iod, at) {
2607
- const previous = this.lastCenter;
2608
- this.lastCenter = { ...center, at };
2609
- if (previous === null || iod <= 0) return 1;
2610
- const dtSeconds = (at - previous.at) / 1e3;
2611
- if (dtSeconds <= 0) return 1;
2612
- let velocityIodPerS = Math.hypot(center.x - previous.x, center.y - previous.y) / iod / dtSeconds;
2613
- if (velocityIodPerS <= this.t.MOTION_DEADBAND_IOD_PER_S)
2614
- velocityIodPerS = 0;
2615
- const alpha = 1 - Math.exp(-dtSeconds / this.t.MOTION_TAU_S);
2616
- this.velocityEma = alpha * velocityIodPerS + (1 - alpha) * this.velocityEma;
2617
- return 1 - clamp012(this.velocityEma / this.t.MOTION_VELOCITY_IOD_PER_S);
2618
- }
2619
- /** Lowest failing factor speaks — fixed priority (diagnostic, incl. light):
2620
- * presence → size → centering → pose → exposure → sharpness → hold.
2621
- *
2622
- * HONESTY FALLBACK (operator ruling 2026-07-12): when every factor clears
2623
- * its guide threshold but q (= min factor) is still below Q_GOOD — i.e.
2624
- * progress is DRAINING — "hold still" would be a lie ("Perfect" while
2625
- * nothing advances; the field symptom was users discovering by accident
2626
- * that only leaning in fires the gate). In that state the WORST factor
2627
- * speaks even though it passed its guide level, so the user always hears
2628
- * the change that actually unblocks recording. */
2629
- guidanceOf(factors, quality, q) {
2630
- if (factors.presence <= 0) return "fcv3.no_face";
2631
- if (factors.size < this.t.GUIDE_SIZE) return this.sizeGuidance();
2632
- if (factors.centering < this.t.GUIDE_CENTERING) return "fcv3.center_face";
2633
- if (factors.pose < this.t.GUIDE_POSE) return "fcv3.straighten";
2634
- if (factors.exposure < this.t.GUIDE_EXPOSURE)
2635
- return this.exposureGuidance(quality);
2636
- if (factors.sharpness < this.t.GUIDE_SHARPNESS) return "fcv3.steady_camera";
2637
- if (factors.motion < this.t.GUIDE_MOTION) return "fcv3.hold_still";
2638
- if (q < this.t.Q_GOOD) {
2639
- const coachable = [
2640
- ["size", this.sizeGuidance()],
2641
- ["centering", "fcv3.center_face"],
2642
- ["pose", "fcv3.straighten"],
2643
- ["exposure", this.exposureGuidance(quality)],
2644
- ["sharpness", "fcv3.steady_camera"],
2645
- ["motion", "fcv3.hold_still"]
2646
- ];
2647
- let worst = coachable[0];
2648
- for (const entry of coachable) {
2649
- if (factors[entry[0]] < factors[worst[0]]) worst = entry;
2650
- }
2651
- return worst[1];
2652
- }
2653
- return "fcv3.hold_still";
2654
- }
2655
- /** Direction from the size band set THIS tick (never inverted at the hard
2656
- * limits: past SIZE_HARD_MAX the direction is 'close' → move_back). */
2657
- sizeGuidance() {
2658
- return this.lastSizeDirection === "far" ? "fcv3.come_closer" : "fcv3.move_back";
2659
- }
2660
- /** Band midpoint — direction only (tracks EXPOSURE_BAND automatically). */
2661
- exposureGuidance(quality) {
2662
- const bandMid = (EXPOSURE_BAND[0] + EXPOSURE_BAND[1]) / 2;
2663
- return quality.meanLuma < bandMid ? "fcv3.more_light" : "fcv3.too_bright";
2664
- }
2665
- };
2666
-
2667
- // src/core/v3/capture-session-v3.ts
2668
- init_frame_quality();
2669
- var KEYFRAME_CANDIDATES = 4;
2670
- var KEYFRAME_WINDOW_MS = 600;
2671
- var NEUTRAL_QUALITY = { sharpness: 1, exposure: 1, meanLuma: 128 };
2672
- var CaptureSessionV3 = class {
2673
- constructor(options) {
2674
- this.handlers = /* @__PURE__ */ new Map();
2675
- this.stateValue = "idle";
2676
- this.attempt = 0;
2677
- this.stream = null;
2678
- this.detector = null;
2679
- this.scheduler = null;
2680
- this.gate = null;
2681
- this.profiler = null;
2682
- this.lastGuidanceKey = null;
2683
- this.positioningStartedAt = 0;
2684
- // Face-capture timing marks of the CURRENT attempt (engine clock; reset per run).
2685
- this.cameraRequestedAt = null;
2686
- this.cameraReadyAt = null;
2687
- this.faceAcquiredAt = null;
2688
- this.captureCompleteAt = null;
2689
- this.fired = false;
2690
- this.carriedDegrade = 0;
2691
- this.carriedMeans = [];
2692
- /** Reused downscale canvas — falls back to the raw video where canvas 2D
2693
- * is unavailable (jsdom) so tests and exotic hosts keep detecting. */
2694
- this.snapshotCanvas = null;
2695
- this.options = options;
2696
- this.facing = options.facingMode ?? "user";
2697
- }
2698
- get state() {
2699
- return this.stateValue;
2700
- }
2701
- on(event, handler) {
2702
- let set = this.handlers.get(event);
2703
- if (!set) {
2704
- set = /* @__PURE__ */ new Set();
2705
- this.handlers.set(event, set);
2706
- }
2707
- set.add(handler);
2708
- return () => set?.delete(handler);
2709
- }
2710
- emit(event, payload) {
2711
- for (const handler of [...this.handlers.get(event) ?? []]) {
2712
- handler(payload);
2713
- }
2714
- }
2715
- async start(options = {}) {
2716
- if (options.facingMode !== void 0) this.facing = options.facingMode;
2717
- this.attempt += 1;
2718
- await this.run(this.attempt);
2719
- }
2720
- /** The camera the current/next attempt requests (start option, switchCamera toggles). */
2721
- get facingMode() {
2722
- return this.facing;
2723
- }
2724
- /** Full reset + camera restart — the documented recovery path (v1 parity). */
2725
- retry() {
2726
- this.teardownAttempt();
2727
- void this.start();
2728
- }
2729
- switchCamera() {
2730
- this.facing = this.facing === "user" ? "environment" : "user";
2731
- this.teardownAttempt();
2732
- void this.start();
2733
- }
2734
- destroy() {
2735
- this.attempt += 1;
2736
- this.teardownAttempt();
2737
- this.detector?.destroy();
2738
- this.detector = null;
2739
- this.options.video.srcObject = null;
2740
- }
2741
- // ── attempt lifecycle ──────────────────────────────────────────────────────
2742
- async run(attempt) {
2743
- const { options } = this;
2744
- this.fired = false;
2745
- this.lastGuidanceKey = null;
2746
- this.carriedDegrade = 0;
2747
- this.carriedMeans = [];
2748
- this.cameraRequestedAt = null;
2749
- this.cameraReadyAt = null;
2750
- this.faceAcquiredAt = null;
2751
- this.captureCompleteAt = null;
2752
- this.setState("preflight");
2753
- const preflight = cameraPreflight();
2754
- if (preflight !== "OK") {
2755
- this.fail(preflight === "INSECURE_CONTEXT" ? "insecure" : "unsupported");
2756
- return;
2757
- }
2758
- this.setState("acquiring");
2759
- const getUserMedia = options.getUserMedia ?? ((constraints) => navigator.mediaDevices.getUserMedia(constraints));
2760
- let stream;
2761
- this.cameraRequestedAt = this.now();
2762
- try {
2763
- stream = await getUserMedia(buildCaptureConstraints(detectIsMobile(), this.facing));
2764
- } catch (err) {
2765
- if (attempt !== this.attempt) return;
2766
- this.fail(mapGetUserMediaError(err));
2767
- return;
2768
- }
2769
- if (attempt !== this.attempt) {
2770
- for (const track of stream.getTracks()) track.stop();
2771
- return;
2772
- }
2773
- this.stream = stream;
2774
- options.video.srcObject = stream;
2775
- await options.video.play().catch(() => void 0);
2776
- if (attempt !== this.attempt) return;
2777
- this.cameraReadyAt = this.now();
2778
- if (this.detector === null) {
2779
- const ladderOptions = {
2780
- ...options.v3AssetBaseUrl !== void 0 ? { v3AssetBaseUrl: options.v3AssetBaseUrl } : {}
2781
- };
2782
- const create = options.createDetector ?? (options.createWorker !== void 0 && workerOffloadSupported() ? async () => {
2783
- try {
2784
- return await WorkerDetectorProxy.create(
2785
- options.createWorker(),
2786
- ladderOptions
2787
- );
2788
- } catch {
2789
- return createDetector(ladderOptions);
2790
- }
2791
- } : () => createDetector(ladderOptions));
2792
- let created;
2793
- try {
2794
- created = await create();
2795
- } catch (err) {
2796
- if (attempt === this.attempt) {
2797
- this.fail(
2798
- "models",
2799
- err instanceof DetectorLadderError ? err.fallbackReason : describeError2(err)
2800
- );
2801
- }
2802
- return;
2803
- }
2804
- if (attempt !== this.attempt) {
2805
- created.destroy();
2806
- return;
2807
- }
2808
- this.detector = created;
2809
- this.options.telemetry?.({
2810
- type: "detector",
2811
- tier: created.tier,
2812
- ...created.fallbackReason !== void 0 ? { fallbackReason: created.fallbackReason } : {}
2813
- });
2814
- }
2815
- const probe = probeDevice();
2816
- const staticClass = options.deviceClass ?? classifyDevice(probe);
2817
- this.profiler = new DeviceProfiler(staticClass);
2818
- this.options.telemetry?.({
2819
- type: "profile",
2820
- staticClass,
2821
- activeClass: this.profiler.deviceClass,
2822
- simd: probe.simd
2823
- });
2824
- this.gate = new FaceGateV3(options.thresholds ?? {});
2825
- this.setState("positioning");
2826
- this.positioningStartedAt = this.now();
2827
- this.startScheduler(attempt);
2828
- }
2829
- /** Chrome hint (Task 11): 'reduced' on LOW even without the media query. */
2830
- get animations() {
2831
- return this.profiler?.profile.animations ?? "full";
2832
- }
2833
- startScheduler(attempt) {
2834
- const profiler = this.profiler;
2835
- if (profiler === null) return;
2836
- if (this.scheduler !== null) {
2837
- const stats = this.scheduler.stats();
2838
- this.carriedDegrade += stats.degradeCount;
2839
- if (stats.meanDetectMs > 0) this.carriedMeans.push(stats.meanDetectMs);
2840
- this.scheduler.stop();
2841
- }
2842
- const scheduler = new DetectScheduler({
2843
- cadenceHz: profiler.profile.cadenceHz,
2844
- video: this.options.video,
2845
- ...this.options.now !== void 0 ? { now: this.options.now } : {},
2846
- run: () => this.detectTick(attempt)
2847
- });
2848
- this.scheduler = scheduler;
2849
- scheduler.start();
2850
- }
2851
- async detectTick(attempt) {
2852
- const { detector, gate, profiler } = this;
2853
- const video = this.options.video;
2854
- if (attempt !== this.attempt || detector === null || gate === null || profiler === null)
2855
- return;
2856
- if (this.fired || video.videoWidth === 0) return;
2857
- const before = profiler.deviceClass;
2858
- const t0 = this.now();
2859
- const source = this.options.makeSnapshot?.(video, profiler.profile.inputWidth) ?? this.defaultSnapshot(video, profiler.profile.inputWidth);
2860
- let observation = null;
2861
- try {
2862
- observation = await detector.detect(source, video.videoWidth, video.videoHeight);
2863
- } catch {
2864
- observation = null;
2865
- }
2866
- if (attempt !== this.attempt || this.fired) return;
2867
- profiler.record(this.now() - t0);
2868
- if (profiler.deviceClass !== before) this.startScheduler(attempt);
2869
- const quality = observation === null ? NEUTRAL_QUALITY : this.options.measureQuality?.(video, observation.box) ?? this.defaultQuality(video, observation.box);
2870
- const tick = gate.tick({
2871
- timestampMs: this.now(),
2872
- observation,
2873
- quality,
2874
- frameWidth: video.videoWidth,
2875
- frameHeight: video.videoHeight
2876
- });
2877
- if (tick.accepted && this.faceAcquiredAt === null) this.faceAcquiredAt = tick.at;
2878
- this.emit("checks", {
2879
- engine: "v3",
2880
- progress: tick.p,
2881
- q: tick.q,
2882
- factors: tick.factors,
2883
- attempt
2884
- });
2885
- if (tick.guidanceKey !== this.lastGuidanceKey) {
2886
- this.lastGuidanceKey = tick.guidanceKey;
2887
- this.emit("guidance", { key: tick.guidanceKey });
2888
- }
2889
- if (tick.ready && this.stateValue === "positioning") {
2890
- this.fired = true;
2891
- this.captureCompleteAt = tick.at;
2892
- void this.fire(attempt);
2893
- }
2894
- }
2895
- async fire(attempt) {
2896
- const { options } = this;
2897
- const scheduler = this.scheduler;
2898
- scheduler?.stop();
2899
- const stats = scheduler?.stats() ?? { degradeCount: 0, meanDetectMs: 0 };
2900
- const means = [...this.carriedMeans, ...stats.meanDetectMs > 0 ? [stats.meanDetectMs] : []];
2901
- options.telemetry?.({
2902
- type: "fired",
2903
- timeToGateMs: this.now() - this.positioningStartedAt,
2904
- degradeCount: this.carriedDegrade + stats.degradeCount,
2905
- meanDetectMs: means.length === 0 ? 0 : means.reduce((sum, value) => sum + value, 0) / means.length
2906
- });
2907
- const mode = options.mode ?? "clip";
2908
- const bestOf = this.collectKeyframes(attempt);
2909
- if (mode === "photo") {
2910
- const best2 = await bestOf;
2911
- if (attempt !== this.attempt) return;
2912
- if (best2 === null) {
2913
- this.fail("generic");
2914
- return;
2915
- }
2916
- this.finishCapture({ keyframe: best2.blob, previewDataUrl: best2.previewDataUrl });
2917
- return;
2918
- }
2919
- this.setState("recording");
2920
- const recorder = options.createRecorder?.() ?? new ClipRecorder();
2921
- const stream = this.stream;
2922
- if (stream === null) {
2923
- this.fail("generic");
2924
- return;
2925
- }
2926
- let frozenBest = null;
2927
- void bestOf.then(
2928
- (candidate) => {
2929
- frozenBest = candidate;
2930
- },
2931
- () => {
2932
- }
2933
- );
2934
- const onRecordingStopped = () => {
2935
- if (attempt !== this.attempt) return;
2936
- if (frozenBest !== null) {
2937
- this.emit("frozen", { previewDataUrl: frozenBest.previewDataUrl });
2938
- }
2939
- };
2940
- let clip;
2941
- let best;
2942
- try {
2943
- [clip, best] = await Promise.all([recorder.record(stream, onRecordingStopped), bestOf]);
2944
- } catch (err) {
2945
- if (attempt !== this.attempt) return;
2946
- const kind = err.kind;
2947
- this.fail(kind === "cliptoolarge" ? "cliptoolarge" : "recorder");
2948
- return;
2949
- }
2950
- if (attempt !== this.attempt) return;
2951
- if (isClipTooLarge(clip.blob)) {
2952
- this.fail("cliptoolarge");
2953
- return;
2954
- }
2955
- if (best === null) {
2956
- this.fail("generic");
2957
- return;
2958
- }
2959
- this.finishCapture({
2960
- clip: clip.blob,
2961
- clipMimeType: clip.mimeType,
2962
- keyframe: best.blob,
2963
- previewDataUrl: best.previewDataUrl
2964
- });
2965
- }
2966
- /** Up to KEYFRAME_CANDIDATES mirrored frames over KEYFRAME_WINDOW_MS —
2967
- * sharpest wins (reuses frame-quality.sharpness via the capture seam). */
2968
- async collectKeyframes(attempt) {
2969
- const capture = this.options.captureKeyframe ?? ((video) => this.defaultKeyframe(video));
2970
- const stepMs = KEYFRAME_WINDOW_MS / (KEYFRAME_CANDIDATES - 1);
2971
- let best = null;
2972
- for (let i2 = 0; i2 < KEYFRAME_CANDIDATES; i2 += 1) {
2973
- if (attempt !== this.attempt) return best;
2974
- try {
2975
- const candidate = await capture(this.options.video);
2976
- if (best === null || candidate.sharpness > best.sharpness) best = candidate;
2977
- } catch {
2978
- }
2979
- if (i2 < KEYFRAME_CANDIDATES - 1) await delay(stepMs);
2980
- }
2981
- return best;
2982
- }
2983
- finishCapture(artifacts) {
2984
- this.stopTracks();
2985
- this.setState("captured");
2986
- const timing = this.captureTiming();
2987
- this.emit("artifacts", timing === void 0 ? artifacts : { ...artifacts, timing });
2988
- }
2989
- /** The attempt's capture-phase timing (whole ms, ≥ 0); undefined when no mark landed. */
2990
- captureTiming() {
2991
- const span = (from, to) => from !== null && to !== null ? Math.max(0, Math.round(to - from)) : void 0;
2992
- const cameraReadyMs = span(this.cameraRequestedAt, this.cameraReadyAt);
2993
- const faceAcquireMs = span(this.cameraReadyAt, this.faceAcquiredAt);
2994
- const captureMs = span(this.faceAcquiredAt, this.captureCompleteAt);
2995
- const timing = {
2996
- ...cameraReadyMs !== void 0 ? { cameraReadyMs } : {},
2997
- ...faceAcquireMs !== void 0 ? { faceAcquireMs } : {},
2998
- ...captureMs !== void 0 ? { captureMs } : {}
2999
- };
3000
- return Object.keys(timing).length > 0 ? timing : void 0;
3001
- }
3002
- // ── defaults for the canvas-bound seams ────────────────────────────────────
3003
- async defaultKeyframe(video) {
3004
- const canvas = document.createElement("canvas");
3005
- const blob = await captureMirroredKeyframe(video, canvas);
3006
- const previewDataUrl = canvas.toDataURL("image/jpeg", 0.92);
3007
- return { blob, previewDataUrl, sharpness: this.centerSharpness(video) };
3008
- }
3009
- defaultSnapshot(video, targetWidth) {
3010
- try {
3011
- const canvas = this.snapshotCanvas ?? document.createElement("canvas");
3012
- const scale = targetWidth / Math.max(1, video.videoWidth);
3013
- const width = Math.max(1, Math.round(video.videoWidth * scale));
3014
- const height = Math.max(1, Math.round(video.videoHeight * scale));
3015
- const ctx = canvas.getContext("2d");
3016
- if (ctx === null) return video;
3017
- if (canvas.width !== width) canvas.width = width;
3018
- if (canvas.height !== height) canvas.height = height;
3019
- ctx.drawImage(video, 0, 0, width, height);
3020
- this.snapshotCanvas = canvas;
3021
- return canvas;
3022
- } catch {
3023
- return video;
3024
- }
3025
- }
3026
- defaultQuality(video, box) {
3027
- const crop = cropImageData(video, box, 96);
3028
- if (crop === null) return NEUTRAL_QUALITY;
3029
- return { sharpness: sharpness(crop), exposure: exposure(crop), meanLuma: meanLuma(crop) };
3030
- }
3031
- centerSharpness(video) {
3032
- const size = intrinsicSize(video);
3033
- const crop = cropImageData(
3034
- video,
3035
- { x: size.width * 0.25, y: size.height * 0.25, width: size.width * 0.5, height: size.height * 0.5 },
3036
- 96
3037
- );
3038
- return crop === null ? 0 : sharpness(crop);
3039
- }
3040
- // ── teardown ──────────────────────────────────────────────────────────────
3041
- teardownAttempt() {
3042
- this.scheduler?.stop();
3043
- this.scheduler = null;
3044
- this.gate = null;
3045
- this.stopTracks();
3046
- }
3047
- stopTracks() {
3048
- if (this.stream === null) return;
3049
- for (const track of this.stream.getTracks()) track.stop();
3050
- this.stream = null;
3051
- }
3052
- fail(kind, fallbackReason) {
3053
- this.scheduler?.stop();
3054
- this.stopTracks();
3055
- this.setState("error");
3056
- this.options.telemetry?.({
3057
- type: "error",
3058
- kind,
3059
- ...fallbackReason !== void 0 ? { fallbackReason } : {}
3060
- });
3061
- this.emit("error", { kind, retryable: kind !== "insecure" && kind !== "unsupported" });
3062
- }
3063
- setState(state) {
3064
- this.stateValue = state;
3065
- this.emit("statechange", { state });
3066
- }
3067
- now() {
3068
- return this.options.now?.() ?? performance.now();
3069
- }
3070
- };
3071
- function delay(ms) {
3072
- return new Promise((resolve) => setTimeout(resolve, ms));
3073
- }
3074
- function describeError2(err) {
3075
- return err instanceof Error ? err.message : String(err);
3076
- }
3077
- function cropImageData(video, box, targetWidth) {
3078
- try {
3079
- const canvas = document.createElement("canvas");
3080
- const scale = targetWidth / Math.max(1, box.width);
3081
- canvas.width = Math.max(1, Math.round(box.width * scale));
3082
- canvas.height = Math.max(1, Math.round(box.height * scale));
3083
- const ctx = canvas.getContext("2d");
3084
- if (ctx === null) return null;
3085
- ctx.drawImage(
3086
- video,
3087
- box.x,
3088
- box.y,
3089
- box.width,
3090
- box.height,
3091
- 0,
3092
- 0,
3093
- canvas.width,
3094
- canvas.height
3095
- );
3096
- return ctx.getImageData(0, 0, canvas.width, canvas.height);
3097
- } catch {
3098
- return null;
3099
- }
3100
- }
3101
-
3102
- // src/verification/emitter.ts
3103
- function createEmitter() {
3104
- const handlers = /* @__PURE__ */ new Map();
3105
- return {
3106
- on(event, handler) {
3107
- let set = handlers.get(event);
3108
- if (set === void 0) {
3109
- set = /* @__PURE__ */ new Set();
3110
- handlers.set(event, set);
3111
- }
3112
- const h2 = handler;
3113
- set.add(h2);
3114
- return () => {
3115
- set?.delete(h2);
3116
- };
3117
- },
3118
- emit(event, payload) {
3119
- const set = handlers.get(event);
3120
- if (set === void 0) return;
3121
- for (const handler of [...set]) {
3122
- handler(payload);
3123
- }
3124
- },
3125
- clear() {
3126
- handlers.clear();
3127
- }
3128
- };
3129
- }
3130
-
3131
- // src/capture/preload.ts
3132
- var PRELOAD_BLAZE_INIT_TIMEOUT_MS = 12e4;
3133
- var PRELOAD_BUDGET_MS = 13e4;
3134
- var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("@sekyro/web.preload.v1");
3135
- function registry() {
3136
- const host = globalThis;
3137
- host[REGISTRY_KEY] ?? (host[REGISTRY_KEY] = /* @__PURE__ */ new Map());
3138
- return host[REGISTRY_KEY];
3139
- }
3140
- function normalizeBase(assetBaseUrl) {
3141
- const base = (assetBaseUrl ?? DEFAULT_V3_ASSET_BASE_URL).replace(/\/+$/, "");
3142
- return base === "" ? "/" : base;
3143
- }
3144
- function setStatus(entry, next) {
3145
- if (entry.status === next) return;
3146
- entry.status = next;
3147
- for (const listener of [...entry.listeners]) listener(next);
3148
- }
3149
- var defaultLoader = (base) => createDetector({ preferred: ["blaze"], v3AssetBaseUrl: base, blazeInitTimeoutMs: PRELOAD_BLAZE_INIT_TIMEOUT_MS });
3150
- var loader = defaultLoader;
3151
- function setPreloadLoaderForTests(next) {
3152
- loader = next ?? defaultLoader;
3153
- }
3154
- function resetLivenessAssetsForTests() {
3155
- for (const entry of registry().values()) entry.detector?.destroy();
3156
- registry().clear();
3157
- loader = defaultLoader;
3158
- }
3159
- function begin(entry, base) {
3160
- if ((entry.status === "loading" || entry.status === "ready") && entry.promise !== null) return entry.promise;
3161
- setStatus(entry, "loading");
3162
- const detectorPromise = new Promise((resolve) => resolve(loader(base)));
3163
- entry.detectorPromise = detectorPromise;
3164
- let timer;
3165
- const budget = new Promise((_2, reject) => {
3166
- timer = setTimeout(() => {
3167
- detectorPromise.then((late) => late.destroy(), () => void 0);
3168
- reject(new Error(`detector preload exceeded ${PRELOAD_BUDGET_MS} ms`));
3169
- }, PRELOAD_BUDGET_MS);
3170
- });
3171
- const settled = Promise.race([detectorPromise, budget]).then(
3172
- (detector) => {
3173
- if (entry.detectorPromise !== detectorPromise) {
3174
- detector.destroy();
3175
- return entry.status;
3176
- }
3177
- entry.detector = detector;
3178
- setStatus(entry, "ready");
3179
- return "ready";
3180
- },
3181
- (err) => {
3182
- if (entry.detectorPromise === detectorPromise) {
3183
- entry.detectorPromise = null;
3184
- entry.detector = null;
3185
- setStatus(entry, "failed");
3186
- console.warn("[@sekyro/web] face-detector preload failed:", err);
3187
- }
3188
- return entry.status;
3189
- }
3190
- );
3191
- const promise = settled.finally(() => clearTimeout(timer));
3192
- entry.promise = promise;
3193
- entry.scheduled?.settle(promise);
3194
- return promise;
3195
- }
3196
- function nonOwningView(shared) {
3197
- return {
3198
- get tier() {
3199
- return shared.tier;
3200
- },
3201
- get fallbackReason() {
3202
- return shared.fallbackReason;
3203
- },
3204
- detect: (...args) => shared.detect(...args),
3205
- destroy: () => {
3206
- }
3207
- };
3208
- }
3209
- function preloadedDetectorFactory(assetBaseUrl) {
3210
- const base = normalizeBase(assetBaseUrl);
3211
- const entry = registry().get(base);
3212
- if (entry === void 0 || entry.detector === null && entry.detectorPromise === null && entry.scheduled === null) {
3213
- return void 0;
3214
- }
3215
- return async () => {
3216
- if (entry.scheduled !== null) void begin(entry, base);
3217
- let waitingOn = entry.promise;
3218
- while (entry.detector === null && waitingOn !== null) {
3219
- await waitingOn;
3220
- if (entry.promise === waitingOn) break;
3221
- waitingOn = entry.promise;
3222
- }
3223
- return entry.detector !== null ? nonOwningView(entry.detector) : createDetector({ v3AssetBaseUrl: base });
3224
- };
3225
- }
3226
-
3227
- // src/capture/wake-lock.ts
3228
- function wakeLockApi() {
3229
- if (typeof navigator === "undefined" || !("wakeLock" in navigator)) return null;
3230
- const api = navigator.wakeLock;
3231
- return typeof api?.request === "function" ? api : null;
3232
- }
3233
- function isVisible() {
3234
- return typeof document === "undefined" || document.visibilityState === "visible";
3235
- }
3236
- function releaseQuietly(sentinel) {
3237
- try {
3238
- void sentinel.release().catch(() => void 0);
3239
- } catch {
3240
- }
3241
- }
3242
- function createScreenWakeLock(options = {}) {
3243
- if (options.enabled === false) return { setActive: () => void 0 };
3244
- let wanted = false;
3245
- let sentinel = null;
3246
- let inFlight = false;
3247
- let listening = false;
3248
- const acquire = () => {
3249
- if (!wanted || inFlight || sentinel !== null && !sentinel.released) return;
3250
- const api = wakeLockApi();
3251
- if (api === null || !isVisible()) return;
3252
- let request;
3253
- try {
3254
- request = api.request("screen");
3255
- } catch {
3256
- return;
3257
- }
3258
- inFlight = true;
3259
- request.then(
3260
- (granted) => {
3261
- inFlight = false;
3262
- if (!wanted) {
3263
- releaseQuietly(granted);
3264
- return;
3265
- }
3266
- sentinel = granted;
3267
- granted.addEventListener?.("release", () => {
3268
- if (sentinel === granted) sentinel = null;
3269
- });
3270
- },
3271
- () => {
3272
- inFlight = false;
3273
- }
3274
- );
3275
- };
3276
- const onVisibilityChange = () => {
3277
- if (isVisible()) acquire();
3278
- };
3279
- const listen = (on) => {
3280
- if (typeof document === "undefined" || on === listening) return;
3281
- listening = on;
3282
- if (on) document.addEventListener("visibilitychange", onVisibilityChange);
3283
- else document.removeEventListener("visibilitychange", onVisibilityChange);
3284
- };
3285
- return {
3286
- setActive: (active) => {
3287
- wanted = active;
3288
- if (active) {
3289
- if (wakeLockApi() === null) return;
3290
- listen(true);
3291
- acquire();
3292
- return;
3293
- }
3294
- listen(false);
3295
- if (sentinel !== null) {
3296
- const held = sentinel;
3297
- sentinel = null;
3298
- releaseQuietly(held);
3299
- }
3300
- }
3301
- };
3302
- }
3303
-
3304
- // src/capture/create-liveness-capture.ts
3305
- function mapGuidanceHint(key) {
3306
- switch (key) {
3307
- case "fcv3.no_face":
3308
- case "fcv3.center_face":
3309
- case "fcv3.straighten":
3310
- return "center";
3311
- case "fcv3.come_closer":
3312
- return "closer";
3313
- case "fcv3.move_back":
3314
- return "farther";
3315
- case "fcv3.more_light":
3316
- case "fcv3.too_bright":
3317
- return "light";
3318
- case "fcv3.hold_still":
3319
- case "fcv3.steady_camera":
3320
- return "still";
3321
- default:
3322
- return null;
3323
- }
3324
- }
3325
- function mapEngineState(state) {
3326
- switch (state) {
3327
- case "preflight":
3328
- case "acquiring":
3329
- return "starting";
3330
- case "positioning":
3331
- return "gating";
3332
- case "idle":
3333
- case "recording":
3334
- case "captured":
3335
- case "error":
3336
- return state;
3337
- default: {
3338
- const unhandled = state;
3339
- throw new Error(`mapEngineState: unhandled state ${unhandled}`);
3340
- }
3341
- }
3342
- }
3343
- function mapErrorKind(kind) {
3344
- switch (kind) {
3345
- case "permission":
3346
- case "notfound":
3347
- case "inuse":
3348
- case "insecure":
3349
- case "unsupported":
3350
- return kind;
3351
- case "overconstrained":
3352
- case "generic":
3353
- case "models":
3354
- case "cliptoolarge":
3355
- case "recorder":
3356
- return "generic";
3357
- default: {
3358
- const unhandled = kind;
3359
- throw new Error(`mapErrorKind: unhandled kind ${unhandled}`);
3360
- }
3361
- }
3362
- }
3363
- function createLivenessCaptureInternal(options, internals = {}) {
3364
- const now = internals.now ?? (() => performance.now());
3365
- const emitter = createEmitter();
3366
- const degraded = !isMediaRecorderSupported();
3367
- const hostSeams = internals.engineOptions;
3368
- const preloadAware = hostSeams?.createDetector === void 0 && hostSeams?.createWorker === void 0 ? {
3369
- createDetector: () => {
3370
- const warmed = preloadedDetectorFactory(options.assetBaseUrl);
3371
- return warmed !== void 0 ? warmed() : createDetector(
3372
- options.assetBaseUrl !== void 0 ? { v3AssetBaseUrl: options.assetBaseUrl } : {}
3373
- );
3374
- }
3375
- } : {};
3376
- const engineOptions = {
3377
- video: options.video,
3378
- mode: degraded ? "photo" : "clip",
3379
- ...options.facing !== void 0 ? { facingMode: options.facing } : {},
3380
- ...options.assetBaseUrl !== void 0 ? { v3AssetBaseUrl: options.assetBaseUrl } : {},
3381
- ...internals.engineOptions ?? {},
3382
- ...preloadAware
3383
- };
3384
- const engine = internals.createEngine?.(engineOptions) ?? new CaptureSessionV3(engineOptions);
3385
- let state = "idle";
3386
- let hint = null;
3387
- let progress = 0;
3388
- let faceDetected = false;
3389
- let animations = "full";
3390
- let recordingStartedAt = null;
3391
- let frozenAt = null;
3392
- let frameWidth = 0;
3393
- let frameHeight = 0;
3394
- const latchFrameSize = () => {
3395
- if (options.video.videoWidth > 0 && options.video.videoHeight > 0) {
3396
- frameWidth = options.video.videoWidth;
3397
- frameHeight = options.video.videoHeight;
3398
- }
3399
- };
3400
- const wakeLock = createScreenWakeLock({ enabled: options.keepScreenAwake !== false });
3401
- const setState = (next) => {
3402
- state = next;
3403
- wakeLock.setActive(next === "starting" || next === "gating" || next === "recording");
3404
- emitter.emit("state", next);
3405
- };
3406
- const emitGate = () => emitter.emit("gate", { progress, hint, faceDetected });
3407
- const syncProfile = () => {
3408
- const next = engine.animations ?? "full";
3409
- if (next === animations) return;
3410
- animations = next;
3411
- emitter.emit("profile", { animations });
3412
- };
3413
- const unsubscribes = [
3414
- engine.on("statechange", ({ state: engineState }) => {
3415
- const next = mapEngineState(engineState);
3416
- if (next === "starting" && state !== "starting") {
3417
- hint = null;
3418
- progress = 0;
3419
- faceDetected = false;
3420
- recordingStartedAt = null;
3421
- frozenAt = null;
3422
- frameWidth = 0;
3423
- frameHeight = 0;
3424
- }
3425
- setState(next);
3426
- syncProfile();
3427
- if (next === "recording") {
3428
- latchFrameSize();
3429
- recordingStartedAt = now();
3430
- hint = "hold";
3431
- progress = 1;
3432
- emitGate();
3433
- }
3434
- }),
3435
- engine.on("checks", (payload) => {
3436
- latchFrameSize();
3437
- progress = payload.progress;
3438
- faceDetected = payload.factors.presence > 0;
3439
- emitGate();
3440
- syncProfile();
3441
- }),
3442
- engine.on("guidance", ({ key }) => {
3443
- hint = mapGuidanceHint(key);
3444
- emitGate();
3445
- }),
3446
- engine.on("frozen", ({ previewDataUrl }) => {
3447
- frozenAt = now();
3448
- emitter.emit("frozen", { previewDataUrl });
3449
- }),
3450
- engine.on("artifacts", (artifacts) => {
3451
- const clipMs = recordingStartedAt !== null && frozenAt !== null ? Math.max(0, Math.round(frozenAt - recordingStartedAt)) : void 0;
3452
- emitter.emit("captured", {
3453
- keyframe: artifacts.keyframe,
3454
- ...artifacts.clip !== void 0 ? { clip: artifacts.clip } : {},
3455
- ...artifacts.clipMimeType !== void 0 ? { clipMime: artifacts.clipMimeType } : {},
3456
- width: options.video.videoWidth || frameWidth,
3457
- height: options.video.videoHeight || frameHeight,
3458
- ...clipMs !== void 0 ? { clipMs } : {},
3459
- captureChannel: detectIsMobile() ? "mobile" : "desktop",
3460
- ...degraded ? { degraded: "NO_RECORDER" } : {},
3461
- engine: "v3",
3462
- // Face-capture timing: the engine's marks, forwarded flat (absent → absent).
3463
- ...artifacts.timing?.cameraReadyMs !== void 0 ? { cameraReadyMs: artifacts.timing.cameraReadyMs } : {},
3464
- ...artifacts.timing?.faceAcquireMs !== void 0 ? { faceAcquireMs: artifacts.timing.faceAcquireMs } : {},
3465
- ...artifacts.timing?.captureMs !== void 0 ? { captureMs: artifacts.timing.captureMs } : {}
3466
- });
3467
- }),
3468
- engine.on("error", ({ kind, retryable }) => {
3469
- emitter.emit("error", { kind: mapErrorKind(kind), retryable });
3470
- })
3471
- ];
3472
- const handle = {
3473
- get state() {
3474
- return state;
3475
- },
3476
- on: (event, handler) => emitter.on(event, handler),
3477
- start: (startOptions) => engine.start(startOptions?.facing !== void 0 ? { facingMode: startOptions.facing } : {}),
3478
- retry: () => engine.retry(),
3479
- switchCamera: () => engine.switchCamera(),
3480
- destroy: () => {
3481
- for (const unsubscribe of unsubscribes) unsubscribe();
3482
- wakeLock.setActive(false);
3483
- engine.destroy();
3484
- emitter.clear();
3485
- }
3486
- };
3487
- return {
3488
- handle,
3489
- setFlowState: (next) => {
3490
- if (state !== next) setState(next);
3491
- }
3492
- };
3493
- }
3494
-
3495
- // src/client/errors.ts
3496
- var HostedApiError = class extends Error {
3497
- constructor(args) {
3498
- super(args.message);
3499
- this.name = "HostedApiError";
3500
- this.status = args.status;
3501
- this.code = args.code;
3502
- if (args.retryAfterSeconds !== void 0) this.retryAfterSeconds = args.retryAfterSeconds;
3503
- }
3504
- };
3505
-
3506
- // src/client/hosted-client.ts
3507
- var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
3508
- var SPACES_PUT_TIMEOUT_MS = 9e5;
3509
- var UPLOAD_ERROR_SNIPPET_CHARS = 200;
3510
- var IN_PROGRESS_RETRY_ATTEMPTS = 5;
3511
- var IN_PROGRESS_RETRY_DELAY_MS = 400;
3512
- function stripMimeParams(contentType) {
3513
- return (contentType.split(";")[0] ?? "").trim();
3514
- }
3515
- var MEDIA_INPUT_FIELD = {
3516
- liveness: "clipKey",
3517
- face_match: "imageKey",
3518
- doc_ocr: "imageKey"
3519
- };
3520
- var HostedClient = class {
3521
- constructor(opts) {
3522
- this.sessionId = null;
3523
- this.bootstrap = null;
3524
- this.apiOrigin = opts.apiOrigin.replace(/\/+$/, "");
3525
- this.sessionToken = opts.sessionToken;
3526
- const impl = opts.fetch;
3527
- this.fetchImpl = (input, init) => (impl ?? globalThis.fetch).call(globalThis, input, init);
3528
- this.requestTimeoutMs = opts.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
3529
- this.retryAttempts = opts.inProgressRetry?.attempts ?? IN_PROGRESS_RETRY_ATTEMPTS;
3530
- this.retryDelayMs = opts.inProgressRetry?.delayMs ?? IN_PROGRESS_RETRY_DELAY_MS;
3531
- }
3532
- /** Token-addressed bootstrap — the hosted page's first call. Caches the sessionId. */
3533
- async getSession() {
3534
- const view = await this.api("GET", "/hosted/session");
3535
- this.sessionId = view.sessionId;
3536
- return view;
3537
- }
3538
- /**
3539
- * Record consent once (201; an idempotent replay answers 200 with
3540
- * `alreadyRecorded: true`). Until recorded, media presign/complete AND check
3541
- * submission answer 409 `consent_required`.
3542
- */
3543
- async recordConsent(locale) {
3544
- return this.api("POST", "/hosted/consent", { body: { locale } });
3545
- }
3546
- /**
3547
- * Presign a Spaces PUT for a new pending object. `contentType` is stripped of
3548
- * MIME parameters defensively (the allowlist holds bare types; the engine's
3549
- * `clipMimeType` carries codec params) — PUT with the SAME bare type, or the
3550
- * signed-header check rejects the upload.
3551
- */
3552
- async presign(kind, contentType, contentLength) {
3553
- const id = await this.ensureSessionId();
3554
- const body = { kind, contentType: stripMimeParams(contentType), contentLength };
3555
- return this.api("POST", `/sessions/${id}/media`, { body });
3556
- }
3557
- /**
3558
- * Bare PUT to the presigned Spaces URL: EXACTLY the signed headers — the
3559
- * declared Content-Type and the blob body. NO `x-session-token` (the
3560
- * signature IS the credential; an extra header breaks nothing but leaks the
3561
- * token to a third-party host) and no JSON envelope.
3562
- *
3563
- * `contentType` is param-stripped here too (idempotent for bare types): the
3564
- * presign strips internally, so a caller composing manually with the engine's
3565
- * parameterful `clipMimeType` would otherwise sign `video/webm` but PUT
3566
- * `video/webm;codecs=…` — a signed-header mismatch S3 rejects at runtime.
3567
- *
3568
- * Timeout: 15 min (`AbortSignal.timeout(900_000)`, matching the presign TTL)
3569
- * rather than the API calls' 30 s — a 15 MB clip on a slow link legitimately
3570
- * exceeds 30 s, but a stalled in-flight socket must still be bounded (the TTL
3571
- * alone only bounds when a PUT can START).
3572
- *
3573
- * Failures are ALWAYS typed: non-2xx throws {@link HostedApiError} with the
3574
- * client-synthesized `upload_failed` (message carries a truncated S3 body
3575
- * snippet — e.g. SignatureDoesNotMatch); a mid-transfer drop → `network_error`;
3576
- * the timeout → `timeout`.
3577
- */
3578
- async uploadToSpaces(uploadUrl, blob, contentType) {
3579
- let res;
3580
- try {
3581
- res = await this.fetchImpl(uploadUrl, {
3582
- method: "PUT",
3583
- headers: { "content-type": stripMimeParams(contentType) },
3584
- body: blob,
3585
- signal: AbortSignal.timeout(SPACES_PUT_TIMEOUT_MS)
3586
- });
3587
- } catch (err) {
3588
- throw asTransportError(err);
3589
- }
3590
- if (!res.ok) {
3591
- const snippet = (await res.text().catch(() => "")).slice(0, UPLOAD_ERROR_SNIPPET_CHARS);
3592
- throw new HostedApiError({
3593
- status: res.status,
3594
- code: "upload_failed",
3595
- message: `media upload failed (HTTP ${res.status})${snippet ? `: ${snippet}` : ""}`
3596
- });
3597
- }
3598
- }
3599
- /** Finalize an upload: the backend sniffs + promotes; returns the PROMOTED key to submit. */
3600
- async completeMedia(key) {
3601
- const id = await this.ensureSessionId();
3602
- return this.api("POST", `/sessions/${id}/media/complete`, {
3603
- body: { key }
3604
- });
3605
- }
3606
- /**
3607
- * Submit one check. Sends `{input, forceOutcome?}` (SubmitCheckSchema) and the
3608
- * optional `x-idempotency-key` header. Returns the whitelisted SessionView.
3609
- */
3610
- async submitCheck(checkType, input, opts = {}) {
3611
- const id = await this.ensureSessionId();
3612
- const body = {
3613
- input,
3614
- ...opts.forceOutcome !== void 0 ? { forceOutcome: opts.forceOutcome } : {}
3615
- };
3616
- return this.api("POST", `/sessions/${id}/checks/${checkType}`, {
3617
- body,
3618
- ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {}
3619
- });
3620
- }
3621
- /**
3622
- * Convenience composition: presign → PUT → complete → submit, passing the
3623
- * PROMOTED key (from complete's response — never the pending presign key)
3624
- * into the check's media input field (`clipKey` for liveness, `imageKey` for
3625
- * face_match/doc_ocr). `extraInput` carries the remaining input fields
3626
- * (liveness `attestation`, doc_ocr `side`). The media content type is
3627
- * param-stripped ONCE and used for both presign and PUT, so the signed
3628
- * header always matches.
3629
- */
3630
- async uploadAndSubmit(checkType, media, extraInput, opts = {}) {
3631
- const bareType = stripMimeParams(media.contentType);
3632
- const presigned = await this.presign(media.kind, bareType, media.blob.size);
3633
- await this.uploadToSpaces(presigned.uploadUrl, media.blob, bareType);
3634
- const completed = await this.completeMedia(presigned.key);
3635
- const input = {
3636
- ...extraInput,
3637
- [MEDIA_INPUT_FIELD[checkType]]: completed.key
3638
- };
3639
- return this.submitCheck(checkType, input, opts);
3640
- }
3641
- // ── transport ──────────────────────────────────────────────────────────────
3642
- /** The token's own sessionId — cached from getSession(), lazily bootstrapped. */
3643
- async ensureSessionId() {
3644
- if (this.sessionId !== null) return this.sessionId;
3645
- this.bootstrap ?? (this.bootstrap = this.getSession().finally(() => {
3646
- this.bootstrap = null;
3647
- }));
3648
- return (await this.bootstrap).sessionId;
3649
- }
3650
- /**
3651
- * One API request: `${apiOrigin}/api/v2${path}`, `x-session-token` always,
3652
- * AbortSignal timeout (30 s default), `{success, data}` unwrap on 2xx, flat
3653
- * `{code, message}` → {@link HostedApiError} on non-2xx. EVERY failure is
3654
- * typed: a rejected fetch → `network_error`, the timeout → `timeout`, an
3655
- * unparseable 2xx body → `unknown_error` — the page never sees a raw
3656
- * TypeError/DOMException. The ONLY automatic retry is 409
3657
- * `idempotency_in_progress` (bounded, short delay).
3658
- */
3659
- async api(method, path, opts = {}) {
3660
- const url = `${this.apiOrigin}/api/v2${path}`;
3661
- const headers = { "x-session-token": this.sessionToken };
3662
- if (opts.body !== void 0) headers["content-type"] = "application/json";
3663
- if (opts.idempotencyKey !== void 0) headers["x-idempotency-key"] = opts.idempotencyKey;
3664
- for (let attempt = 0; ; attempt++) {
3665
- let res;
3666
- try {
3667
- res = await this.fetchImpl(url, {
3668
- method,
3669
- headers,
3670
- ...opts.body !== void 0 ? { body: JSON.stringify(opts.body) } : {},
3671
- signal: AbortSignal.timeout(this.requestTimeoutMs)
3672
- });
3673
- } catch (err2) {
3674
- throw asTransportError(err2);
3675
- }
3676
- if (res.ok) {
3677
- let raw;
3678
- try {
3679
- raw = await res.json();
3680
- } catch {
3681
- throw new HostedApiError({
3682
- status: res.status,
3683
- code: "unknown_error",
3684
- message: `response body was not valid JSON (HTTP ${res.status})`
3685
- });
3686
- }
3687
- return unwrap(raw);
3688
- }
3689
- const err = await parseErrorResponse(res);
3690
- if (err.code === "idempotency_in_progress" && attempt < this.retryAttempts) {
3691
- if (this.retryDelayMs > 0) await sleep(this.retryDelayMs);
3692
- continue;
3693
- }
3694
- throw err;
3695
- }
3696
- }
3697
- };
3698
- function asTransportError(err) {
3699
- const name = typeof err === "object" && err !== null ? err.name : void 0;
3700
- if (name === "TimeoutError") {
3701
- return new HostedApiError({ status: 0, code: "timeout", message: "request timed out" });
3702
- }
3703
- const detail = err instanceof Error ? err.message : String(err);
3704
- return new HostedApiError({
3705
- status: 0,
3706
- code: "network_error",
3707
- message: `network request failed: ${detail}`
3708
- });
3709
- }
3710
- function unwrap(raw) {
3711
- if (raw !== null && typeof raw === "object" && "success" in raw && "data" in raw) {
3712
- return raw.data;
3713
- }
3714
- return raw;
3715
- }
3716
- async function parseErrorResponse(res) {
3717
- let code = "unknown_error";
3718
- let message = `request failed (HTTP ${res.status})`;
3719
- try {
3720
- const body = await res.json();
3721
- if (body !== null && typeof body === "object") {
3722
- const env = body;
3723
- if (typeof env.code === "string" && env.code.length > 0) code = env.code;
3724
- if (typeof env.message === "string" && env.message.length > 0) message = env.message;
3725
- }
3726
- } catch {
3727
- }
3728
- const retryAfterRaw = res.headers.get("retry-after");
3729
- const retryAfter = retryAfterRaw === null ? Number.NaN : Number.parseInt(retryAfterRaw, 10);
3730
- return new HostedApiError({
3731
- status: res.status,
3732
- code,
3733
- message,
3734
- ...Number.isFinite(retryAfter) && retryAfter >= 0 ? { retryAfterSeconds: retryAfter } : {}
3735
- });
3736
- }
3737
- function sleep(ms) {
3738
- return new Promise((resolve) => setTimeout(resolve, ms));
3739
- }
3740
-
3741
- // src/verification/result.ts
3742
- var RETRYABLE_REASONS = /* @__PURE__ */ new Set([
3743
- "no_face",
3744
- "media_unreadable",
3745
- "clip_too_short",
3746
- "no_face_source",
3747
- "side_missing",
3748
- "unreadable",
3749
- "registry_unavailable",
3750
- "otp_mismatch",
3751
- "otp_expired",
3752
- "otp_send_failed"
3753
- ]);
3754
- var BIOMETRIC_CHECKS = /* @__PURE__ */ new Set(["liveness", "face_match"]);
3755
- function isExecutable(step) {
3756
- return step !== void 0 && (step.state === "pending" || step.state === "input_required");
3757
- }
3758
- function isTerminalView(view) {
3759
- return view.status !== "created" && view.status !== "in_progress";
3760
- }
3761
- function frontierStep(view) {
3762
- return view.steps.find((step) => isExecutable(step));
3763
- }
3764
- function stepOf(view, checkType) {
3765
- return view.steps.find((step) => step.checkType === checkType);
3766
- }
3767
- function mergeSessionView(prev, next, submitted) {
3768
- const byType = new Map(prev.steps.map((step) => [step.checkType, step]));
3769
- const steps = next.steps.map((step) => {
3770
- const before = byType.get(step.checkType);
3771
- const attemptsBefore = before?.attemptsRemaining ?? 0;
3772
- const merged = {
3773
- ...before ?? {},
3774
- checkType: step.checkType,
3775
- state: step.state,
3776
- attemptsRemaining: step.checkType === submitted ? Math.max(0, attemptsBefore - 1) : attemptsBefore
3777
- };
3778
- if (step.reason !== void 0) merged.reason = step.reason;
3779
- else delete merged.reason;
3780
- return merged;
3781
- });
3782
- return { ...prev, status: next.status, outcome: next.outcome, steps, expiresAt: next.expiresAt };
3783
- }
3784
- function unavailable(sessionId, reason) {
3785
- return reason === void 0 ? { sessionId, status: "unavailable" } : { sessionId, status: "unavailable", reason };
3786
- }
3787
- function withReason(sessionId, status, reason) {
3788
- return reason === void 0 ? { sessionId, status } : { sessionId, status, reason };
3789
- }
3790
- function mapSessionResult(view, opts) {
3791
- const { sessionId } = view;
3792
- switch (view.status) {
3793
- case "completed":
3794
- if (view.outcome === "approved") return { sessionId, status: "approved" };
3795
- if (view.outcome === "review") return withReason(sessionId, "review", reasonIn(view, "review"));
3796
- return withReason(sessionId, "rejected", reasonIn(view, "failed"));
3797
- case "failed":
3798
- return withReason(sessionId, "rejected", reasonIn(view, "failed"));
3799
- case "review_pending":
3800
- return withReason(sessionId, "review", reasonIn(view, "review"));
3801
- case "expired":
3802
- return unavailable(sessionId);
3803
- case "created":
3804
- case "in_progress":
3805
- break;
3806
- default: {
3807
- const unhandled = view.status;
3808
- throw new Error(`mapSessionResult: unhandled status ${unhandled}`);
3809
- }
3810
- }
3811
- const parked = view.steps.find(
3812
- (step) => BIOMETRIC_CHECKS.has(step.checkType) && step.state === "input_required" && step.reason !== void 0
3813
- );
3814
- if (parked?.reason !== void 0) {
3815
- const canRetry = opts.autoRetry && RETRYABLE_REASONS.has(parked.reason) && parked.attemptsRemaining > 0;
3816
- return {
3817
- sessionId,
3818
- status: canRetry ? "retry" : "rejected",
3819
- reason: parked.reason,
3820
- attemptsRemaining: parked.attemptsRemaining
3821
- };
3822
- }
3823
- if (frontierStep(view) === void 0 && view.steps.some((step) => step.state === "review")) {
3824
- return withReason(sessionId, "review", reasonIn(view, "review"));
3825
- }
3826
- return unavailable(sessionId);
3827
- }
3828
- function reasonIn(view, state) {
3829
- return view.steps.find((step) => step.state === state && step.reason !== void 0)?.reason;
3830
- }
3831
-
3832
- // src/verification/liveness-flow.ts
3833
- var CLIP_MIME_ALLOWLIST = ["video/webm", "video/mp4"];
3834
- var KEYFRAME_MIME = "image/jpeg";
3835
- var TRANSPORT_REPLAY_ATTEMPTS = 2;
3836
- var TRANSPORT_REPLAY_DELAY_MS = 1e3;
3837
- var MAX_RETRY_AFTER_MS = 1e4;
3838
- var RESYNC_REENTRY_MAX = 3;
3839
- var TRANSPORT_CODES = /* @__PURE__ */ new Set([
3840
- "network_error",
3841
- "timeout",
3842
- "upload_failed",
3843
- "unknown_error",
3844
- "rate_limit_exceeded"
3845
- ]);
3846
- var RESYNC_CODES = /* @__PURE__ */ new Set([
3847
- "session_not_active",
3848
- "check_not_found",
3849
- "check_already_finalized",
3850
- "check_out_of_order"
3851
- ]);
3852
- var AttestationError = class extends Error {
3853
- constructor(message) {
3854
- super(message);
3855
- this.name = "AttestationError";
3856
- }
3857
- };
3858
- async function runSubmission(rt, executor, hooks = {}) {
3859
- let key = rt.uuid();
3860
- let consentRecovered = false;
3861
- let attestationRetried = false;
3862
- let transportReplays = 0;
3863
- for (; ; ) {
3864
- try {
3865
- return await executor(rt.client, key);
3866
- } catch (err) {
3867
- if (err instanceof AttestationError) {
3868
- if (attestationRetried) throw err;
3869
- attestationRetried = true;
3870
- hooks.onAttestationInvalid?.();
3871
- key = rt.uuid();
3872
- continue;
3873
- }
3874
- if (!(err instanceof HostedApiError)) throw err;
3875
- if (err.code === "consent_required" && !consentRecovered) {
3876
- consentRecovered = true;
3877
- await rt.ensureConsent({ force: true });
3878
- key = rt.uuid();
3879
- continue;
3880
- }
3881
- if (err.code === "attestation_invalid" && !attestationRetried) {
3882
- attestationRetried = true;
3883
- hooks.onAttestationInvalid?.();
3884
- key = rt.uuid();
3885
- continue;
3886
- }
3887
- if (TRANSPORT_CODES.has(err.code) && transportReplays < TRANSPORT_REPLAY_ATTEMPTS) {
3888
- transportReplays += 1;
3889
- const retryAfterMs = err.retryAfterSeconds !== void 0 ? err.retryAfterSeconds * 1e3 : void 0;
3890
- await rt.sleep(
3891
- retryAfterMs !== void 0 ? Math.min(retryAfterMs, MAX_RETRY_AFTER_MS) : TRANSPORT_REPLAY_DELAY_MS
3892
- );
3893
- continue;
3894
- }
3895
- throw err;
3896
- }
3897
- }
3898
- }
3899
- var LIVENESS_CHAINABLE = /* @__PURE__ */ new Set(["passed", "review", "processing", "skipped"]);
3900
- async function runLivenessFlow(deps) {
3901
- const { artifacts } = deps;
3902
- const clip = artifacts.clip;
3903
- const bareMime = stripMimeParams(artifacts.clipMime ?? "");
3904
- if (artifacts.degraded === "NO_RECORDER" || clip === void 0 || !CLIP_MIME_ALLOWLIST.includes(bareMime)) {
3905
- return { kind: "unavailable", reason: "no_recorder" };
3906
- }
3907
- const submitLiveness = buildLivenessSubmit(deps, clip, bareMime);
3908
- const submitFaceMatch = buildFaceMatchSubmit(deps, artifacts.keyframe);
3909
- let livenessSubmitted = false;
3910
- let faceMatchSubmitted = false;
3911
- let livenessChainable = true;
3912
- let resyncs = 0;
3913
- for (; ; ) {
3914
- if (deps.isCancelled()) return { kind: "cancelled" };
3915
- const view = deps.getView();
3916
- if (isTerminalView(view)) return { kind: "settled" };
3917
- const frontier = frontierStep(view)?.checkType;
3918
- const next = frontier === "liveness" && !livenessSubmitted ? "liveness" : frontier === "face_match" && !faceMatchSubmitted && livenessChainable ? "face_match" : null;
3919
- if (next === null) return { kind: "settled" };
3920
- try {
3921
- if (next === "liveness") {
3922
- livenessSubmitted = true;
3923
- const response = await submitLiveness();
3924
- if (deps.isCancelled()) return { kind: "cancelled" };
3925
- deps.applySubmit(response, "liveness");
3926
- const state = stepOf(deps.getView(), "liveness")?.state;
3927
- livenessChainable = state === void 0 || LIVENESS_CHAINABLE.has(state);
3928
- } else {
3929
- faceMatchSubmitted = true;
3930
- const response = await submitFaceMatch();
3931
- if (deps.isCancelled()) return { kind: "cancelled" };
3932
- deps.applySubmit(response, "face_match");
3933
- }
3934
- } catch (err) {
3935
- if (deps.isCancelled()) return { kind: "cancelled" };
3936
- const outcome = classifyFailure(err);
3937
- if (outcome.kind !== "resync" || resyncs >= RESYNC_REENTRY_MAX) return outcome;
3938
- resyncs += 1;
3939
- await deps.refreshView();
3940
- }
3941
- }
3942
- }
3943
- function buildLivenessSubmit(deps, clip, bareMime) {
3944
- let clipKey = null;
3945
- let attestation = null;
3946
- return () => runSubmission(
3947
- deps,
3948
- async (client, idempotencyKey) => {
3949
- if (clipKey === null) {
3950
- deps.onPhase("uploading");
3951
- const presigned = await client.presign("clip", bareMime, clip.size);
3952
- await client.uploadToSpaces(presigned.uploadUrl, clip, bareMime);
3953
- clipKey = (await client.completeMedia(presigned.key)).key;
3954
- }
3955
- if (attestation === null) {
3956
- try {
3957
- attestation = await deps.getAttestation();
3958
- } catch (err) {
3959
- throw new AttestationError(err instanceof Error ? err.message : String(err));
3960
- }
3961
- }
3962
- deps.onPhase("checking");
3963
- return client.submitCheck(
3964
- "liveness",
3965
- {
3966
- clipKey,
3967
- attestation,
3968
- captureChannel: deps.artifacts.captureChannel,
3969
- capture: captureInputOf(deps.artifacts)
3970
- },
3971
- { idempotencyKey }
3972
- );
3973
- },
3974
- {
3975
- onAttestationInvalid: () => {
3976
- attestation = null;
3977
- }
3978
- }
3979
- );
3980
- }
3981
- function captureInputOf(artifacts) {
3982
- return {
3983
- ...artifacts.engine !== void 0 ? { engine: artifacts.engine } : {},
3984
- width: artifacts.width,
3985
- height: artifacts.height,
3986
- ...artifacts.clipMs !== void 0 ? { clipMs: artifacts.clipMs } : {},
3987
- ...artifacts.cameraReadyMs !== void 0 ? { cameraReadyMs: artifacts.cameraReadyMs } : {},
3988
- ...artifacts.faceAcquireMs !== void 0 ? { faceAcquireMs: artifacts.faceAcquireMs } : {},
3989
- ...artifacts.captureMs !== void 0 ? { captureMs: artifacts.captureMs } : {}
3990
- };
3991
- }
3992
- function buildFaceMatchSubmit(deps, keyframe) {
3993
- let imageKey = null;
3994
- return () => runSubmission(deps, async (client, idempotencyKey) => {
3995
- if (imageKey === null) {
3996
- deps.onPhase("uploading");
3997
- const presigned = await client.presign("image", KEYFRAME_MIME, keyframe.size);
3998
- await client.uploadToSpaces(presigned.uploadUrl, keyframe, KEYFRAME_MIME);
3999
- imageKey = (await client.completeMedia(presigned.key)).key;
4000
- }
4001
- deps.onPhase("checking");
4002
- return client.submitCheck("face_match", { imageKey }, { idempotencyKey });
4003
- });
4004
- }
4005
- function classifyFailure(err) {
4006
- if (err instanceof AttestationError) return { kind: "unavailable", reason: "attestation" };
4007
- if (err instanceof HostedApiError) {
4008
- if (err.code === "attestation_invalid") return { kind: "unavailable", reason: "attestation" };
4009
- if (RESYNC_CODES.has(err.code)) return { kind: "resync" };
4010
- }
4011
- return { kind: "unavailable", reason: "network" };
4012
- }
4013
-
4014
- // src/verification/turnstile.ts
4015
- var TURNSTILE_SCRIPT_SRC = "https://challenges.cloudflare.com/turnstile/v0/api.js";
4016
- var TURNSTILE_EXECUTE_TIMEOUT_MS = 3e4;
4017
- function installedApi() {
4018
- return window.turnstile;
4019
- }
4020
- var loaderPromise = null;
4021
- function resetTurnstileForTests() {
4022
- loaderPromise = null;
4023
- }
4024
- function loadTurnstile() {
4025
- loaderPromise ?? (loaderPromise = new Promise((resolve, reject) => {
4026
- const present = installedApi();
4027
- if (present) {
4028
- resolve(present);
4029
- return;
4030
- }
4031
- const script = document.createElement("script");
4032
- script.src = TURNSTILE_SCRIPT_SRC;
4033
- script.async = true;
4034
- script.onload = () => {
4035
- const api = installedApi();
4036
- if (api) {
4037
- resolve(api);
4038
- } else {
4039
- loaderPromise = null;
4040
- reject(new Error("Turnstile script loaded but exposed no API"));
4041
- }
4042
- };
4043
- script.onerror = () => {
4044
- loaderPromise = null;
4045
- script.remove();
4046
- reject(new Error("Turnstile script failed to load"));
4047
- };
4048
- document.head.appendChild(script);
4049
- }));
4050
- return loaderPromise;
4051
- }
4052
- function abortError() {
4053
- return new Error("Turnstile challenge aborted");
4054
- }
4055
- async function executeTurnstile(siteKey, opts = {}) {
4056
- const timeoutMs = opts.timeoutMs ?? TURNSTILE_EXECUTE_TIMEOUT_MS;
4057
- const signal = opts.signal;
4058
- if (signal?.aborted) throw abortError();
4059
- const api = await loadTurnstile();
4060
- if (signal?.aborted) throw abortError();
4061
- const container = document.createElement("div");
4062
- document.body.appendChild(container);
4063
- let widgetId;
4064
- let timer;
4065
- let onAbort;
4066
- try {
4067
- return await new Promise((resolve, reject) => {
4068
- timer = setTimeout(
4069
- () => reject(new Error(`Turnstile challenge timed out (${timeoutMs} ms)`)),
4070
- timeoutMs
4071
- );
4072
- if (signal !== void 0) {
4073
- onAbort = () => reject(abortError());
4074
- signal.addEventListener("abort", onAbort, { once: true });
4075
- }
4076
- widgetId = api.render(container, {
4077
- sitekey: siteKey,
4078
- execution: "execute",
4079
- appearance: "execute",
4080
- callback: resolve,
4081
- "error-callback": (code) => {
4082
- reject(new Error(`Turnstile challenge failed${code ? ` (${code})` : ""}`));
4083
- }
4084
- });
4085
- if (widgetId === void 0) {
4086
- reject(new Error("Turnstile render returned no widget id"));
4087
- return;
4088
- }
4089
- api.execute(widgetId);
4090
- });
4091
- } finally {
4092
- clearTimeout(timer);
4093
- if (signal !== void 0 && onAbort !== void 0) signal.removeEventListener("abort", onAbort);
4094
- if (widgetId !== void 0) {
4095
- try {
4096
- api.remove(widgetId);
4097
- } catch {
4098
- }
4099
- }
4100
- container.remove();
4101
- }
4102
- }
4103
-
4104
- // src/verification/create-verification.ts
4105
- var DEFAULT_API_ORIGIN = "https://api.sekyro.ai";
4106
- var REGISTRY_RETRY_DELAY_MS = 5e3;
4107
- var PROCESSING_POLL_DELAY_MS = 1500;
4108
- var PROCESSING_POLL_MAX = 10;
4109
- function defaultSleep(ms) {
4110
- return new Promise((resolve) => setTimeout(resolve, ms));
4111
- }
4112
- function randomUuid() {
4113
- const c2 = globalThis.crypto;
4114
- if (c2 !== void 0 && typeof c2.randomUUID === "function") return c2.randomUUID();
4115
- const bytes = new Uint8Array(16);
4116
- if (c2 !== void 0 && typeof c2.getRandomValues === "function") c2.getRandomValues(bytes);
4117
- else for (let i2 = 0; i2 < 16; i2 += 1) bytes[i2] = Math.floor(Math.random() * 256);
4118
- bytes[6] = (bytes[6] ?? 0) & 15 | 64;
4119
- bytes[8] = (bytes[8] ?? 0) & 63 | 128;
4120
- const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
4121
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
4122
- }
4123
- function createVerificationInternal(options, internals) {
4124
- const apiOrigin = options.apiOrigin ?? DEFAULT_API_ORIGIN;
4125
- const autoRetry = options.autoRetry ?? true;
4126
- const rearm = options.rearm ?? "auto";
4127
- const client = internals.client ?? new HostedClient({
4128
- apiOrigin,
4129
- sessionToken: options.clientToken,
4130
- ...options.fetch !== void 0 ? { fetch: options.fetch } : {}
4131
- });
4132
- const sleep2 = internals.sleep ?? defaultSleep;
4133
- const uuid = internals.uuid ?? randomUuid;
4134
- const getTurnstileToken = internals.getTurnstileToken ?? executeTurnstile;
4135
- const emitter = createEmitter();
4136
- let destroyed = false;
4137
- const lifetime = new AbortController();
4138
- let view = null;
4139
- let bootstrap = null;
4140
- const setView = (next) => {
4141
- view = next;
4142
- emitter.emit("view", next);
4143
- };
4144
- const ensureView = () => {
4145
- if (view !== null) return Promise.resolve(view);
4146
- bootstrap ?? (bootstrap = client.getSession().then((next) => {
4147
- setView(next);
4148
- return next;
4149
- }).finally(() => {
4150
- bootstrap = null;
4151
- }));
4152
- return bootstrap;
4153
- };
4154
- const refreshView = async () => {
4155
- const next = await client.getSession();
4156
- setView(next);
4157
- return next;
4158
- };
4159
- const applySubmit = (response, submitted) => {
4160
- if (view !== null) setView(mergeSessionView(view, response, submitted));
4161
- };
4162
- let consentInFlight = null;
4163
- const recordConsent = async (force) => {
4164
- const current = await ensureView();
4165
- if (!force && current.consentRecorded) return;
4166
- await client.recordConsent(options.locale);
4167
- if (view !== null) setView({ ...view, consentRecorded: true });
4168
- };
4169
- const ensureConsent = (opts) => {
4170
- if (opts?.force === true) return recordConsent(true);
4171
- consentInFlight ?? (consentInFlight = recordConsent(false).finally(() => {
4172
- consentInFlight = null;
4173
- }));
4174
- return consentInFlight;
4175
- };
4176
- const runtime = {
4177
- client,
4178
- ensureConsent: (opts) => ensureConsent(opts),
4179
- sleep: sleep2,
4180
- uuid
4181
- };
4182
- let terminalEmitted = false;
4183
- const emitResult = (result) => {
4184
- if (result.status === "approved" || result.status === "rejected" || result.status === "review") {
4185
- if (terminalEmitted) return;
4186
- terminalEmitted = true;
4187
- }
4188
- emitter.emit("result", result);
4189
- };
4190
- let registry2 = null;
4191
- let registryFailed = false;
4192
- let registryUnbound = false;
4193
- const submitRegistry = () => runSubmission(
4194
- runtime,
4195
- (c2, idempotencyKey) => (
4196
- // `{}` input: the session is bound to a SERVER-provided NNI (Plan A Task 2).
4197
- c2.submitCheck("population_registry", {}, { idempotencyKey })
4198
- )
4199
- );
4200
- const runRegistry = async () => {
4201
- try {
4202
- const current = await ensureView();
4203
- if (isTerminalView(current) || frontierStep(current)?.checkType !== "population_registry") {
4204
- return;
4205
- }
4206
- if (current.nniBound !== true) {
4207
- registryUnbound = true;
4208
- return;
4209
- }
4210
- await ensureConsent();
4211
- applySubmit(await submitRegistry(), "population_registry");
4212
- const step = view === null ? void 0 : stepOf(view, "population_registry");
4213
- if (step?.state === "input_required" && step.reason === "registry_unavailable" && step.attemptsRemaining > 0) {
4214
- await sleep2(REGISTRY_RETRY_DELAY_MS);
4215
- if (destroyed) return;
4216
- applySubmit(await submitRegistry(), "population_registry");
4217
- }
4218
- } catch {
4219
- registryFailed = true;
4220
- return;
4221
- }
4222
- if (view !== null && isTerminalView(view)) emitResult(mapSessionResult(view, { autoRetry }));
4223
- };
4224
- const startRegistry = () => {
4225
- registry2 ?? (registry2 = runRegistry());
4226
- return registry2;
4227
- };
4228
- const getAttestation = async () => {
4229
- const current = await ensureView();
4230
- const siteKey = current.turnstileSiteKey;
4231
- if (siteKey === null) return { sandbox: true };
4232
- return {
4233
- channel: "hosted_web",
4234
- siteKey,
4235
- turnstileToken: await getTurnstileToken(siteKey, { signal: lifetime.signal })
4236
- };
4237
- };
4238
- let active = null;
4239
- let chain = Promise.resolve();
4240
- let chainDepth = 0;
4241
- const settleProcessing = async () => {
4242
- let current = await ensureView();
4243
- for (let i2 = 0; i2 < PROCESSING_POLL_MAX && !destroyed && !isTerminalView(current) && frontierStep(current) === void 0 && current.steps.some((step) => step.state === "processing"); i2 += 1) {
4244
- await sleep2(PROCESSING_POLL_DELAY_MS);
4245
- if (destroyed) break;
4246
- current = await refreshView();
4247
- }
4248
- return current;
4249
- };
4250
- const runFlow = async (bound, artifacts, capturedAttempt) => {
4251
- const { capture } = bound;
4252
- const isCancelled = () => destroyed;
4253
- const ownsHandle = () => bound.alive && bound.attempt === capturedAttempt;
4254
- const setPhase = (phase) => {
4255
- if (ownsHandle()) capture.setFlowState(phase);
4256
- };
4257
- const finish = (result) => {
4258
- if (isCancelled()) return;
4259
- emitResult(result);
4260
- if (!ownsHandle()) return;
4261
- if (result.status === "retry" && rearm === "auto") {
4262
- capture.handle.retry();
4263
- return;
4264
- }
4265
- capture.setFlowState("done");
4266
- };
4267
- if (artifacts.degraded === "NO_RECORDER") {
4268
- const sessionId = view?.sessionId ?? (await ensureView().catch(() => null))?.sessionId ?? "";
4269
- finish(unavailable(sessionId, "no_recorder"));
4270
- return;
4271
- }
4272
- setPhase("uploading");
4273
- try {
4274
- await startRegistry();
4275
- if (isCancelled()) return;
4276
- let current = await ensureView();
4277
- if (!isTerminalView(current)) {
4278
- if (frontierStep(current)?.checkType === "population_registry") {
4279
- finish(
4280
- unavailable(
4281
- current.sessionId,
4282
- registryUnbound ? "nni_unbound" : registryFailed ? "network" : "registry_unavailable"
4283
- )
4284
- );
4285
- return;
4286
- }
4287
- await ensureConsent();
4288
- if (isCancelled()) return;
4289
- const outcome = await runLivenessFlow({
4290
- ...runtime,
4291
- artifacts,
4292
- getAttestation,
4293
- getView: () => view ?? current,
4294
- refreshView,
4295
- applySubmit,
4296
- onPhase: setPhase,
4297
- isCancelled
4298
- });
4299
- if (isCancelled()) return;
4300
- if (outcome.kind === "unavailable") {
4301
- finish(unavailable(current.sessionId, outcome.reason));
4302
- return;
4303
- }
4304
- if (outcome.kind === "resync") await refreshView();
4305
- current = await settleProcessing();
4306
- }
4307
- finish(mapSessionResult(current, { autoRetry }));
4308
- } catch {
4309
- if (isCancelled()) return;
4310
- finish(unavailable(view?.sessionId ?? "", "network"));
4311
- }
4312
- };
4313
- const enqueueFlow = (bound, artifacts) => {
4314
- const capturedAttempt = bound.attempt;
4315
- if (chainDepth > 0 && bound.alive) {
4316
- bound.capture.setFlowState("uploading");
4317
- }
4318
- chainDepth += 1;
4319
- chain = chain.then(() => runFlow(bound, artifacts, capturedAttempt)).finally(() => {
4320
- chainDepth -= 1;
4321
- }).catch(() => void 0);
4322
- };
4323
- const liveness = (captureOptions) => {
4324
- active?.capture.handle.destroy();
4325
- if (active !== null) active.alive = false;
4326
- const capture = createLivenessCaptureInternal(captureOptions, internals.capture);
4327
- const bound = { capture, alive: true, attempt: 0 };
4328
- active = bound;
4329
- capture.handle.on("state", (state) => {
4330
- if (state === "starting") bound.attempt += 1;
4331
- });
4332
- capture.handle.on("captured", (artifacts) => {
4333
- void Promise.resolve().then(() => enqueueFlow(bound, artifacts));
4334
- });
4335
- const inner = capture.handle;
4336
- return {
4337
- get state() {
4338
- return inner.state;
4339
- },
4340
- on: (event, handler) => inner.on(event, handler),
4341
- start: (startOptions) => inner.start(startOptions),
4342
- retry: () => inner.retry(),
4343
- switchCamera: () => inner.switchCamera(),
4344
- destroy: () => {
4345
- bound.alive = false;
4346
- if (active === bound) active = null;
4347
- inner.destroy();
4348
- }
4349
- };
4350
- };
4351
- return {
4352
- consent: () => ensureConsent(),
4353
- startRegistry,
4354
- liveness,
4355
- voiceClips: async () => {
4356
- if (destroyed) return null;
4357
- try {
4358
- const current = await ensureView();
4359
- if (destroyed) return null;
4360
- return current.voice ?? null;
4361
- } catch {
4362
- return null;
4363
- }
4364
- },
4365
- on: (event, handler) => emitter.on(event, handler),
4366
- destroy: () => {
4367
- destroyed = true;
4368
- lifetime.abort();
4369
- if (active !== null) {
4370
- active.alive = false;
4371
- active.capture.handle.destroy();
4372
- active = null;
4373
- }
4374
- emitter.clear();
4375
- }
4376
- };
4377
- }
4378
- // Annotate the CommonJS export names for ESM import in node:
4379
- 0 && (module.exports = {
4380
- ASPECT_BANDS,
4381
- AttestationError,
4382
- CAPTURE_CANDIDATE_SPACING_MS,
4383
- CAPTURE_EXTRA_CANDIDATES,
4384
- CENTERED_FACTOR,
4385
- CIRCLE_RADIUS_FACTOR,
4386
- CLIP_MIME_ALLOWLIST,
4387
- CaptureSessionDoc,
4388
- DOC_ANALYSIS_DEFAULTS,
4389
- DOC_CADENCE_HZ,
4390
- DOC_DETECT_WIDTH,
4391
- DOC_FEEDBACK_STATES,
4392
- DOC_GATE_V1_DEFAULTS,
4393
- DocFeedbackAggregator,
4394
- DocGateV1,
4395
- IN_CIRCLE_FACTOR,
4396
- MRZ_BAND_DEFAULTS,
4397
- MR_DOC_CATALOG,
4398
- PRELOAD_BLAZE_INIT_TIMEOUT_MS,
4399
- PRELOAD_BUDGET_MS,
4400
- PROCESSING_POLL_DELAY_MS,
4401
- PROCESSING_POLL_MAX,
4402
- REGISTRY_RETRY_DELAY_MS,
4403
- RETRYABLE_REASONS,
4404
- TRANSPORT_REPLAY_ATTEMPTS,
4405
- TRANSPORT_REPLAY_DELAY_MS,
4406
- TURNSTILE_EXECUTE_TIMEOUT_MS,
4407
- TURNSTILE_SCRIPT_SRC,
4408
- analyzeDocFrame,
4409
- aspectBand,
4410
- createLivenessCaptureInternal,
4411
- createVerificationInternal,
4412
- detectMrzBand,
4413
- executeTurnstile,
4414
- feedbackVoteOf,
4415
- frontierStep,
4416
- isExecutable,
4417
- isTerminalView,
4418
- loadTurnstile,
4419
- mapEngineState,
4420
- mapErrorKind,
4421
- mapGuidanceHint,
4422
- mapSessionResult,
4423
- mergeSessionView,
4424
- preloadedDetectorFactory,
4425
- quadAreaFrac,
4426
- quadBounds,
4427
- quadIou,
4428
- quadTiltRatio,
4429
- randomUuid,
4430
- resetLivenessAssetsForTests,
4431
- resetTurnstileForTests,
4432
- runLivenessFlow,
4433
- runSubmission,
4434
- setPreloadLoaderForTests,
4435
- specularFraction,
4436
- stepOf,
4437
- warmDocDetector
4438
- });
4439
- //# sourceMappingURL=index.cjs.map
1
+ "use strict";var Si=Object.create;var WA=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var vi=Object.getOwnPropertyNames;var ki=Object.getPrototypeOf,Mi=Object.prototype.hasOwnProperty;var hA=(e,A)=>()=>(e&&(A=e(e=0)),A);var Ne=(e,A)=>{for(var t in A)WA(e,t,{get:A[t],enumerable:!0})},pt=(e,A,t,i)=>{if(A&&typeof A=="object"||typeof A=="function")for(let n of vi(A))!Mi.call(e,n)&&n!==t&&WA(e,n,{get:()=>A[n],enumerable:!(i=Ri(A,n))||i.enumerable});return e};var xi=(e,A,t)=>(t=e!=null?Si(ki(e)):{},pt(A||!e||!e.__esModule?WA(t,"default",{value:e,enumerable:!0}):t,e)),Ni=e=>pt(WA({},"__esModule",{value:!0}),e);function wA(e){return yt[e]}var yt,Fi,XA=hA(()=>{"use strict";yt={"ID-1":{center:1.586,tolerance:.15},"ID-3":{center:1.42,tolerance:.2}};Fi=[{docType:"carte_identite",format:"ID-1",sides:["recto","verso"],mrz:"td1",portraitSide:"recto",aspectRatio:1.586,identifierSource:"mrz"},{docType:"passport",format:"ID-3",sides:["single"],mrz:"td3",portraitSide:"single",aspectRatio:1.42,identifierSource:"mrz"}]});function wt(e,A){return .299*(e[A]??0)+.587*(e[A+1]??0)+.114*(e[A+2]??0)}function DA(e){let{data:A,width:t,height:i}=e,n=t*i;if(n===0)return 0;let o=0;for(let r=0;r<n;r+=1)o+=wt(A,r*4);return o/n}function QA(e){let{data:A,width:t,height:i}=e;if(t<3||i<3)return 0;let n=new Float32Array(t*i);for(let g=0;g<n.length;g+=1)n[g]=wt(A,g*4);let o=0,r=0,s=0;for(let g=1;g<i-1;g+=1)for(let l=1;l<t-1;l+=1){let d=g*t+l,C=(n[d-t]??0)+(n[d-1]??0)+(n[d+1]??0)+(n[d+t]??0)-4*(n[d]??0);o+=C,r+=C*C,s+=1}if(s===0)return 0;let a=o/s,c=r/s-a*a;return Math.min(1,Math.max(0,c)/180)}function zA(e){let A=DA(e),[t,i]=nA,n=A<t?t-A:A>i?A-i:0;return Math.max(0,1-n/Li)}var nA,Li,mA=hA(()=>{"use strict";nA=[100,190],Li=64});function jA(e,A,t){let i=[e.topLeft,e.topRight,e.bottomRight,e.bottomLeft],n=0;for(let r=0;r<4;r++){let s=i[r],a=i[(r+1)%4];n+=s.x*a.y-a.x*s.y}let o=A*t;return o>0?Math.abs(n/2)/o:0}function Dt(e,A){let t=Le(e),i=Le(A),n=Math.max(t.x1,i.x1),o=Math.max(t.y1,i.y1),r=Math.min(t.x2,i.x2),s=Math.min(t.y2,i.y2),a=Math.max(0,r-n)*Math.max(0,s-o),c=(t.x2-t.x1)*(t.y2-t.y1),g=(i.x2-i.x1)*(i.y2-i.y1),l=c+g-a;return l>0?a/l:0}function SA(e){let A=Le(e);return{width:A.x2-A.x1,height:A.y2-A.y1}}function Le(e){let A=[e.topLeft,e.topRight,e.bottomRight,e.bottomLeft];return{x1:Math.min(...A.map(t=>t.x)),y1:Math.min(...A.map(t=>t.y)),x2:Math.max(...A.map(t=>t.x)),y2:Math.max(...A.map(t=>t.y))}}function Ti(e){let A=Math.hypot(e.topRight.x-e.topLeft.x,e.topRight.y-e.topLeft.y),t=Math.hypot(e.bottomRight.x-e.bottomLeft.x,e.bottomRight.y-e.bottomLeft.y),i=Math.hypot(e.bottomLeft.x-e.topLeft.x,e.bottomLeft.y-e.topLeft.y),n=Math.hypot(e.bottomRight.x-e.topRight.x,e.bottomRight.y-e.topRight.y),o=(A+t)/2,r=(i+n)/2;return o<=0||r<=0?0:Math.max(o,r)/Math.min(o,r)}var dA,ZA,Fe,bA,RA=hA(()=>{"use strict";mA();XA();dA=480,ZA=Object.freeze({MIN_AREA_FRAC:.15,EDGE_CLIP_MARGIN_PX:4,STABLE_TICKS:3,IOU_STABLE_MIN:.85,RISE_PER_S:.9,FALL_PER_S:.25,GUIDE_EXPOSURE:.6,GUIDE_SHARPNESS:.35,ID3_BAND_MIN_WIDTH_FRAC:.55,ID3_BAND_ASPECT_MIN:4,ID3_BAND_ASPECT_MAX:40}),Fe=e=>Math.min(1,Math.max(0,e));bA=class{constructor(A,t={}){this.p=0;this.lastTickAt=null;this.lastQuad=null;this.streak=0;this.format=A,this.t={...ZA,...t}}reset(){this.p=0,this.lastTickAt=null,this.lastQuad=null,this.streak=0}tick(A){let{quad:t,quality:i,timestampMs:n}=A,o=this.lastTickAt===null?0:Math.max(0,(n-this.lastTickAt)/1e3);this.lastTickAt=n;let r=null;if(t===null)r="dcv1.no_doc";else if(this.format==="ID-3"){let u=SA(t),E=u.height>0?u.width/u.height:0;u.width<this.t.ID3_BAND_MIN_WIDTH_FRAC*A.frameWidth?r="dcv1.come_closer":this.edgeClipped(t,A.frameWidth,A.frameHeight)?r="dcv1.fit_document":(E<this.t.ID3_BAND_ASPECT_MIN||E>this.t.ID3_BAND_ASPECT_MAX)&&(r="dcv1.wrong_shape")}else if(jA(t,A.frameWidth,A.frameHeight)<this.t.MIN_AREA_FRAC)r="dcv1.come_closer";else if(this.edgeClipped(t,A.frameWidth,A.frameHeight))r="dcv1.fit_document";else{let u=wA(this.format),E=Ti(t);Math.abs(E-u.center)>u.tolerance&&(r="dcv1.wrong_shape")}let s=r===null,a=Fe(i.exposure)>=this.t.GUIDE_EXPOSURE,c=Fe(i.sharpness)>=this.t.GUIDE_SHARPNESS,g=a&&c;if(s&&g&&t!==null){let u=this.lastQuad===null||Dt(t,this.lastQuad)>=this.t.IOU_STABLE_MIN;this.streak=u?this.streak+1:1}else this.streak=0;this.lastQuad=t;let l=s&&g;this.p=Fe(this.p+(l?this.t.RISE_PER_S:-this.t.FALL_PER_S)*o);let d=l&&this.streak>=this.t.STABLE_TICKS,C;if(r!==null)C=r;else if(a)c?C="dcv1.hold_still":C="dcv1.steady";else{let u=(nA[0]+nA[1])/2;C=i.meanLuma<u?"dcv1.more_light":"dcv1.too_bright"}return{at:n,quad:t,plausible:s,p:this.p,guidanceKey:C,ready:d,stableTicks:this.streak}}edgeClipped(A,t,i){let n=this.t.EDGE_CLIP_MARGIN_PX;return[A.topLeft,A.topRight,A.bottomRight,A.bottomLeft].some(r=>r.x<=n||r.y<=n||r.x>=t-n||r.y>=i-n)}}});var _t={};Ne(_t,{default:()=>qi,initMlDetector:()=>Oi});function Oi(){throw new Error("scanic ML detector is not vendored (classical pipeline only)")}var qi,Ht=hA(()=>{"use strict";qi={}});function Wi(e,A={}){let t=A.width||Math.sqrt(e.length),i=A.height||e.length/t,n=A.mode!==void 0?A.mode:1,o=A.method!==void 0?A.method:2,r=A.minArea||Ki,s=t+2,a=i+2,c=new Int32Array(s*a);for(let C=0;C<i;C++)for(let u=0;u<t;u++)e[C*t+u]>0&&(c[(C+1)*s+(u+1)]=1);let g=[],l=2;for(let C=1;C<=i;C++)for(let u=1;u<=t;u++){let E=c[C*s+u],p=c[C*s+(u-1)],I=null,Q=!1,D=-1;if(E===1&&p===0?(Q=!0,I={x:u,y:C},D=2):E===0&&p>=1&&p!==-1&&p===1&&(Q=!1,I={x:u-1,y:C},D=6),I){if(n===0&&!Q){c[I.y*s+I.x]=-1;continue}let w=l++,R=Xi(c,s,a,I,D,w);if(R&&R.length>0){let m=R;o===2&&(m=zi(R));let f=m.map(b=>({x:b.x-1,y:b.y-1}));if(f.length>=(o===2?4:Vi)){let b={id:w,points:f,isOuter:Q};g.push(b)}}else c[I.y*s+I.x]===1&&(c[I.y*s+I.x]=w)}}g.forEach(C=>{C.area=(function(u){let E=0,p=u.length;if(p<3)return 0;for(let I=0;I<p;I++){let Q=(I+1)%p;E+=u[I].x*u[Q].y,E-=u[Q].x*u[I].y}return Math.abs(E)/2})(C.points),C.boundingBox=(function(u){if(u.length===0)return{minX:0,minY:0,maxX:0,maxY:0};let E=u[0].x,p=u[0].y,I=u[0].x,Q=u[0].y;for(let D=1;D<u.length;D++){let w=u[D];E=Math.min(E,w.x),p=Math.min(p,w.y),I=Math.max(I,w.x),Q=Math.max(Q,w.y)}return{minX:E,minY:p,maxX:I,maxY:Q}})(C.points)});let d=g.filter(C=>C.area>=r);return d.sort((C,u)=>u.area-C.area),A.debug&&(A.debug.labels=c,A.debug.rawContours=g,A.debug.finalContours=d),d}function Xi(e,A,t,i,n,o){let r=[],s=new Set,a=i.x,c=i.y,g=a,l=c,d=-1;e[l*A+g]=o;let C=0,u=A*t,E=[0,1,1,1,0,-1,-1,-1],p=[-1,-1,0,1,1,1,0,-1];for(;C++<u;){let I;if(d===-1){let m=!1;for(let f=0;f<8;f++){I=n+f&7;let b=a+E[I],h=c+p[I];if(b>=0&&b<A&&h>=0&&h<t&&e[h*A+b]>0){m=!0;break}}if(!m)return null}else I=d+2&7;let Q=-1,D=-1;for(let m=0;m<8;m++){let f=I+m&7,b=a+E[f],h=c+p[f];if(b>=0&&b<A&&h>=0&&h<t&&e[h*A+b]>0){Q=b,D=h,d=f+4&7;break}}if(Q===-1){r.length===0&&r.push({x:a,y:c});break}let w=c*A+a;if(s.has(w))return r;r.push({x:a,y:c}),s.add(w);let R=D*A+Q;if(e[R]===1&&(e[R]=o),a=Q,c=D,a===g&&c===l)break}return C>=u?null:r}function zi(e){let A=e.length;if(A<=2)return e;let t=[],i=e[A-1],n=e[0],o=i,r=n,s=e[1],a=r.x-o.x,c=r.y-o.y,g=s.x-r.x,l=s.y-r.y;a*l!==c*g&&t.push(r);for(let d=1;d<A-1;d++)o=e[d-1],r=e[d],s=e[d+1],a=r.x-o.x,c=r.y-o.y,g=s.x-r.x,l=s.y-r.y,a*l!==c*g&&t.push(r);if(o=e[A-2],r=i,s=n,a=r.x-o.x,c=r.y-o.y,g=s.x-r.x,l=s.y-r.y,a*l!==c*g&&t.push(r),t.length===0){if(A===1)return[e[0]];if(A===2)return e;let d=0,C=1,u=n.x,E=n.y;for(let p=1;p<A;p++){let I=e[p],Q=I.x-u,D=I.y-E,w=Q*Q+D*D;w>d&&(d=w,C=p)}return[n,e[C]]}return t}function Ke(e,A=1){if(e.length<=2)return e;let t=0,i=0,n=e[0],o=e[e.length-1];for(let r=1;r<e.length-1;r++){let s=Zi(e[r],n,o);s>t&&(t=s,i=r)}if(t>A){let r=Ke(e.slice(0,i+1),A),s=Ke(e.slice(i),A);return r.slice(0,-1).concat(s)}return[n,o]}function Zi(e,A,t){let i=t.x-A.x,n=t.y-A.y,o=i*i+n*n;if(o===0)return Math.sqrt(Math.pow(e.x-A.x,2)+Math.pow(e.y-A.y,2));let r=((e.x-A.x)*i+(e.y-A.y)*n)/o,s,a;r<0?(s=A.x,a=A.y):r>1?(s=t.x,a=t.y):(s=A.x+r*i,a=A.y+r*n);let c=e.x-s,g=e.y-a;return Math.sqrt(c*c+g*g)}function Kt(e,A=.02){return Ke(e,A*(function(t){let i=0,n=t.length;if(n<2)return 0;for(let o=0;o<n;o++){let r=(o+1)%n,s=t[o].x-t[r].x,a=t[o].y-t[r].y;i+=Math.sqrt(s*s+a*a)}return i})(e))}function Ve(e,A){return Math.hypot(A.x-e.x,A.y-e.y)}function Ut(e){let A=0,t=0;for(let i of e)A+=i.x,t+=i.y;return{x:A/e.length,y:t/e.length}}function ji(e,A={}){if(!e||!e.points||e.points.length<4)return null;let t=A.epsilon||.02,i=(function(o,r){if(!o||o.length<4)return null;let s=[r,1.3*r,1.6*r,2*r],a=new Set;for(let c of s){let g=Math.min(.12,c),l=g.toFixed(4);if(a.has(l))continue;a.add(l);let d=$i(Kt(o,g));if(d&&d.length===4)return d}return null})(e.points,t),n;return i&&i.length===4?n=(function(o){if(o.length!==4)return null;let r=Ut(o),s=[...o].sort((l,d)=>Math.atan2(l.y-r.y,l.x-r.x)-Math.atan2(d.y-r.y,d.x-r.x)),a=1/0,c=0;for(let l=0;l<4;l++){let d=s[l].x+s[l].y;d<a&&(a=d,c=l)}let g=[s[c],s[(c+1)%4],s[(c+2)%4],s[(c+3)%4]];return{topLeft:g[0],topRight:g[1],bottomRight:g[2],bottomLeft:g[3]}})(i):(n=(function(o){if(!o||o.length<4)return null;let r=Ut(o),s=null,a=null,c=null,g=null,l=0,d=0,C=0,u=0;for(let E of o){let p=Ve(E,r);E.x<r.x&&E.y<r.y?p>l&&(s=E,l=p):E.x>r.x&&E.y<r.y?p>d&&(a=E,d=p):E.x>r.x&&E.y>r.y?p>C&&(c=E,C=p):E.x<r.x&&E.y>r.y&&p>u&&(g=E,u=p)}return s&&a&&c&&g?{topLeft:s,topRight:a,bottomRight:c,bottomLeft:g}:null})(e.points),n&&n.topLeft&&n.topRight&&n.bottomRight&&n.bottomLeft||(n=(function(o){if(!o||o.length===0)return null;let r=o[0],s=o[0],a=o[0],c=o[0],g=r.x+r.y,l=s.x-s.y,d=a.x+a.y,C=c.x-c.y;for(let u=1;u<o.length;u++){let E=o[u],p=E.x+E.y,I=E.x-E.y;p<g&&(g=p,r=E),p>d&&(d=p,a=E),I>l&&(l=I,s=E),I<C&&(C=I,c=E)}return{topLeft:r,topRight:s,bottomRight:a,bottomLeft:c}})(e.points))),n&&n.topLeft&&n.topRight&&n.bottomRight&&n.bottomLeft?n:null}function $i(e){if(!e||e.length<4)return null;if(e.length===4)return e;if(e.length>8)return null;let A=(function(t,i){if(!t||t.length===0)return[];let n=[];for(let o of t)(n.length===0||Ve(o,n[n.length-1])>i)&&n.push(o);return n.length>2&&Ve(n[0],n[n.length-1])<=i&&n.pop(),n})(e,6);return A.length===4?A:(A.length,null)}function Vt(){return xA!==null&&xA.byteLength!==0||(xA=new Uint8Array(W.memory.buffer)),xA}function Oe(e,A){let t=A(1*e.length,1)>>>0;return Vt().set(e,t/1),aA=e.length,t}function ae(e,A){return e>>>=0,Vt().subarray(e/1,e/1+A)}function Wt(){return NA!==null&&NA.byteLength!==0||(NA=new Float32Array(W.memory.buffer)),NA}function An(e,A,t,i,n){let o=(function(c,g){let l=g(4*c.length,4)>>>0;return Wt().set(c,l/4),aA=c.length,l})(e,W.__wbindgen_malloc),r=aA,s=W.hysteresis_thresholding(o,r,A,t,i,n);var a=ae(s[0],s[1]).slice();return W.__wbindgen_free(s[0],1*s[1],1),a}function Jt(e,A){let t=A(2*e.length,2)>>>0;return(FA!==null&&FA.byteLength!==0||(FA=new Uint16Array(W.memory.buffer)),FA).set(e,t/2),aA=e.length,t}function en(e,A,t,i,n){let o=Jt(e,W.__wbindgen_malloc),r=aA,s=Jt(A,W.__wbindgen_malloc),a=aA,c=W.non_maximum_suppression(o,r,s,a,t,i,n);var g,l,d=(g=c[0],l=c[1],g>>>=0,Wt().subarray(g/4,g/4+l)).slice();return W.__wbindgen_free(c[0],4*c[1],4),d}async function Xt(e){if(W!==void 0)return W;if(e!==void 0&&Object.getPrototypeOf(e)===Object.prototype&&({module_or_path:e}=e),e===void 0)throw new Error("scanic: WASM module bytes must be passed to init().");let A=(function(){let n={wbg:{}};return n.wbg.__wbindgen_init_externref_table=function(){let o=W.__wbindgen_export_0,r=o.grow(4);o.set(0,void 0),o.set(r+0,void 0),o.set(r+1,null),o.set(r+2,!0),o.set(r+3,!1)},n})();(typeof e=="string"||typeof Request=="function"&&e instanceof Request||typeof URL=="function"&&e instanceof URL)&&(e=fetch(e));let{instance:t,module:i}=await(async function(n,o){if(typeof Response=="function"&&n instanceof Response){if(typeof WebAssembly.instantiateStreaming=="function")try{return await WebAssembly.instantiateStreaming(n,o)}catch(s){if(n.headers.get("Content-Type")=="application/wasm")throw s}let r=await n.arrayBuffer();return await WebAssembly.instantiate(r,o)}{let r=await WebAssembly.instantiate(n,o);return r instanceof WebAssembly.Instance?{instance:r,module:n}:r}})(await e,A);return(function(n,o){return W=n.exports,Xt.__wbindgen_wasm_module=o,NA=null,FA=null,xA=null,W.__wbindgen_start(),W})(t,i)}function tn(e){if(typeof atob=="function"){let A=atob(e),t=new Uint8Array(A.length);for(let i=0;i<A.length;i++)t[i]=A.charCodeAt(i);return t}return Uint8Array.from(Buffer.from(e,"base64"))}async function nn(){if(!(function(){if(qe!==null)return qe;let e=!1;if(typeof WebAssembly=="object"&&typeof WebAssembly.validate=="function"){let A=new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11]),t=new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,111,3,2,1,0,10,6,1,4,0,208,111,11]);try{e=WebAssembly.validate(A)&&WebAssembly.validate(t)}catch{e=!1}}return qe=e,e})())throw new Error("scanic: WebAssembly features required by the WASM module (reference-types, SIMD) are unavailable in this engine; using the JavaScript fallback.");return await Xt({module_or_path:tn("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JAAgAiABIAJqIgFLBEBBAEEAEC0ACyADQQRqIAAoAgAiAiAAKAIEQQggASACQQF0IgIgASACSxsiASABQQhNGyIBQQFBARARIAMoAgRBAUYEQCADKAIIIAMoAgwQLQALIAMoAgghAiAAIAE2AgAgACACNgIEIANBEGokAAt5AQF/IwBBIGsiAiQAAn8gACgCAEGAgICAeEcEQCABIAAoAgQgACgCCBAwDAELIAJBEGogACgCDCgCACIAQQhqKQIANwMAIAJBGGogAEEQaikCADcDACACIAApAgA3AwggASgCACABKAIEIAJBCGoQBwsgAkEgaiQAC2kBA38jAEEQayIBJAAgAUEEaiAAKAIAIgIgACgCBEEEIAJBAXQiAiACQQRNGyICQQRBBBARIAEoAgRBAUYEQCABKAIIIAEoAgwQLQALIAEoAgghAyAAIAI2AgAgACADNgIEIAFBEGokAAtpAQN/IwBBEGsiASQAIAFBBGogACgCACICIAAoAgRBBCACQQF0IgIgAkEETRsiAkEEQQgQESABKAIEQQFGBEAgASgCCCABKAIMEC0ACyABKAIIIQMgACACNgIAIAAgAzYCBCABQRBqJAALaQEDfyMAQRBrIgEkACABQQRqIAAoAgAiAiAAKAIEQQQgAkEBdCICIAJBBE0bIgJBAkECEBEgASgCBEEBRgRAIAEoAgggASgCDBAtAAsgASgCCCEDIAAgAjYCACAAIAM2AgQgAUEQaiQACxIAIwBBMGsiACQAIABBMGokAAtoAgF/AX4jAEEwayIDJAAgAyABNgIEIAMgADYCACADQQI2AgwgA0Hkl8AANgIIIANCAjcCFCADQoCAgIAwIgQgA62ENwMoIAMgBCADQQRqrYQ3AyAgAyADQSBqNgIQIANBCGogAhAmAAtHAQF/IAAoAgAgACgCCCIDayACSQRAIAAgAyACEBIgACgCCCEDCyACBEAgACgCBCADaiABIAL8CgAACyAAIAIgA2o2AghBAAtEAQJ/IAEoAgQhAiABKAIAIQNBCEEEEDUiAUUEQEEEQQgQOQALIAEgAjYCBCABIAM2AgAgAEHcksAANgIEIAAgATYCAAvGAgACQCAAIAJNBEAgACABTSABIAJLcg0BIwBBMGsiAiQAIAIgATYCBCACIAA2AgAgAkECNgIMIAJB2JbAADYCCCACQgI3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IAAAABwAEAAMAAAAEgAAABcAAAAcABAADAAAABcAAAAZAAAAHAAQAAwAAAAUAAAAGQAAABwAEAAMAAAAUQAAAB4AAAAcABAADAAAAFIAAAAeAAAATGF6eSBpbnN0YW5jZSBoYXMgcHJldmlvdXNseSBiZWVuIHBvaXNvbmVkAAA8CBAAKgAAAEgBEABaAAAACAMAABkAAAByZWVudHJhbnQgaW5pdAAAgAgQAA4AAABIARAAWgAAAHoCAAANAAAAfP2LMlfmV/kC30S/40jnr21dy9YsUOtjeEGmV3Ebi7ltZW1vcnkgYWxsb2NhdGlvbiBvZiAgYnl0ZXMgZmFpbGVkAADICBAAFQAAAN0IEAANAAAALwEQABgAAABkAQAACQAAAAQAAAAMAAAABAAAAAUAAAAGAAAABwAAAAAAAAAIAAAABAAAAAgAAAAJAAAACgAAAAsAAAAMAAAAEAAAAAQAAAANAAAADgAAAA8AAAAQAAAAAAAAAAgAAAAEAAAAEQAAAGFzc2VydGlvbiBmYWlsZWQ6IHBzaXplID49IHNpemUgKyBtaW5fb3ZlcmhlYWQAAAQBEAAqAAAAsQQAAAkAAABhc3NlcnRpb24gZmFpbGVkOiBwc2l6ZSA8PSBzaXplICsgbWF4X292ZXJoZWFkAAAEARAAKgAAALcEAAANAAAABAAAAAwAAAAEAAAAEgAAAGNhcGFjaXR5IG92ZXJmbG93AAAA/AkQABEAAADjABAAIAAAABwAAAAFAAAAMDAwMTAyMDMwNDA1MDYwNzA4MDkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjEyMjIzMjQyNTI2MjcyODI5MzAzMTMyMzMzNDM1MzYzNzM4Mzk0MDQxNDI0MzQ0NDU0NjQ3NDg0OTUwNTE1MjUzNTQ1NTU2NTc1ODU5NjA2MTYyNjM2NDY1NjY2NzY4Njk3MDcxNzI3Mzc0NzU3Njc3Nzg3OTgwODE4MjgzODQ4NTg2ODc4ODg5OTA5MTkyOTM5NDk1OTY5Nzk4OTlyYW5nZSBlbmQgaW5kZXggIG91dCBvZiByYW5nZSBmb3Igc2xpY2Ugb2YgbGVuZ3RoIAAA8AoQABAAAAAACxAAIgAAAHNsaWNlIGluZGV4IHN0YXJ0cyBhdCAgYnV0IGVuZHMgYXQgADQLEAAWAAAASgsQAA0AAAByYW5nZSBzdGFydCBpbmRleCAAAGgLEAASAAAAAAsQACIAAABhdHRlbXB0IHRvIGRpdmlkZSBieSB6ZXJvAAAAjAsQABkAAABpbmRleCBvdXQgb2YgYm91bmRzOiB0aGUgbGVuIGlzICBidXQgdGhlIGluZGV4IGlzIAAAsAsQACAAAADQCxAAEgAAAAAAAD8AAAC/AEGUmMAACwEBAHwJcHJvZHVjZXJzAghsYW5ndWFnZQEEUnVzdAAMcHJvY2Vzc2VkLWJ5AwVydXN0Yx0xLjkyLjAgKGRlZDVjMDZjZiAyMDI1LTEyLTA4KQZ3YWxydXMGMC4yMy4zDHdhc20tYmluZGdlbhMwLjIuMTAwICgyNDA1ZWMyYjQpAHQPdGFyZ2V0X2ZlYXR1cmVzBysPbXV0YWJsZS1nbG9iYWxzKxNub250cmFwcGluZy1mcHRvaW50KwdzaW1kMTI4KwtidWxrLW1lbW9yeSsIc2lnbi1leHQrD3JlZmVyZW5jZS10eXBlcysKbXVsdGl2YWx1ZQ==")})}function MA(){return se||(se=nn().catch(e=>{throw se=null,e})),se}function on(e,A,t,i=5,n=0){n===0&&(n=.3*(.5*(i-1)-1)+.8);let o=Math.floor(i/2),r=(function(c,g){let l=new Float32Array(c),d=Math.floor(c/2),C=0;for(let u=0;u<c;u++){let E=u-d;l[u]=Math.exp(-E*E/(2*g*g)),C+=l[u]}for(let u=0;u<c;u++)l[u]/=C;return l})(i,n),s=new Uint8ClampedArray(A*t),a=new Uint8ClampedArray(A*t);for(let c=0;c<t;c++){let g=c*A;for(let l=0;l<A;l++){let d=0;for(let C=-o;C<=o;C++)d+=e[g+Math.min(A-1,Math.max(0,l+C))]*r[o+C];s[g+l]=d}}for(let c=0;c<A;c++)for(let g=0;g<t;g++){let l=0;for(let d=-o;d<=o;d++)l+=s[Math.min(t-1,Math.max(0,g+d))*A+c]*r[o+d];a[g*A+c]=Math.round(l)}return a}function Yt(e,A,t,i,n){let o=new Uint8Array(A*t),r=[];for(let c=1;c<t-1;c++)for(let g=1;g<A-1;g++){let l=c*A+g,d=e[l];d>=n?(o[l]=2,r.push({x:g,y:c})):o[l]=d>=i?0:1}for(let c=0;c<A;c++)o[c]=1,o[(t-1)*A+c]=1;for(let c=1;c<t-1;c++)o[c*A]=1,o[c*A+A-1]=1;let s=[-1,0,1,-1,1,-1,0,1],a=[-1,-1,-1,0,0,1,1,1];for(;r.length>0;){let{x:c,y:g}=r.pop();for(let l=0;l<8;l++){let d=c+s[l],C=g+a[l],u=C*A+d;o[u]===0&&(o[u]=2,r.push({x:d,y:C}))}}return o}async function rn(e,A={}){let t=!(!A.debug||A.debug._timingsOnly),i=[],n=performance.now(),o,r,s;if(A.skipGrayscale)o=A.width,r=A.height,s=e,t&&(A.debug.grayscale=s);else{o=e.width,r=e.height;let T=performance.now();s=(function(k){let{width:q,height:J,data:G}=k,L=new Uint8ClampedArray(q*J);for(let v=0,M=0;v<G.length;v+=4,M++)L[M]=54*G[v]+183*G[v+1]+19*G[v+2]>>8;return L})(e);let S=performance.now();i.push({step:"Grayscale",ms:(S-T).toFixed(2)}),t&&(A.debug.grayscale=s)}let a=A.lowThreshold!==void 0?A.lowThreshold:null,c=A.highThreshold!==void 0?A.highThreshold:null;if(a===null||c===null){let S=new Uint32Array(1024),k=0;for(let L=1;L<r-1;L++)for(let v=1;v<o-1;v++){let M=L*o+v,F=-s[M-o-1]+s[M-o+1]-2*s[M-1]+2*s[M+1]-s[M+o-1]+s[M+o+1],H=-s[M-o-1]-2*s[M-o]-s[M-o+1]+s[M+o-1]+2*s[M+o]+s[M+o+1],x=Math.abs(F)+Math.abs(H);x>=1024&&(x=1023),x>0&&(S[x]++,k++)}let q=Math.round(.7*k),J=0,G=75;for(let L=1;L<1024;L++)if(J+=S[L],J>=q){G=L;break}a===null&&(a=Math.max(5,Math.round(.5*G))),c===null&&(c=Math.min(500,Math.round(1.5*G)))}let g=A.kernelSize||5,l=A.sigma||0,d=A.L2gradient!==void 0&&A.L2gradient,C=A.applyDilation===void 0||A.applyDilation,u=A.dilationKernelSize||5,E=A.useWasmHysteresis!==void 0&&A.useWasmHysteresis,p=A.useWasmFullCanny!==void 0&&A.useWasmFullCanny;if(a>=c&&([a,c]=[c,a]),p)try{await MA();let T=performance.now(),S=new Uint8ClampedArray((function(J,G,L,v,M,F,H,x,N,_){let B=Oe(J,W.__wbindgen_malloc),y=aA,U=W.canny_edge_detector_full(B,y,G,L,v,M,F,H,x,N,_);var Y=ae(U[0],U[1]).slice();return W.__wbindgen_free(U[0],1*U[1],1),Y})(s,o,r,a,c,g,l,d,C,u)),k=(performance.now()-T).toFixed(2);i.push({step:"Edge Processing (WASM)",ms:k}),t&&(A.debug.finalEdges=S),A.debug?A.debug.timings=i:A.debug={timings:i};let q=performance.now();return i.unshift({step:"Edge Detection Total",ms:(q-n).toFixed(2)}),S}catch(T){Pt||(Pt=!0,T instanceof Error?T.message:String(T))}let I,Q,D,w,R,m;I=performance.now();try{await MA(),D=(function(T,S,k,q,J){let G=Oe(T,W.__wbindgen_malloc),L=aA,v=W.blur(G,L,S,k,q,J);var M=ae(v[0],v[1]).slice();return W.__wbindgen_free(v[0],1*v[1],1),M})(s,o,r,g,l)}catch{D=on(s,o,r,g,l)}Q=performance.now(),i.push({step:"Gaussian Blur",ms:(Q-I).toFixed(2)}),t&&(A.debug.blurred=D),I=performance.now();{let T=(function(S,k,q){let J=new Int16Array(k*q),G=new Int16Array(k*q);for(let L=1;L<q-1;L++){let v=L*k,M=(L-1)*k,F=(L+1)*k;for(let H=1;H<k-1;H++){let x=v+H,N=S[M+H-1],_=S[M+H],B=S[M+H+1],y=S[v+H-1],U=S[v+H+1],Y=S[F+H-1],K=S[F+H],X=S[F+H+1],Z=B-N+2*(U-y)+(X-Y),j=Y+2*K+X-(N+2*_+B);J[x]=Z,G[x]=j}}return{dx:J,dy:G}})(D,o,r);w=T.dx,R=T.dy}Q=performance.now(),i.push({step:"Gradients",ms:(Q-I).toFixed(2)}),I=performance.now();try{await MA(),m=await en(w,R,o,r,d)}catch{m=(function(T,S,k,q,J){let G=new Float32Array(k*q),L=new Float32Array(k*q);for(let v=0;v<T.length;v++){let M=T[v],F=S[v];G[v]=J?Math.sqrt(M*M+F*F):Math.abs(M)+Math.abs(F)}for(let v=1;v<q-1;v++)for(let M=1;M<k-1;M++){let F=v*k+M,H=G[F];if(H===0){L[F]=0;continue}let x=T[F],N=S[F],_=0,B=0,y=Math.abs(x),U=Math.abs(N);if(U>2.4142*y)_=G[F-k],B=G[F+k];else if(y>2.4142*U)_=G[F-1],B=G[F+1];else{let Y=(x^N)<0?-1:1;N>0?(_=G[(v-1)*k+(M-Y)],B=G[(v+1)*k+(M+Y)]):(_=G[(v+1)*k+(M-Y)],B=G[(v-1)*k+(M+Y)]),x>0&&N>0||x<0&&N<0?(_=G[(v-1)*k+(M+1)],B=G[(v+1)*k+(M-1)]):(_=G[(v-1)*k+(M-1)],B=G[(v+1)*k+(M+1)])}L[F]=H>=_&&H>=B?H:0}return L})(w,R,o,r,d)}Q=performance.now(),i.push({step:"Non-Max Suppression",ms:(Q-I).toFixed(2)}),I=performance.now();let f=d?a*a:a,b=d?c*c:c,h;if(E)try{await MA(),h=An(m,o,r,f,b)}catch{h=Yt(m,o,r,f,b)}else h=Yt(m,o,r,f,b);Q=performance.now(),i.push({step:"Hysteresis",ms:(Q-I).toFixed(2)}),I=performance.now();let P=new Uint8ClampedArray(o*r);for(let T=0;T<h.length;T++)P[T]=h[T]===2?255:0;Q=performance.now(),i.push({step:"Binary Image",ms:(Q-I).toFixed(2)}),I=performance.now();let O=P;if(C)try{await MA(),O=(function(T,S,k,q){let J=Oe(T,W.__wbindgen_malloc),G=aA,L=W.dilate(J,G,S,k,q);var v=ae(L[0],L[1]).slice();return W.__wbindgen_free(L[0],1*L[1],1),v})(P,o,r,u)}catch{O=(function(T,S,k,q=5){let J=Math.floor(q/2),G=new Uint8ClampedArray(S*k),L=new Uint8ClampedArray(S*k);for(let v=0;v<k;v++){let M=v*S;for(let F=0;F<S;F++){let H=0;for(let x=-J;x<=J;x++){let N=F+x;if(N>=0&&N<S){let _=T[M+N];_>H&&(H=_)}}G[M+F]=H}}for(let v=0;v<S;v++)for(let M=0;M<k;M++){let F=0;for(let H=-J;H<=J;H++){let x=M+H;if(x>=0&&x<k){let N=G[x*S+v];N>F&&(F=N)}}L[M*S+v]=F}return L})(P,o,r,u)}if(Q=performance.now(),i.push({step:"Dilation",ms:(Q-I).toFixed(2)}),t){A.debug.dx=w,A.debug.dy=R;let T=new Float32Array(o*r);for(let S=0;S<w.length;S++){let k=w[S],q=R[S];T[S]=d?Math.sqrt(k*k+q*q):Math.abs(k)+Math.abs(q)}A.debug.magnitude=T,A.debug.suppressed=m,A.debug.edgeMap=h,A.debug.cannyEdges=P,A.debug.finalEdges=O}A.debug?A.debug.timings=i:A.debug||(A.debug={timings:i});let z=performance.now();return i.unshift({step:"Edge Detection Total",ms:(z-n).toFixed(2)}),O}function LA(e){return e<=0?0:e>=1?1:e}function TA(e,A){return Math.hypot(e.x-A.x,e.y-A.y)}function Ot(e){return[TA(e.topLeft,e.topRight),TA(e.topRight,e.bottomRight),TA(e.bottomRight,e.bottomLeft),TA(e.bottomLeft,e.topLeft)]}function sn(e){let A=(function(i){let n=[i.topLeft,i.topRight,i.bottomRight,i.bottomLeft],o=[];for(let r=0;r<n.length;r++){let s=n[(r+n.length-1)%n.length],a=n[r],c=n[(r+1)%n.length],g=s.x-a.x,l=s.y-a.y,d=c.x-a.x,C=c.y-a.y,u=g*d+l*C,E=Math.max(1e-6,Math.hypot(g,l)*Math.hypot(d,C)),p=Math.max(-1,Math.min(1,u/E));o.push(180*Math.acos(p)/Math.PI)}return o})(e),t=0;for(let i of A)t+=LA(1-Math.abs(i-90)/55);return t/Math.max(1,A.length)}function qt(e,A){let t=Number(A.isValid)-Number(e.isValid);if(t!==0)return t;let i=A.confidence-e.confidence;if(!(Math.abs(i)<.015)&&i!==0)return i;let n=Math.abs((e.approxCount??99)-4)-Math.abs((A.approxCount??99)-4);if(n!==0)return n;let o=(A.rightAngleScore??0)-(e.rightAngleScore??0);if(Math.abs(o)>1e-6)return o;let r=Math.abs(1-(e.contourFitRatio??1))-Math.abs(1-(A.contourFitRatio??1));return Math.abs(r)>1e-6?r:i||A.score-e.score||A.coverageRatio-e.coverageRatio||A.area-e.area}function an(e,A,t,i,n={}){let o=n.epsilon||.02,r=Kt(e.points,o).length,s=ji(e,{epsilon:o});if(!s)return{contour:e,corners:null,score:0,confidence:0,isValid:!1,area:e.area||0,fillRatio:0,coverageRatio:0,cornersArea:0,approxCount:r,convex:!1,edgeSupport:0,aspectRatio:1/0,minSide:0,rightAngleScore:0,oppositeSideConsistency:0,contourFitRatio:0,contourFitScore:0};let a=t*i,c=e.area||0,g=e.boundingBox||{minX:0,minY:0,maxX:0,maxY:0},l=c/Math.max(1,(g.maxX-g.minX+1)*(g.maxY-g.minY+1)),d=(function(x){if(!x)return 0;let N=[x.topLeft,x.topRight,x.bottomRight,x.bottomLeft],_=0;for(let B=0;B<N.length;B++){let y=(B+1)%N.length;_+=N[B].x*N[y].y-N[y].x*N[B].y}return Math.abs(_)/2})(s),C=d/Math.max(1,a),u=Ot(s),E=Math.min(...u),p=(u[0]+u[2])/2,I=(u[1]+u[3])/2,Q=p>I?p/Math.max(1e-6,I):I/Math.max(1e-6,p),D=(function(x){let N=[x.topLeft,x.topRight,x.bottomRight,x.bottomLeft],_=[];for(let y=0;y<N.length;y++){let U=N[y],Y=N[(y+1)%N.length],K=N[(y+2)%N.length],X=(Y.x-U.x)*(K.y-Y.y)-(Y.y-U.y)*(K.x-Y.x);Math.abs(X)<1e-6||_.push(Math.sign(X))}if(_.length<3)return!1;let B=_[0];return _.every(y=>y===B)})(s),w=(function(x,N,_,B){if(!x?.points||x.points.length===0)return 0;let y=Math.max(1,Math.floor(x.points.length/240)),U=0,Y=0;for(let K=0;K<x.points.length;K+=y){let X=x.points[K],Z=Math.max(0,Math.min(_-1,0|X.x)),j=Math.max(0,Math.min(B-1,0|X.y));U++;let V=!1;for(let $=-1;$<=1&&!V;$++){let sA=j+$;if(!(sA<0||sA>=B))for(let gA=-1;gA<=1;gA++){let IA=Z+gA;if(!(IA<0||IA>=_)&&N[sA*_+IA]>0){V=!0;break}}}V&&Y++}return U===0?0:Y/U})(e,A,t,i),R=sn(s),m=(function(x){let N=Ot(x);return(Math.min(N[0],N[2])/Math.max(1e-6,Math.max(N[0],N[2]))+Math.min(N[1],N[3])/Math.max(1e-6,Math.max(N[1],N[3])))/2})(s),f=c/Math.max(1,d),b=LA(1-Math.abs(f-1)/.55),h=r===4?1:r===5?.9:r===6?.7:r<=8?.5:.28,P=LA(c/Math.max(1,.4*a)),O=LA((l-.08)/.72),z=LA((C-.03)/.82),T=n.minDocumentSideRatio!==void 0?n.minDocumentSideRatio:.06,S=n.minDocumentCoverageRatio!==void 0?n.minDocumentCoverageRatio:.04,k=n.maxDocumentAspectRatio!==void 0?n.maxDocumentAspectRatio:8,q=n.minDocumentFillRatio!==void 0?n.minDocumentFillRatio:.07,J=n.minContourFitRatio!==void 0?n.minContourFitRatio:.11,G=n.maxContourFitRatio!==void 0?n.maxContourFitRatio:1.2,L=n.minRightAngleScore!==void 0?n.minRightAngleScore:.42,v=n.minOppositeSideConsistency!==void 0?n.minOppositeSideConsistency:.3,M=Math.min(t,i)*T,F=(function(x,N=6){let _=[x?.topLeft,x?.topRight,x?.bottomRight,x?.bottomLeft];if(_.some(B=>!B||!Number.isFinite(B.x)||!Number.isFinite(B.y)))return!1;for(let B=0;B<_.length;B++)for(let y=B+1;y<_.length;y++)if(TA(_[B],_[y])<N)return!1;return!0})(s)&&D&&E>=M&&C>=S&&Q<=k&&l>=q&&f>=J&&f<=G&&R>=L&&m>=v,H=.22*P+.14*O+.15*h+.08*(D?1:0)+.08*w+.13*z+.1*R+.05*m+.05*b;return{contour:e,corners:s,score:H,confidence:F?H:.33*H,isValid:F,area:c,fillRatio:l,coverageRatio:C,cornersArea:d,approxCount:r,convex:D,edgeSupport:w,aspectRatio:Q,minSide:E,rightAngleScore:R,oppositeSideConsistency:m,contourFitRatio:f,contourFitScore:b}}async function cn(e,A,t,i,n={}){let o=n.debug?{}:{_timingsOnly:!0},r=[];o&&!o._timingsOnly&&(o.preprocessing={scaledDimensions:{width:A,height:t},scaleFactor:i,maxProcessingDimension:n.maxProcessingDimension||800});let s=(function(I={}){let Q=I.dilationKernelSize||3,D=I.dilationIterations||1,w=I.applyDilation===void 0||I.applyDilation,R=[{name:"default",lowThreshold:I.lowThreshold,highThreshold:I.highThreshold,dilationKernelSize:Q,dilationIterations:D,applyDilation:w}];if(I.enableDetectionCascade===!1)return R;R.push({name:"connect-edges",lowThreshold:I.lowThreshold,highThreshold:I.highThreshold,dilationKernelSize:Math.max(Q,5),dilationIterations:Math.max(D,2),applyDilation:!0}),R.push({name:"no-dilation",lowThreshold:I.lowThreshold,highThreshold:I.highThreshold,dilationKernelSize:Q,dilationIterations:D,applyDilation:!1}),I.lowThreshold===void 0&&I.highThreshold===void 0&&R.push({name:"fixed-mid-thresholds",lowThreshold:60,highThreshold:180,dilationKernelSize:Q,dilationIterations:D,applyDilation:w});let m=[],f=new Set;for(let b of R){let h=[b.lowThreshold,b.highThreshold,b.dilationKernelSize,b.dilationIterations,b.applyDilation].join(":");f.has(h)||(f.add(h),m.push(b))}return m})(n),a=[],c=async(I,Q)=>{let D=I.name||`pass-${Q+1}`,w=Q===0?"":` (${D})`,R=n.debug?{}:{_timingsOnly:!0},m=await rn(e,{width:A,height:t,lowThreshold:I.lowThreshold,highThreshold:I.highThreshold,dilationKernelSize:I.dilationKernelSize,dilationIterations:I.dilationIterations,applyDilation:I.applyDilation,debug:R,skipGrayscale:!0,useWasmBlur:!0,useWasmHysteresis:n.useWasmHysteresis,useWasmFullCanny:n.useWasmFullCanny});R.timings&&R.timings.forEach(O=>{O.step!=="Edge Detection Total"&&r.push({step:`${O.step}${w}`,ms:O.ms})});let f=performance.now(),b=Wi(m,{minArea:(n.minArea||1e3)/(i*i),width:A,height:t});r.push({step:`Find Contours${w}`,ms:(performance.now()-f).toFixed(2)}),f=performance.now();let{best:h,candidates:P}=(function(O,z,T,S,k={}){let q=k.maxCandidateContours||12,J=O.slice(0,q).map((G,L)=>({rankByArea:L,...an(G,z,T,S,k)})).sort(qt);return{best:J[0]||null,candidates:J}})(b,m,A,t,n);return r.push({step:`Corner Detection${w}`,ms:(performance.now()-f).toFixed(2)}),{name:D,params:{lowThreshold:I.lowThreshold,highThreshold:I.highThreshold,dilationKernelSize:I.dilationKernelSize,dilationIterations:I.dilationIterations,applyDilation:I.applyDilation},contours:b,best:h,candidates:P}},g=await c(s[0],0);if(a.push(g),(function(I,Q={}){if(Q.enableDetectionCascade===!1)return!1;if(!I||!I.corners)return!0;let D=Q.minCascadeTriggerConfidence!==void 0?Q.minCascadeTriggerConfidence:.68;return!I.isValid||I.confidence<D||I.approxCount>5||I.rightAngleScore<.55||I.contourFitRatio<.14})(g.best,n))for(let I=1;I<s.length;I++)a.push(await c(s[I],I));let l=[];for(let I of a)for(let Q of I.candidates)l.push({...Q,passName:I.name,passParams:I.params});l.sort(qt);let d=l[0]||null,C=l;if(!d||!d.corners)return{success:!1,message:"No document detected",debug:o._timingsOnly?null:o,timings:r};o&&!o._timingsOnly&&(o.passes=a.map(I=>({name:I.name,params:I.params,contourCount:I.contours.length,bestCandidate:I.best?{score:I.best.score,confidence:I.best.confidence,isValid:I.best.isValid,approxCount:I.best.approxCount,coverageRatio:I.best.coverageRatio,fillRatio:I.best.fillRatio,rightAngleScore:I.best.rightAngleScore,contourFitRatio:I.best.contourFitRatio}:null})),o.candidates=C.map(I=>({passName:I.passName,rankByArea:I.rankByArea,area:I.area,fillRatio:I.fillRatio,coverageRatio:I.coverageRatio,cornersArea:I.cornersArea,approxCount:I.approxCount,convex:I.convex,edgeSupport:I.edgeSupport,aspectRatio:I.aspectRatio,minSide:I.minSide,rightAngleScore:I.rightAngleScore,oppositeSideConsistency:I.oppositeSideConsistency,contourFitRatio:I.contourFitRatio,contourFitScore:I.contourFitScore,score:I.score,confidence:I.confidence,isValid:I.isValid})),o.selectedCandidate=C[0]?{passName:C[0].passName,rankByArea:C[0].rankByArea,area:C[0].area,fillRatio:C[0].fillRatio,coverageRatio:C[0].coverageRatio,approxCount:C[0].approxCount,edgeSupport:C[0].edgeSupport,aspectRatio:C[0].aspectRatio,minSide:C[0].minSide,rightAngleScore:C[0].rightAngleScore,oppositeSideConsistency:C[0].oppositeSideConsistency,contourFitRatio:C[0].contourFitRatio,score:C[0].score,confidence:C[0].confidence,isValid:C[0].isValid}:null);let u=d.corners,E=d.contour,p=u;return i!==1&&(p={topLeft:{x:u.topLeft.x*i,y:u.topLeft.y*i},topRight:{x:u.topRight.x*i,y:u.topRight.y*i},bottomRight:{x:u.bottomRight.x*i,y:u.bottomRight.y*i},bottomLeft:{x:u.bottomLeft.x*i,y:u.bottomLeft.y*i}}),{success:!0,contour:E,corners:p,confidence:d.confidence,debug:o._timingsOnly?null:o,timings:r}}function gn(e,A,t){let{topLeft:i,topRight:n,bottomRight:o,bottomLeft:r}=t,s=Math.hypot(o.x-r.x,o.y-r.y),a=Math.hypot(n.x-i.x,n.y-i.y),c=Math.round(Math.max(s,a)),g=Math.hypot(n.x-o.x,n.y-o.y),l=Math.hypot(i.x-r.x,i.y-r.y),d=Math.round(Math.max(g,l));e.canvas.width=c,e.canvas.height=d,(function(C,u,E,p,I){let Q=u&&typeof u.width=="number"&&typeof u.height=="number"&&u.data,D=u.width||u.naturalWidth,w=u.height||u.naturalHeight,R=document.createElement("canvas");R.width=D,R.height=w;let m=R.getContext("2d",{willReadFrequently:!0});Q?m.putImageData(u,0,0):m.drawImage(u,0,0,D,w);let f=m.getImageData(0,0,D,w).data,b=(function(F){let H=F[0][0],x=F[0][1],N=F[0][2],_=F[1][0],B=F[1][1],y=F[1][2],U=F[2][0],Y=F[2][1],K=F[2][2],X=B*K-y*Y,Z=-(_*K-y*U),j=_*Y-B*U,V=-(x*K-N*Y),$=H*K-N*U,sA=-(H*Y-x*U),gA=x*y-N*B,IA=-(H*y-N*_),yA=H*B-x*_,AA=H*X+x*Z+N*j;if(AA===0)throw new Error("Singular matrix");return[[X/AA,V/AA,gA/AA],[Z/AA,$/AA,IA/AA],[j/AA,sA/AA,yA/AA]]})(E),h=b[0][0],P=b[0][1],O=b[0][2],z=b[1][0],T=b[1][1],S=b[1][2],k=b[2][0],q=b[2][1],J=b[2][2],G=C.createImageData(p,I),L=G.data,v=D-1,M=w-1;for(let F=0;F<I;F++){let H=P*F+O,x=T*F+S,N=q*F+J;for(let _=0;_<p;_++){let B=1/(k*_+N),y=(h*_+H)*B,U=(z*_+x)*B,Y=y<0?0:y>v?v:y,K=U<0?0:U>M?M:U,X=0|Y,Z=0|K,j=X<v?X+1:X,V=Z<M?Z+1:Z,$=Y-X,sA=K-Z,gA=1-$,IA=1-sA,yA=gA*IA,AA=$*IA,Se=gA*sA,Re=$*sA,ve=Z*D+X<<2,ke=Z*D+j<<2,Me=V*D+X<<2,xe=V*D+j<<2,VA=F*p+_<<2;L[VA]=f[ve]*yA+f[ke]*AA+f[Me]*Se+f[xe]*Re+.5|0,L[VA+1]=f[ve+1]*yA+f[ke+1]*AA+f[Me+1]*Se+f[xe+1]*Re+.5|0,L[VA+2]=f[ve+2]*yA+f[ke+2]*AA+f[Me+2]*Se+f[xe+2]*Re+.5|0,L[VA+3]=255}}C.putImageData(G,0,0)})(e,A,(function(C,u){let E=(function(p,I){let Q=p.length,D=p[0].length,w=p.map(f=>f.slice()),R=I.slice();for(let f=0;f<D;f++){let b=f;for(let h=f+1;h<Q;h++)Math.abs(w[h][f])>Math.abs(w[b][f])&&(b=h);[w[f],w[b]]=[w[b],w[f]],[R[f],R[b]]=[R[b],R[f]];for(let h=f+1;h<Q;h++){let P=w[h][f]/w[f][f];for(let O=f;O<D;O++)w[h][O]-=P*w[f][O];R[h]-=P*R[f]}}let m=new Array(D);for(let f=D-1;f>=0;f--){let b=R[f];for(let h=f+1;h<D;h++)b-=w[f][h]*m[h];m[f]=b/w[f][f]}return m})((function(p){let I=[];for(let Q=0;Q<4;Q++){let[D,w]=p[Q];I.push([D,w,1,0,0,0,-D*u[Q][0],-w*u[Q][0]]),I.push([0,0,0,D,w,1,-D*u[Q][1],-w*u[Q][1]])}return I})(C),[u[0][0],u[0][1],u[1][0],u[1][1],u[2][0],u[2][1],u[3][0],u[3][1]]);return[[E[0],E[1],E[2]],[E[3],E[4],E[5]],[E[6],E[7],1]]})([[i.x,i.y],[n.x,n.y],[o.x,o.y],[r.x,r.y]],[[0,0],[c-1,0],[c-1,d-1],[0,d-1]]),c,d)}async function zt(e,A={}){let t=[],i=performance.now(),n=A.mode||"detect",o=A.output||"canvas",r=A.maxProcessingDimension||800,s,a,c,g;if((A.detector||"classical")==="ml"){a=performance.now();let{detectDocumentMl:d}=await Promise.resolve().then(()=>(Ht(),_t));s=await d(e,A.ml||{}),t.push({step:"ML Detection Total",ms:(performance.now()-a).toFixed(2)}),s.timings&&s.timings.forEach(C=>t.push(C))}else{a=performance.now();let{grayscaleData:d,scaleFactor:C,scaledDimensions:u}=await(async function(E,p=800){let I,Q,D=E&&typeof E.width=="number"&&typeof E.height=="number"&&E.data;if(D)I=E.width,Q=E.height;else{if(!E)throw new Error("No image provided");I=E.width||E.naturalWidth,Q=E.height||E.naturalHeight}let w=Math.max(I,Q),R,m,f;if(w<=p)R=I,m=Q,f=1;else{let S=p/w;R=Math.round(I*S),m=Math.round(Q*S),f=1/S}let b=typeof OffscreenCanvas<"u",h=b?new OffscreenCanvas(R,m):document.createElement("canvas");b||(h.width=R,h.height=m);let P=h.getContext("2d",{willReadFrequently:!0});if(P.imageSmoothingEnabled=!0,P.imageSmoothingQuality="medium",D){let S=b?new OffscreenCanvas(I,Q):document.createElement("canvas");b||(S.width=I,S.height=Q),S.getContext("2d").putImageData(E,0,0),P.drawImage(S,0,0,I,Q,0,0,R,m)}else P.drawImage(E,0,0,I,Q,0,0,R,m);let O=P.getImageData(0,0,R,m),z=O.data,T=new Uint8ClampedArray(R*m);for(let S=0,k=0;S<z.length;S+=4,k++){let q=54*z[S]+183*z[S+1]+19*z[S+2]>>8;T[k]=q,z[S]=z[S+1]=z[S+2]=q}return{grayscaleData:T,imageData:O,scaleFactor:f,originalDimensions:{width:I,height:Q},scaledDimensions:{width:R,height:m}}})(e,r);t.push({step:"Image Prep + Scale + Gray",ms:(performance.now()-a).toFixed(2)}),s=await cn(d,u.width,u.height,C,A),s.timings&&s.timings.forEach(E=>t.push(E))}if(!s.success){let d=performance.now();return t.unshift({step:"Total",ms:(d-i).toFixed(2)}),{output:null,corners:null,contour:null,confidence:s.confidence||null,score:s.score??null,debug:s.debug,success:!1,message:s.message||"No document detected",timings:t}}n==="detect"?g=null:n==="extract"&&(a=performance.now(),c=document.createElement("canvas"),gn(c.getContext("2d"),e,s.corners),t.push({step:"Perspective Transform",ms:(performance.now()-a).toFixed(2)})),n!=="detect"&&c&&(a=performance.now(),g=o==="canvas"?c:o==="imagedata"?c.getContext("2d").getImageData(0,0,c.width,c.height):o==="dataurl"?c.toDataURL():c,t.push({step:"Output Conversion",ms:(performance.now()-a).toFixed(2)}));let l=performance.now();return t.unshift({step:"Total",ms:(l-i).toFixed(2)}),{output:g,corners:s.corners,contour:s.contour??null,confidence:s.confidence||null,score:s.score??null,debug:s.debug,success:!0,message:"Document detected",timings:t}}var W,Ki,Vi,xA,aA,NA,FA,se,Pt,qe,Zt=hA(()=>{"use strict";Ki=1e3,Vi=10;xA=null;aA=0;NA=null;FA=null;se=null,Pt=!1,qe=null});var We={};Ne(We,{DOC_DETECT_MIN_CONFIDENCE:()=>jt,DOC_DETECT_WIDTH:()=>dA,SCANIC_VERSION:()=>In,detectQuad:()=>ln});async function ln(e){let A=await zt(e,{mode:"detect",detector:"classical",maxProcessingDimension:dA});return!A.success||A.corners===null||typeof A.confidence=="number"&&A.confidence<jt?null:A.corners}var In,jt,Xe=hA(()=>{"use strict";Zt();RA();In="1.5.0",jt=.35});var ro={};Ne(ro,{ASPECT_BANDS:()=>yt,AttestationError:()=>BA,CAPTURE_CANDIDATE_SPACING_MS:()=>ii,CAPTURE_EXTRA_CANDIDATES:()=>ti,CENTERED_FACTOR:()=>si,CIRCLE_RADIUS_FACTOR:()=>oi,CLIP_MIME_ALLOWLIST:()=>gt,CaptureSessionDoc:()=>ze,DOC_ANALYSIS_DEFAULTS:()=>Rt,DOC_CADENCE_HZ:()=>ei,DOC_DETECT_WIDTH:()=>dA,DOC_FEEDBACK_STATES:()=>vA,DOC_GATE_V1_DEFAULTS:()=>ZA,DocFeedbackAggregator:()=>kA,DocGateV1:()=>bA,INFERENCE_RETRY_ATTEMPTS:()=>ut,INFERENCE_RETRY_DEFAULT_S:()=>dt,IN_CIRCLE_FACTOR:()=>ri,MRZ_BAND_DEFAULTS:()=>bt,MR_DOC_CATALOG:()=>Fi,PRELOAD_BLAZE_INIT_TIMEOUT_MS:()=>tt,PRELOAD_BUDGET_MS:()=>me,PROCESSING_POLL_DELAY_MS:()=>Qt,PROCESSING_POLL_MAX:()=>mt,REGISTRY_RETRY_DELAY_MS:()=>ht,RETRYABLE_REASONS:()=>at,TRANSPORT_REPLAY_ATTEMPTS:()=>It,TRANSPORT_REPLAY_DELAY_MS:()=>lt,TURNSTILE_EXECUTE_TIMEOUT_MS:()=>wi,TURNSTILE_SCRIPT_SRC:()=>Et,analyzeDocFrame:()=>_e,aspectBand:()=>wA,createLivenessCaptureInternal:()=>pe,createVerificationInternal:()=>bi,detectIsMobile:()=>lA,detectMrzBand:()=>Te,executeTurnstile:()=>be,feedbackVoteOf:()=>He,frontierStep:()=>rA,isExecutable:()=>EA,isTerminalView:()=>tA,loadTurnstile:()=>Bt,mapEngineState:()=>rt,mapErrorKind:()=>st,mapGuidanceHint:()=>ot,mapSessionResult:()=>OA,mergeSessionView:()=>we,preloadedDetectorFactory:()=>fe,quadAreaFrac:()=>jA,quadBounds:()=>SA,quadIou:()=>Dt,quadTiltRatio:()=>vt,randomUuid:()=>ft,resetLivenessAssetsForTests:()=>Ei,resetTurnstileForTests:()=>Di,runLivenessFlow:()=>De,runSubmission:()=>pA,setPreloadLoaderForTests:()=>Ci,specularFraction:()=>Ge,stepOf:()=>iA,warmDocDetector:()=>Cn});module.exports=Ni(ro);XA();RA();var bt=Object.freeze({EDGE_LUMA_DELTA:40,MIN_ROW_DENSITY:.08,MIN_COLUMN_COVERAGE:.6,MIN_WIDTH_FRAC:.55,MIN_HEIGHT_FRAC:.02,MAX_HEIGHT_FRAC:.16,ROW_MERGE_GAP:18}),$A=12;function Te(e,A={}){let t={...bt,...A},{data:i,width:n,height:o}=e;if(n<32||o<32)return null;let r=new Array(o).fill(!1),s=new Float32Array(o),a=new Int32Array(o).fill(n),c=new Int32Array(o).fill(-1),g=n/$A,l=new Array($A);for(let m=0;m<o;m++){let f=0;l.fill(!1);let b=m*n*4,h=.299*(i[b]??0)+.587*(i[b+1]??0)+.114*(i[b+2]??0);for(let O=1;O<n;O++){let z=b+O*4,T=.299*(i[z]??0)+.587*(i[z+1]??0)+.114*(i[z+2]??0);Math.abs(T-h)>=t.EDGE_LUMA_DELTA&&(f+=1,l[Math.min($A-1,Math.floor(O/g))]=!0,O<a[m]&&(a[m]=O),O>c[m]&&(c[m]=O)),h=T}s[m]=f/n;let P=l.filter(Boolean).length/$A;r[m]=s[m]>=t.MIN_ROW_DENSITY&&P>=t.MIN_COLUMN_COVERAGE&&c[m]-a[m]>=t.MIN_WIDTH_FRAC*n}let d=null,C=-1,u=-1,E=0,p=m=>{if(C<0)return;let f=m-C+1;f>=t.MIN_HEIGHT_FRAC*o&&f<=t.MAX_HEIGHT_FRAC*o&&E>=4&&(d===null||E>d.rows)&&(d={top:C,bottom:m,rows:E}),C=-1,E=0};for(let m=0;m<o;m++)r[m]&&(C<0?C=m:m-u>t.ROW_MERGE_GAP&&(p(u),C=m),u=m,E+=1);if(p(u),d===null)return null;let I=d,Q=n,D=-1,w=0,R=0;for(let m=I.top;m<=I.bottom;m++)r[m]&&(a[m]<Q&&(Q=a[m]),c[m]>D&&(D=c[m]),w+=s[m],R+=1);return D-Q<t.MIN_WIDTH_FRAC*n?null:{x:Q,y:I.top,width:D-Q,height:I.bottom-I.top+1,density:R>0?w/R:0}}mA();XA();RA();var Rt=Object.freeze({MAX_AREA_FRAC:.92,TILT_MAX_SIDE_RATIO:1.3,GLARE_MAX_SPECULAR_FRAC:.025});function Ge(e){let{data:A,width:t,height:i}=e,n=t*i;if(n===0)return 0;let o=0;for(let r=0;r<n;r++){let s=r*4;.299*(A[s]??0)+.587*(A[s+1]??0)+.114*(A[s+2]??0)>=252&&o++}return o/n}function vt(e){let A=(a,c)=>Math.hypot(c.x-a.x,c.y-a.y),t=A(e.topLeft,e.topRight),i=A(e.bottomLeft,e.bottomRight),n=A(e.topLeft,e.bottomLeft),o=A(e.topRight,e.bottomRight),r=Math.max(t,i)/Math.max(1e-6,Math.min(t,i)),s=Math.max(n,o)/Math.max(1e-6,Math.min(n,o));return Math.max(r,s)}function _e(e){let A={...ZA,...e.thresholds},t=Rt,{quad:i,frameWidth:n,frameHeight:o,measures:r}=e,s=e.format==="ID-3",a="ok";if(i===null)a="no_document";else if(s){let d=SA(i),C=n>0?d.width/n:0,u=d.height>0?d.width/d.height:0;C<A.ID3_BAND_MIN_WIDTH_FRAC?a="too_far":St(i,n,o,A.EDGE_CLIP_MARGIN_PX)?a="edge_clipped":(u<A.ID3_BAND_ASPECT_MIN||u>A.ID3_BAND_ASPECT_MAX)&&(a="wrong_shape")}else{let d=jA(i,n,o),C=wA(e.format),u=SA(i),E=Math.max(u.width,u.height)/Math.max(1e-6,Math.min(u.width,u.height));d<A.MIN_AREA_FRAC?a="too_far":d>t.MAX_AREA_FRAC?a="too_close":St(i,n,o,A.EDGE_CLIP_MARGIN_PX)?a="edge_clipped":Math.abs(E-C.center)>C.tolerance?a="wrong_shape":vt(i)>t.TILT_MAX_SIDE_RATIO&&(a="tilted")}let c=r.exposure>=A.GUIDE_EXPOSURE?"ok":r.meanLuma<(nA[0]+nA[1])/2?"too_dark":"too_bright",g=r.sharpness>=A.GUIDE_SHARPNESS?"ok":"blurry",l=r.specularFraction>=t.GLARE_MAX_SPECULAR_FRAC?"glare":"ok";return{framing:a,lighting:c,blur:g,glare:l,acceptable:a==="ok"&&c==="ok"&&g==="ok"&&l==="ok"}}function St(e,A,t,i){return[e.topLeft,e.topRight,e.bottomRight,e.bottomLeft].some(o=>o.x<=i||o.y<=i||o.x>=A-i||o.y>=t-i)}var vA=Object.freeze({sensing:{key:"sensing",reticle:"searching",minDurationMs:900},too_far:{key:"too_far",reticle:"coaching",minDurationMs:1400},too_close:{key:"too_close",reticle:"coaching",minDurationMs:1400},edge_clipped:{key:"edge_clipped",reticle:"coaching",minDurationMs:1400},wrong_shape:{key:"wrong_shape",reticle:"coaching",minDurationMs:1400},tilted:{key:"tilted",reticle:"coaching",minDurationMs:1400},too_dark:{key:"too_dark",reticle:"coaching",minDurationMs:1400},too_bright:{key:"too_bright",reticle:"coaching",minDurationMs:1400},blurry:{key:"blurry",reticle:"coaching",minDurationMs:1400},glare:{key:"glare",reticle:"coaching",minDurationMs:1400},hold_still:{key:"hold_still",reticle:"locking",minDurationMs:900},processing:{key:"processing",reticle:"processing",minDurationMs:800},side_captured:{key:"side_captured",reticle:"flip",minDurationMs:2600},captured:{key:"captured",reticle:"done",minDurationMs:800}});function He(e){return e.framing==="no_document"?"sensing":e.framing==="too_far"?"too_far":e.framing==="too_close"?"too_close":e.framing==="edge_clipped"?"edge_clipped":e.framing==="wrong_shape"?"wrong_shape":e.framing==="tilted"?"tilted":e.lighting==="too_dark"?"too_dark":e.lighting==="too_bright"?"too_bright":e.glare==="glare"?"glare":e.blur==="blurry"?"blurry":"hold_still"}var kA=class{constructor(A=2600,t=.35){this.windowMs=A;this.decayPerSecond=t;this.votes=[];this.current=vA.sensing;this.currentSinceMs=null}reset(){this.votes=[],this.current=vA.sensing,this.currentSinceMs=null}force(A,t){return this.votes=[],this.current=vA[A],this.currentSinceMs=t,this.current}tick(A,t){if(this.currentSinceMs===null&&(this.currentSinceMs=t),this.votes.push({key:A,atMs:t}),this.votes=this.votes.filter(r=>t-r.atMs<=this.windowMs),t-this.currentSinceMs<this.current.minDurationMs)return this.current;let i=new Map;for(let r of this.votes){let s=(t-r.atMs)/1e3,a=this.decayPerSecond**s;i.set(r.key,(i.get(r.key)??0)+a)}let n=this.current.key,o=-1;for(let[r,s]of i)s>o&&(o=s,n=r);return n!==this.current.key&&(this.current=vA[n],this.currentSinceMs=t),this.current}};var kt="0.1.0-rc.7";var Mt="sekyro.did",xt;function Nt(){let e=globalThis.crypto;try{if(typeof e?.randomUUID=="function")return e.randomUUID()}catch{}try{if(typeof e?.getRandomValues=="function"){let A=e.getRandomValues(new Uint8Array(16));return Array.from(A,t=>t.toString(16).padStart(2,"0")).join("")}}catch{}}function Gi(){try{let e=localStorage.getItem(Mt);if(e)return e;let A=Nt();return A!==void 0&&localStorage.setItem(Mt,A),A}catch{return xt??(xt=Nt()),xt}}async function _i(){let e=globalThis.crypto?.subtle;if(!e)return"";let A=navigator,t=JSON.stringify([A.userAgent,A.platform,A.hardwareConcurrency??null,A.deviceMemory??null,A.maxTouchPoints??0,screen.width,screen.height,screen.colorDepth,globalThis.devicePixelRatio??1,Intl.DateTimeFormat().resolvedOptions().timeZone,A.languages?.join(",")??A.language]),i=await e.digest("SHA-256",new TextEncoder().encode(t));return Array.from(new Uint8Array(i),n=>n.toString(16).padStart(2,"0")).join("").slice(0,32)}function Hi(e){let A=new TextEncoder().encode(e),t="";for(let i of A)t+=String.fromCharCode(i);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Ui(e){let A,t;return{timezone(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone?.slice(0,64)||void 0}catch{return}},noteCameraLabel(i){i&&(A=i.slice(0,128))},async deviceHeader(){try{t??(t=_i().catch(()=>""));let i=[];navigator.webdriver&&i.push("webdriver"),/HeadlessChrome/.test(navigator.userAgent)&&i.push("headless");let n=await t,o=Gi(),r={v:1,platform:"web",sdk:e.sdk.slice(0,64),ids:[...o?[{kind:"web_local",value:o.slice(0,128)}]:[],...n?[{kind:"web_fp",value:n}]:[]],screen:{w:screen.width,h:screen.height,dpr:globalThis.devicePixelRatio??1},...A?{cameraLabel:A}:{},...i.length?{signals:i}:{}};return Hi(JSON.stringify(r))}catch{return}}}}var Ue=Symbol.for("sekyro.web.clientContext"),Je=globalThis,Ae=Je[Ue]??(Je[Ue]=Ui({sdk:`@sekyro/web@${kt}`}));function ee(e){try{let A=e.getVideoTracks?.()[0];A&&Ae.noteCameraLabel(A.label)}catch{}}var Ji=["video/mp4;codecs=avc1.42E01E,mp4a.40.2","video/mp4;codecs=avc1.42E01E","video/mp4","video/webm;codecs=vp9,opus","video/webm;codecs=vp9","video/webm;codecs=vp8,opus","video/webm;codecs=vp8","video/webm"];function Ft(){let e=globalThis.MediaRecorder;return!e||typeof e.isTypeSupported!="function"?"":Ji.find(A=>e.isTypeSupported(A))??""}var Lt="video/webm";function te(e){if(e instanceof TypeError)return"insecure";switch(e?.name??""){case"NotAllowedError":case"PermissionDeniedError":return"permission";case"NotFoundError":case"DevicesNotFoundError":return"notfound";case"NotReadableError":case"TrackStartError":return"inuse";case"OverconstrainedError":case"ConstraintNotSatisfiedError":return"overconstrained";default:return"generic"}}function Tt(){let e=globalThis;if(typeof e.window<"u"&&e.window.isSecureContext===!1)return"INSECURE_CONTEXT";let A=e.navigator?.mediaDevices;return!A||typeof A.getUserMedia!="function"?"UNSUPPORTED":"OK"}function Gt(){let e=globalThis.MediaRecorder;return typeof e<"u"&&typeof e.isTypeSupported=="function"}var Pe=8*1024*1024;function ie(e){return e.size>Pe}var Pi=Object.freeze({LOW:Object.freeze({cadenceHz:5,inputWidth:128,animations:"reduced"}),MID:Object.freeze({cadenceHz:8,inputWidth:160,animations:"full"}),HIGH:Object.freeze({cadenceHz:10,inputWidth:192,animations:"full"})}),Yi=new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11]);function oe(){let e=typeof navigator>"u"?void 0:navigator,A=!1;try{A=typeof WebAssembly<"u"&&WebAssembly.validate(Yi)}catch{A=!1}return{cores:e?.hardwareConcurrency??2,memGB:e?.deviceMemory??null,simd:A}}function re(e){let A=e.memGB??4;return e.cores<4||A<3?"LOW":e.cores>=8&&A>=6?"HIGH":"MID"}var Ye=["LOW","MID","HIGH"],ne=class{constructor(A){this.samples=[];this.adjusted=!1;this.current=A}get deviceClass(){return this.current}get profile(){return Pi[this.current]}record(A){if(this.adjusted||this.samples.length>=10)return this.current;if(this.samples.push(A),this.samples.length<10)return this.current;this.adjusted=!0;let t=this.samples.reduce((i,n)=>i+n,0)/this.samples.length;if(t>70)this.current="LOW";else if(t<25){let i=Ye.indexOf(this.current);this.current=Ye[Math.min(Ye.length-1,i+1)]??this.current}return this.current}};mA();RA();var GA=null;async function un(e){return GA===null&&(GA=(await Promise.resolve().then(()=>(Xe(),We))).detectQuad),GA(e)}async function dn(e){let A=Te(e);return A===null?null:{topLeft:{x:A.x,y:A.y},topRight:{x:A.x+A.width,y:A.y},bottomRight:{x:A.x+A.width,y:A.y+A.height},bottomLeft:{x:A.x,y:A.y+A.height}}}function Cn(){GA===null&&Promise.resolve().then(()=>(Xe(),We)).then(e=>{GA=e.detectQuad}).catch(()=>{})}var ei=Object.freeze({LOW:3,MID:5,HIGH:6}),ze=class{constructor(A){this.handlers=new Map;this.stream=null;this.timer=null;this.state="idle";this.lastGuidance=null;this.attempt=0;this.capturing=!1;this.feedback=new kA;this.lastFeedbackKey=null;this.opts=A,this.gate=new bA(A.format??"ID-1",A.thresholds);let t=A.deviceClass??re(oe());this.cadenceMs=1e3/ei[t]}on(A,t){let i=this.handlers.get(A);return i||(i=new Set,this.handlers.set(A,i)),i.add(t),()=>i?.delete(t)}emit(A,t){for(let i of[...this.handlers.get(A)??[]])i(t)}async start(){let A=++this.attempt;this.gate.reset(),this.feedback.reset(),this.lastFeedbackKey=null,this.lastGuidance=null,this.capturing=!1,this.setState("preflight");try{let t=this.opts.getUserMedia??(i=>navigator.mediaDevices.getUserMedia(i));if(this.setState("acquiring"),this.stream=await t({audio:!1,video:{facingMode:{ideal:"environment"},width:{ideal:1920},height:{ideal:1080}}}),ee(this.stream),A!==this.attempt){for(let i of this.stream.getTracks())i.stop();return}this.opts.video.srcObject=this.stream,await this.opts.video.play().catch(()=>{}),this.setState("positioning"),this.scheduleTick(A)}catch(t){let i=te(t);this.setState("error"),this.emit("error",{kind:i,retryable:!0})}}rearm(A){A!==void 0&&(this.opts.side=A),this.gate.reset(),this.feedback.reset(),this.lastFeedbackKey=null,this.lastGuidance=null,this.capturing=!1,this.state==="captured"&&(this.setState("positioning"),this.scheduleTick(this.attempt))}destroy(){if(this.attempt+=1,this.timer!==null&&(this.opts.clearTimer??clearTimeout)(this.timer),this.timer=null,this.stream)for(let A of this.stream.getTracks())A.stop();this.stream=null,this.opts.video.srcObject=null}setState(A){this.state=A,this.emit("statechange",{state:A})}scheduleTick(A){let t=this.opts.setTimer??setTimeout;this.timer=t(()=>{this.tick(A)},this.cadenceMs)}async tick(A){if(A!==this.attempt||this.state!=="positioning"||this.capturing)return;let t=this.opts.now??(()=>performance.now()),i=this.opts.grabDetectFrame??$t,n=this.opts.detect??((this.opts.format??"ID-1")==="ID-3"?dn:un),o=i(this.opts.video,dA);if(o===null){this.scheduleTick(A);return}let r=null;try{r=await n(o)}catch{r=null}if(A!==this.attempt)return;let s=r!==null?Ai(o,r):o,a=t(),c={sharpness:QA(s),exposure:zA(s),meanLuma:DA(s),specularFraction:Ge(s)},g=_e({format:this.opts.format??"ID-1",quad:r,frameWidth:o.width,frameHeight:o.height,measures:c,...this.opts.thresholds!==void 0?{thresholds:this.opts.thresholds}:{}}),l=this.gate.tick({timestampMs:a,quad:r,quality:c,frameWidth:o.width,frameHeight:o.height});this.emit("checks",{engine:"docv1",p:l.p,plausible:l.plausible,stableTicks:l.stableTicks,quad:l.quad,frameWidth:o.width,frameHeight:o.height,analysis:g});let d=this.feedback.tick(He(g),a);if(d.key!==this.lastFeedbackKey&&(this.lastFeedbackKey=d.key,this.emit("feedback",d)),l.guidanceKey!==this.lastGuidance&&(this.lastGuidance=l.guidanceKey,this.emit("guidance",{key:l.guidanceKey})),l.ready&&r!==null){let C=this.feedback.force("processing",a);this.lastFeedbackKey=C.key,this.emit("feedback",C),await this.fire(A,r,{width:o.width,height:o.height,tickSharpness:c.sharpness});return}this.scheduleTick(A)}async fire(A,t,i){this.capturing=!0;let n=this.opts.captureStill??Bn,o=this.opts.grabDetectFrame??$t,r=this.opts.setTimer??setTimeout,s={width:i.width,height:i.height};try{let a={still:await n(this.opts.video,t,s),sharpness:i.tickSharpness};for(let c=0;c<ti;c++){if(await new Promise(d=>{r(()=>d(),ii)}),A!==this.attempt)return;let g=o(this.opts.video,dA);if(g===null)continue;let l=QA(Ai(g,t));if(l>a.sharpness*En){let d=await n(this.opts.video,t,s);if(A!==this.attempt)return;a={still:d,sharpness:l}}}if(A!==this.attempt)return;this.setState("captured"),this.emit("artifacts",{keyframe:a.still.blob,previewDataUrl:a.still.previewDataUrl,...this.opts.side!==void 0?{side:this.opts.side}:{}})}catch{if(A!==this.attempt)return;this.capturing=!1,this.gate.reset(),this.scheduleTick(A)}}},ti=2,ii=260,En=1.08;function $t(e,A){let t=e.videoWidth,i=e.videoHeight;if(t===0||i===0)return null;let n=Math.min(1,A/t),o=Math.round(t*n),r=Math.round(i*n),s=document.createElement("canvas");s.width=o,s.height=r;let a=s.getContext("2d",{willReadFrequently:!0});return a===null?null:(a.drawImage(e,0,0,o,r),a.getImageData(0,0,o,r))}async function Bn(e,A,t){let i=document.createElement("canvas");i.width=Math.max(1,e.videoWidth),i.height=Math.max(1,e.videoHeight);let n=i.getContext("2d");if(n===null)throw new Error("2d context unavailable");return n.drawImage(e,0,0,i.width,i.height),{blob:await new Promise((r,s)=>{i.toBlob(a=>a?r(a):s(new Error("toBlob failed")),"image/jpeg",.92)}),previewDataUrl:i.toDataURL("image/jpeg",.85)}}function Ai(e,A){let t=[A.topLeft.x,A.topRight.x,A.bottomRight.x,A.bottomLeft.x],i=[A.topLeft.y,A.topRight.y,A.bottomRight.y,A.bottomLeft.y],n=Math.max(0,Math.floor(Math.min(...t))),o=Math.max(0,Math.floor(Math.min(...i))),r=Math.min(e.width,Math.ceil(Math.max(...t))),s=Math.min(e.height,Math.ceil(Math.max(...i))),a=Math.max(1,r-n),c=Math.max(1,s-o),g=new Uint8ClampedArray(a*c*4);for(let l=0;l<c;l++){let d=((o+l)*e.width+n)*4;g.set(e.data.subarray(d,d+a*4),l*a*4)}return{data:g,width:a,height:c,colorSpace:e.colorSpace}}function ni(e,A){return{video:{width:{ideal:1280,max:1280},height:{ideal:720,max:720},facingMode:A,frameRate:{ideal:24,max:30}},audio:!1}}function lA(){return typeof window>"u"||typeof navigator>"u"?!1:window.innerWidth<=768||/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(String(navigator.userAgent??""))}var oi=.45,ri=.9,si=.4;var hn=2500,Qn=1e3,mn=1500,ai=25e5,uA=class extends Error{constructor(A,t){super(t??A),this.kind=A}},ce=class{constructor(){this.recorder=null;this.stream=null;this.chunks=[];this.bytes=0;this.hardStopTimer=null;this.graceTimer=null;this.settled=!1}clearTimers(){this.hardStopTimer&&clearTimeout(this.hardStopTimer),this.graceTimer&&clearTimeout(this.graceTimer),this.hardStopTimer=null,this.graceTimer=null}record(A,t){if(this.recorder&&!this.settled)return Promise.reject(new uA("generic","record() called while a recording is in flight \u2014 ClipRecorder handles one recording at a time"));this.recorder=null,this.clearTimers(),this.chunks=[],this.bytes=0,this.settled=!1,this.stream=A;let i=Ft();return new Promise((n,o)=>{let r;try{r=new MediaRecorder(A,i?{mimeType:i,videoBitsPerSecond:ai}:{videoBitsPerSecond:ai})}catch{try{r=new MediaRecorder(A)}catch{o(new uA("unsupported"));return}}this.recorder=r;let s=c=>{this.settled||(this.settled=!0,this.clearTimers(),c())},a=()=>s(()=>{let c=r.mimeType||i||Lt,g=new Blob(this.chunks,{type:c});if(ie(g)){o(new uA("cliptoolarge"));return}n({blob:g,mimeType:c})});r.ondataavailable=c=>{c.data&&c.data.size&&(this.chunks.push(c.data),this.bytes+=c.data.size,this.bytes>Pe&&s(()=>{try{r.state!=="inactive"&&r.stop()}catch{}o(new uA("cliptoolarge"))}))},r.onstop=a,r.onerror=()=>s(()=>o(new uA("generic")));try{r.start(Qn)}catch{s(()=>o(new uA("generic")));return}this.hardStopTimer=setTimeout(()=>{if(this.settled||t?.(),r.state!=="inactive"){try{r.stop()}catch{a()}this.graceTimer=setTimeout(a,mn)}else a()},hn)})}stop(A){this.clearTimers();let t=this.recorder;if(t&&t.state!=="inactive")try{t.stop()}catch{}this.recorder=null,(A??this.stream)?.getTracks().forEach(n=>n.stop()),this.stream=null}};function ci(e,A,t=.92){return new Promise((i,n)=>{let o=e.videoWidth,r=e.videoHeight;if(!o||!r){n(new Error("video-not-ready"));return}let s=A.getContext("2d");if(!s){n(new Error("no-2d-context"));return}A.width=o,A.height=r,s.scale(-1,1),s.drawImage(e,-o,0),A.toBlob(a=>a?i(a):n(new Error("empty-keyframe")),"image/jpeg",t)})}var gi=1e4,ge=class e{constructor(A,t){this.tier="blaze";this.inner=A,t!==void 0&&(this.fallbackReason=t)}static async create(A,t){let i=await import("@mediapipe/tasks-vision"),n=await i.FilesetResolver.forVisionTasks(A),o=await i.FaceDetector.createFromOptions(n,{baseOptions:{modelAssetPath:`${A}/blaze_face_short_range.tflite`,delegate:"CPU"},runningMode:"IMAGE"});return new e(o,t)}async detect(A,t,i){let n;try{n=this.inner.detect(A).detections}catch{return null}let o=fn(n);if(o?.boundingBox===void 0)return null;let r=_A(A),s=pn(o.keypoints,r),a={box:{x:o.boundingBox.originX,y:o.boundingBox.originY,width:o.boundingBox.width,height:o.boundingBox.height},...s!==void 0?{eyes:s}:{},score:o.categories[0]?.score??0};return Ie(a,A,t,i)}destroy(){try{this.inner.close()}catch{}}};function fn(e){let A,t=-1;for(let i of e){let n=i.categories[0]?.score??0;n>t&&(A=i,t=n)}return A}function pn(e,A){let t=e?.[0],i=e?.[1];if(t===void 0||i===void 0)return;let n=s=>({x:s.x*A.width,y:s.y*A.height}),[o,r]=[n(t),n(i)];return o.x<=r.x?{left:o,right:r}:{left:r,right:o}}function yn(){if(typeof OffscreenCanvas=="function")return new OffscreenCanvas(2,2);let e=document.createElement("canvas");return e.width=2,e.height=2,e}async function Ii(){let e=globalThis.FaceDetector;if(typeof e!="function")return{ok:!1,reason:"unsupported"};try{let A=new e({fastMode:!0,maxDetectedFaces:1});return await A.detect(yn()),{ok:!0,instance:A}}catch(A){return{ok:!1,reason:`smoke_failed:${A instanceof Error?A.message:String(A)}`}}}var le=class{constructor(A,t){this.tier="native";this.inner=A,t!==void 0&&(this.fallbackReason=t)}async detect(A,t,i){let n;try{n=await this.inner.detect(A)}catch{return null}let o=n[0];if(o===void 0)return null;let r=wn(o.landmarks),s={box:{x:o.boundingBox.x,y:o.boundingBox.y,width:o.boundingBox.width,height:o.boundingBox.height},...r!==void 0?{eyes:r}:{},score:1};return Ie(s,A,t,i)}destroy(){}};function wn(e){if(e===void 0)return;let A=e.filter(n=>n.type==="eye").map(n=>n.locations[0]).filter(n=>n!==void 0),[t,i]=A;if(!(t===void 0||i===void 0))return t.x<=i.x?{left:t,right:i}:{left:i,right:t}}var je="/models-v3",Dn=["native","blaze"],HA=class extends Error{constructor(A){super(`no detector tier available (${A})`),this.name="DetectorLadderError",this.fallbackReason=A}};function _A(e){let A=e;if(typeof A.videoWidth=="number"&&A.videoWidth>0)return{width:A.videoWidth,height:A.videoHeight??0};if(typeof A.naturalWidth=="number"&&A.naturalWidth>0)return{width:A.naturalWidth,height:A.naturalHeight??0};let t=typeof A.width=="number"?A.width:0,i=typeof A.height=="number"?A.height:0;return{width:t,height:i}}function Ie(e,A,t,i){let n=_A(A),o=n.width>0?t/n.width:1,r=n.height>0?i/n.height:1,s=a=>({x:a.x*o,y:a.y*r});return{box:{x:e.box.x*o,y:e.box.y*r,width:e.box.width*o,height:e.box.height*r},...e.eyes!==void 0?{eyes:{left:s(e.eyes.left),right:s(e.eyes.right)}}:{},score:e.score}}function bn(e){return e instanceof Error?e.message:String(e)}async function oA(e){let A=e.preferred??Dn,t=[];for(let i of A){if(i==="native"){let n=await Ii();if(n.ok)return new le(n.instance,Ze(t));t.push(`native:${n.reason}`);continue}try{return await Sn(ge.create(e.v3AssetBaseUrl??je,Ze(t)),e.blazeInitTimeoutMs??gi)}catch(n){t.push(n instanceof ue?"blaze:blaze_init_timeout":`blaze:${bn(n)}`)}}throw new HA(Ze(t)??"no_tier_available")}function Ze(e){return e.length>0?e.join("; "):void 0}var ue=class extends Error{};function Sn(e,A){return new Promise((t,i)=>{let n=setTimeout(()=>{i(new ue(`init exceeded ${A}ms`)),e.then(o=>o.destroy(),()=>{})},A);e.then(o=>{clearTimeout(n),t(o)},o=>{clearTimeout(n),i(o)})})}var CA=1;function li(){return typeof OffscreenCanvas=="function"&&typeof createImageBitmap=="function"&&typeof Worker=="function"}function Rn(e,A={}){let t=A.createDetector??oA,i=null;e.onmessage=n=>{let o=n.data;if(o.v!==CA){o.bitmap?.close?.();return}if(o.type==="init"){t(o.options).then(r=>{i=r;let s={v:CA,type:"ready",tier:r.tier,...r.fallbackReason!==void 0?{fallbackReason:r.fallbackReason}:{}};e.postMessage(s)});return}if(o.type==="detect"){let r=s=>{let a={v:CA,type:"result",id:o.id,observation:s};e.postMessage(a),o.bitmap.close?.()};if(i===null){r(null);return}i.detect(o.bitmap,o.streamWidth,o.streamHeight).then(r,()=>r(null))}}}typeof self<"u"&&typeof self.importScripts=="function"&&Rn(self);var de=class e{constructor(A,t){this.pending=new Map;this.nextId=1;this.worker=A,this.tier=t.tier,t.fallbackReason!==void 0&&(this.fallbackReason=t.fallbackReason),A.addEventListener("message",i=>{let n=i.data;if(n.v!==CA||n.type!=="result")return;let o=this.pending.get(n.id);this.pending.delete(n.id),o?.(n.observation)})}static create(A,t,i=1e4){return new Promise((n,o)=>{let r=setTimeout(()=>{A.removeEventListener("message",s),A.terminate(),o(new Error(`worker detector not ready within ${i}ms`))},i),s=c=>{let g=c.data;g.v!==CA||g.type!=="ready"||(clearTimeout(r),A.removeEventListener("message",s),n(new e(A,g)))};A.addEventListener("message",s);let a={v:CA,type:"init",options:t};A.postMessage(a)})}async detect(A,t,i){let n;try{typeof ImageBitmap<"u"&&A instanceof ImageBitmap?n=A:typeof createImageBitmap=="function"?n=await createImageBitmap(A):n=A}catch{return null}let o=this.nextId;return this.nextId+=1,new Promise(r=>{this.pending.set(o,r);let s={v:CA,type:"detect",id:o,bitmap:n,streamWidth:t,streamHeight:i};this.worker.postMessage(s,[n])})}destroy(){for(let A of this.pending.values())A(null);this.pending.clear(),this.worker.terminate()}};var Ce=class{constructor(A){this.timer=null;this.frameCallbackId=null;this.running=!1;this.busy=!1;this.lastRunAt=Number.NEGATIVE_INFINITY;this.degradeCount=0;this.durations=[];this.options=A,this.periodMs=1e3/A.cadenceHz}start(){if(this.running)return;this.running=!0;let A=this.options.video;if(typeof A?.requestVideoFrameCallback=="function"){let t=()=>{this.running&&(this.frameCallbackId=A.requestVideoFrameCallback?.(()=>{this.frameCallbackId=null,this.now()-this.lastRunAt>=this.periodMs&&this.tick(),t()}))};t();return}this.timer=setInterval(()=>this.tick(),this.periodMs)}stop(){this.running=!1,this.timer!==null&&(clearInterval(this.timer),this.timer=null),this.frameCallbackId!==null&&(this.options.video?.cancelVideoFrameCallback?.(this.frameCallbackId),this.frameCallbackId=null)}stats(){let A=this.durations.length===0?0:this.durations.reduce((t,i)=>t+i,0)/this.durations.length;return{degradeCount:this.degradeCount,meanDetectMs:A}}now(){return this.options.now?.()??performance.now()}tick(){if(!this.running)return;if(this.busy){this.degradeCount+=1;return}this.busy=!0,this.lastRunAt=this.now();let A=this.now();this.options.run().catch(()=>{}).finally(()=>{this.busy=!1,this.durations.push(this.now()-A),this.durations.length>20&&this.durations.shift()})}};mA();var vn=Object.freeze({Q_GOOD:.6,RISE_PER_S:.9,FALL_PER_S:.25,CENTER_FALLOFF_IOD_MULTIPLE:1.35,BOX_EYE_OFFSET_FACTOR:.12,IOD_BOX_PROXY_FACTOR:.42,SIZE_IDEAL_MIN:.12,SIZE_IDEAL_MAX:.3,SIZE_HARD_MIN:.08,SIZE_HARD_MAX:.45,ROLL_MAX_DEG:25,MOTION_VELOCITY_IOD_PER_S:.5,MOTION_TAU_S:.4,MOTION_DEADBAND_IOD_PER_S:.1,READY_WINDOW_MS:500,GUIDE_SIZE:.6,GUIDE_CENTERING:.6,GUIDE_POSE:.6,GUIDE_EXPOSURE:.6,GUIDE_SHARPNESS:.35,GUIDE_MOTION:.5}),fA=e=>Math.min(1,Math.max(0,e)),Ee=class{constructor(A={}){this.p=0;this.lastTickAt=null;this.lastCenter=null;this.velocityEma=0;this.qWindow=[];this.lastSizeDirection="ideal";this.t={...vn,...A}}reset(){this.p=0,this.lastTickAt=null,this.lastCenter=null,this.velocityEma=0,this.qWindow=[],this.lastSizeDirection="ideal"}tick(A){let{observation:t,quality:i,timestampMs:n}=A,o=this.lastTickAt===null?0:Math.max(0,(n-this.lastTickAt)/1e3);this.lastTickAt=n;let r={presence:0,centering:0,size:0,pose:0,sharpness:fA(i.sharpness),exposure:fA(i.exposure),motion:1};if(t!==null){r.presence=1;let g=this.geometryOf(t,A);r.centering=g.centering,r.size=g.size,r.pose=g.pose,r.motion=this.motionOf(g.center,g.iod,n)}else this.lastCenter=null,this.velocityEma=0;let s=Math.min(r.presence,r.centering,r.size,r.pose,r.sharpness,r.exposure,r.motion);this.p=fA(this.p+(s>=this.t.Q_GOOD?this.t.RISE_PER_S*s:-this.t.FALL_PER_S*(1-s))*o),this.qWindow.push({at:n,q:s}),this.qWindow=this.qWindow.filter(g=>g.at>=n-this.t.READY_WINDOW_MS);let a=this.qWindow.map(g=>g.q);if(a.length>=3){let g=Math.min(...a),l=a.indexOf(g);a=a.filter((d,C)=>C!==l)}let c=this.p>=1&&a.every(g=>g>=this.t.Q_GOOD);return{at:n,q:s,p:this.p,factors:r,guidanceKey:this.guidanceOf(r,i,s),ready:c,accepted:s>=this.t.Q_GOOD}}geometryOf(A,t){let{box:i,eyes:n}=A,o={x:t.frameWidth/2,y:t.frameHeight/2},r=Math.min(t.frameWidth,t.frameHeight),s=n!==void 0?{x:(n.left.x+n.right.x)/2,y:(n.left.y+n.right.y)/2}:{x:i.x+i.width/2,y:i.y+i.height/2-this.t.BOX_EYE_OFFSET_FACTOR*i.height},a=n!==void 0?Math.hypot(n.right.x-n.left.x,n.right.y-n.left.y):this.t.IOD_BOX_PROXY_FACTOR*i.width,c=Math.hypot(s.x-o.x,s.y-o.y),g=a<=0?0:1-fA(c/(this.t.CENTER_FALLOFF_IOD_MULTIPLE*a)),l=r>0?a/r:0;this.lastSizeDirection=l<this.t.SIZE_IDEAL_MIN?"far":l>this.t.SIZE_IDEAL_MAX?"close":"ideal";let d;l<this.t.SIZE_HARD_MIN||l>this.t.SIZE_HARD_MAX?d=0:l<this.t.SIZE_IDEAL_MIN?d=(l-this.t.SIZE_HARD_MIN)/(this.t.SIZE_IDEAL_MIN-this.t.SIZE_HARD_MIN):l>this.t.SIZE_IDEAL_MAX?d=(this.t.SIZE_HARD_MAX-l)/(this.t.SIZE_HARD_MAX-this.t.SIZE_IDEAL_MAX):d=1;let C=1;if(n!==void 0){let u=Math.abs(Math.atan2(n.right.y-n.left.y,n.right.x-n.left.x))*180/Math.PI;C=1-fA(u/this.t.ROLL_MAX_DEG)}return{center:s,iod:a,centering:g,size:d,pose:C}}motionOf(A,t,i){let n=this.lastCenter;if(this.lastCenter={...A,at:i},n===null||t<=0)return 1;let o=(i-n.at)/1e3;if(o<=0)return 1;let r=Math.hypot(A.x-n.x,A.y-n.y)/t/o;r<=this.t.MOTION_DEADBAND_IOD_PER_S&&(r=0);let s=1-Math.exp(-o/this.t.MOTION_TAU_S);return this.velocityEma=s*r+(1-s)*this.velocityEma,1-fA(this.velocityEma/this.t.MOTION_VELOCITY_IOD_PER_S)}guidanceOf(A,t,i){if(A.presence<=0)return"fcv3.no_face";if(A.size<this.t.GUIDE_SIZE)return this.sizeGuidance();if(A.centering<this.t.GUIDE_CENTERING)return"fcv3.center_face";if(A.pose<this.t.GUIDE_POSE)return"fcv3.straighten";if(A.exposure<this.t.GUIDE_EXPOSURE)return this.exposureGuidance(t);if(A.sharpness<this.t.GUIDE_SHARPNESS)return"fcv3.steady_camera";if(A.motion<this.t.GUIDE_MOTION)return"fcv3.hold_still";if(i<this.t.Q_GOOD){let n=[["size",this.sizeGuidance()],["centering","fcv3.center_face"],["pose","fcv3.straighten"],["exposure",this.exposureGuidance(t)],["sharpness","fcv3.steady_camera"],["motion","fcv3.hold_still"]],o=n[0];for(let r of n)A[r[0]]<A[o[0]]&&(o=r);return o[1]}return"fcv3.hold_still"}sizeGuidance(){return this.lastSizeDirection==="far"?"fcv3.come_closer":"fcv3.move_back"}exposureGuidance(A){let t=(nA[0]+nA[1])/2;return A.meanLuma<t?"fcv3.more_light":"fcv3.too_bright"}};mA();var $e=4,kn=600,ui={sharpness:1,exposure:1,meanLuma:128},Be=class{constructor(A){this.handlers=new Map;this.stateValue="idle";this.attempt=0;this.stream=null;this.detector=null;this.scheduler=null;this.gate=null;this.profiler=null;this.lastGuidanceKey=null;this.positioningStartedAt=0;this.cameraRequestedAt=null;this.cameraReadyAt=null;this.faceAcquiredAt=null;this.captureCompleteAt=null;this.fired=!1;this.carriedDegrade=0;this.carriedMeans=[];this.snapshotCanvas=null;this.options=A,this.facing=A.facingMode??"user"}get state(){return this.stateValue}on(A,t){let i=this.handlers.get(A);return i||(i=new Set,this.handlers.set(A,i)),i.add(t),()=>i?.delete(t)}emit(A,t){for(let i of[...this.handlers.get(A)??[]])i(t)}async start(A={}){A.facingMode!==void 0&&(this.facing=A.facingMode),this.attempt+=1,await this.run(this.attempt)}get facingMode(){return this.facing}retry(){this.teardownAttempt(),this.start()}switchCamera(){this.facing=this.facing==="user"?"environment":"user",this.teardownAttempt(),this.start()}destroy(){this.attempt+=1,this.teardownAttempt(),this.detector?.destroy(),this.detector=null,this.options.video.srcObject=null}async run(A){let{options:t}=this;this.fired=!1,this.lastGuidanceKey=null,this.carriedDegrade=0,this.carriedMeans=[],this.cameraRequestedAt=null,this.cameraReadyAt=null,this.faceAcquiredAt=null,this.captureCompleteAt=null,this.setState("preflight");let i=Tt();if(i!=="OK"){this.fail(i==="INSECURE_CONTEXT"?"insecure":"unsupported");return}this.setState("acquiring");let n=t.getUserMedia??(a=>navigator.mediaDevices.getUserMedia(a)),o;this.cameraRequestedAt=this.now();try{o=await n(ni(lA(),this.facing))}catch(a){if(A!==this.attempt)return;this.fail(te(a));return}if(ee(o),A!==this.attempt){for(let a of o.getTracks())a.stop();return}if(this.stream=o,t.video.srcObject=o,await t.video.play().catch(()=>{}),A!==this.attempt)return;if(this.cameraReadyAt=this.now(),this.detector===null){let a={...t.v3AssetBaseUrl!==void 0?{v3AssetBaseUrl:t.v3AssetBaseUrl}:{}},c=t.createDetector??(t.createWorker!==void 0&&li()?async()=>{try{return await de.create(t.createWorker(),a)}catch{return oA(a)}}:()=>oA(a)),g;try{g=await c()}catch(l){A===this.attempt&&this.fail("models",l instanceof HA?l.fallbackReason:xn(l));return}if(A!==this.attempt){g.destroy();return}this.detector=g,this.options.telemetry?.({type:"detector",tier:g.tier,...g.fallbackReason!==void 0?{fallbackReason:g.fallbackReason}:{}})}let r=oe(),s=t.deviceClass??re(r);this.profiler=new ne(s),this.options.telemetry?.({type:"profile",staticClass:s,activeClass:this.profiler.deviceClass,simd:r.simd}),this.gate=new Ee(t.thresholds??{}),this.setState("positioning"),this.positioningStartedAt=this.now(),this.startScheduler(A)}get animations(){return this.profiler?.profile.animations??"full"}startScheduler(A){let t=this.profiler;if(t===null)return;if(this.scheduler!==null){let n=this.scheduler.stats();this.carriedDegrade+=n.degradeCount,n.meanDetectMs>0&&this.carriedMeans.push(n.meanDetectMs),this.scheduler.stop()}let i=new Ce({cadenceHz:t.profile.cadenceHz,video:this.options.video,...this.options.now!==void 0?{now:this.options.now}:{},run:()=>this.detectTick(A)});this.scheduler=i,i.start()}async detectTick(A){let{detector:t,gate:i,profiler:n}=this,o=this.options.video;if(A!==this.attempt||t===null||i===null||n===null||this.fired||o.videoWidth===0)return;let r=n.deviceClass,s=this.now(),a=this.options.makeSnapshot?.(o,n.profile.inputWidth)??this.defaultSnapshot(o,n.profile.inputWidth),c=null;try{c=await t.detect(a,o.videoWidth,o.videoHeight)}catch{c=null}if(A!==this.attempt||this.fired)return;n.record(this.now()-s),n.deviceClass!==r&&this.startScheduler(A);let g=c===null?ui:this.options.measureQuality?.(o,c.box)??this.defaultQuality(o,c.box),l=i.tick({timestampMs:this.now(),observation:c,quality:g,frameWidth:o.videoWidth,frameHeight:o.videoHeight});l.accepted&&this.faceAcquiredAt===null&&(this.faceAcquiredAt=l.at),this.emit("checks",{engine:"v3",progress:l.p,q:l.q,factors:l.factors,attempt:A}),l.guidanceKey!==this.lastGuidanceKey&&(this.lastGuidanceKey=l.guidanceKey,this.emit("guidance",{key:l.guidanceKey})),l.ready&&this.stateValue==="positioning"&&(this.fired=!0,this.captureCompleteAt=l.at,this.fire(A))}async fire(A){let{options:t}=this,i=this.scheduler;i?.stop();let n=i?.stats()??{degradeCount:0,meanDetectMs:0},o=[...this.carriedMeans,...n.meanDetectMs>0?[n.meanDetectMs]:[]];t.telemetry?.({type:"fired",timeToGateMs:this.now()-this.positioningStartedAt,degradeCount:this.carriedDegrade+n.degradeCount,meanDetectMs:o.length===0?0:o.reduce((u,E)=>u+E,0)/o.length});let r=t.mode??"clip",s=this.collectKeyframes(A);if(r==="photo"){let u=await s;if(A!==this.attempt)return;if(u===null){this.fail("generic");return}this.finishCapture({keyframe:u.blob,previewDataUrl:u.previewDataUrl});return}this.setState("recording");let a=t.createRecorder?.()??new ce,c=this.stream;if(c===null){this.fail("generic");return}let g=null;s.then(u=>{g=u},()=>{});let l=()=>{A===this.attempt&&g!==null&&this.emit("frozen",{previewDataUrl:g.previewDataUrl})},d,C;try{[d,C]=await Promise.all([a.record(c,l),s])}catch(u){if(A!==this.attempt)return;let E=u.kind;this.fail(E==="cliptoolarge"?"cliptoolarge":"recorder");return}if(A===this.attempt){if(ie(d.blob)){this.fail("cliptoolarge");return}if(C===null){this.fail("generic");return}this.finishCapture({clip:d.blob,clipMimeType:d.mimeType,keyframe:C.blob,previewDataUrl:C.previewDataUrl})}}async collectKeyframes(A){let t=this.options.captureKeyframe??(o=>this.defaultKeyframe(o)),i=kn/($e-1),n=null;for(let o=0;o<$e;o+=1){if(A!==this.attempt)return n;try{let r=await t(this.options.video);(n===null||r.sharpness>n.sharpness)&&(n=r)}catch{}o<$e-1&&await Mn(i)}return n}finishCapture(A){this.stopTracks(),this.setState("captured");let t=this.captureTiming();this.emit("artifacts",t===void 0?A:{...A,timing:t})}captureTiming(){let A=(r,s)=>r!==null&&s!==null?Math.max(0,Math.round(s-r)):void 0,t=A(this.cameraRequestedAt,this.cameraReadyAt),i=A(this.cameraReadyAt,this.faceAcquiredAt),n=A(this.faceAcquiredAt,this.captureCompleteAt),o={...t!==void 0?{cameraReadyMs:t}:{},...i!==void 0?{faceAcquireMs:i}:{},...n!==void 0?{captureMs:n}:{}};return Object.keys(o).length>0?o:void 0}async defaultKeyframe(A){let t=document.createElement("canvas"),i=await ci(A,t),n=t.toDataURL("image/jpeg",.92);return{blob:i,previewDataUrl:n,sharpness:this.centerSharpness(A)}}defaultSnapshot(A,t){try{let i=this.snapshotCanvas??document.createElement("canvas"),n=t/Math.max(1,A.videoWidth),o=Math.max(1,Math.round(A.videoWidth*n)),r=Math.max(1,Math.round(A.videoHeight*n)),s=i.getContext("2d");return s===null?A:(i.width!==o&&(i.width=o),i.height!==r&&(i.height=r),s.drawImage(A,0,0,o,r),this.snapshotCanvas=i,i)}catch{return A}}defaultQuality(A,t){let i=di(A,t,96);return i===null?ui:{sharpness:QA(i),exposure:zA(i),meanLuma:DA(i)}}centerSharpness(A){let t=_A(A),i=di(A,{x:t.width*.25,y:t.height*.25,width:t.width*.5,height:t.height*.5},96);return i===null?0:QA(i)}teardownAttempt(){this.scheduler?.stop(),this.scheduler=null,this.gate=null,this.stopTracks()}stopTracks(){if(this.stream!==null){for(let A of this.stream.getTracks())A.stop();this.stream=null}}fail(A,t){this.scheduler?.stop(),this.stopTracks(),this.setState("error"),this.options.telemetry?.({type:"error",kind:A,...t!==void 0?{fallbackReason:t}:{}}),this.emit("error",{kind:A,retryable:A!=="insecure"&&A!=="unsupported"})}setState(A){this.stateValue=A,this.emit("statechange",{state:A})}now(){return this.options.now?.()??performance.now()}};function Mn(e){return new Promise(A=>setTimeout(A,e))}function xn(e){return e instanceof Error?e.message:String(e)}function di(e,A,t){try{let i=document.createElement("canvas"),n=t/Math.max(1,A.width);i.width=Math.max(1,Math.round(A.width*n)),i.height=Math.max(1,Math.round(A.height*n));let o=i.getContext("2d");return o===null?null:(o.drawImage(e,A.x,A.y,A.width,A.height,0,0,i.width,i.height),o.getImageData(0,0,i.width,i.height))}catch{return null}}function he(){let e=new Map;return{on(A,t){let i=e.get(A);i===void 0&&(i=new Set,e.set(A,i));let n=t;return i.add(n),()=>{i?.delete(n)}},emit(A,t){let i=e.get(A);if(i!==void 0)for(let n of[...i])n(t)},clear(){e.clear()}}}var tt=12e4,me=13e4;var Qe=Symbol.for("@sekyro/web.preload.v1");function et(){let e=globalThis;return e[Qe]??(e[Qe]=new Map),e[Qe]}function Nn(e){let A=(e??je).replace(/\/+$/,"");return A===""?"/":A}function At(e,A){if(e.status!==A){e.status=A;for(let t of[...e.listeners])t(A)}}var it=e=>oA({preferred:["blaze"],v3AssetBaseUrl:e,blazeInitTimeoutMs:tt}),nt=it;function Ci(e){nt=e??it}function Ei(){for(let e of et().values())e.detector?.destroy();et().clear(),nt=it}function Fn(e,A){if((e.status==="loading"||e.status==="ready")&&e.promise!==null)return e.promise;At(e,"loading");let t=new Promise(s=>s(nt(A)));e.detectorPromise=t;let i,n=new Promise((s,a)=>{i=setTimeout(()=>{t.then(c=>c.destroy(),()=>{}),a(new Error(`detector preload exceeded ${me} ms`))},me)}),r=Promise.race([t,n]).then(s=>e.detectorPromise!==t?(s.destroy(),e.status):(e.detector=s,At(e,"ready"),"ready"),s=>(e.detectorPromise===t&&(e.detectorPromise=null,e.detector=null,At(e,"failed"),console.warn("[@sekyro/web] face-detector preload failed:",s)),e.status)).finally(()=>clearTimeout(i));return e.promise=r,e.scheduled?.settle(r),r}function Ln(e){return{get tier(){return e.tier},get fallbackReason(){return e.fallbackReason},detect:(...A)=>e.detect(...A),destroy:()=>{}}}function fe(e){let A=Nn(e),t=et().get(A);if(!(t===void 0||t.detector===null&&t.detectorPromise===null&&t.scheduled===null))return async()=>{t.scheduled!==null&&Fn(t,A);let i=t.promise;for(;t.detector===null&&i!==null&&(await i,t.promise!==i);)i=t.promise;return t.detector!==null?Ln(t.detector):oA({v3AssetBaseUrl:A})}}function Bi(){if(typeof navigator>"u"||!("wakeLock"in navigator))return null;let e=navigator.wakeLock;return typeof e?.request=="function"?e:null}function hi(){return typeof document>"u"||document.visibilityState==="visible"}function Qi(e){try{e.release().catch(()=>{})}catch{}}function mi(e={}){if(e.enabled===!1)return{setActive:()=>{}};let A=!1,t=null,i=!1,n=!1,o=()=>{if(!A||i||t!==null&&!t.released)return;let a=Bi();if(a===null||!hi())return;let c;try{c=a.request("screen")}catch{return}i=!0,c.then(g=>{if(i=!1,!A){Qi(g);return}t=g,g.addEventListener?.("release",()=>{t===g&&(t=null)})},()=>{i=!1})},r=()=>{hi()&&o()},s=a=>{typeof document>"u"||a===n||(n=a,a?document.addEventListener("visibilitychange",r):document.removeEventListener("visibilitychange",r))};return{setActive:a=>{if(A=a,a){if(Bi()===null)return;s(!0),o();return}if(s(!1),t!==null){let c=t;t=null,Qi(c)}}}}function ot(e){switch(e){case"fcv3.no_face":case"fcv3.center_face":case"fcv3.straighten":return"center";case"fcv3.come_closer":return"closer";case"fcv3.move_back":return"farther";case"fcv3.more_light":case"fcv3.too_bright":return"light";case"fcv3.hold_still":case"fcv3.steady_camera":return"still";default:return null}}function rt(e){switch(e){case"preflight":case"acquiring":return"starting";case"positioning":return"gating";case"idle":case"recording":case"captured":case"error":return e;default:{let A=e;throw new Error(`mapEngineState: unhandled state ${A}`)}}}function st(e){switch(e){case"permission":case"notfound":case"inuse":case"insecure":case"unsupported":return e;case"overconstrained":case"generic":case"models":case"cliptoolarge":case"recorder":return"generic";default:{let A=e;throw new Error(`mapErrorKind: unhandled kind ${A}`)}}}function pe(e,A={}){let t=A.now??(()=>performance.now()),i=he(),n=!Gt(),o=A.engineOptions,r=o?.createDetector===void 0&&o?.createWorker===void 0?{createDetector:()=>{let h=fe(e.assetBaseUrl);return h!==void 0?h():oA(e.assetBaseUrl!==void 0?{v3AssetBaseUrl:e.assetBaseUrl}:{})}}:{},s={video:e.video,mode:n?"photo":"clip",...e.facing!==void 0?{facingMode:e.facing}:{},...e.assetBaseUrl!==void 0?{v3AssetBaseUrl:e.assetBaseUrl}:{},...A.engineOptions??{},...r},a=A.createEngine?.(s)??new Be(s),c="idle",g=null,l=0,d=!1,C="full",u=null,E=null,p=0,I=0,Q=()=>{e.video.videoWidth>0&&e.video.videoHeight>0&&(p=e.video.videoWidth,I=e.video.videoHeight)},D=mi({enabled:e.keepScreenAwake!==!1}),w=h=>{c=h,D.setActive(h==="starting"||h==="gating"||h==="recording"),i.emit("state",h)},R=()=>i.emit("gate",{progress:l,hint:g,faceDetected:d}),m=()=>{let h=a.animations??"full";h!==C&&(C=h,i.emit("profile",{animations:C}))},f=[a.on("statechange",({state:h})=>{let P=rt(h);P==="starting"&&c!=="starting"&&(g=null,l=0,d=!1,u=null,E=null,p=0,I=0),w(P),m(),P==="recording"&&(Q(),u=t(),g="hold",l=1,R())}),a.on("checks",h=>{Q(),l=h.progress,d=h.factors.presence>0,R(),m()}),a.on("guidance",({key:h})=>{g=ot(h),R()}),a.on("frozen",({previewDataUrl:h})=>{E=t(),i.emit("frozen",{previewDataUrl:h})}),a.on("artifacts",h=>{let P=u!==null&&E!==null?Math.max(0,Math.round(E-u)):void 0;i.emit("captured",{keyframe:h.keyframe,...h.clip!==void 0?{clip:h.clip}:{},...h.clipMimeType!==void 0?{clipMime:h.clipMimeType}:{},width:e.video.videoWidth||p,height:e.video.videoHeight||I,...P!==void 0?{clipMs:P}:{},captureChannel:lA()?"mobile":"desktop",...n?{degraded:"NO_RECORDER"}:{},engine:"v3",...h.timing?.cameraReadyMs!==void 0?{cameraReadyMs:h.timing.cameraReadyMs}:{},...h.timing?.faceAcquireMs!==void 0?{faceAcquireMs:h.timing.faceAcquireMs}:{},...h.timing?.captureMs!==void 0?{captureMs:h.timing.captureMs}:{}})}),a.on("error",({kind:h,retryable:P})=>{i.emit("error",{kind:st(h),retryable:P})})];return{handle:{get state(){return c},on:(h,P)=>i.on(h,P),start:h=>a.start(h?.facing!==void 0?{facingMode:h.facing}:{}),retry:()=>a.retry(),switchCamera:()=>a.switchCamera(),destroy:()=>{for(let h of f)h();D.setActive(!1),a.destroy(),i.clear()}},setFlowState:h=>{c!==h&&w(h)}}}var eA=class extends Error{constructor(A){super(A.message),this.name="HostedApiError",this.status=A.status,this.code=A.code,A.retryAfterSeconds!==void 0&&(this.retryAfterSeconds=A.retryAfterSeconds)}};var Tn=3e4,Gn=9e5,_n=200,Hn=5,Un=400;function UA(e){return(e.split(";")[0]??"").trim()}var Jn={liveness:"clipKey",face_match:"imageKey",doc_ocr:"imageKey"},ye=class{constructor(A){this.sessionId=null;this.bootstrap=null;this.apiOrigin=A.apiOrigin.replace(/\/+$/,""),this.sessionToken=A.sessionToken;let t=A.fetch;this.fetchImpl=(i,n)=>(t??globalThis.fetch).call(globalThis,i,n),this.requestTimeoutMs=A.requestTimeoutMs??Tn,this.retryAttempts=A.inProgressRetry?.attempts??Hn,this.retryDelayMs=A.inProgressRetry?.delayMs??Un}async getSession(){let A=await this.api("GET","/hosted/session");return this.sessionId=A.sessionId,A}async recordConsent(A){return this.api("POST","/hosted/consent",{body:{locale:A}})}async selectMethod(A){let t=await this.api("POST","/hosted/method",{body:{method:A}});return this.sessionId=t.sessionId,t}async presign(A,t,i){let n=await this.ensureSessionId(),o={kind:A,contentType:UA(t),contentLength:i};return this.api("POST",`/sessions/${n}/media`,{body:o})}async uploadToSpaces(A,t,i){let n;try{n=await this.fetchImpl(A,{method:"PUT",headers:{"content-type":UA(i)},body:t,signal:AbortSignal.timeout(Gn)})}catch(o){throw fi(o)}if(!n.ok){let o=(await n.text().catch(()=>"")).slice(0,_n);throw new eA({status:n.status,code:"upload_failed",message:`media upload failed (HTTP ${n.status})${o?`: ${o}`:""}`})}}async completeMedia(A){let t=await this.ensureSessionId();return this.api("POST",`/sessions/${t}/media/complete`,{body:{key:A}})}async submitCheck(A,t,i={}){let n=await this.ensureSessionId(),o={input:t,...i.forceOutcome!==void 0?{forceOutcome:i.forceOutcome}:{}};return this.api("POST",`/sessions/${n}/checks/${A}`,{body:o,...i.idempotencyKey!==void 0?{idempotencyKey:i.idempotencyKey}:{}})}async uploadAndSubmit(A,t,i,n={}){let o=UA(t.contentType),r=await this.presign(t.kind,o,t.blob.size);await this.uploadToSpaces(r.uploadUrl,t.blob,o);let s=await this.completeMedia(r.key),a={...i,[Jn[A]]:s.key};return this.submitCheck(A,a,n)}async ensureSessionId(){return this.sessionId!==null?this.sessionId:(this.bootstrap??(this.bootstrap=this.getSession().finally(()=>{this.bootstrap=null})),(await this.bootstrap).sessionId)}async api(A,t,i={}){let n=`${this.apiOrigin}/api/v2${t}`,o={"x-session-token":this.sessionToken};i.body!==void 0&&(o["content-type"]="application/json"),i.idempotencyKey!==void 0&&(o["x-idempotency-key"]=i.idempotencyKey);try{let r=Ae.timezone();r!==void 0&&(o["sekyro-client-timezone"]=r)}catch{}try{let r=await Ae.deviceHeader();r!==void 0&&(o["sekyro-client-device"]=r)}catch{}for(let r=0;;r++){let s;try{s=await this.fetchImpl(n,{method:A,headers:o,...i.body!==void 0?{body:JSON.stringify(i.body)}:{},signal:AbortSignal.timeout(this.requestTimeoutMs)})}catch(c){throw fi(c)}if(s.ok){let c;try{c=await s.json()}catch{throw new eA({status:s.status,code:"unknown_error",message:`response body was not valid JSON (HTTP ${s.status})`})}return Pn(c)}let a=await Yn(s);if(a.code==="idempotency_in_progress"&&r<this.retryAttempts){this.retryDelayMs>0&&await On(this.retryDelayMs);continue}throw a}}};function fi(e){if((typeof e=="object"&&e!==null?e.name:void 0)==="TimeoutError")return new eA({status:0,code:"timeout",message:"request timed out"});let t=e instanceof Error?e.message:String(e);return new eA({status:0,code:"network_error",message:`network request failed: ${t}`})}function Pn(e){return e!==null&&typeof e=="object"&&"success"in e&&"data"in e?e.data:e}async function Yn(e){let A="unknown_error",t=`request failed (HTTP ${e.status})`,i=Number.NaN;try{let r=await e.json();if(r!==null&&typeof r=="object"){let s=r;typeof s.code=="string"&&s.code.length>0&&(A=s.code),typeof s.message=="string"&&s.message.length>0&&(t=s.message),typeof s.retryAfterSeconds=="number"&&(i=s.retryAfterSeconds)}}catch{}let n=e.headers.get("retry-after"),o=n===null?Math.floor(i):Number.parseInt(n,10);return new eA({status:e.status,code:A,message:t,...Number.isFinite(o)&&o>=0?{retryAfterSeconds:o}:{}})}function On(e){return new Promise(A=>setTimeout(A,e))}var at=new Set(["no_face","media_unreadable","clip_too_short","no_face_source","side_missing","unreadable","registry_unavailable","otp_mismatch","otp_expired","otp_send_failed","document_type_not_accepted","age_unverifiable","liveness_inconclusive","match_inconclusive","document_authenticity"]);function YA(e){let A=e.methodChoice;return A===void 0||!A.available||A.selected!==null||rA(e)?.checkType==="phone_otp"?null:A}var qn=new Set(["liveness","face_match"]);function EA(e){return e!==void 0&&(e.state==="pending"||e.state==="input_required")}function tA(e){return e.status!=="created"&&e.status!=="in_progress"}function rA(e){return e.steps.find(A=>EA(A))}function iA(e,A){return e.steps.find(t=>t.checkType===A)}function ct(e,A){let t=A.steps.find(n=>n.checkType==="liveness"),i=A.steps.find(n=>n.checkType==="face_match");return iA(e,"face_match")?.state==="pending"&&(t?.state==="passed"||t?.state==="review")&&i!==void 0&&i.state!=="pending"&&i.state!=="skipped"}function we(e,A,t){let i=new Map(e.steps.map(r=>[r.checkType,r])),n=t==="liveness"&&ct(e,A),o=A.steps.map(r=>{let s=i.get(r.checkType),a=s?.attemptsRemaining??0,c={...s??{},checkType:r.checkType,state:r.state,attemptsRemaining:r.checkType===t||r.checkType==="face_match"&&n?Math.max(0,a-1):a};return r.reason!==void 0?c.reason=r.reason:delete c.reason,r.attemptsExhausted!==void 0?c.attemptsExhausted=r.attemptsExhausted:delete c.attemptsExhausted,c});return{...e,status:A.status,outcome:A.outcome,failureReason:A.failureReason,steps:o,expiresAt:A.expiresAt}}function cA(e,A){return A===void 0?{sessionId:e,status:"unavailable"}:{sessionId:e,status:"unavailable",reason:A}}function JA(e,A,t){return t===void 0?{sessionId:e,status:A}:{sessionId:e,status:A,reason:t}}function OA(e,A){let{sessionId:t}=e;switch(e.status){case"completed":return e.outcome==="approved"?{sessionId:t,status:"approved"}:e.outcome==="review"?JA(t,"review",PA(e,"review")):JA(t,"rejected",PA(e,"failed"));case"failed":{let n=JA(t,"rejected",e.failureReason??PA(e,"failed"));return e.failureReason==="device_cooldown"&&e.retryAfter!==void 0&&(n.retryAfter=e.retryAfter),n}case"review_pending":return JA(t,"review",PA(e,"review"));case"expired":return cA(t);case"created":case"in_progress":break;default:{let n=e.status;throw new Error(`mapSessionResult: unhandled status ${n}`)}}let i=e.steps.find(n=>qn.has(n.checkType)&&n.state==="input_required"&&n.reason!==void 0);if(i?.reason==="mobile_required")return cA(t,"mobile_required");if(i?.reason!==void 0){let n=A.autoRetry&&at.has(i.reason)&&i.attemptsRemaining>0;return{sessionId:t,status:n?"retry":"rejected",reason:i.reason,attemptsRemaining:i.attemptsRemaining}}return rA(e)===void 0&&e.steps.some(n=>n.state==="review")?JA(t,"review",PA(e,"review")):cA(t)}function PA(e,A){return e.steps.find(t=>t.state===A&&t.reason!==void 0)?.reason}var gt=["video/webm","video/mp4"],pi="image/jpeg",It=2,lt=1e3,Kn=1e4,ut=3,dt=10,Vn=30,Wn=3,Xn=new Set(["network_error","timeout","upload_failed","unknown_error","rate_limit_exceeded"]),zn=new Set(["session_not_active","check_not_found","check_already_finalized","check_out_of_order"]),qA=class extends Error{constructor(){super("verification destroyed"),this.name="FlowCancelledError"}};function Zn(e){let A=e.steps.findIndex(i=>i.checkType==="liveness");return A<0?!1:e.steps.slice(A+1).find(i=>EA(i))?.checkType==="face_match"}var BA=class extends Error{constructor(A){super(A),this.name="AttestationError"}};async function pA(e,A,t={}){let i=e.uuid(),n=!1,o=!1,r=0,s=0;for(;;)try{return await A(e.client,i)}catch(a){if(a instanceof BA){if(o)throw a;o=!0,t.onAttestationInvalid?.(),i=e.uuid();continue}if(!(a instanceof eA))throw a;if(a.code==="consent_required"&&!n){n=!0,await e.ensureConsent({force:!0}),i=e.uuid();continue}if(a.code==="attestation_invalid"&&!o){o=!0,t.onAttestationInvalid?.(),i=e.uuid();continue}if(a.code==="inference_unavailable"&&s<ut){s+=1;let c=Math.min(a.retryAfterSeconds??dt,Vn);e.onBusy?.({attempt:s,retryAfterSeconds:c}),await e.sleep(c*1e3),t.onAttestationInvalid?.(),i=e.uuid();continue}if(Xn.has(a.code)&&r<It){r+=1;let c=a.retryAfterSeconds!==void 0?a.retryAfterSeconds*1e3:void 0;await e.sleep(c!==void 0?Math.min(c,Kn):lt);continue}throw a}}var jn=new Set(["passed","review","processing","skipped"]);async function De(e){let{artifacts:A}=e,t=A.clip,i=UA(A.clipMime??"");if(A.degraded==="NO_RECORDER"||t===void 0||!gt.includes(i))return{kind:"unavailable",reason:"no_recorder"};let n=$n(e,A.keyframe),o=Ao(e,t,i,n),r=eo(e,n),s=!1,a=!1,c=!0,g=0;for(;;){if(e.isCancelled())return{kind:"cancelled"};let l=e.getView();if(tA(l))return{kind:"settled"};let d=rA(l)?.checkType,C=d==="liveness"&&!s?"liveness":d==="face_match"&&!a&&c?"face_match":null;if(C===null)return{kind:"settled"};if(C==="liveness"&&A.captureChannel==="desktop"&&iA(l,"liveness")?.requiresMobile===!0)return{kind:"unavailable",reason:"mobile_required"};try{if(C==="liveness"){s=!0;let u=await o();if(e.isCancelled())return{kind:"cancelled"};a=ct(l,u),e.applySubmit(u,"liveness");let E=iA(e.getView(),"liveness")?.state;c=E===void 0||jn.has(E)}else{a=!0;let u=await r();if(e.isCancelled())return{kind:"cancelled"};e.applySubmit(u,"face_match")}}catch(u){if(e.isCancelled()||u instanceof qA)return{kind:"cancelled"};let E=io(u);if(E.kind!=="resync"||g>=Wn)return E;g+=1,await e.refreshView()}}}function $n(e,A){let t=null,i=null,n=()=>t!==null?Promise.resolve(t):(i??(i=(async()=>{let o=await e.client.presign("image",pi,A.size);return await e.client.uploadToSpaces(o.uploadUrl,A,pi),t=(await e.client.completeMedia(o.key)).key,t})().finally(()=>{i=null})),i);return{ensure:n,attempt:()=>n().catch(()=>null),current:()=>t}}function Ao(e,A,t,i){let n=null,o,r=null;return()=>pA(e,async(s,a)=>{if(n===null||o===void 0){if(e.isCancelled())throw new qA;o===void 0&&!Zn(e.getView())&&(o=null),e.onPhase("uploading");let[c,g]=await Promise.all([n!==null?Promise.resolve(n):(async()=>{let l=await s.presign("clip",t,A.size);return await s.uploadToSpaces(l.uploadUrl,A,t),(await s.completeMedia(l.key)).key})(),o!==void 0?Promise.resolve(o===null?null:o.imageKey):i.attempt()]);n=c,o===void 0&&(o=g===null?null:{imageKey:g})}if(r===null)try{r=await e.getAttestation()}catch(c){throw new BA(c instanceof Error?c.message:String(c))}return e.onPhase("checking"),s.submitCheck("liveness",{clipKey:n,attestation:r,captureChannel:e.artifacts.captureChannel,capture:to(e.artifacts),...o!==null?{faceMatch:o}:{}},{idempotencyKey:a})},{onAttestationInvalid:()=>{r=null}})}function eo(e,A){return()=>pA(e,async(t,i)=>{if(A.current()===null){if(e.isCancelled())throw new qA;e.onPhase("uploading")}let n=await A.ensure();return e.onPhase("checking"),t.submitCheck("face_match",{imageKey:n},{idempotencyKey:i})})}function to(e){return{...e.engine!==void 0?{engine:e.engine}:{},width:e.width,height:e.height,...e.clipMs!==void 0?{clipMs:e.clipMs}:{},...e.cameraReadyMs!==void 0?{cameraReadyMs:e.cameraReadyMs}:{},...e.faceAcquireMs!==void 0?{faceAcquireMs:e.faceAcquireMs}:{},...e.captureMs!==void 0?{captureMs:e.captureMs}:{}}}function io(e){if(e instanceof BA)return{kind:"unavailable",reason:"attestation"};if(e instanceof eA){if(e.code==="attestation_invalid")return{kind:"unavailable",reason:"attestation"};if(e.code==="method_required")return{kind:"unavailable",reason:"method_required"};if(e.code==="inference_unavailable")return{kind:"unavailable",reason:"inference_unavailable"};if(e.code==="mobile_required")return{kind:"unavailable",reason:"mobile_required"};if(zn.has(e.code))return{kind:"resync"}}return{kind:"unavailable",reason:"network"}}var Et="https://challenges.cloudflare.com/turnstile/v0/api.js",wi=3e4;function yi(){return window.turnstile}var KA=null;function Di(){KA=null}function Bt(){return KA??(KA=new Promise((e,A)=>{let t=yi();if(t){e(t);return}let i=document.createElement("script");i.src=Et,i.async=!0,i.onload=()=>{let n=yi();n?e(n):(KA=null,A(new Error("Turnstile script loaded but exposed no API")))},i.onerror=()=>{KA=null,i.remove(),A(new Error("Turnstile script failed to load"))},document.head.appendChild(i)})),KA}function Ct(){return new Error("Turnstile challenge aborted")}async function be(e,A={}){let t=A.timeoutMs??3e4,i=A.signal;if(i?.aborted)throw Ct();let n=await Bt();if(i?.aborted)throw Ct();let o=document.createElement("div");document.body.appendChild(o);let r,s,a;try{return await new Promise((c,g)=>{if(s=setTimeout(()=>g(new Error(`Turnstile challenge timed out (${t} ms)`)),t),i!==void 0&&(a=()=>g(Ct()),i.addEventListener("abort",a,{once:!0})),r=n.render(o,{sitekey:e,execution:"execute",appearance:"execute",callback:c,"error-callback":l=>{g(new Error(`Turnstile challenge failed${l?` (${l})`:""}`))}}),r===void 0){g(new Error("Turnstile render returned no widget id"));return}n.execute(r)})}finally{if(clearTimeout(s),i!==void 0&&a!==void 0&&i.removeEventListener("abort",a),r!==void 0)try{n.remove(r)}catch{}o.remove()}}var no="https://api.sekyro.ai",ht=5e3,Qt=1500,mt=10;function oo(e){return new Promise(A=>setTimeout(A,e))}function ft(){let e=globalThis.crypto;if(e!==void 0&&typeof e.randomUUID=="function")return e.randomUUID();let A=new Uint8Array(16);if(e!==void 0&&typeof e.getRandomValues=="function")e.getRandomValues(A);else for(let i=0;i<16;i+=1)A[i]=Math.floor(Math.random()*256);A[6]=(A[6]??0)&15|64,A[8]=(A[8]??0)&63|128;let t=[...A].map(i=>i.toString(16).padStart(2,"0")).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}function bi(e,A){let t=e.apiOrigin??no,i=e.autoRetry??!0,n=e.rearm??"auto",o=A.client??new ye({apiOrigin:t,sessionToken:e.clientToken,...e.fetch!==void 0?{fetch:e.fetch}:{}}),r=A.sleep??oo,s=A.uuid??ft,a=A.getTurnstileToken??be,c=he(),g=!1,l=new AbortController,d=null,C=null,u=B=>{d=B,c.emit("view",B)},E=()=>d!==null?Promise.resolve(d):(C??(C=o.getSession().then(B=>(u(B),B)).finally(()=>{C=null})),C),p=async()=>{let B=await o.getSession();return u(B),B},I=(B,y)=>{d!==null&&u(we(d,B,y))},Q=null,D=async B=>{let y=await E();!B&&y.consentRecorded||(await o.recordConsent(e.locale),d!==null&&u({...d,consentRecorded:!0}))},w=B=>B?.force===!0?D(!0):(Q??(Q=D(!1).finally(()=>{Q=null})),Q),R={client:o,ensureConsent:B=>w(B),sleep:r,uuid:s,onBusy:B=>{g||c.emit("busy",B)}},m=!1,f=B=>{if(B.status==="approved"||B.status==="rejected"||B.status==="review"){if(m)return;m=!0}c.emit("result",B)},b=async B=>{let y=d;B&&(y=await p().catch(()=>d));let U=y===null?null:YA(y);return U!==null&&!g&&c.emit("method",U),U!==null},h=null,P=!1,O=!1,z=()=>pA(R,(B,y)=>B.submitCheck("population_registry",{},{idempotencyKey:y})),T=B=>B.nniBound===!0||iA(B,"population_registry")?.nniFromDocument===!0,S=async()=>{try{let B=await E();if(tA(B)||YA(B)!==null||rA(B)?.checkType!=="population_registry")return;if(!T(B)&&iA(B,"population_registry")?.nniFromDocument===void 0&&(B=await p()),!T(B)){O=!0;return}await w(),I(await z(),"population_registry");let y=d===null?void 0:iA(d,"population_registry");if(y?.state==="input_required"&&y.reason==="registry_unavailable"&&y.attemptsRemaining>0){if(await r(ht),g)return;I(await z(),"population_registry")}}catch(B){if(B instanceof eA&&B.code==="method_required"){await p().catch(()=>{});return}P=!0;return}d!==null&&tA(d)&&f(OA(d,{autoRetry:i}))},k=()=>(h??(h=S()),h),q=async()=>{let y=(await E()).turnstileSiteKey;return y===null?{sandbox:!0}:{channel:"hosted_web",siteKey:y,turnstileToken:await a(y,{signal:l.signal})}},J=null,G=Promise.resolve(),L=0,v=async()=>{let B=await E();for(let y=0;y<mt&&!g&&!tA(B)&&rA(B)===void 0&&B.steps.some(U=>U.state==="processing")&&(await r(Qt),!g);y+=1)B=await p();return B},M=async(B,y,U)=>{let{capture:Y}=B,K=()=>g,X=()=>B.alive&&B.attempt===U,Z=V=>{X()&&Y.setFlowState(V)},j=V=>{if(!K()&&(f(V),!!X())){if(V.status==="retry"&&n==="auto"){Y.handle.retry();return}Y.setFlowState("done")}};if(y.degraded==="NO_RECORDER"){let V=d?.sessionId??(await E().catch(()=>null))?.sessionId??"";j(cA(V,"no_recorder"));return}Z("uploading");try{if(await k(),K())return;let V=await E();if(!tA(V)&&YA(V)!==null){await b(!1),j(cA(V.sessionId,"method_required"));return}if(!tA(V)){if(rA(V)?.checkType==="population_registry"){j(cA(V.sessionId,O?"nni_unbound":P?"network":"registry_unavailable"));return}if(await w(),K())return;let $=await De({...R,artifacts:y,getAttestation:q,getView:()=>d??V,refreshView:p,applySubmit:I,onPhase:Z,isCancelled:K});if(K())return;if($.kind==="unavailable"){if($.reason==="method_required"&&await b(!0),K())return;j(cA(V.sessionId,$.reason));return}$.kind==="resync"&&await p(),V=await v()}j(OA(V,{autoRetry:i}))}catch{if(K())return;j(cA(d?.sessionId??"","network"))}},F=(B,y)=>{let U=B.attempt;L>0&&B.alive&&B.capture.setFlowState("uploading"),L+=1,G=G.then(()=>M(B,y,U)).finally(()=>{L-=1}).catch(()=>{})};return{consent:()=>w(),startRegistry:k,methodChoice:async()=>{if(g)return null;try{let B=await E();return g?null:YA(B)}catch{return null}},selectMethod:async B=>{let y=await o.selectMethod(B);g||u(y)},mobileRequired:async()=>{if(g)return!1;try{let B=await E();if(g||tA(B))return!1;let y=iA(B,"liveness");return EA(y)&&y?.requiresMobile===!0&&!lA()}catch{return!1}},liveness:B=>{J?.capture.handle.destroy(),J!==null&&(J.alive=!1);let y=pe(B,A.capture),U={capture:y,alive:!0,attempt:0};J=U,y.handle.on("state",K=>{K==="starting"&&(U.attempt+=1)}),y.handle.on("captured",K=>{Promise.resolve().then(()=>F(U,K))});let Y=y.handle;return{get state(){return Y.state},on:(K,X)=>Y.on(K,X),start:K=>Y.start(K),retry:()=>Y.retry(),switchCamera:()=>Y.switchCamera(),destroy:()=>{U.alive=!1,J===U&&(J=null),Y.destroy()}}},voiceClips:async()=>{if(g)return null;try{let B=await E();return g?null:B.voice??null}catch{return null}},on:(B,y)=>c.on(B,y),destroy:()=>{g=!0,l.abort(),J!==null&&(J.alive=!1,J.capture.handle.destroy(),J=null),c.clear()}}}0&&(module.exports={ASPECT_BANDS,AttestationError,CAPTURE_CANDIDATE_SPACING_MS,CAPTURE_EXTRA_CANDIDATES,CENTERED_FACTOR,CIRCLE_RADIUS_FACTOR,CLIP_MIME_ALLOWLIST,CaptureSessionDoc,DOC_ANALYSIS_DEFAULTS,DOC_CADENCE_HZ,DOC_DETECT_WIDTH,DOC_FEEDBACK_STATES,DOC_GATE_V1_DEFAULTS,DocFeedbackAggregator,DocGateV1,INFERENCE_RETRY_ATTEMPTS,INFERENCE_RETRY_DEFAULT_S,IN_CIRCLE_FACTOR,MRZ_BAND_DEFAULTS,MR_DOC_CATALOG,PRELOAD_BLAZE_INIT_TIMEOUT_MS,PRELOAD_BUDGET_MS,PROCESSING_POLL_DELAY_MS,PROCESSING_POLL_MAX,REGISTRY_RETRY_DELAY_MS,RETRYABLE_REASONS,TRANSPORT_REPLAY_ATTEMPTS,TRANSPORT_REPLAY_DELAY_MS,TURNSTILE_EXECUTE_TIMEOUT_MS,TURNSTILE_SCRIPT_SRC,analyzeDocFrame,aspectBand,createLivenessCaptureInternal,createVerificationInternal,detectIsMobile,detectMrzBand,executeTurnstile,feedbackVoteOf,frontierStep,isExecutable,isTerminalView,loadTurnstile,mapEngineState,mapErrorKind,mapGuidanceHint,mapSessionResult,mergeSessionView,preloadedDetectorFactory,quadAreaFrac,quadBounds,quadIou,quadTiltRatio,randomUuid,resetLivenessAssetsForTests,resetTurnstileForTests,runLivenessFlow,runSubmission,setPreloadLoaderForTests,specularFraction,stepOf,warmDocDetector});