idmission-web-sdk 2.3.124 → 2.3.126

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.
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('react-dom/client'), require('platform'), require('styled-components'), require('react-dom'), require('tus-js-client'), require('prop-types'), require('react-dom/server')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'react', 'react-dom/client', 'platform', 'styled-components', 'react-dom', 'tus-js-client', 'prop-types', 'react-dom/server'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Sdk2 = {}, global.React, global.ReactDOM, global.platform, global.styled, global.ReactDOM, global.tusJsClient, global.PropTypes, global.server));
5
- })(this, (function (exports, React, ReactDOM, platform, styled, reactDom, tusJsClient, require$$0, server) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('react-dom/client'), require('platform'), require('styled-components'), require('react-dom'), require('tus-js-client'), require('prop-types')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'react', 'react-dom/client', 'platform', 'styled-components', 'react-dom', 'tus-js-client', 'prop-types'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Sdk2 = {}, global.React, global.ReactDOM, global.platform, global.styled, global.ReactDOM, global.tusJsClient, global.PropTypes));
5
+ })(this, (function (exports, React, ReactDOM, platform, styled, reactDom, tusJsClient, require$$0) { 'use strict';
6
6
 
7
7
  function _interopNamespaceDefault(e) {
8
8
  var n = Object.create(null);
@@ -211,7 +211,7 @@
211
211
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
212
212
  };
213
213
 
214
- var webSdkVersion = '2.3.124';
214
+ var webSdkVersion = '2.3.126';
215
215
 
216
216
  function getPlatform() {
217
217
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -24283,6 +24283,9 @@
24283
24283
 
24284
24284
  var signatureRecorder = null;
24285
24285
  var signatureChunks = [];
24286
+ var ondataavailableInvocations = [];
24287
+ var ondataavailableStartTime;
24288
+ var lastCalculatedVideoChunkRate;
24286
24289
  var videoSignatureInitialState = {
24287
24290
  startRecording: function startRecording() {
24288
24291
  return null;
@@ -24307,6 +24310,10 @@
24307
24310
  signatureValid: false,
24308
24311
  supportsRequestVideoFrameCallback: undefined,
24309
24312
  supportsRoundRect: undefined,
24313
+ nullChunksReceived: 0,
24314
+ timesSignatureCleared: 0,
24315
+ finalChunkReceived: false,
24316
+ requestDataInterval: undefined,
24310
24317
  onSignatureVideoCaptured: function onSignatureVideoCaptured() {
24311
24318
  return null;
24312
24319
  }
@@ -24319,8 +24326,11 @@
24319
24326
  captureAudio = false;
24320
24327
  }
24321
24328
  if (!camera) throw new Error('Camera not found');
24322
- // set our flag and clear whatever we have recorded so far.
24329
+ // clear whatever we have recorded so far.
24323
24330
  signatureChunks = [];
24331
+ ondataavailableInvocations = [];
24332
+ ondataavailableStartTime = undefined;
24333
+ lastCalculatedVideoChunkRate = undefined;
24324
24334
  // start recording from the output canvas to capture the signature
24325
24335
  var outputStream = (_a = get().outputCanvas.current) === null || _a === void 0 ? void 0 : _a.captureStream(24);
24326
24336
  if (!outputStream) throw new Error('outputStream not found');
@@ -24338,77 +24348,123 @@
24338
24348
  recordingStartedAt: e.timeStamp
24339
24349
  });
24340
24350
  };
24341
- var hasFirstChunk = false;
24342
24351
  signatureRecorder.ondataavailable = function (event) {
24352
+ var now = performance.now();
24343
24353
  signatureChunks.push(event.data);
24344
- if (!hasFirstChunk) {
24345
- hasFirstChunk = true;
24346
- set({
24347
- firstChunkReceivedAt: performance.now(),
24348
- lastChunkReceivedAt: performance.now()
24354
+ trackVideoChunkRate(now);
24355
+ if (event.data.size > 0) {
24356
+ set(function (state) {
24357
+ var _a;
24358
+ return {
24359
+ firstChunkReceivedAt: (_a = state.firstChunkReceivedAt) !== null && _a !== void 0 ? _a : now,
24360
+ lastChunkReceivedAt: now
24361
+ };
24349
24362
  });
24350
24363
  } else {
24351
- set({
24352
- lastChunkReceivedAt: performance.now()
24364
+ set(function (state) {
24365
+ var _a;
24366
+ return {
24367
+ nullChunksReceived: state.nullChunksReceived + 1,
24368
+ firstNullChunkReceivedAt: (_a = state.firstNullChunkReceivedAt) !== null && _a !== void 0 ? _a : now,
24369
+ lastNullChunkReceivedAt: now
24370
+ };
24353
24371
  });
24354
24372
  }
24355
24373
  };
24356
- signatureRecorder.start(250);
24374
+ signatureRecorder.start();
24375
+ var interval = setInterval(function () {
24376
+ return signatureRecorder === null || signatureRecorder === void 0 ? void 0 : signatureRecorder.requestData();
24377
+ }, 250);
24357
24378
  set({
24379
+ requestDataInterval: interval,
24358
24380
  recordingStartRequestedAt: performance.now()
24359
24381
  });
24360
24382
  },
24361
24383
  stopRecording: function stopRecording(signatureData, imageUrl) {
24362
24384
  return __awaiter(this, void 0, void 0, function () {
24363
- var _this = this;
24364
- return __generator(this, function (_a) {
24365
- switch (_a.label) {
24385
+ function processVideo() {
24386
+ return __awaiter(this, void 0, void 0, function () {
24387
+ var recordingStoppedAt, mimeType, blob, _a, onSignatureVideoCaptured, recordingStartRequestedAt, recordingStartedAt, firstChunkReceivedAt, signatureStartedAt, signatureEndedAt, acceptClickedAt, clearClickedAt, recordingStopRequestedAt, lastChunkReceivedAt, supportsRequestVideoFrameCallback, supportsRoundRect, nullChunksReceived, firstNullChunkReceivedAt, lastNullChunkReceivedAt, timesSignatureCleared, metadata;
24388
+ return __generator(this, function (_b) {
24389
+ if (get().recordingStoppedAt) return [2 /*return*/];
24390
+ recordingStoppedAt = performance.now();
24391
+ set({
24392
+ recordingStoppedAt: recordingStoppedAt
24393
+ });
24394
+ mimeType = inferBlobType(signatureChunks[0]) || (signatureRecorder === null || signatureRecorder === void 0 ? void 0 : signatureRecorder.mimeType) || 'video/mp4';
24395
+ blob = new Blob(signatureChunks, {
24396
+ type: mimeType
24397
+ });
24398
+ signatureChunks = [];
24399
+ signatureRecorder = null;
24400
+ _a = get(), onSignatureVideoCaptured = _a.onSignatureVideoCaptured, recordingStartRequestedAt = _a.recordingStartRequestedAt, recordingStartedAt = _a.recordingStartedAt, firstChunkReceivedAt = _a.firstChunkReceivedAt, signatureStartedAt = _a.signatureStartedAt, signatureEndedAt = _a.signatureEndedAt, acceptClickedAt = _a.acceptClickedAt, clearClickedAt = _a.clearClickedAt, recordingStopRequestedAt = _a.recordingStopRequestedAt, lastChunkReceivedAt = _a.lastChunkReceivedAt, supportsRequestVideoFrameCallback = _a.supportsRequestVideoFrameCallback, supportsRoundRect = _a.supportsRoundRect, nullChunksReceived = _a.nullChunksReceived, firstNullChunkReceivedAt = _a.firstNullChunkReceivedAt, lastNullChunkReceivedAt = _a.lastNullChunkReceivedAt, timesSignatureCleared = _a.timesSignatureCleared;
24401
+ metadata = {
24402
+ mimeType: mimeType,
24403
+ browserFeatures: {
24404
+ supportsRoundRect: supportsRoundRect,
24405
+ supportsRequestVideoFrameCallback: supportsRequestVideoFrameCallback
24406
+ },
24407
+ diagnostics: {
24408
+ nullChunksReceived: nullChunksReceived,
24409
+ firstNullChunkReceivedAt: firstNullChunkReceivedAt ? Math.ceil(firstNullChunkReceivedAt) : 0,
24410
+ lastNullChunkReceivedAt: lastNullChunkReceivedAt ? Math.ceil(lastNullChunkReceivedAt) : 0,
24411
+ finalChunkReceived: finalChunkReceived,
24412
+ finalChunkTimedOut: timedOut,
24413
+ finalChunkWaitedMs: Math.ceil(waitedMs),
24414
+ videoChunkRate: lastCalculatedVideoChunkRate,
24415
+ timesSignatureCleared: timesSignatureCleared
24416
+ },
24417
+ timingData: {
24418
+ recordingStartRequestedAt: recordingStartRequestedAt ? Math.ceil(recordingStartRequestedAt) : 0,
24419
+ recordingStartedAt: recordingStartedAt ? Math.ceil(recordingStartedAt) : 0,
24420
+ firstChunkReceivedAt: firstChunkReceivedAt ? Math.ceil(firstChunkReceivedAt) : 0,
24421
+ signatureStartedAt: signatureStartedAt ? Math.ceil(signatureStartedAt) : 0,
24422
+ signatureEndedAt: signatureEndedAt ? Math.ceil(signatureEndedAt) : 0,
24423
+ acceptClickedAt: acceptClickedAt ? Math.ceil(acceptClickedAt) : 0,
24424
+ clearClickedAt: clearClickedAt ? Math.ceil(clearClickedAt) : 0,
24425
+ recordingStopRequestedAt: recordingStopRequestedAt ? Math.ceil(recordingStopRequestedAt) : 0,
24426
+ recordingStoppedAt: Math.ceil(recordingStoppedAt),
24427
+ lastChunkReceivedAt: lastChunkReceivedAt ? Math.ceil(lastChunkReceivedAt) : 0
24428
+ }
24429
+ };
24430
+ debug('signature video metadata', metadata);
24431
+ onSignatureVideoCaptured(blob, signatureData !== null && signatureData !== void 0 ? signatureData : null, imageUrl !== null && imageUrl !== void 0 ? imageUrl : null, metadata);
24432
+ return [2 /*return*/];
24433
+ });
24434
+ });
24435
+ }
24436
+ var _a, recordingStartedAt, recordingStopRequestedAt, isRecording, _b, finalChunkReceived, timedOut, waitedMs;
24437
+ return __generator(this, function (_c) {
24438
+ switch (_c.label) {
24366
24439
  case 0:
24440
+ _a = get(), recordingStartedAt = _a.recordingStartedAt, recordingStopRequestedAt = _a.recordingStopRequestedAt;
24441
+ isRecording = !!recordingStartedAt && !recordingStopRequestedAt;
24442
+ if (!isRecording) return [2 /*return*/];
24367
24443
  set({
24368
- recordingStopRequestedAt: performance.now()
24444
+ recordingStopRequestedAt: performance.now(),
24445
+ recordingStoppedAt: undefined
24369
24446
  });
24370
- if (!signatureRecorder) return [2 /*return*/];
24371
- return [4 /*yield*/, waitForOneMoreChunk()];
24447
+ clearInterval(get().requestDataInterval);
24448
+ return [4 /*yield*/, waitForOneMoreChunk()
24449
+ // this represents the time that it is safe to release the camera access
24450
+ ];
24372
24451
  case 1:
24373
- _a.sent();
24374
- signatureRecorder.onstop = function () {
24375
- return __awaiter(_this, void 0, void 0, function () {
24376
- var recordingStoppedAt, mimeType, blob, _a, onSignatureVideoCaptured, recordingStartRequestedAt, recordingStartedAt, firstChunkReceivedAt, signatureStartedAt, signatureEndedAt, acceptClickedAt, recordingStopRequestedAt, lastChunkReceivedAt, supportsRequestVideoFrameCallback, supportsRoundRect;
24377
- return __generator(this, function (_b) {
24378
- recordingStoppedAt = performance.now();
24379
- set({
24380
- recordingStoppedAt: recordingStoppedAt
24381
- });
24382
- mimeType = inferBlobType(signatureChunks[0]) || (signatureRecorder === null || signatureRecorder === void 0 ? void 0 : signatureRecorder.mimeType) || 'video/mp4';
24383
- blob = new Blob(signatureChunks, {
24384
- type: mimeType
24385
- });
24386
- signatureChunks = [];
24387
- signatureRecorder = null;
24388
- _a = get(), onSignatureVideoCaptured = _a.onSignatureVideoCaptured, recordingStartRequestedAt = _a.recordingStartRequestedAt, recordingStartedAt = _a.recordingStartedAt, firstChunkReceivedAt = _a.firstChunkReceivedAt, signatureStartedAt = _a.signatureStartedAt, signatureEndedAt = _a.signatureEndedAt, acceptClickedAt = _a.acceptClickedAt, recordingStopRequestedAt = _a.recordingStopRequestedAt, lastChunkReceivedAt = _a.lastChunkReceivedAt, supportsRequestVideoFrameCallback = _a.supportsRequestVideoFrameCallback, supportsRoundRect = _a.supportsRoundRect;
24389
- onSignatureVideoCaptured(blob, signatureData !== null && signatureData !== void 0 ? signatureData : null, imageUrl !== null && imageUrl !== void 0 ? imageUrl : null, {
24390
- mimeType: mimeType,
24391
- browserFeatures: {
24392
- supportsRoundRect: supportsRoundRect,
24393
- supportsRequestVideoFrameCallback: supportsRequestVideoFrameCallback
24394
- },
24395
- timingData: {
24396
- recordingStartRequestedAt: recordingStartRequestedAt ? Math.ceil(recordingStartRequestedAt) : 0,
24397
- recordingStartedAt: recordingStartedAt ? Math.ceil(recordingStartedAt) : 0,
24398
- firstChunkReceivedAt: firstChunkReceivedAt ? Math.ceil(firstChunkReceivedAt) : 0,
24399
- signatureStartedAt: signatureStartedAt ? Math.ceil(signatureStartedAt) : 0,
24400
- signatureEndedAt: signatureEndedAt ? Math.ceil(signatureEndedAt) : 0,
24401
- acceptClickedAt: acceptClickedAt ? Math.ceil(acceptClickedAt) : 0,
24402
- recordingStopRequestedAt: recordingStopRequestedAt ? Math.ceil(recordingStopRequestedAt) : 0,
24403
- recordingStoppedAt: Math.ceil(recordingStoppedAt),
24404
- lastChunkReceivedAt: lastChunkReceivedAt ? Math.ceil(lastChunkReceivedAt) : 0
24405
- }
24406
- });
24407
- return [2 /*return*/];
24408
- });
24409
- });
24410
- };
24452
+ _b = _c.sent(), finalChunkReceived = _b.finalChunkReceived, timedOut = _b.timedOut, waitedMs = _b.waitedMs;
24453
+ // this represents the time that it is safe to release the camera access
24454
+ set({
24455
+ finalChunkReceived: true
24456
+ });
24457
+ if (!signatureRecorder) return [3 /*break*/, 2];
24458
+ signatureRecorder.onstop = processVideo;
24411
24459
  signatureRecorder.stop();
24460
+ return [3 /*break*/, 4];
24461
+ case 2:
24462
+ warn('signature recorder not found, processing video immediately');
24463
+ return [4 /*yield*/, processVideo()];
24464
+ case 3:
24465
+ _c.sent();
24466
+ _c.label = 4;
24467
+ case 4:
24412
24468
  return [2 /*return*/];
24413
24469
  }
24414
24470
  });
@@ -24416,6 +24472,9 @@
24416
24472
  },
24417
24473
  clearRecordedData: function clearRecordedData() {
24418
24474
  signatureChunks = [];
24475
+ ondataavailableInvocations = [];
24476
+ ondataavailableStartTime = undefined;
24477
+ lastCalculatedVideoChunkRate = undefined;
24419
24478
  signatureRecorder === null || signatureRecorder === void 0 ? void 0 : signatureRecorder.stop();
24420
24479
  signatureRecorder = null;
24421
24480
  set({
@@ -24430,8 +24489,13 @@
24430
24489
  signatureStartedAt: undefined,
24431
24490
  signatureEndedAt: undefined,
24432
24491
  acceptClickedAt: undefined,
24492
+ // Note: clearClickedAt is intentionally preserved for telemetry metadata
24433
24493
  supportsRequestVideoFrameCallback: undefined,
24434
- supportsRoundRect: undefined
24494
+ supportsRoundRect: undefined,
24495
+ nullChunksReceived: 0,
24496
+ firstNullChunkReceivedAt: undefined,
24497
+ lastNullChunkReceivedAt: undefined,
24498
+ finalChunkReceived: false
24435
24499
  });
24436
24500
  }
24437
24501
  });
@@ -24441,11 +24505,11 @@
24441
24505
  * @param delayMs - The delay in milliseconds before the first check -- this is used to make sure we get at least one extra second of video.
24442
24506
  * @param checkEveryMs - The interval in milliseconds between checks after the initial delay has passed.
24443
24507
  * @param timeoutMs - The maximum time in milliseconds to wait for the chunk -- this is used to prevent infinite loops.
24444
- * @returns A promise that resolves when the delay has passed and at least one chunk has been received received.
24508
+ * @returns A promise that resolves when the delay has passed and at least one chunk has been received received. The return value is the number of milliseconds that we waited, whether we received a chunk, and whether we timed out.
24445
24509
  */
24446
24510
  function waitForOneMoreChunk(delayMs, checkEveryMs, timeoutMs) {
24447
24511
  if (delayMs === void 0) {
24448
- delayMs = 1000;
24512
+ delayMs = 250;
24449
24513
  }
24450
24514
  if (checkEveryMs === void 0) {
24451
24515
  checkEveryMs = 100;
@@ -24453,29 +24517,44 @@
24453
24517
  if (timeoutMs === void 0) {
24454
24518
  timeoutMs = 3000;
24455
24519
  }
24456
- var start = performance.now();
24457
24520
  return new Promise(function (resolve) {
24458
- var initialLastChunkReceivedAt = useVideoSignatureStore.getState().lastChunkReceivedAt;
24459
- function gotAChunk() {
24521
+ var _a;
24522
+ var start = performance.now();
24523
+ var initialLastChunkReceivedAt = (_a = useVideoSignatureStore.getState().lastChunkReceivedAt) !== null && _a !== void 0 ? _a : start;
24524
+ signatureRecorder === null || signatureRecorder === void 0 ? void 0 : signatureRecorder.requestData();
24525
+ function checkForChunk() {
24460
24526
  var lastChunkReceivedAt = useVideoSignatureStore.getState().lastChunkReceivedAt;
24461
- return performance.now() - start > timeoutMs || !lastChunkReceivedAt || !initialLastChunkReceivedAt || lastChunkReceivedAt > initialLastChunkReceivedAt;
24527
+ var waitedMs = performance.now() - start;
24528
+ var timedOut = waitedMs > timeoutMs;
24529
+ var finalChunkReceived = !!lastChunkReceivedAt && !!initialLastChunkReceivedAt && lastChunkReceivedAt > initialLastChunkReceivedAt;
24530
+ return {
24531
+ waitedMs: waitedMs,
24532
+ finalChunkReceived: finalChunkReceived,
24533
+ timedOut: timedOut
24534
+ };
24462
24535
  }
24463
24536
  setTimeout(function () {
24464
- if (gotAChunk()) return resolve(); // check immediately
24537
+ // check immediately
24538
+ var result = checkForChunk();
24539
+ if (result.finalChunkReceived || result.timedOut) return resolve(result);
24465
24540
  // otherwise, check on a configured interval
24466
24541
  var interval = setInterval(function () {
24467
- if (gotAChunk()) {
24542
+ var result = checkForChunk();
24543
+ if (result.finalChunkReceived || result.timedOut) {
24468
24544
  clearInterval(interval);
24469
- resolve();
24545
+ resolve(result);
24470
24546
  }
24471
24547
  }, checkEveryMs);
24472
24548
  }, delayMs);
24473
24549
  });
24474
24550
  }
24475
24551
  function VideoSignatureContextProvider(_a) {
24476
- var _b, _c;
24477
24552
  var children = _a.children;
24478
- var videoRef = useCameraStore().videoRef;
24553
+ var _b = useCameraStore(),
24554
+ videoRef = _b.videoRef,
24555
+ videoWidth = _b.videoWidth,
24556
+ videoHeight = _b.videoHeight,
24557
+ releaseCameraAccess = _b.releaseCameraAccess;
24479
24558
  var outputCanvas = React.useRef(null);
24480
24559
  React.useEffect(function () {
24481
24560
  return useVideoSignatureStore.setState({
@@ -24483,18 +24562,13 @@
24483
24562
  });
24484
24563
  }, []);
24485
24564
  var drawOutputFrame = React.useCallback(function () {
24486
- if (!outputCanvas.current || !videoRef.current) return;
24565
+ if (!outputCanvas.current) return;
24487
24566
  var ctx = outputCanvas.current.getContext('2d');
24488
24567
  if (!ctx) return;
24489
- var _a = [videoRef.current.videoWidth, videoRef.current.videoHeight],
24568
+ var _a = [outputCanvas.current.width, outputCanvas.current.height],
24490
24569
  w = _a[0],
24491
24570
  h = _a[1];
24492
24571
  var isPortrait = w < h;
24493
- // Only update canvas dimensions if they changed (setting dimensions clears the canvas!)
24494
- if (outputCanvas.current.width !== w || outputCanvas.current.height !== h) {
24495
- outputCanvas.current.width = w;
24496
- outputCanvas.current.height = h;
24497
- }
24498
24572
  var rect = [w * (isPortrait ? 0.02 : 0.15),
24499
24573
  // x
24500
24574
  h * (isPortrait ? 0.15 : 0.25),
@@ -24503,7 +24577,9 @@
24503
24577
  // width
24504
24578
  h * (isPortrait ? 0.7 : 0.5) // height
24505
24579
  ];
24506
- ctx.drawImage(videoRef.current, 0, 0, w, h);
24580
+ if (videoRef.current) {
24581
+ ctx.drawImage(videoRef.current, 0, 0, w, h);
24582
+ }
24507
24583
  ctx.beginPath();
24508
24584
  ctx.fillStyle = 'rgba(255,255,255,0.5)';
24509
24585
  var supportsRoundRect = typeof ctx.roundRect === 'function';
@@ -24525,11 +24601,15 @@
24525
24601
  ctx.drawImage.apply(ctx, __spreadArray([signatureCanvas], rect, false));
24526
24602
  }
24527
24603
  }, [videoRef]);
24528
- useVideoFrameLoop(videoRef, drawOutputFrame);
24604
+ var finalChunkReceived = useVideoSignatureStore().finalChunkReceived;
24605
+ React.useEffect(function () {
24606
+ if (finalChunkReceived) releaseCameraAccess();
24607
+ }, [finalChunkReceived, releaseCameraAccess]);
24608
+ useVideoFrameLoop(videoRef, drawOutputFrame, !finalChunkReceived);
24529
24609
  return /*#__PURE__*/React.createElement(React.Fragment, null, children, /*#__PURE__*/React.createElement(InvisibleCanvas, {
24530
24610
  ref: outputCanvas,
24531
- width: (_b = videoRef.current) === null || _b === void 0 ? void 0 : _b.videoWidth,
24532
- height: (_c = videoRef.current) === null || _c === void 0 ? void 0 : _c.videoHeight
24611
+ width: videoWidth,
24612
+ height: videoHeight
24533
24613
  }));
24534
24614
  }
24535
24615
  function requestVideoFrameCallback(video, onFrame) {
@@ -24549,8 +24629,11 @@
24549
24629
  };
24550
24630
  }
24551
24631
  }
24552
- function videoFrameLoop(video, onFrame) {
24553
- if (!video) return;
24632
+ function videoFrameLoop(video, onFrame, running) {
24633
+ if (running === void 0) {
24634
+ running = true;
24635
+ }
24636
+ if (!video || !running) return;
24554
24637
  var cancelFn;
24555
24638
  var canceled = false;
24556
24639
  function onFrameRecursive() {
@@ -24571,10 +24654,51 @@
24571
24654
  if (cancelFn !== undefined) cancelFn();
24572
24655
  };
24573
24656
  }
24574
- function useVideoFrameLoop(ref, onFrame) {
24657
+ function useVideoFrameLoop(ref, onFrame, running) {
24658
+ if (running === void 0) {
24659
+ running = true;
24660
+ }
24575
24661
  React.useEffect(function () {
24576
- return videoFrameLoop(ref.current, onFrame);
24577
- }, [onFrame, ref]);
24662
+ return videoFrameLoop(ref.current, onFrame, running);
24663
+ }, [onFrame, ref, running]);
24664
+ }
24665
+ function calculateAndStoreOndataavailableRate() {
24666
+ if (ondataavailableInvocations.length < 2 || !ondataavailableStartTime) {
24667
+ lastCalculatedVideoChunkRate = {
24668
+ averageRate: 0,
24669
+ minRate: 0,
24670
+ maxRate: 0,
24671
+ totalChunksReceived: ondataavailableInvocations.length,
24672
+ recordingDurationMs: 0
24673
+ };
24674
+ return;
24675
+ }
24676
+ var totalDuration = ondataavailableInvocations[ondataavailableInvocations.length - 1] - ondataavailableStartTime;
24677
+ var averageRate = (ondataavailableInvocations.length - 1) / (totalDuration / 1000); // invocations per second
24678
+ // Calculate rates for each interval between invocations
24679
+ var rates = [];
24680
+ for (var i = 1; i < ondataavailableInvocations.length; i++) {
24681
+ var intervalMs = ondataavailableInvocations[i] - ondataavailableInvocations[i - 1];
24682
+ var rate = 1000 / intervalMs; // invocations per second for this interval
24683
+ rates.push(rate);
24684
+ }
24685
+ var minRate = Math.min.apply(Math, rates);
24686
+ var maxRate = Math.max.apply(Math, rates);
24687
+ lastCalculatedVideoChunkRate = {
24688
+ averageRate: Math.round(averageRate * 100) / 100,
24689
+ // Round to 2 decimal places
24690
+ minRate: Math.round(minRate * 100) / 100,
24691
+ maxRate: Math.round(maxRate * 100) / 100,
24692
+ totalChunksReceived: ondataavailableInvocations.length,
24693
+ recordingDurationMs: Math.round(totalDuration)
24694
+ };
24695
+ }
24696
+ function trackVideoChunkRate(now) {
24697
+ // Track ondataavailable invocations for rate calculation
24698
+ ondataavailableStartTime !== null && ondataavailableStartTime !== void 0 ? ondataavailableStartTime : ondataavailableStartTime = now;
24699
+ ondataavailableInvocations.push(now);
24700
+ // Calculate and store the current rate
24701
+ calculateAndStoreOndataavailableRate();
24578
24702
  }
24579
24703
 
24580
24704
  function VideoSignaturePad(_a) {
@@ -25512,13 +25636,18 @@
25512
25636
  });
25513
25637
  }, []);
25514
25638
  var onClearBtnClicked = React.useCallback(function () {
25515
- var _a, _b;
25639
+ var _a;
25640
+ var _b = useVideoSignatureStore.getState(),
25641
+ timesSignatureCleared = _b.timesSignatureCleared,
25642
+ signaturePad = _b.signaturePad;
25516
25643
  useVideoSignatureStore.setState({
25644
+ clearClickedAt: performance.now(),
25645
+ timesSignatureCleared: timesSignatureCleared + 1,
25517
25646
  signatureStartedAt: undefined,
25518
25647
  signaturePadEmpty: true,
25519
25648
  signatureValid: false
25520
25649
  });
25521
- (_b = (_a = useVideoSignatureStore.getState().signaturePad) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.clear();
25650
+ (_a = signaturePad.current) === null || _a === void 0 ? void 0 : _a.clear();
25522
25651
  if (restartVideoOnSignaturePadCleared) {
25523
25652
  setTimeout(function () {
25524
25653
  useVideoSignatureStore.getState().clearRecordedData();
@@ -25907,6 +26036,13 @@
25907
26036
  }, [audioRecordingIntentionallyStopped, audioRecordingStopped, audioUrl, isRecordingAudio, isRecordingVideo, videoRecordingIntentionallyStopped, videoRecordingStopped, videoUrl]);
25908
26037
  };
25909
26038
 
26039
+ var DEFAULT_CLASSNAMES = {};
26040
+ var DEFAULT_VERBIAGE = {};
26041
+ var VERBIAGE_FALLBACKS = {
26042
+ headingText: 'Please read the following text aloud',
26043
+ promptText: '',
26044
+ doneBtnText: 'Done'
26045
+ };
25910
26046
  var ReadTextPrompt = function ReadTextPrompt(_a) {
25911
26047
  var onComplete = _a.onComplete,
25912
26048
  _b = _a.durationMs,
@@ -25914,18 +26050,27 @@
25914
26050
  _c = _a.minReadingMs,
25915
26051
  minReadingMs = _c === void 0 ? 10000 : _c,
25916
26052
  _d = _a.classNames,
25917
- classNames = _d === void 0 ? {} : _d,
26053
+ classNames = _d === void 0 ? DEFAULT_CLASSNAMES : _d,
25918
26054
  _e = _a.verbiage,
25919
- rawVerbiage = _e === void 0 ? {} : _e;
26055
+ rawVerbiage = _e === void 0 ? DEFAULT_VERBIAGE : _e,
26056
+ onPromptTextRendered = _a.onPromptTextRendered;
25920
26057
  var countdownTimeoutRef = React.useRef(undefined);
25921
26058
  var _f = React.useState(durationMs / 1000),
25922
26059
  countdownRemaining = _f[0],
25923
26060
  setCountdownRemaining = _f[1];
25924
- var verbiage = useTranslations(rawVerbiage, {
25925
- headingText: 'Please read the following text aloud',
25926
- promptText: '',
25927
- doneBtnText: 'Done'
25928
- });
26061
+ var promptTextRef = React.useRef(null);
26062
+ var verbiage = useTranslations(rawVerbiage, VERBIAGE_FALLBACKS);
26063
+ // Each time the rendered DOM contents changes for the prompt text,
26064
+ // notify the parent via callback so it can respond.
26065
+ // [NOTE]
26066
+ // This is a bit of a workaround for extracting the text of a react component.
26067
+ // Grabbing from the dom is not ideal but it works for now.
26068
+ // [TODO] Can this be pulled form the react tree instead?
26069
+ React.useEffect(function () {
26070
+ if (promptTextRef.current && onPromptTextRendered) {
26071
+ onPromptTextRendered(promptTextRef.current);
26072
+ }
26073
+ }, [onPromptTextRendered, verbiage.promptText]);
25929
26074
  var manualCountdown = React.useCallback(function (remainingTime) {
25930
26075
  if (remainingTime > 0) {
25931
26076
  var nextCycle_1 = remainingTime - 1;
@@ -25960,7 +26105,8 @@
25960
26105
  }, /*#__PURE__*/React.createElement(ReadTextPromptHeading, {
25961
26106
  className: classNames.heading
25962
26107
  }, verbiage.headingText), /*#__PURE__*/React.createElement(ReadTextPromptText, {
25963
- className: classNames.prompt
26108
+ className: classNames.prompt,
26109
+ ref: promptTextRef
25964
26110
  }, verbiage.promptText), /*#__PURE__*/React.createElement(ReadTextPromptButtonsRow, {
25965
26111
  className: classNames.buttonsRow
25966
26112
  }, /*#__PURE__*/React.createElement(ReadTextPromptTimeRemaining, {
@@ -26006,8 +26152,101 @@
26006
26152
  return ((_c = (_b = (_a = props.theme.idVideoCapture) === null || _a === void 0 ? void 0 : _a.readTextPrompt) === null || _b === void 0 ? void 0 : _b.timeRemaining) === null || _c === void 0 ? void 0 : _c.borderRadius) ? "border-radius: ".concat((_f = (_e = (_d = props.theme.idVideoCapture) === null || _d === void 0 ? void 0 : _d.readTextPrompt) === null || _e === void 0 ? void 0 : _e.timeRemaining) === null || _f === void 0 ? void 0 : _f.borderRadius, ";") : "";
26007
26153
  });
26008
26154
  var DoneButton = styled(LoaderButton)(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n margin: auto 0;\n"], ["\n margin: auto 0;\n"])));
26155
+ var ReadTextPromptWrapped = /*#__PURE__*/React.memo(ReadTextPrompt);
26009
26156
  var templateObject_1$6, templateObject_2$6, templateObject_3$5, templateObject_4$1, templateObject_5$1, templateObject_6;
26010
26157
 
26158
+ // Precompiled regexes for performance and clarity
26159
+ var RE_ESCAPE_N = /\\n/g;
26160
+ var RE_ESCAPE_T = /\\t/g;
26161
+ var RE_ESCAPE_R = /\\r/g;
26162
+ // Remove entire script/style blocks before anything else
26163
+ var RE_SCRIPT_BLOCK = /<script[\s\S]*?<\/script>/gi;
26164
+ var RE_STYLE_BLOCK = /<style[\s\S]*?<\/style>/gi;
26165
+ // Replace common block-level tags with spaces to preserve boundaries
26166
+ var RE_BLOCK_OPEN = /<(div|p|h[1-6]|li|ul|ol|blockquote|pre|section|article|header|footer|aside|nav|main|form|fieldset|table|tr|td|th|br)[^>]*>/gi;
26167
+ var RE_BLOCK_CLOSE = /<\/(div|p|h[1-6]|li|ul|ol|blockquote|pre|section|article|header|footer|aside|nav|main|form|fieldset|table|tr|td|th|br)>/gi;
26168
+ // Any remaining HTML tag
26169
+ var RE_ALL_TAGS = /<[^>]*>/g;
26170
+ // Numeric entities (be lenient on optional semicolon)
26171
+ var RE_NUM_DEC = /&#(\d+);?/g;
26172
+ var RE_NUM_HEX = /&#x([0-9a-f]+);?/gi;
26173
+ // Invisible/whitespace variants
26174
+ var RE_NBSP_CHAR = /\u00A0/g;
26175
+ var RE_ZERO_WIDTH = /[\u200B-\u200D\uFEFF]/g;
26176
+ // Named entities map; case-insensitive replacement will be applied
26177
+ var NAMED_ENTITIES = {
26178
+ nbsp: ' ',
26179
+ amp: '&',
26180
+ lt: '<',
26181
+ gt: '>',
26182
+ quot: '"',
26183
+ '#39': "'",
26184
+ // some encoders output &#39; but handle via numeric too
26185
+ apos: "'",
26186
+ cent: '¢',
26187
+ pound: '£',
26188
+ yen: '¥',
26189
+ euro: '€',
26190
+ copy: '©',
26191
+ reg: '®',
26192
+ mdash: '—',
26193
+ ndash: '–',
26194
+ hellip: '…',
26195
+ ldquo: '"',
26196
+ rdquo: '"',
26197
+ lsquo: "'",
26198
+ rsquo: "'"
26199
+ };
26200
+ function decodeNamedEntities(input) {
26201
+ return input.replace(/&([a-z#0-9]+);/gi, function (_, name) {
26202
+ var key = name.toLowerCase();
26203
+ if (Object.prototype.hasOwnProperty.call(NAMED_ENTITIES, key)) {
26204
+ return NAMED_ENTITIES[key];
26205
+ }
26206
+ return "&".concat(name, ";");
26207
+ });
26208
+ }
26209
+ function getRawTextFromHtml(str) {
26210
+ if (!str) return '';
26211
+ var s = str;
26212
+ // 1) Handle literal escape sequences (avoid confusing with HTML)
26213
+ s = s.replace(RE_ESCAPE_N, ' ').replace(RE_ESCAPE_T, ' ').replace(RE_ESCAPE_R, ' ');
26214
+ // 2) Remove script/style blocks entirely
26215
+ s = s.replace(RE_SCRIPT_BLOCK, ' ').replace(RE_STYLE_BLOCK, ' ');
26216
+ // 3) Replace block-level elements with spaces, then strip remaining tags
26217
+ s = s.replace(RE_BLOCK_OPEN, ' ').replace(RE_BLOCK_CLOSE, ' ');
26218
+ s = s.replace(RE_ALL_TAGS, '');
26219
+ // 4) Decode numeric entities using code points (handles >0xFFFF)
26220
+ s = s.replace(RE_NUM_DEC, function (_, dec) {
26221
+ var codePoint = parseInt(dec, 10);
26222
+ if (Number.isFinite(codePoint) && codePoint >= 0) {
26223
+ try {
26224
+ return String.fromCodePoint(codePoint);
26225
+ } catch (_a) {
26226
+ return '';
26227
+ }
26228
+ }
26229
+ return '';
26230
+ }).replace(RE_NUM_HEX, function (_, hex) {
26231
+ var codePoint = parseInt(hex, 16);
26232
+ if (Number.isFinite(codePoint) && codePoint >= 0) {
26233
+ try {
26234
+ return String.fromCodePoint(codePoint);
26235
+ } catch (_a) {
26236
+ return '';
26237
+ }
26238
+ }
26239
+ return '';
26240
+ });
26241
+ // 5) Decode common named entities (case-insensitive)
26242
+ s = decodeNamedEntities(s);
26243
+ // 6) Replace Unicode NBSP and remove zero-width characters
26244
+ s = s.replace(RE_NBSP_CHAR, ' ').replace(RE_ZERO_WIDTH, '');
26245
+ // 7) Normalize whitespace
26246
+ s = s.replace(/\s+/g, ' ').trim();
26247
+ return s;
26248
+ }
26249
+
26011
26250
  var edgeBoundary = 0.05;
26012
26251
  var defaultVideoIdCaptureThresholds = {
26013
26252
  detection: {
@@ -26238,18 +26477,22 @@
26238
26477
  }, [goodFramesCount]);
26239
26478
  var delaySatisfied = !['SHOW_ID_FRONT', 'SHOW_PASSPORT'].includes(requestedAction) || idFrontCaptureStartedAt !== null && new Date().getTime() > idFrontCaptureStartedAt + idCardFrontDelay;
26240
26479
  var translatedText = useVerbiage(readTextPrompt, '');
26480
+ var handlePromptTextRendered = React.useCallback(function (element) {
26481
+ if (element) {
26482
+ var rawText = getRawTextFromHtml(element.innerHTML);
26483
+ setExpectedAudioText(rawText);
26484
+ }
26485
+ }, [setExpectedAudioText]);
26241
26486
  var onIdCaptureComplete = React.useCallback(function () {
26242
26487
  var _a;
26243
26488
  if (translatedText) {
26244
26489
  setRequestedAction('READ_TEXT');
26245
26490
  useVideoRecorderStore.getState().startRecordingAudio();
26246
26491
  setIdCaptureVideoAudioStartsAt(new Date().getTime() - ((_a = videoStartsAt === null || videoStartsAt === void 0 ? void 0 : videoStartsAt.getTime()) !== null && _a !== void 0 ? _a : 0));
26247
- var renderedTranslatedText = typeof translatedText === 'string' ? translatedText : server.renderToString(translatedText);
26248
- setExpectedAudioText(renderedTranslatedText);
26249
26492
  } else {
26250
26493
  useVideoRecorderStore.getState().stopRecordingVideo();
26251
26494
  }
26252
- }, [setExpectedAudioText, setIdCaptureVideoAudioStartsAt, translatedText, videoStartsAt]);
26495
+ }, [setIdCaptureVideoAudioStartsAt, translatedText, videoStartsAt]);
26253
26496
  var frameWidth = (_c = (_b = videoRef.current) === null || _b === void 0 ? void 0 : _b.videoWidth) !== null && _c !== void 0 ? _c : 0;
26254
26497
  var frameHeight = (_e = (_d = videoRef.current) === null || _d === void 0 ? void 0 : _d.videoHeight) !== null && _e !== void 0 ? _e : 0;
26255
26498
  var faceBox = face === null || face === void 0 ? void 0 : face.box;
@@ -26407,13 +26650,14 @@
26407
26650
  className: classNames.container
26408
26651
  }, /*#__PURE__*/React.createElement(InvisibleCanvas, {
26409
26652
  ref: photoCanvas
26410
- }), requestedAction === 'READ_TEXT' ? ( /*#__PURE__*/React.createElement(ReadTextPrompt, {
26653
+ }), requestedAction === 'READ_TEXT' ? ( /*#__PURE__*/React.createElement(ReadTextPromptWrapped, {
26411
26654
  startedAt: timeoutStartedAt || undefined,
26412
26655
  durationMs: readTextTimeoutDurationMs,
26413
26656
  minReadingMs: readTextMinReadingMs,
26414
26657
  classNames: classNames.readTextPrompt,
26415
26658
  verbiage: readTextPromptVerbiage,
26416
- onComplete: stopRecording
26659
+ onComplete: stopRecording,
26660
+ onPromptTextRendered: handlePromptTextRendered
26417
26661
  })) : ( /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(IdVideoCaptureGuides, {
26418
26662
  classNames: classNames.guides,
26419
26663
  verbiage: rawVerbiage.guides,