@a4anthony/proctorkit-vue 0.1.2 → 0.1.4

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 +1 @@
1
- {"version":3,"file":"ProctoredAssessment.vue.d.ts","sourceRoot":"","sources":["../src/ProctoredAssessment.vue"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ProctoredAssessment.vue.d.ts","sourceRoot":"","sources":["../src/ProctoredAssessment.vue"],"names":[],"mappings":"AAqzFA,OAAO,EAAgE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAGlG,OAAO,EAOL,KAAK,gBAAgB,EAOtB,MAAM,2BAA2B,CAAC;AAoCnC,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,0CAA0C,CAAC;AAGlD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAMvD,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,yBAAyB,EAE9B,KAAK,qBAAqB,EAC3B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAEV,+BAA+B,EAC/B,sBAAsB,EAEtB,mCAAmC,EACnC,mCAAmC,EACnC,iCAAiC,EACjC,mCAAmC,EACnC,iCAAiC,EACjC,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AAYzC,OAAO,KAAK,EACV,qBAAqB,EAErB,wBAAwB,EACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAwNzE,KAAK,WAAW,GAAG;IACjB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,mCAAmC,KAAK,OAAO,CAAC;IAClE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,mCAAmC,KAAK,OAAO,CAAC;IAClE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,iCAAiC,KAAK,OAAO,CAAC;IAC9D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,mCAAmC,KAAK,OAAO,CAAC;IAClE;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,iCAAiC,KAAK,OAAO,CAAC;CAC/D,CAAC;AAivGF,QAAA,MAAM,eAAe;;;;;;;;;;cAgBD,QAAQ,CAAC,SAAS,GAAG,SAAS,CAAC;;;;cAI/B,QAAQ,CAAC,qBAAqB,GAAG,SAAS,CAAC;;;;cAIzC,QAAQ,CAAC,wBAAwB,GAAG,SAAS,CAAC;;;;cAIhD,QAAQ,CAAC,yBAAyB,GAAG,SAAS,CAAC;;;IAGjE;;;OAGG;;cAEe,QAAQ,CAAC,qBAAqB,GAAG,SAAS,CAAC;;;;;;;;;;;;;;;;;;;IAmB7D;;;;OAIG;;cAEe,QAAQ,CAAC,WAAW,CAAC;;2BAElB,MAAM;;;;;;;cAOF,QAAQ,CAAC,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;;;IAG3D;;;;;;OAMG;;cAEe,QAAQ,CAAC,gBAAgB,GAAG,SAAS,CAAC;;;IAGxD;;;;;;;OAOG;;cAEiB,QAAQ,CAAC,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;IAG/E;;;;;OAKG;;cAEiB,QAAQ,CAAC,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;cAI9D,QAAQ,CACpB;YACE,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;SAC3B,GACD,SAAS,CACZ;;;;;;;;;;;IAWH;;;;;;OAMG;;;;;IAKH;;;;;;;;OAQG;;;;;IAKH;;;;;;;OAOG;;;;;IAKH;;;;OAIG;;cAEe,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;;;IAGtD;;;;OAIG;;;;;IAKH;;;;OAIG;;cAEc,QAAQ,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;;cAxKtC,QAAQ,CAAC,SAAS,GAAG,SAAS,CAAC;;;;cAI/B,QAAQ,CAAC,qBAAqB,GAAG,SAAS,CAAC;;;;cAIzC,QAAQ,CAAC,wBAAwB,GAAG,SAAS,CAAC;;;;cAIhD,QAAQ,CAAC,yBAAyB,GAAG,SAAS,CAAC;;;IAGjE;;;OAGG;;cAEe,QAAQ,CAAC,qBAAqB,GAAG,SAAS,CAAC;;;;;;;;;;;;;;;;;;;IAmB7D;;;;OAIG;;cAEe,QAAQ,CAAC,WAAW,CAAC;;2BAElB,MAAM;;;;;;;cAOF,QAAQ,CAAC,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;;;IAG3D;;;;;;OAMG;;cAEe,QAAQ,CAAC,gBAAgB,GAAG,SAAS,CAAC;;;IAGxD;;;;;;;OAOG;;cAEiB,QAAQ,CAAC,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;IAG/E;;;;;OAKG;;cAEiB,QAAQ,CAAC,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;cAI9D,QAAQ,CACpB;YACE,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;SAC3B,GACD,SAAS,CACZ;;;;;;;;;;;IAWH;;;;;;OAMG;;;;;IAKH;;;;;;;;OAQG;;;;;IAKH;;;;;;;OAOG;;;;;IAKH;;;;OAIG;;cAEe,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;;;IAGtD;;;;OAIG;;;;;IAKH;;;;OAIG;;cAEc,QAAQ,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;wBA3EhC,MAAM;2BACH,MAAM;;;;;;;;;;;;;;4BAjBG,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;+BAU1C,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;;;;;;4EAqF/E,CAAC;wBACkB,eAAe,CAAC,OAAO,eAAe,EAAE,WAAW,CAAC;AAAzE,wBAA0E;AAE1E,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProctoringSystemCheck.vue.d.ts","sourceRoot":"","sources":["../src/ProctoringSystemCheck.vue"],"names":[],"mappings":"AAozBA,OAAO,EAA4C,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAE9E,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAM3F,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAgBvD,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC9B,MAAM,uBAAuB,CAAC;AAM/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAuiCrD,QAAA,IAAI,OAAO,IAAU,EAAE,QAAQ,IAAU,EAAE,QAAQ,IAAY,CAAE;AACjE,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC/C;IAAE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,GACjD;IAAE,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AA0OxD,QAAA,MAAM,eAAe;;cAQD,QAAQ,CAAC,eAAe,CAAC;;;;cAIzB,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;;;IAG5D;;;;;;;OAOG;;cAEe,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;;;;cAIjC,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;;;IAGtD;;;;;;OAMG;;;;;;;;;;cAWc,QAAQ,CAAC,oBAAoB,EAAE,CAAC;;;;;;;IAOjD;;;;;OAKG;;;;;;;;;;;;;IAaH;;;;;OAKG;;;;;IAKH;;;;;;OAMG;;;;;;cAMe,QAAQ,CAAC;YACvB,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;SAC3B,CAAC;;;;;;;;cAQc,QAAQ,CAAC,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;;;;;;;IAOnE;;;;;;;;;;OAUG;;;;;IAKH;;;;OAIG;;;;;IAKH;;;OAGG;;cAEe,QAAQ,CAAC;YACvB,EAAE,EAAE,MAAM,CAAC;YACX,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACpC,CAAC;;;;cAIc,QAAQ,CAAC,qBAAqB,GAAG,SAAS,CAAC;;;;cAIzC,QAAQ,CAAC,wBAAwB,GAAG,SAAS,CAAC;;;IAGlE;;;OAGG;;;;;IAKH,qEAAqE;;cAEnD,QAAQ,CAAC,WAAW,CAAC;;;;;;cAtwCR,SAAS;cAAQ,QAAQ;gBAAU,MAAM;;;;;;;cAsmCtD,QAAQ,CAAC,eAAe,CAAC;;;;cAIzB,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;;;IAG5D;;;;;;;OAOG;;cAEe,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;;;;cAIjC,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;;;IAGtD;;;;;;OAMG;;;;;;;;;;cAWc,QAAQ,CAAC,oBAAoB,EAAE,CAAC;;;;;;;IAOjD;;;;;OAKG;;;;;;;;;;;;;IAaH;;;;;OAKG;;;;;IAKH;;;;;;OAMG;;;;;;cAMe,QAAQ,CAAC;YACvB,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;SAC3B,CAAC;;;;;;;;cAQc,QAAQ,CAAC,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;;;;;;;IAOnE;;;;;;;;;;OAUG;;;;;IAKH;;;;OAIG;;;;;IAKH;;;OAGG;;cAEe,QAAQ,CAAC;YACvB,EAAE,EAAE,MAAM,CAAC;YACX,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACpC,CAAC;;;;cAIc,QAAQ,CAAC,qBAAqB,GAAG,SAAS,CAAC;;;;cAIzC,QAAQ,CAAC,wBAAwB,GAAG,SAAS,CAAC;;;IAGlE;;;OAGG;;;;;IAKH,qEAAqE;;cAEnD,QAAQ,CAAC,WAAW,CAAC;;;;;;cAtwCR,SAAS;cAAQ,QAAQ;gBAAU,MAAM;;;;;;;;;YA6uChE,MAAM;eACH,MAAM;gBACL,MAAM;mBACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;wBAlDlB,MAAM;2BACH,MAAM;;;;;;;;;;;;;;;;;4EA2E7B,CAAC;wBACkB,eAAe,CAAC,OAAO,eAAe,EAAE,WAAW,CAAC;AAAzE,wBAA0E;AAE1E,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"ProctoringSystemCheck.vue.d.ts","sourceRoot":"","sources":["../src/ProctoringSystemCheck.vue"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as Vue from "vue";
2
2
  import { shallowRef, ref, computed, onUnmounted, watch, onMounted, effectScope, isRef, defineComponent, h as h$1, getCurrentScope, onScopeDispose, Fragment, inject, createVNode, Text, useAttrs, openBlock, createElementBlock, mergeProps, unref, createBlock, normalizeClass, resolveDynamicComponent, renderSlot, createCommentVNode, nextTick, onBeforeUnmount, Teleport, Transition, withCtx, createElementVNode, toDisplayString as toDisplayString$1, renderList, withModifiers, createTextVNode, watchEffect, cloneVNode, provide, toRaw, withDirectives, vShow, useSlots, useId, normalizeStyle, createSlots, markRaw, reactive, toValue } from "vue";
3
- import { SystemCheck, SUPPORTED_BROWSERS, isRetryableFailCode, MIN_SPEED_MBPS, MIN_DEVICE_MEMORY_GB, THRESHOLD_DEFAULTS, computeDeviceFingerprint, runDeepCameraCheck, RuntimeDeviceSwitchError, displayVerdict, deviceVerdict, getTabLockToken, AssessmentReplayController, ProctoringClient, DeliveryReadinessError, classifyClipStartError, normalizeClipDropCode, createTextAnswerRecorder } from "@a4anthony/proctorkit-sdk";
3
+ import { SystemCheck, SUPPORTED_BROWSERS, isRetryableFailCode, MIN_DEVICE_MEMORY_GB, THRESHOLD_DEFAULTS, computeDeviceFingerprint, runDeepCameraCheck, RuntimeDeviceSwitchError, displayVerdict, deviceVerdict, getTabLockToken, measureRecordingDeliveryReadiness, AssessmentReplayController, ProctoringClient, DeliveryReadinessError, classifyClipStartError, normalizeClipDropCode, createTextAnswerRecorder } from "@a4anthony/proctorkit-sdk";
4
4
  import { enumerateMediaDevices } from "@a4anthony/proctorkit-sdk";
5
5
  const CONTENT_PROJECT = "proctoring-candidate";
6
6
  const CONTENT_SCHEMA_VERSION = 1;
@@ -1275,7 +1275,7 @@ const DEFAULT_MESSAGES = {
1275
1275
  device: "Incompatible device",
1276
1276
  layout: "Screen layout problem",
1277
1277
  monitor: "External monitor detected",
1278
- connection: "Connection problem",
1278
+ connection: "Something went wrong",
1279
1279
  microphone: "Microphone problem",
1280
1280
  speaker: "Speaker problem",
1281
1281
  camera: "Camera problem",
@@ -1293,9 +1293,9 @@ const DEFAULT_MESSAGES = {
1293
1293
  "incompatible-device": "Your device is not compatible. Please use a desktop or laptop computer.",
1294
1294
  "bad-layout": "Your screen is too wide. Rotate to portrait or resize the window taller than wide, then click the {retry} button below.",
1295
1295
  "external-monitor": "An external display was detected. Disconnect any external monitors, then click the {retry} button below.",
1296
- offline: "You appear to be offline. Check your Wi-Fi or ethernet, open another site to confirm, then click the {retry} button below.",
1297
- "slow-connection": "Your connection is below the required minimum of {minSpeed} Mbps for this assessment. Pause other downloads or uploads, then click the {retry} button below to test again.",
1298
- "speed-test-failed": "We couldn't measure your connection. Click the {retry} button below to try the check again.",
1296
+ offline: "We couldn't complete this check. Click the {retry} button below to try again.",
1297
+ "slow-connection": "We couldn't complete this check. Click the {retry} button below to try again.",
1298
+ "speed-test-failed": "We couldn't complete this check. Click the {retry} button below to try again.",
1299
1299
  "permission-denied": "Permission was denied. Re-enable it in your browser settings, then retry.",
1300
1300
  "permission-required": "Permission is required. Allow access when prompted, then retry.",
1301
1301
  "device-disconnected": "The previously selected device is no longer connected. Plug it in or select another, then retry.",
@@ -1338,7 +1338,7 @@ const DEFAULT_MESSAGES = {
1338
1338
  readyButtonResume: "Resume test",
1339
1339
  readyButtonBegin: "Begin test",
1340
1340
  deliveryChecking: "Verifying the secure evidence connection",
1341
- deliveryUnavailable: "The secure evidence connection could not be verified. Check your network connection before starting the assessment again.",
1341
+ deliveryUnavailable: "We couldn't complete this check. Click the Try again button below.",
1342
1342
  startingTitle: "Starting proctored session",
1343
1343
  startingEnterFullscreen: "Enter fullscreen to continue.",
1344
1344
  startingScreenRecording: "Starting screen recording.",
@@ -1546,8 +1546,8 @@ const DEFAULT_MESSAGES = {
1546
1546
  description: "We'll quickly verify your browser, device, and connection.",
1547
1547
  continueLabel: "Continue",
1548
1548
  retryLabel: "Retry checks",
1549
- slowUploadTitle: "Upload speed too slow",
1550
- slowUploadMessage: "Your upload speed is {speed} Mbps, below the required {minSpeed} Mbps. Pause uploads or cloud sync, then click the {retry} button below."
1549
+ slowUploadTitle: "Something went wrong",
1550
+ slowUploadMessage: "We couldn't complete this check. Click the {retry} button below to try again."
1551
1551
  },
1552
1552
  microphone: {
1553
1553
  title: "Microphone",
@@ -1724,7 +1724,7 @@ const MESSAGES_FR = {
1724
1724
  device: "Appareil incompatible",
1725
1725
  layout: "Problème de disposition de l'écran",
1726
1726
  monitor: "Écran externe détecté",
1727
- connection: "Problème de connexion",
1727
+ connection: "Un problème est survenu",
1728
1728
  microphone: "Problème de microphone",
1729
1729
  speaker: "Problème de haut-parleur",
1730
1730
  camera: "Problème de caméra",
@@ -1742,9 +1742,9 @@ const MESSAGES_FR = {
1742
1742
  "incompatible-device": "Votre appareil n'est pas compatible. Veuillez utiliser un ordinateur de bureau ou portable.",
1743
1743
  "bad-layout": "Votre écran est trop large. Passez en mode portrait ou redimensionnez la fenêtre pour qu'elle soit plus haute que large, puis cliquez sur le bouton {retry} ci-dessous.",
1744
1744
  "external-monitor": "Un écran externe a été détecté. Déconnectez tout écran externe, puis cliquez sur le bouton {retry} ci-dessous.",
1745
- offline: "Vous semblez être hors ligne. Vérifiez votre Wi-Fi ou votre câble ethernet, ouvrez un autre site pour confirmer, puis cliquez sur le bouton {retry} ci-dessous.",
1746
- "slow-connection": "Votre connexion est inférieure au minimum requis de {minSpeed} Mbps pour cette évaluation. Suspendez les autres téléchargements ou téléversements, puis cliquez sur le bouton {retry} ci-dessous pour relancer le test.",
1747
- "speed-test-failed": "Nous n'avons pas pu mesurer votre connexion. Cliquez sur le bouton {retry} ci-dessous pour relancer la vérification.",
1745
+ offline: "Nous n'avons pas pu terminer cette vérification. Cliquez sur le bouton {retry} ci-dessous pour réessayer.",
1746
+ "slow-connection": "Nous n'avons pas pu terminer cette vérification. Cliquez sur le bouton {retry} ci-dessous pour réessayer.",
1747
+ "speed-test-failed": "Nous n'avons pas pu terminer cette vérification. Cliquez sur le bouton {retry} ci-dessous pour réessayer.",
1748
1748
  "permission-denied": "L'autorisation a été refusée. Réactivez-la dans les paramètres de votre navigateur, puis réessayez.",
1749
1749
  "permission-required": "Une autorisation est requise. Autorisez l'accès lorsque cela vous est demandé, puis réessayez.",
1750
1750
  "device-disconnected": "L'appareil précédemment sélectionné n'est plus connecté. Branchez-le ou sélectionnez-en un autre, puis réessayez.",
@@ -1787,7 +1787,7 @@ const MESSAGES_FR = {
1787
1787
  readyButtonResume: "Reprendre le test",
1788
1788
  readyButtonBegin: "Commencer le test",
1789
1789
  deliveryChecking: "Vérification de la connexion sécurisée des preuves",
1790
- deliveryUnavailable: "La connexion sécurisée des preuves n’a pas pu être vérifiée. Vérifiez votre connexion réseau avant de relancer l’évaluation.",
1790
+ deliveryUnavailable: "Nous n'avons pas pu terminer cette vérification. Cliquez sur le bouton Réessayer ci-dessous.",
1791
1791
  startingTitle: "Démarrage de la session surveillée",
1792
1792
  startingEnterFullscreen: "Passez en plein écran pour continuer.",
1793
1793
  startingScreenRecording: "Démarrage de l'enregistrement de l'écran.",
@@ -1995,8 +1995,8 @@ const MESSAGES_FR = {
1995
1995
  description: "Nous allons rapidement vérifier votre navigateur, votre matériel et votre connexion.",
1996
1996
  continueLabel: "Continuer",
1997
1997
  retryLabel: "Relancer les vérifications",
1998
- slowUploadTitle: "Vitesse de téléversement insuffisante",
1999
- slowUploadMessage: "Votre vitesse de téléversement est de {speed} Mbps, en dessous des {minSpeed} Mbps requis. Suspendez les téléversements ou la synchronisation cloud, puis cliquez sur le bouton {retry} ci-dessous."
1998
+ slowUploadTitle: "Un problème est survenu",
1999
+ slowUploadMessage: "Nous n'avons pas pu terminer cette vérification. Cliquez sur le bouton {retry} ci-dessous pour réessayer."
2000
2000
  },
2001
2001
  microphone: {
2002
2002
  title: "Microphone",
@@ -2140,6 +2140,30 @@ const MESSAGES_FR = {
2140
2140
  }
2141
2141
  }
2142
2142
  };
2143
+ const PUBLISHED_CONNECTION_COPY_EN = {
2144
+ "failHeaders.connection": "Connection problem",
2145
+ "failMessages.offline": "You appear to be offline. Check your Wi-Fi or ethernet, open another site to confirm, then click the {retry} button below.",
2146
+ "failMessages.slow-connection": "Your connection is below the required minimum of {minSpeed} Mbps for this assessment. Pause other downloads or uploads, then click the {retry} button below to test again.",
2147
+ "failMessages.speed-test-failed": "We couldn't measure your connection. Click the {retry} button below to try the check again.",
2148
+ "wizard.system.slowUploadTitle": "Upload speed too slow",
2149
+ "wizard.system.slowUploadMessage": "Your upload speed is {speed} Mbps, below the required {minSpeed} Mbps. Pause uploads or cloud sync, then click the {retry} button below."
2150
+ };
2151
+ const PUBLISHED_CONNECTION_COPY_FR = {
2152
+ "failHeaders.connection": "Problème de connexion",
2153
+ "failMessages.offline": "Vous semblez être hors ligne. Vérifiez votre Wi-Fi ou votre câble ethernet, ouvrez un autre site pour confirmer, puis cliquez sur le bouton {retry} ci-dessous.",
2154
+ "failMessages.slow-connection": "Votre connexion est inférieure au minimum requis de {minSpeed} Mbps pour cette évaluation. Suspendez les autres téléchargements ou téléversements, puis cliquez sur le bouton {retry} ci-dessous pour relancer le test.",
2155
+ "failMessages.speed-test-failed": "Nous n'avons pas pu mesurer votre connexion. Cliquez sur le bouton {retry} ci-dessous pour relancer la vérification.",
2156
+ "wizard.system.slowUploadTitle": "Vitesse de téléversement insuffisante",
2157
+ "wizard.system.slowUploadMessage": "Votre vitesse de téléversement est de {speed} Mbps, en dessous des {minSpeed} Mbps requis. Suspendez les téléversements ou la synchronisation cloud, puis cliquez sur le bouton {retry} ci-dessous."
2158
+ };
2159
+ function preservePublishedConnectionCopy(messages, published) {
2160
+ const preserved = { ...messages };
2161
+ for (const [key, value] of Object.entries(published)) {
2162
+ if (Object.hasOwn(preserved, key))
2163
+ preserved[key] = value;
2164
+ }
2165
+ return preserved;
2166
+ }
2143
2167
  const CONTENT_SCHEMA_V2_VERSION = 2;
2144
2168
  const postV2Keys = /* @__PURE__ */ new Set([
2145
2169
  "failCodeHeaders.low-memory",
@@ -2191,14 +2215,14 @@ const postV2Keys = /* @__PURE__ */ new Set([
2191
2215
  "wizard.system.slowUploadMessage",
2192
2216
  "wizard.system.slowUploadTitle"
2193
2217
  ]);
2194
- function buildV2Messages(messages, mediaHelp) {
2195
- const catalog = buildCandidateCatalogMessages(withoutPlatformMessages(messages), mediaHelp);
2218
+ function buildV2Messages(messages, mediaHelp, publishedConnectionCopy) {
2219
+ const catalog = preservePublishedConnectionCopy(buildCandidateCatalogMessages(withoutPlatformMessages(messages), mediaHelp), publishedConnectionCopy);
2196
2220
  for (const key of postV2Keys)
2197
2221
  delete catalog[key];
2198
2222
  return catalog;
2199
2223
  }
2200
2224
  const SCHEMA_V2_EN_MESSAGES = {
2201
- ...buildV2Messages(DEFAULT_MESSAGES, MEDIA_HELP_EN),
2225
+ ...buildV2Messages(DEFAULT_MESSAGES, MEDIA_HELP_EN, PUBLISHED_CONNECTION_COPY_EN),
2202
2226
  // Preserve the original v2 rich-text contract. Later copy revisions moved
2203
2227
  // the <strong> markup from the recovery list into the introduction.
2204
2228
  "wizard.screenShare.intro": "When the test starts, your browser will ask you to share your screen. We record your full display until the test ends, then release the share automatically.",
@@ -2209,7 +2233,7 @@ const SCHEMA_V2_EN_MESSAGES = {
2209
2233
  ]
2210
2234
  };
2211
2235
  const SCHEMA_V2_FR_MESSAGES = {
2212
- ...buildV2Messages(MESSAGES_FR, MEDIA_HELP_FR),
2236
+ ...buildV2Messages(MESSAGES_FR, MEDIA_HELP_FR, PUBLISHED_CONNECTION_COPY_FR),
2213
2237
  "wizard.screenShare.intro": "Au début du test, votre navigateur vous demandera de partager votre écran. Nous enregistrons l'intégralité de votre écran jusqu'à la fin du test, puis nous libérons le partage automatiquement.",
2214
2238
  "wizard.screenShare.unsupportedSteps": [
2215
2239
  "Utilisez une version récente de <strong>Chrome</strong>, <strong>Edge</strong> ou <strong>Firefox</strong>.",
@@ -2222,8 +2246,8 @@ function withoutPlatformMessages(messages) {
2222
2246
  delete legacy.platform;
2223
2247
  return legacy;
2224
2248
  }
2225
- const numericPlaceholders$2 = /* @__PURE__ */ new Set(["complete", "minMemory", "minSpeed", "n", "seconds", "total"]);
2226
- function buildSchemaDefinitions(messages, numericNames = numericPlaceholders$2) {
2249
+ const numericPlaceholders$3 = /* @__PURE__ */ new Set(["complete", "minMemory", "minSpeed", "n", "seconds", "total"]);
2250
+ function buildSchemaDefinitions(messages, numericNames = numericPlaceholders$3) {
2227
2251
  return Object.entries(messages).map(([key, value], index) => {
2228
2252
  const values = Array.isArray(value) ? value : [value];
2229
2253
  const metadata = values.map((message) => inspectIcuMessage(message));
@@ -2378,23 +2402,22 @@ const SCHEMA_V3_FR_MESSAGES = {
2378
2402
  })
2379
2403
  };
2380
2404
  const SCHEMA_V3_DEFINITIONS = buildSchemaDefinitions(SCHEMA_V3_EN_MESSAGES);
2381
- const sourceKeys$2 = Object.keys(SCHEMA_V3_EN_MESSAGES).sort();
2382
- const localeKeys$2 = Object.keys(SCHEMA_V3_FR_MESSAGES).sort();
2383
- if (sourceKeys$2.join("\0") !== localeKeys$2.join("\0")) {
2405
+ const sourceKeys$3 = Object.keys(SCHEMA_V3_EN_MESSAGES).sort();
2406
+ const localeKeys$3 = Object.keys(SCHEMA_V3_FR_MESSAGES).sort();
2407
+ if (sourceKeys$3.join("\0") !== localeKeys$3.join("\0")) {
2384
2408
  throw new Error("Schema v3 locale keys do not match the English source catalog");
2385
2409
  }
2386
2410
  const CONTENT_SCHEMA_V4_VERSION = 4;
2387
- function buildV4Messages(messages, mediaHelp, deviceSettings) {
2388
- const catalog = buildCandidateCatalogMessages(messages, mediaHelp, { deviceSettings });
2389
- return catalog;
2411
+ function buildV4Messages(messages, mediaHelp, deviceSettings, publishedConnectionCopy) {
2412
+ return preservePublishedConnectionCopy(buildCandidateCatalogMessages(messages, mediaHelp, { deviceSettings }), publishedConnectionCopy);
2390
2413
  }
2391
2414
  const SCHEMA_V4_EN_MESSAGES = {
2392
- ...buildV4Messages(DEFAULT_MESSAGES, MEDIA_HELP_EN, DEFAULT_DEVICE_SETTINGS_MESSAGES)
2415
+ ...buildV4Messages(DEFAULT_MESSAGES, MEDIA_HELP_EN, DEFAULT_DEVICE_SETTINGS_MESSAGES, PUBLISHED_CONNECTION_COPY_EN)
2393
2416
  };
2394
2417
  const SCHEMA_V4_FR_MESSAGES = {
2395
- ...buildV4Messages(MESSAGES_FR, MEDIA_HELP_FR, DEVICE_SETTINGS_MESSAGES_FR)
2418
+ ...buildV4Messages(MESSAGES_FR, MEDIA_HELP_FR, DEVICE_SETTINGS_MESSAGES_FR, PUBLISHED_CONNECTION_COPY_FR)
2396
2419
  };
2397
- const numericPlaceholders$1 = /* @__PURE__ */ new Set([
2420
+ const numericPlaceholders$2 = /* @__PURE__ */ new Set([
2398
2421
  "complete",
2399
2422
  "count",
2400
2423
  "height",
@@ -2406,19 +2429,48 @@ const numericPlaceholders$1 = /* @__PURE__ */ new Set([
2406
2429
  "total",
2407
2430
  "width"
2408
2431
  ]);
2409
- const SCHEMA_V4_DEFINITIONS = buildSchemaDefinitions(SCHEMA_V4_EN_MESSAGES, numericPlaceholders$1);
2410
- const sourceKeys$1 = Object.keys(SCHEMA_V4_EN_MESSAGES).sort();
2411
- const localeKeys$1 = Object.keys(SCHEMA_V4_FR_MESSAGES).sort();
2412
- if (sourceKeys$1.join("\0") !== localeKeys$1.join("\0")) {
2432
+ const SCHEMA_V4_DEFINITIONS = buildSchemaDefinitions(SCHEMA_V4_EN_MESSAGES, numericPlaceholders$2);
2433
+ const sourceKeys$2 = Object.keys(SCHEMA_V4_EN_MESSAGES).sort();
2434
+ const localeKeys$2 = Object.keys(SCHEMA_V4_FR_MESSAGES).sort();
2435
+ if (sourceKeys$2.join("\0") !== localeKeys$2.join("\0")) {
2413
2436
  throw new Error("Schema v4 locale keys do not match the English source catalog");
2414
2437
  }
2415
2438
  const CONTENT_SCHEMA_V5_VERSION = 5;
2416
2439
  const SCHEMA_V5_EN_MESSAGES = {
2440
+ ...preservePublishedConnectionCopy(buildCandidateCatalogMessages(DEFAULT_MESSAGES, MEDIA_HELP_EN, {
2441
+ deviceSettings: DEFAULT_DEVICE_SETTINGS_MESSAGES
2442
+ }), PUBLISHED_CONNECTION_COPY_EN)
2443
+ };
2444
+ const SCHEMA_V5_FR_MESSAGES = {
2445
+ ...preservePublishedConnectionCopy(buildCandidateCatalogMessages(MESSAGES_FR, MEDIA_HELP_FR, {
2446
+ deviceSettings: DEVICE_SETTINGS_MESSAGES_FR
2447
+ }), PUBLISHED_CONNECTION_COPY_FR)
2448
+ };
2449
+ const numericPlaceholders$1 = /* @__PURE__ */ new Set([
2450
+ "complete",
2451
+ "count",
2452
+ "height",
2453
+ "minMemory",
2454
+ "minSpeed",
2455
+ "n",
2456
+ "seconds",
2457
+ "speed",
2458
+ "total",
2459
+ "width"
2460
+ ]);
2461
+ const SCHEMA_V5_DEFINITIONS = buildSchemaDefinitions(SCHEMA_V5_EN_MESSAGES, numericPlaceholders$1);
2462
+ const sourceKeys$1 = Object.keys(SCHEMA_V5_EN_MESSAGES).sort();
2463
+ const localeKeys$1 = Object.keys(SCHEMA_V5_FR_MESSAGES).sort();
2464
+ if (sourceKeys$1.join("\0") !== localeKeys$1.join("\0")) {
2465
+ throw new Error("Schema v5 locale keys do not match the English source catalog");
2466
+ }
2467
+ const CONTENT_SCHEMA_V6_VERSION = 6;
2468
+ const SCHEMA_V6_EN_MESSAGES = {
2417
2469
  ...buildCandidateCatalogMessages(DEFAULT_MESSAGES, MEDIA_HELP_EN, {
2418
2470
  deviceSettings: DEFAULT_DEVICE_SETTINGS_MESSAGES
2419
2471
  })
2420
2472
  };
2421
- const SCHEMA_V5_FR_MESSAGES = {
2473
+ const SCHEMA_V6_FR_MESSAGES = {
2422
2474
  ...buildCandidateCatalogMessages(MESSAGES_FR, MEDIA_HELP_FR, {
2423
2475
  deviceSettings: DEVICE_SETTINGS_MESSAGES_FR
2424
2476
  })
@@ -2435,11 +2487,11 @@ const numericPlaceholders = /* @__PURE__ */ new Set([
2435
2487
  "total",
2436
2488
  "width"
2437
2489
  ]);
2438
- const SCHEMA_V5_DEFINITIONS = buildSchemaDefinitions(SCHEMA_V5_EN_MESSAGES, numericPlaceholders);
2439
- const sourceKeys = Object.keys(SCHEMA_V5_EN_MESSAGES).sort();
2440
- const localeKeys = Object.keys(SCHEMA_V5_FR_MESSAGES).sort();
2490
+ const SCHEMA_V6_DEFINITIONS = buildSchemaDefinitions(SCHEMA_V6_EN_MESSAGES, numericPlaceholders);
2491
+ const sourceKeys = Object.keys(SCHEMA_V6_EN_MESSAGES).sort();
2492
+ const localeKeys = Object.keys(SCHEMA_V6_FR_MESSAGES).sort();
2441
2493
  if (sourceKeys.join("\0") !== localeKeys.join("\0")) {
2442
- throw new Error("Schema v5 locale keys do not match the English source catalog");
2494
+ throw new Error("Schema v6 locale keys do not match the English source catalog");
2443
2495
  }
2444
2496
  const CONTENT_SCHEMA_LINES = [
2445
2497
  {
@@ -2466,9 +2518,14 @@ const CONTENT_SCHEMA_LINES = [
2466
2518
  version: CONTENT_SCHEMA_V5_VERSION,
2467
2519
  definitions: SCHEMA_V5_DEFINITIONS,
2468
2520
  messagesByLocale: { en: SCHEMA_V5_EN_MESSAGES, fr: SCHEMA_V5_FR_MESSAGES }
2521
+ },
2522
+ {
2523
+ version: CONTENT_SCHEMA_V6_VERSION,
2524
+ definitions: SCHEMA_V6_DEFINITIONS,
2525
+ messagesByLocale: { en: SCHEMA_V6_EN_MESSAGES, fr: SCHEMA_V6_FR_MESSAGES }
2469
2526
  }
2470
2527
  ];
2471
- const LATEST_CONTENT_SCHEMA_VERSION = CONTENT_SCHEMA_V5_VERSION;
2528
+ const LATEST_CONTENT_SCHEMA_VERSION = CONTENT_SCHEMA_V6_VERSION;
2472
2529
  function getContentSchemaLine(version2) {
2473
2530
  const schema = CONTENT_SCHEMA_LINES.find((candidate) => candidate.version === version2);
2474
2531
  if (!schema)
@@ -7220,7 +7277,7 @@ const supportedLocales = [
7220
7277
  { code: "fr", endonym: "Français", direction: "ltr" }
7221
7278
  ];
7222
7279
  const release = {
7223
- releaseId: "bundled-schema-5",
7280
+ releaseId: "bundled-schema-6",
7224
7281
  releaseNumber: 1,
7225
7282
  publishedAt: "2026-07-17T00:00:00.000Z",
7226
7283
  supportedLocales
@@ -7230,14 +7287,14 @@ const BUNDLED_EN_MANIFEST = compileManifest({
7230
7287
  schemaVersion: LATEST_CONTENT_SCHEMA_VERSION,
7231
7288
  requestedLocale: "en",
7232
7289
  locale: supportedLocales[0],
7233
- messages: SCHEMA_V5_EN_MESSAGES
7290
+ messages: SCHEMA_V6_EN_MESSAGES
7234
7291
  });
7235
7292
  const BUNDLED_FR_MANIFEST = compileManifest({
7236
7293
  ...release,
7237
7294
  schemaVersion: LATEST_CONTENT_SCHEMA_VERSION,
7238
7295
  requestedLocale: "fr",
7239
7296
  locale: supportedLocales[1],
7240
- messages: SCHEMA_V5_FR_MESSAGES
7297
+ messages: SCHEMA_V6_FR_MESSAGES
7241
7298
  });
7242
7299
  const usePreflightCheck = (options = {}) => {
7243
7300
  const engineOptions = options;
@@ -7779,7 +7836,12 @@ const usePreflightTelemetry = (options) => {
7779
7836
  ...row.mbps !== void 0 ? { downloadMbps: row.mbps } : {},
7780
7837
  ...row.uploadMbps !== void 0 ? { uploadMbps: row.uploadMbps } : {},
7781
7838
  ...row.latencyMs !== void 0 ? { latencyMs: row.latencyMs } : {},
7782
- ...row.jitterMs !== void 0 ? { jitterMs: row.jitterMs } : {}
7839
+ ...row.jitterMs !== void 0 ? { jitterMs: row.jitterMs } : {},
7840
+ ...row.recordingUploadMode !== void 0 ? { recordingUploadMode: row.recordingUploadMode } : {},
7841
+ ...row.readinessPayloadBytes !== void 0 ? { readinessPayloadBytes: row.readinessPayloadBytes } : {},
7842
+ ...row.readinessMedianMs !== void 0 ? { readinessMedianMs: row.readinessMedianMs } : {},
7843
+ ...row.readinessWindowMs !== void 0 ? { readinessWindowMs: row.readinessWindowMs } : {},
7844
+ ...row.readinessSampleCount !== void 0 ? { readinessSampleCount: row.readinessSampleCount } : {}
7783
7845
  };
7784
7846
  };
7785
7847
  onMounted(() => {
@@ -16593,6 +16655,7 @@ const _sfc_main$t = /* @__PURE__ */ defineComponent({
16593
16655
  }
16594
16656
  return localizedSystemDetail(row, row.state.detail, details);
16595
16657
  case "fail":
16658
+ if (row.kind === "connection") return "";
16596
16659
  return localizedSystemDetail(row, row.state.detail, details);
16597
16660
  case "skipped":
16598
16661
  return props.messages.rowSkipped;
@@ -16682,16 +16745,12 @@ const _sfc_main$t = /* @__PURE__ */ defineComponent({
16682
16745
  );
16683
16746
  const failMessage = (row) => {
16684
16747
  if (row.state.kind !== "fail") return "";
16685
- const isUploadFailure = row.kind === "connection" && row.state.detail.startsWith("Upload ");
16686
- const minSpeed = isUploadFailure ? props.minUploadBandwidthMbps ?? MIN_SPEED_MBPS : props.minBandwidthMbps ?? MIN_SPEED_MBPS;
16687
- const template = isUploadFailure ? props.messages.wizard.system.slowUploadMessage : props.messages.failMessages[row.state.code];
16688
- return template.replace("{minMemory}", String(MIN_DEVICE_MEMORY_GB)).replace("{minSpeed}", String(minSpeed)).replace("{speed}", row.state.detail.replace(/^Upload\s+/, "").replace(/\s*Mbps$/i, "")).replace("{retry}", props.messages.wizard.system.retryLabel);
16748
+ const template = row.kind === "connection" ? props.messages.failMessages["speed-test-failed"] : props.messages.failMessages[row.state.code];
16749
+ return template.replace("{minMemory}", String(MIN_DEVICE_MEMORY_GB)).replace("{retry}", props.messages.wizard.system.retryLabel);
16689
16750
  };
16690
16751
  const failTitle = (row) => {
16691
16752
  if (row.state.kind !== "fail") return props.messages.failHeaders[row.kind];
16692
- if (row.kind === "connection" && row.state.detail.startsWith("Upload ")) {
16693
- return props.messages.wizard.system.slowUploadTitle;
16694
- }
16753
+ if (row.kind === "connection") return props.messages.failHeaders.connection;
16695
16754
  return props.messages.failCodeHeaders[row.state.code] ?? props.messages.failHeaders[row.kind];
16696
16755
  };
16697
16756
  const cardStatus = computed(() => {
@@ -21945,7 +22004,7 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
21945
22004
  }
21946
22005
  } : supplied;
21947
22006
  const baseUrl = detectFaceBaseUrlFromIngestUrl(props.ingestUrl);
21948
- const options = props.appId && configured.system?.connection !== false && !configured.connectionTest ? {
22007
+ const options = props.appId && configured.system?.connection !== false && !configured.connectionReadiness && !configured.connectionTest ? {
21949
22008
  ...configured,
21950
22009
  connectionTest: {
21951
22010
  downloadUrl: `${baseUrl}/preflight/network/download`,
@@ -24059,6 +24118,34 @@ function buildPreflightEngineOptions(policy, detectFace) {
24059
24118
  ...policy.preflight.camera && detectFace ? { deepCamera: { detectFace } } : {}
24060
24119
  };
24061
24120
  }
24121
+ function recordingReadinessWorkload(policy) {
24122
+ const streams = [];
24123
+ if (policy.proctoring.screenShare.enabled) {
24124
+ streams.push({
24125
+ bitrate: positiveNumber(policy.proctoring.screenShare.videoBitrate, 5e5),
24126
+ chunkMs: positiveNumber(policy.proctoring.screenShare.chunkMs, 1e4)
24127
+ });
24128
+ }
24129
+ if (policy.proctoring.webcam.mode === "recording") {
24130
+ streams.push({
24131
+ bitrate: positiveNumber(policy.proctoring.webcam.recordVideoBitrate, 5e5),
24132
+ chunkMs: positiveNumber(policy.proctoring.webcam.recordChunkMs, 1e4)
24133
+ });
24134
+ }
24135
+ if (streams.length === 0) return null;
24136
+ const workloadWindowMs = Math.min(...streams.map((stream) => stream.chunkMs));
24137
+ const totalBitrate = streams.reduce((sum, stream) => sum + stream.bitrate, 0);
24138
+ return {
24139
+ payloadBytes: Math.min(
24140
+ 1e7,
24141
+ Math.max(1024, Math.ceil(totalBitrate * workloadWindowMs / 8e3))
24142
+ ),
24143
+ completionWindowMs: Math.max(1e3, Math.round(workloadWindowMs / 2))
24144
+ };
24145
+ }
24146
+ function positiveNumber(value, fallback) {
24147
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
24148
+ }
24062
24149
  function buildSdkObservers(policy) {
24063
24150
  const screenShareEnabled = policy.proctoring.screenShare.enabled;
24064
24151
  const snapshotInterval = resolveSnapshotIntervalMs(policy.proctoring.webcam);
@@ -24300,7 +24387,7 @@ function deepFreeze(value) {
24300
24387
  }
24301
24388
  return Object.freeze(value);
24302
24389
  }
24303
- const workerSource = 'const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\nfunction getIdbProxyableTypes() {\n return idbProxyableTypes || (idbProxyableTypes = [\n IDBDatabase,\n IDBObjectStore,\n IDBIndex,\n IDBCursor,\n IDBTransaction\n ]);\n}\nfunction getCursorAdvanceMethods() {\n return cursorAdvanceMethods || (cursorAdvanceMethods = [\n IDBCursor.prototype.advance,\n IDBCursor.prototype.continue,\n IDBCursor.prototype.continuePrimaryKey\n ]);\n}\nconst transactionDoneMap = /* @__PURE__ */ new WeakMap();\nconst transformCache = /* @__PURE__ */ new WeakMap();\nconst reverseTransformCache = /* @__PURE__ */ new WeakMap();\nfunction promisifyRequest(request) {\n const promise = new Promise((resolve, reject) => {\n const unlisten = () => {\n request.removeEventListener("success", success);\n request.removeEventListener("error", error);\n };\n const success = () => {\n resolve(wrap(request.result));\n unlisten();\n };\n const error = () => {\n reject(request.error);\n unlisten();\n };\n request.addEventListener("success", success);\n request.addEventListener("error", error);\n });\n reverseTransformCache.set(promise, request);\n return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n if (transactionDoneMap.has(tx))\n return;\n const done = new Promise((resolve, reject) => {\n const unlisten = () => {\n tx.removeEventListener("complete", complete);\n tx.removeEventListener("error", error);\n tx.removeEventListener("abort", error);\n };\n const complete = () => {\n resolve();\n unlisten();\n };\n const error = () => {\n reject(tx.error || new DOMException("AbortError", "AbortError"));\n unlisten();\n };\n tx.addEventListener("complete", complete);\n tx.addEventListener("error", error);\n tx.addEventListener("abort", error);\n });\n transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n get(target, prop, receiver) {\n if (target instanceof IDBTransaction) {\n if (prop === "done")\n return transactionDoneMap.get(target);\n if (prop === "store") {\n return receiver.objectStoreNames[1] ? void 0 : receiver.objectStore(receiver.objectStoreNames[0]);\n }\n }\n return wrap(target[prop]);\n },\n set(target, prop, value) {\n target[prop] = value;\n return true;\n },\n has(target, prop) {\n if (target instanceof IDBTransaction && (prop === "done" || prop === "store")) {\n return true;\n }\n return prop in target;\n }\n};\nfunction replaceTraps(callback) {\n idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n if (getCursorAdvanceMethods().includes(func)) {\n return function(...args) {\n func.apply(unwrap(this), args);\n return wrap(this.request);\n };\n }\n return function(...args) {\n return wrap(func.apply(unwrap(this), args));\n };\n}\nfunction transformCachableValue(value) {\n if (typeof value === "function")\n return wrapFunction(value);\n if (value instanceof IDBTransaction)\n cacheDonePromiseForTransaction(value);\n if (instanceOfAny(value, getIdbProxyableTypes()))\n return new Proxy(value, idbProxyTraps);\n return value;\n}\nfunction wrap(value) {\n if (value instanceof IDBRequest)\n return promisifyRequest(value);\n if (transformCache.has(value))\n return transformCache.get(value);\n const newValue = transformCachableValue(value);\n if (newValue !== value) {\n transformCache.set(value, newValue);\n reverseTransformCache.set(newValue, value);\n }\n return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n const request = indexedDB.open(name, version);\n const openPromise = wrap(request);\n if (upgrade) {\n request.addEventListener("upgradeneeded", (event) => {\n upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);\n });\n }\n if (blocked) {\n request.addEventListener("blocked", (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion,\n event.newVersion,\n event\n ));\n }\n openPromise.then((db) => {\n if (terminated)\n db.addEventListener("close", () => terminated());\n if (blocking) {\n db.addEventListener("versionchange", (event) => blocking(event.oldVersion, event.newVersion, event));\n }\n }).catch(() => {\n });\n return openPromise;\n}\nfunction deleteDB(name, { blocked } = {}) {\n const request = indexedDB.deleteDatabase(name);\n if (blocked) {\n request.addEventListener("blocked", (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion,\n event\n ));\n }\n return wrap(request).then(() => void 0);\n}\nconst readMethods = ["get", "getKey", "getAll", "getAllKeys", "count"];\nconst writeMethods = ["put", "add", "delete", "clear"];\nconst cachedMethods = /* @__PURE__ */ new Map();\nfunction getMethod(target, prop) {\n if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === "string")) {\n return;\n }\n if (cachedMethods.get(prop))\n return cachedMethods.get(prop);\n const targetFuncName = prop.replace(/FromIndex$/, "");\n const useIndex = prop !== targetFuncName;\n const isWrite = writeMethods.includes(targetFuncName);\n if (\n // Bail if the target doesn\'t exist on the target. Eg, getAll isn\'t in Edge.\n !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))\n ) {\n return;\n }\n const method = async function(storeName, ...args) {\n const tx = this.transaction(storeName, isWrite ? "readwrite" : "readonly");\n let target2 = tx.store;\n if (useIndex)\n target2 = target2.index(args.shift());\n return (await Promise.all([\n target2[targetFuncName](...args),\n isWrite && tx.done\n ]))[0];\n };\n cachedMethods.set(prop, method);\n return method;\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop)\n}));\nconst advanceMethodProps = ["continue", "continuePrimaryKey", "advance"];\nconst methodMap = {};\nconst advanceResults = /* @__PURE__ */ new WeakMap();\nconst ittrProxiedCursorToOriginalProxy = /* @__PURE__ */ new WeakMap();\nconst cursorIteratorTraps = {\n get(target, prop) {\n if (!advanceMethodProps.includes(prop))\n return target[prop];\n let cachedFunc = methodMap[prop];\n if (!cachedFunc) {\n cachedFunc = methodMap[prop] = function(...args) {\n advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));\n };\n }\n return cachedFunc;\n }\n};\nasync function* iterate(...args) {\n let cursor = this;\n if (!(cursor instanceof IDBCursor)) {\n cursor = await cursor.openCursor(...args);\n }\n if (!cursor)\n return;\n cursor = cursor;\n const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);\n ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);\n reverseTransformCache.set(proxiedCursor, unwrap(cursor));\n while (cursor) {\n yield proxiedCursor;\n cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());\n advanceResults.delete(proxiedCursor);\n }\n}\nfunction isIteratorProp(target, prop) {\n return prop === Symbol.asyncIterator && instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor]) || prop === "iterate" && instanceOfAny(target, [IDBIndex, IDBObjectStore]);\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get(target, prop, receiver) {\n if (isIteratorProp(target, prop))\n return iterate;\n return oldTraps.get(target, prop, receiver);\n },\n has(target, prop) {\n return isIteratorProp(target, prop) || oldTraps.has(target, prop);\n }\n}));\nconst DEFAULT_DB_NAME = "proctoring-sdk";\nconst DEFAULT_MAX_BYTES = 50 * 1024 * 1024;\nconst SEQ_KEY = "seq";\nconst BYTES_KEY = "bytes";\nconst SESSION_DB_PREFIX = "proctoring-sess";\nfunction sessionDbName(sessionId) {\n return `proctoring-${sessionId}`;\n}\nclass EventQueue {\n db = null;\n memory = null;\n dbName;\n maxBytes;\n storage;\n fallbackToMemory;\n constructor(options = {}) {\n this.dbName = options.dbName ?? DEFAULT_DB_NAME;\n this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n this.storage = options.storage ?? "indexeddb";\n this.fallbackToMemory = options.fallbackToMemory ?? true;\n }\n /** Opens (or upgrades) the underlying IndexedDB database. Must be called once before any other method. Idempotent. */\n async open() {\n if (this.db || this.memory) return;\n if (this.storage === "memory") {\n this.openMemory("configured-memory-storage");\n return;\n }\n try {\n this.db = await openDB(this.dbName, 1, {\n upgrade(db) {\n const events = db.createObjectStore("events", { keyPath: "id" });\n events.createIndex("by-seq", "seq");\n db.createObjectStore("meta", { keyPath: "key" });\n }\n });\n } catch (err) {\n if (!this.fallbackToMemory) throw err;\n this.openMemory(indexedDbOpenFailureReason(err));\n }\n }\n storageMode() {\n return this.memory ? "memory" : "indexeddb";\n }\n storageFallbackReason() {\n return this.memory?.reason ?? null;\n }\n /**\n * Appends an event to the tail. If the queue would exceed\n * `maxBytes`, drops the oldest events until it fits — the new\n * event is never the one dropped. Returns the count of dropped\n * events so callers can surface backpressure to the host.\n */\n async enqueue(event) {\n if (this.memory) return this.enqueueMemory(event);\n const db = this.requireDb();\n const bytes = byteLength(event);\n const tx = db.transaction(["events", "meta"], "readwrite");\n const events = tx.objectStore("events");\n const meta = tx.objectStore("meta");\n const seq = ((await meta.get(SEQ_KEY))?.value ?? 0) + 1;\n let totalBytes = ((await meta.get(BYTES_KEY))?.value ?? 0) + bytes;\n await events.put({ ...event, seq, bytes });\n await meta.put({ key: SEQ_KEY, value: seq });\n let dropped = 0;\n if (totalBytes > this.maxBytes) {\n const cursor = await events.index("by-seq").openCursor();\n let c = cursor;\n while (c && totalBytes > this.maxBytes) {\n const stored = c.value;\n if (stored.id === event.id) {\n c = await c.continue();\n continue;\n }\n totalBytes -= stored.bytes;\n dropped += 1;\n await c.delete();\n c = await c.continue();\n }\n }\n await meta.put({ key: BYTES_KEY, value: totalBytes });\n await tx.done;\n return { dropped };\n }\n /** Returns up to `limit` oldest events without removing them. */\n async peek(limit) {\n if (this.memory) {\n return this.memory.events.slice(0, limit).map(({ seq: _seq, bytes: _bytes, ...event }) => event);\n }\n const db = this.requireDb();\n const tx = db.transaction("events", "readonly");\n const out = [];\n let cursor = await tx.store.index("by-seq").openCursor();\n while (cursor && out.length < limit) {\n const { seq: _seq, bytes: _bytes, ...event } = cursor.value;\n out.push(event);\n cursor = await cursor.continue();\n }\n return out;\n }\n /**\n * Removes events by id. Unknown ids are silently skipped so callers\n * can safely ack the same id twice (eg. when an idempotency-keyed\n * server retry returns success after we already acked locally).\n */\n async ack(ids) {\n if (ids.length === 0) return;\n if (this.memory) {\n const idSet = new Set(ids);\n let bytes = this.memory.bytes;\n this.memory.events = this.memory.events.filter((event) => {\n if (!idSet.has(event.id)) return true;\n bytes -= event.bytes;\n return false;\n });\n this.memory.bytes = Math.max(0, bytes);\n return;\n }\n const db = this.requireDb();\n const tx = db.transaction(["events", "meta"], "readwrite");\n const events = tx.objectStore("events");\n const meta = tx.objectStore("meta");\n let totalBytes = (await meta.get(BYTES_KEY))?.value ?? 0;\n for (const id of ids) {\n const stored = await events.get(id);\n if (!stored) continue;\n totalBytes -= stored.bytes;\n await events.delete(id);\n }\n await meta.put({ key: BYTES_KEY, value: Math.max(0, totalBytes) });\n await tx.done;\n }\n /** Number of events currently queued. */\n async size() {\n if (this.memory) return this.memory.events.length;\n const db = this.requireDb();\n return db.count("events");\n }\n /** Cumulative byte size of all queued events (JSON-encoded). */\n async bytes() {\n if (this.memory) return this.memory.bytes;\n const db = this.requireDb();\n return (await db.get("meta", BYTES_KEY))?.value ?? 0;\n }\n /** Closes the database handle. Safe to call multiple times. */\n async close() {\n this.db?.close();\n this.db = null;\n this.memory = null;\n }\n /**\n * Closes the handle AND deletes the underlying database from disk.\n *\n * Call this only once the queue is known to be fully drained — a\n * deleted database takes any not-yet-uploaded events with it. The\n * worker gates this on `size() === 0` after draining at teardown, so\n * an offline teardown (events still queued) keeps the database for a\n * later page load to flush. Reclaiming the database is what stops the\n * per-session databases accumulating until the origin hits its\n * storage quota and `open()` starts throwing.\n */\n async destroy() {\n if (this.memory) {\n await this.close();\n return;\n }\n await this.close();\n await deleteDB(this.dbName);\n }\n /**\n * Best-effort reclamation of leaked per-session databases left by\n * earlier sessions on this origin. Enumerates all IndexedDB\n * databases, and for each `proctoring-sess-*` one NOT in `keep`,\n * opens it, checks it holds zero events, and deletes it if so. A\n * database with pending events is left alone — it may still flush on\n * a future load.\n *\n * No-ops where `indexedDB.databases()` is unavailable (Firefox, older\n * Safari): there is no enumeration API there, so leaked databases\n * can\'t be discovered. New sessions still self-clean via destroy(),\n * so the leak is bounded going forward even on those browsers.\n *\n * Never throws — cleanup must not be able to fail a session.\n */\n static async sweepStale(keep = /* @__PURE__ */ new Set()) {\n let removed = 0;\n try {\n if (typeof indexedDB === "undefined" || typeof indexedDB.databases !== "function") {\n return 0;\n }\n const entries = await indexedDB.databases();\n for (const { name } of entries) {\n if (!name || keep.has(name) || !name.startsWith(SESSION_DB_PREFIX)) {\n continue;\n }\n try {\n const queue = new EventQueue({ dbName: name });\n await queue.open();\n const pending = await queue.size();\n await queue.close();\n if (pending === 0) {\n await deleteDB(name);\n removed += 1;\n }\n } catch {\n }\n }\n } catch {\n }\n return removed;\n }\n requireDb() {\n if (!this.db) {\n throw new Error("EventQueue: call open() before any other operation");\n }\n return this.db;\n }\n openMemory(reason) {\n this.db = null;\n this.memory = {\n events: [],\n seq: 0,\n bytes: 0,\n reason\n };\n }\n enqueueMemory(event) {\n if (!this.memory) {\n throw new Error("EventQueue: call open() before any other operation");\n }\n const bytes = byteLength(event);\n const stored = {\n ...event,\n seq: this.memory.seq + 1,\n bytes\n };\n this.memory.seq = stored.seq;\n this.memory.events.push(stored);\n this.memory.bytes += bytes;\n let dropped = 0;\n while (this.memory.events.length > 1 && this.memory.bytes > this.maxBytes) {\n const oldest = this.memory.events[0];\n if (!oldest || oldest.id === event.id) break;\n this.memory.events.shift();\n this.memory.bytes -= oldest.bytes;\n dropped += 1;\n }\n return { dropped };\n }\n}\nfunction byteLength(event) {\n return new TextEncoder().encode(JSON.stringify(event)).byteLength;\n}\nfunction indexedDbOpenFailureReason(err) {\n if (err instanceof Error) {\n return `${err.name}: ${err.message}`;\n }\n return String(err);\n}\nclass DeliveryReadinessError extends Error {\n code;\n status;\n constructor(code, message, options) {\n super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);\n this.name = "DeliveryReadinessError";\n this.code = code;\n this.status = options?.status;\n }\n}\nfunction newId(prefix) {\n if (typeof crypto !== "undefined" && "randomUUID" in crypto) {\n return crypto.randomUUID();\n }\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\nconst EVENT_REQUEST_TIMEOUT_MS = 1e4;\nclass RequestDeadlineError extends Error {\n constructor(operation, timeoutMs) {\n super(`${operation} timed out after ${timeoutMs}ms`);\n this.operation = operation;\n this.timeoutMs = timeoutMs;\n this.name = "RequestDeadlineError";\n }\n code = "request-timeout";\n}\nasync function withRequestDeadline(operation, timeoutMs, run, parentSignal) {\n if (parentSignal?.aborted) throw abortError();\n const controller = new AbortController();\n let timedOut = false;\n let timer;\n let onParentAbort;\n const cancelled = new Promise((_resolve, reject) => {\n onParentAbort = () => {\n controller.abort();\n reject(abortError());\n };\n parentSignal?.addEventListener("abort", onParentAbort, { once: true });\n timer = setTimeout(\n () => {\n timedOut = true;\n controller.abort();\n reject(new RequestDeadlineError(operation, timeoutMs));\n },\n Math.max(0, timeoutMs)\n );\n });\n try {\n return await Promise.race([Promise.resolve().then(() => run(controller.signal)), cancelled]);\n } catch (error) {\n if (timedOut) throw new RequestDeadlineError(operation, timeoutMs);\n throw error;\n } finally {\n if (timer !== void 0) clearTimeout(timer);\n if (onParentAbort) parentSignal?.removeEventListener("abort", onParentAbort);\n }\n}\nfunction abortError() {\n const error = new Error("The request was aborted");\n error.name = "AbortError";\n return error;\n}\nclass Uploader {\n opts;\n events = {};\n timer = null;\n draining = false;\n stopped = false;\n controller = null;\n constructor(options) {\n this.opts = {\n queue: options.queue,\n ingestUrl: options.ingestUrl,\n sessionId: options.sessionId,\n batchSize: options.batchSize ?? 50,\n batchIntervalMs: options.batchIntervalMs ?? 2e3,\n maxRetries: options.maxRetries ?? 5,\n fetchImpl: options.fetchImpl ?? fetch.bind(globalThis),\n newBatchId: options.newBatchId ?? (() => newId("batch")),\n appId: options.appId ?? null,\n candidate: options.candidate ?? (() => void 0)\n };\n }\n /** Replaces the lifecycle handlers. The Uploader keeps a single set; pass `{}` to clear. */\n on(events) {\n this.events = events;\n }\n /** Starts the periodic drain timer. No-op if already started or stopped. */\n start() {\n if (this.timer || this.stopped) return;\n this.timer = setInterval(() => {\n void this.drain();\n }, this.opts.batchIntervalMs);\n }\n /**\n * Drains the queue in batches until empty, no progress was made, or\n * a send fails. Re-entrant calls are guarded — only one drain runs\n * at a time even under concurrent invocations.\n */\n async drain() {\n if (this.draining || this.stopped) return;\n this.draining = true;\n try {\n while (!this.stopped) {\n const events = await this.opts.queue.peek(this.opts.batchSize);\n if (events.length === 0) return;\n const sizeBefore = await this.opts.queue.size();\n const result = await this.sendBatch(events, { keepalive: false });\n if (!result.progress) return;\n const sizeAfter = await this.opts.queue.size();\n if (sizeAfter >= sizeBefore) return;\n }\n } finally {\n this.draining = false;\n }\n }\n /**\n * Sends one batch. With `keepalive: true` the request survives page\n * navigation but is capped by the browser to ~64KB total in-flight;\n * we therefore send at most one batch and do not retry on failure.\n */\n async flush(options) {\n const events = await this.opts.queue.peek(this.opts.batchSize);\n if (events.length === 0) return;\n await this.sendBatch(events, { keepalive: options.keepalive, noRetry: options.keepalive });\n }\n /**\n * Prove that the real ingest route accepts an event before SDK readiness is\n * announced. This uses the same request builder, auth headers, response\n * validation, and retry path as normal queue delivery. It is intentionally\n * not configurable by SDK consumers.\n */\n async verifyDelivery(event, timeoutMs) {\n const result = await this.sendBatch([event], {\n keepalive: false,\n ackQueue: false,\n maxAttempts: 2,\n timeoutMs\n });\n if (result.accepted.includes(event.id)) return;\n if (result.rejected.includes(event.id)) {\n throw new DeliveryReadinessError(\n "ingest-rejected",\n "The evidence ingest route rejected the delivery canary.",\n { status: result.status }\n );\n }\n if (result.timedOut) {\n throw new DeliveryReadinessError(\n "ingest-timeout",\n "Timed out while verifying evidence delivery.",\n { cause: result.error }\n );\n }\n if (result.status === 401 || result.status === 403) {\n throw new DeliveryReadinessError(\n "ingest-not-authorized",\n "The evidence ingest route did not authorize this application and origin.",\n { status: result.status, cause: result.error }\n );\n }\n if (result.status !== void 0 && result.status >= 400 && result.status < 500) {\n throw new DeliveryReadinessError(\n "ingest-rejected",\n "The evidence ingest route rejected the delivery canary.",\n { status: result.status, cause: result.error }\n );\n }\n if (result.invalidResponse) {\n throw new DeliveryReadinessError(\n "ingest-invalid-response",\n "The evidence ingest route returned an invalid acknowledgement.",\n { cause: result.error }\n );\n }\n throw new DeliveryReadinessError(\n "ingest-unreachable",\n "The evidence ingest route could not be reached.",\n { cause: result.error, status: result.status }\n );\n }\n /** Stops the drain timer and aborts any in-flight non-keepalive request. */\n async stop() {\n this.stopped = true;\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.controller?.abort();\n }\n async sendBatch(events, {\n keepalive,\n noRetry = false,\n ackQueue = true,\n maxAttempts = this.opts.maxRetries,\n timeoutMs\n }) {\n const batchId = this.opts.newBatchId();\n const candidate = this.opts.candidate();\n const body = {\n batchId,\n sessionId: this.opts.sessionId,\n events,\n ...candidate ? { candidate } : {}\n };\n const controller = keepalive ? null : new AbortController();\n this.controller = controller;\n const signal = controller?.signal;\n let timedOut = false;\n const deadlineAt = timeoutMs === void 0 ? void 0 : Date.now() + timeoutMs;\n const timeout = controller && timeoutMs !== void 0 ? setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, timeoutMs) : null;\n let lastError;\n let lastStatus;\n let invalidResponse = false;\n try {\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n if (this.stopped && !keepalive) {\n return { progress: false, accepted: [], rejected: [] };\n }\n let res;\n let parsedResponse;\n let parseError;\n try {\n const attemptTimeoutMs = deadlineAt === void 0 ? EVENT_REQUEST_TIMEOUT_MS : Math.max(1, Math.min(EVENT_REQUEST_TIMEOUT_MS, deadlineAt - Date.now()));\n const response = keepalive ? await this.opts.fetchImpl(this.opts.ingestUrl, {\n method: "POST",\n headers: {\n "content-type": "application/json",\n "idempotency-key": batchId,\n ...this.opts.appId ? { "x-app-id": this.opts.appId } : {}\n },\n body: JSON.stringify(body),\n keepalive\n }) : await withRequestDeadline(\n "event-ingest",\n attemptTimeoutMs,\n async (requestSignal) => {\n const request = await this.opts.fetchImpl(this.opts.ingestUrl, {\n method: "POST",\n headers: {\n "content-type": "application/json",\n "idempotency-key": batchId,\n ...this.opts.appId ? { "x-app-id": this.opts.appId } : {}\n },\n body: JSON.stringify(body),\n keepalive: false,\n signal: requestSignal\n });\n if (request.ok) {\n try {\n parsedResponse = await request.json();\n } catch (error) {\n parseError = error instanceof Error ? error : new Error(String(error));\n }\n }\n return request;\n },\n signal\n );\n res = response;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n lastError = error;\n if (error instanceof RequestDeadlineError) timedOut = true;\n if (error.name === "AbortError") break;\n this.events.onUploadFailed?.(batchId, attempt, error);\n if (noRetry || attempt === maxAttempts) break;\n await sleep(backoffMs(attempt), signal);\n continue;\n }\n lastStatus = res.status;\n timedOut = false;\n if (res.ok) {\n let parsed;\n if (keepalive) {\n try {\n parsed = await res.json();\n } catch (error) {\n parseError = error instanceof Error ? error : new Error(String(error));\n parsed = { batchId, accepted: [], rejected: [] };\n }\n } else {\n parsed = parsedResponse ?? { batchId, accepted: [], rejected: [] };\n }\n if (parseError) {\n invalidResponse = true;\n lastError = parseError;\n this.events.onUploadFailed?.(batchId, attempt, lastError);\n if (noRetry || attempt === maxAttempts) break;\n await sleep(backoffMs(attempt), signal);\n continue;\n }\n const accepted = Array.isArray(parsed.accepted) ? parsed.accepted : [];\n const rejected = Array.isArray(parsed.rejected) ? parsed.rejected : [];\n if (accepted.length === 0 && rejected.length === 0) {\n invalidResponse = true;\n lastError = new Error("malformed response: empty accepted and rejected");\n this.events.onUploadFailed?.(batchId, attempt, lastError);\n } else {\n const toAck = [...accepted, ...rejected];\n if (ackQueue) await this.opts.queue.ack(toAck);\n this.events.onUploaded?.(batchId, accepted.length, accepted, rejected);\n return {\n progress: toAck.length > 0,\n accepted,\n rejected,\n status: res.status\n };\n }\n } else if (res.status >= 400 && res.status < 500 && res.status !== 408 && res.status !== 429) {\n lastError = new Error(`non-retryable ${res.status}`);\n this.events.onUploadFailed?.(batchId, attempt, lastError);\n return {\n progress: false,\n accepted: [],\n rejected: [],\n error: lastError,\n status: res.status\n };\n } else {\n lastError = new Error(`retryable ${res.status}`);\n this.events.onUploadFailed?.(batchId, attempt, lastError);\n }\n if (noRetry || attempt === maxAttempts) break;\n await sleep(backoffMs(attempt), signal);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n lastError = error;\n if (error.name !== "AbortError" || timedOut) {\n this.events.onUploadFailed?.(batchId, Math.max(1, maxAttempts), error);\n }\n } finally {\n if (timeout) clearTimeout(timeout);\n if (this.controller === controller) this.controller = null;\n }\n return {\n progress: false,\n accepted: [],\n rejected: [],\n ...lastError ? { error: lastError } : {},\n ...lastStatus !== void 0 ? { status: lastStatus } : {},\n ...timedOut ? { timedOut: true } : {},\n ...invalidResponse ? { invalidResponse: true } : {}\n };\n }\n}\nfunction backoffMs(attempt) {\n const base = Math.min(3e4, 500 * Math.pow(2, attempt - 1));\n const jitter = Math.random() * base * 0.25;\n return base + jitter;\n}\nfunction sleep(ms, signal) {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n const id = setTimeout(resolve, ms);\n signal?.addEventListener(\n "abort",\n () => {\n clearTimeout(id);\n resolve();\n },\n { once: true }\n );\n });\n}\nconst SDK_VERSION = "0.1.1";\nconst SDK_BUILD_SHA = "de98da0125619b3b2d4486f45c10d4a8f7a85113";\nconst SDK_BUILD_INFO = Object.freeze({\n sdkVersion: SDK_VERSION,\n buildSha: SDK_BUILD_SHA\n});\nconst DELIVERY_CANARY_TIMEOUT_MS = 8e3;\nclass WorkerCore {\n constructor(host, deps = {}) {\n this.host = host;\n this.deps = {\n queueFactory: deps.queueFactory ?? ((sessionId) => new EventQueue({ dbName: sessionDbName(sessionId) })),\n uploaderFactory: deps.uploaderFactory ?? ((queue, config) => new Uploader({\n queue,\n ingestUrl: config.ingestUrl,\n sessionId: config.sessionId,\n appId: config.appId,\n candidate: () => this.candidate,\n batchSize: config.batchSize,\n batchIntervalMs: config.batchIntervalMs,\n maxRetries: config.maxRetries\n })),\n newEventId: deps.newEventId ?? (() => newId("evt")),\n now: deps.now ?? Date.now,\n deliveryCanaryTimeoutMs: deps.deliveryCanaryTimeoutMs ?? DELIVERY_CANARY_TIMEOUT_MS\n };\n this.host.onMessage((msg) => {\n void this.handle(msg);\n });\n }\n queue = null;\n uploader = null;\n config = null;\n candidate;\n deps;\n async handle(msg) {\n switch (msg.type) {\n case "init":\n await this.init(msg.config);\n return;\n case "identify":\n this.candidate = msg.candidate;\n return;\n case "emit":\n await this.emit(msg.event);\n return;\n case "flush":\n await this.uploader?.flush({ keepalive: true });\n return;\n case "stop":\n await this.stop();\n return;\n }\n }\n async init(config) {\n try {\n this.config = config;\n this.queue = this.deps.queueFactory(config.sessionId);\n await this.queue.open();\n this.uploader = this.deps.uploaderFactory(this.queue, config);\n this.uploader.on({\n onUploaded: (batchId, count, accepted, rejected) => this.host.postMessage({\n type: "uploaded",\n batchId,\n count,\n accepted,\n rejected\n }),\n onUploadFailed: (batchId, attempt, error) => this.host.postMessage({\n type: "upload-failed",\n batchId,\n attempt,\n error: error.message\n })\n });\n const deliveryCanary = this.createEvent({\n kind: "sdk.delivery.ready",\n payload: {\n phase: "startup",\n ...SDK_BUILD_INFO\n }\n });\n await this.uploader.verifyDelivery(deliveryCanary, this.deps.deliveryCanaryTimeoutMs);\n this.uploader.start();\n this.host.postMessage({ type: "ready" });\n if (this.queue.storageMode() === "memory") {\n this.host.postMessage({\n type: "storage-fallback",\n mode: "memory",\n reason: this.queue.storageFallbackReason() ?? "IndexedDB unavailable; using in-memory queue"\n });\n }\n void EventQueue.sweepStale(/* @__PURE__ */ new Set([sessionDbName(config.sessionId)]));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n await this.uploader?.stop().catch(() => void 0);\n await this.queue?.close().catch(() => void 0);\n this.config = null;\n this.queue = null;\n this.uploader = null;\n this.host.postMessage({\n type: "init-failed",\n error: message,\n ...err instanceof DeliveryReadinessError ? { code: err.code } : {}\n });\n }\n }\n async emit(event) {\n if (!this.queue || !this.config) return;\n const stored = this.createEvent(event);\n const { dropped } = await this.queue.enqueue(stored);\n this.host.postMessage({ type: "queued", eventId: stored.id });\n if (dropped > 0) {\n this.host.postMessage({ type: "dropped", reason: "overflow", count: dropped });\n }\n }\n createEvent(event) {\n if (!this.config) {\n throw new Error("worker is not configured");\n }\n return {\n id: event.id ?? this.deps.newEventId(),\n sessionId: this.config.sessionId,\n kind: event.kind,\n timestamp: event.timestamp ?? this.deps.now(),\n ...event.payload !== void 0 ? { payload: event.payload } : {},\n // Stamp the per-device fingerprint on every event so the\n // server can render multi-device timelines. The\n // fingerprint is computed once on the main thread and\n // forwarded via the init message; the worker never\n // recomputes it because every event in a single SDK\n // session has the same device id by definition.\n ...this.config.fingerprintId !== void 0 ? { fingerprintId: this.config.fingerprintId } : {}\n };\n }\n async stop() {\n await this.uploader?.drain();\n await this.uploader?.stop();\n const pending = await this.queue?.size() ?? 0;\n if (this.queue && pending === 0) {\n await this.queue.destroy();\n } else {\n await this.queue?.close();\n }\n this.host.postMessage({ type: "stopped" });\n }\n}\nconst ctx = self;\nnew WorkerCore({\n postMessage: (msg) => ctx.postMessage(msg),\n onMessage: (handler) => {\n ctx.addEventListener("message", (event) => {\n handler(event.data);\n });\n }\n});\n';
24390
+ const workerSource = 'const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\nfunction getIdbProxyableTypes() {\n return idbProxyableTypes || (idbProxyableTypes = [\n IDBDatabase,\n IDBObjectStore,\n IDBIndex,\n IDBCursor,\n IDBTransaction\n ]);\n}\nfunction getCursorAdvanceMethods() {\n return cursorAdvanceMethods || (cursorAdvanceMethods = [\n IDBCursor.prototype.advance,\n IDBCursor.prototype.continue,\n IDBCursor.prototype.continuePrimaryKey\n ]);\n}\nconst transactionDoneMap = /* @__PURE__ */ new WeakMap();\nconst transformCache = /* @__PURE__ */ new WeakMap();\nconst reverseTransformCache = /* @__PURE__ */ new WeakMap();\nfunction promisifyRequest(request) {\n const promise = new Promise((resolve, reject) => {\n const unlisten = () => {\n request.removeEventListener("success", success);\n request.removeEventListener("error", error);\n };\n const success = () => {\n resolve(wrap(request.result));\n unlisten();\n };\n const error = () => {\n reject(request.error);\n unlisten();\n };\n request.addEventListener("success", success);\n request.addEventListener("error", error);\n });\n reverseTransformCache.set(promise, request);\n return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n if (transactionDoneMap.has(tx))\n return;\n const done = new Promise((resolve, reject) => {\n const unlisten = () => {\n tx.removeEventListener("complete", complete);\n tx.removeEventListener("error", error);\n tx.removeEventListener("abort", error);\n };\n const complete = () => {\n resolve();\n unlisten();\n };\n const error = () => {\n reject(tx.error || new DOMException("AbortError", "AbortError"));\n unlisten();\n };\n tx.addEventListener("complete", complete);\n tx.addEventListener("error", error);\n tx.addEventListener("abort", error);\n });\n transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n get(target, prop, receiver) {\n if (target instanceof IDBTransaction) {\n if (prop === "done")\n return transactionDoneMap.get(target);\n if (prop === "store") {\n return receiver.objectStoreNames[1] ? void 0 : receiver.objectStore(receiver.objectStoreNames[0]);\n }\n }\n return wrap(target[prop]);\n },\n set(target, prop, value) {\n target[prop] = value;\n return true;\n },\n has(target, prop) {\n if (target instanceof IDBTransaction && (prop === "done" || prop === "store")) {\n return true;\n }\n return prop in target;\n }\n};\nfunction replaceTraps(callback) {\n idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n if (getCursorAdvanceMethods().includes(func)) {\n return function(...args) {\n func.apply(unwrap(this), args);\n return wrap(this.request);\n };\n }\n return function(...args) {\n return wrap(func.apply(unwrap(this), args));\n };\n}\nfunction transformCachableValue(value) {\n if (typeof value === "function")\n return wrapFunction(value);\n if (value instanceof IDBTransaction)\n cacheDonePromiseForTransaction(value);\n if (instanceOfAny(value, getIdbProxyableTypes()))\n return new Proxy(value, idbProxyTraps);\n return value;\n}\nfunction wrap(value) {\n if (value instanceof IDBRequest)\n return promisifyRequest(value);\n if (transformCache.has(value))\n return transformCache.get(value);\n const newValue = transformCachableValue(value);\n if (newValue !== value) {\n transformCache.set(value, newValue);\n reverseTransformCache.set(newValue, value);\n }\n return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n const request = indexedDB.open(name, version);\n const openPromise = wrap(request);\n if (upgrade) {\n request.addEventListener("upgradeneeded", (event) => {\n upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);\n });\n }\n if (blocked) {\n request.addEventListener("blocked", (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion,\n event.newVersion,\n event\n ));\n }\n openPromise.then((db) => {\n if (terminated)\n db.addEventListener("close", () => terminated());\n if (blocking) {\n db.addEventListener("versionchange", (event) => blocking(event.oldVersion, event.newVersion, event));\n }\n }).catch(() => {\n });\n return openPromise;\n}\nfunction deleteDB(name, { blocked } = {}) {\n const request = indexedDB.deleteDatabase(name);\n if (blocked) {\n request.addEventListener("blocked", (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion,\n event\n ));\n }\n return wrap(request).then(() => void 0);\n}\nconst readMethods = ["get", "getKey", "getAll", "getAllKeys", "count"];\nconst writeMethods = ["put", "add", "delete", "clear"];\nconst cachedMethods = /* @__PURE__ */ new Map();\nfunction getMethod(target, prop) {\n if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === "string")) {\n return;\n }\n if (cachedMethods.get(prop))\n return cachedMethods.get(prop);\n const targetFuncName = prop.replace(/FromIndex$/, "");\n const useIndex = prop !== targetFuncName;\n const isWrite = writeMethods.includes(targetFuncName);\n if (\n // Bail if the target doesn\'t exist on the target. Eg, getAll isn\'t in Edge.\n !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))\n ) {\n return;\n }\n const method = async function(storeName, ...args) {\n const tx = this.transaction(storeName, isWrite ? "readwrite" : "readonly");\n let target2 = tx.store;\n if (useIndex)\n target2 = target2.index(args.shift());\n return (await Promise.all([\n target2[targetFuncName](...args),\n isWrite && tx.done\n ]))[0];\n };\n cachedMethods.set(prop, method);\n return method;\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop)\n}));\nconst advanceMethodProps = ["continue", "continuePrimaryKey", "advance"];\nconst methodMap = {};\nconst advanceResults = /* @__PURE__ */ new WeakMap();\nconst ittrProxiedCursorToOriginalProxy = /* @__PURE__ */ new WeakMap();\nconst cursorIteratorTraps = {\n get(target, prop) {\n if (!advanceMethodProps.includes(prop))\n return target[prop];\n let cachedFunc = methodMap[prop];\n if (!cachedFunc) {\n cachedFunc = methodMap[prop] = function(...args) {\n advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));\n };\n }\n return cachedFunc;\n }\n};\nasync function* iterate(...args) {\n let cursor = this;\n if (!(cursor instanceof IDBCursor)) {\n cursor = await cursor.openCursor(...args);\n }\n if (!cursor)\n return;\n cursor = cursor;\n const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);\n ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);\n reverseTransformCache.set(proxiedCursor, unwrap(cursor));\n while (cursor) {\n yield proxiedCursor;\n cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());\n advanceResults.delete(proxiedCursor);\n }\n}\nfunction isIteratorProp(target, prop) {\n return prop === Symbol.asyncIterator && instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor]) || prop === "iterate" && instanceOfAny(target, [IDBIndex, IDBObjectStore]);\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get(target, prop, receiver) {\n if (isIteratorProp(target, prop))\n return iterate;\n return oldTraps.get(target, prop, receiver);\n },\n has(target, prop) {\n return isIteratorProp(target, prop) || oldTraps.has(target, prop);\n }\n}));\nconst DEFAULT_DB_NAME = "proctoring-sdk";\nconst DEFAULT_MAX_BYTES = 50 * 1024 * 1024;\nconst SEQ_KEY = "seq";\nconst BYTES_KEY = "bytes";\nconst SESSION_DB_PREFIX = "proctoring-sess";\nfunction sessionDbName(sessionId) {\n return `proctoring-${sessionId}`;\n}\nclass EventQueue {\n db = null;\n memory = null;\n dbName;\n maxBytes;\n storage;\n fallbackToMemory;\n constructor(options = {}) {\n this.dbName = options.dbName ?? DEFAULT_DB_NAME;\n this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n this.storage = options.storage ?? "indexeddb";\n this.fallbackToMemory = options.fallbackToMemory ?? true;\n }\n /** Opens (or upgrades) the underlying IndexedDB database. Must be called once before any other method. Idempotent. */\n async open() {\n if (this.db || this.memory) return;\n if (this.storage === "memory") {\n this.openMemory("configured-memory-storage");\n return;\n }\n try {\n this.db = await openDB(this.dbName, 1, {\n upgrade(db) {\n const events = db.createObjectStore("events", { keyPath: "id" });\n events.createIndex("by-seq", "seq");\n db.createObjectStore("meta", { keyPath: "key" });\n }\n });\n } catch (err) {\n if (!this.fallbackToMemory) throw err;\n this.openMemory(indexedDbOpenFailureReason(err));\n }\n }\n storageMode() {\n return this.memory ? "memory" : "indexeddb";\n }\n storageFallbackReason() {\n return this.memory?.reason ?? null;\n }\n /**\n * Appends an event to the tail. If the queue would exceed\n * `maxBytes`, drops the oldest events until it fits — the new\n * event is never the one dropped. Returns the count of dropped\n * events so callers can surface backpressure to the host.\n */\n async enqueue(event) {\n if (this.memory) return this.enqueueMemory(event);\n const db = this.requireDb();\n const bytes = byteLength(event);\n const tx = db.transaction(["events", "meta"], "readwrite");\n const events = tx.objectStore("events");\n const meta = tx.objectStore("meta");\n const seq = ((await meta.get(SEQ_KEY))?.value ?? 0) + 1;\n let totalBytes = ((await meta.get(BYTES_KEY))?.value ?? 0) + bytes;\n await events.put({ ...event, seq, bytes });\n await meta.put({ key: SEQ_KEY, value: seq });\n let dropped = 0;\n if (totalBytes > this.maxBytes) {\n const cursor = await events.index("by-seq").openCursor();\n let c = cursor;\n while (c && totalBytes > this.maxBytes) {\n const stored = c.value;\n if (stored.id === event.id) {\n c = await c.continue();\n continue;\n }\n totalBytes -= stored.bytes;\n dropped += 1;\n await c.delete();\n c = await c.continue();\n }\n }\n await meta.put({ key: BYTES_KEY, value: totalBytes });\n await tx.done;\n return { dropped };\n }\n /** Returns up to `limit` oldest events without removing them. */\n async peek(limit) {\n if (this.memory) {\n return this.memory.events.slice(0, limit).map(({ seq: _seq, bytes: _bytes, ...event }) => event);\n }\n const db = this.requireDb();\n const tx = db.transaction("events", "readonly");\n const out = [];\n let cursor = await tx.store.index("by-seq").openCursor();\n while (cursor && out.length < limit) {\n const { seq: _seq, bytes: _bytes, ...event } = cursor.value;\n out.push(event);\n cursor = await cursor.continue();\n }\n return out;\n }\n /**\n * Removes events by id. Unknown ids are silently skipped so callers\n * can safely ack the same id twice (eg. when an idempotency-keyed\n * server retry returns success after we already acked locally).\n */\n async ack(ids) {\n if (ids.length === 0) return;\n if (this.memory) {\n const idSet = new Set(ids);\n let bytes = this.memory.bytes;\n this.memory.events = this.memory.events.filter((event) => {\n if (!idSet.has(event.id)) return true;\n bytes -= event.bytes;\n return false;\n });\n this.memory.bytes = Math.max(0, bytes);\n return;\n }\n const db = this.requireDb();\n const tx = db.transaction(["events", "meta"], "readwrite");\n const events = tx.objectStore("events");\n const meta = tx.objectStore("meta");\n let totalBytes = (await meta.get(BYTES_KEY))?.value ?? 0;\n for (const id of ids) {\n const stored = await events.get(id);\n if (!stored) continue;\n totalBytes -= stored.bytes;\n await events.delete(id);\n }\n await meta.put({ key: BYTES_KEY, value: Math.max(0, totalBytes) });\n await tx.done;\n }\n /** Number of events currently queued. */\n async size() {\n if (this.memory) return this.memory.events.length;\n const db = this.requireDb();\n return db.count("events");\n }\n /** Cumulative byte size of all queued events (JSON-encoded). */\n async bytes() {\n if (this.memory) return this.memory.bytes;\n const db = this.requireDb();\n return (await db.get("meta", BYTES_KEY))?.value ?? 0;\n }\n /** Closes the database handle. Safe to call multiple times. */\n async close() {\n this.db?.close();\n this.db = null;\n this.memory = null;\n }\n /**\n * Closes the handle AND deletes the underlying database from disk.\n *\n * Call this only once the queue is known to be fully drained — a\n * deleted database takes any not-yet-uploaded events with it. The\n * worker gates this on `size() === 0` after draining at teardown, so\n * an offline teardown (events still queued) keeps the database for a\n * later page load to flush. Reclaiming the database is what stops the\n * per-session databases accumulating until the origin hits its\n * storage quota and `open()` starts throwing.\n */\n async destroy() {\n if (this.memory) {\n await this.close();\n return;\n }\n await this.close();\n await deleteDB(this.dbName);\n }\n /**\n * Best-effort reclamation of leaked per-session databases left by\n * earlier sessions on this origin. Enumerates all IndexedDB\n * databases, and for each `proctoring-sess-*` one NOT in `keep`,\n * opens it, checks it holds zero events, and deletes it if so. A\n * database with pending events is left alone — it may still flush on\n * a future load.\n *\n * No-ops where `indexedDB.databases()` is unavailable (Firefox, older\n * Safari): there is no enumeration API there, so leaked databases\n * can\'t be discovered. New sessions still self-clean via destroy(),\n * so the leak is bounded going forward even on those browsers.\n *\n * Never throws — cleanup must not be able to fail a session.\n */\n static async sweepStale(keep = /* @__PURE__ */ new Set()) {\n let removed = 0;\n try {\n if (typeof indexedDB === "undefined" || typeof indexedDB.databases !== "function") {\n return 0;\n }\n const entries = await indexedDB.databases();\n for (const { name } of entries) {\n if (!name || keep.has(name) || !name.startsWith(SESSION_DB_PREFIX)) {\n continue;\n }\n try {\n const queue = new EventQueue({ dbName: name });\n await queue.open();\n const pending = await queue.size();\n await queue.close();\n if (pending === 0) {\n await deleteDB(name);\n removed += 1;\n }\n } catch {\n }\n }\n } catch {\n }\n return removed;\n }\n requireDb() {\n if (!this.db) {\n throw new Error("EventQueue: call open() before any other operation");\n }\n return this.db;\n }\n openMemory(reason) {\n this.db = null;\n this.memory = {\n events: [],\n seq: 0,\n bytes: 0,\n reason\n };\n }\n enqueueMemory(event) {\n if (!this.memory) {\n throw new Error("EventQueue: call open() before any other operation");\n }\n const bytes = byteLength(event);\n const stored = {\n ...event,\n seq: this.memory.seq + 1,\n bytes\n };\n this.memory.seq = stored.seq;\n this.memory.events.push(stored);\n this.memory.bytes += bytes;\n let dropped = 0;\n while (this.memory.events.length > 1 && this.memory.bytes > this.maxBytes) {\n const oldest = this.memory.events[0];\n if (!oldest || oldest.id === event.id) break;\n this.memory.events.shift();\n this.memory.bytes -= oldest.bytes;\n dropped += 1;\n }\n return { dropped };\n }\n}\nfunction byteLength(event) {\n return new TextEncoder().encode(JSON.stringify(event)).byteLength;\n}\nfunction indexedDbOpenFailureReason(err) {\n if (err instanceof Error) {\n return `${err.name}: ${err.message}`;\n }\n return String(err);\n}\nclass DeliveryReadinessError extends Error {\n code;\n status;\n /** Structured operator diagnostics. Never render this object in candidate UI. */\n details;\n constructor(code, message, options) {\n super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);\n this.name = "DeliveryReadinessError";\n this.code = code;\n this.status = options?.status;\n this.details = options?.details;\n }\n}\nfunction newId(prefix) {\n if (typeof crypto !== "undefined" && "randomUUID" in crypto) {\n return crypto.randomUUID();\n }\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\nconst EVENT_REQUEST_TIMEOUT_MS = 1e4;\nclass RequestDeadlineError extends Error {\n constructor(operation, timeoutMs) {\n super(`${operation} timed out after ${timeoutMs}ms`);\n this.operation = operation;\n this.timeoutMs = timeoutMs;\n this.name = "RequestDeadlineError";\n }\n code = "request-timeout";\n}\nasync function withRequestDeadline(operation, timeoutMs, run, parentSignal) {\n if (parentSignal?.aborted) throw abortError();\n const controller = new AbortController();\n let timedOut = false;\n let timer;\n let onParentAbort;\n const cancelled = new Promise((_resolve, reject) => {\n onParentAbort = () => {\n controller.abort();\n reject(abortError());\n };\n parentSignal?.addEventListener("abort", onParentAbort, { once: true });\n timer = setTimeout(\n () => {\n timedOut = true;\n controller.abort();\n reject(new RequestDeadlineError(operation, timeoutMs));\n },\n Math.max(0, timeoutMs)\n );\n });\n try {\n return await Promise.race([Promise.resolve().then(() => run(controller.signal)), cancelled]);\n } catch (error) {\n if (timedOut) throw new RequestDeadlineError(operation, timeoutMs);\n throw error;\n } finally {\n if (timer !== void 0) clearTimeout(timer);\n if (onParentAbort) parentSignal?.removeEventListener("abort", onParentAbort);\n }\n}\nfunction abortError() {\n const error = new Error("The request was aborted");\n error.name = "AbortError";\n return error;\n}\nclass Uploader {\n opts;\n events = {};\n timer = null;\n draining = false;\n stopped = false;\n controller = null;\n constructor(options) {\n this.opts = {\n queue: options.queue,\n ingestUrl: options.ingestUrl,\n sessionId: options.sessionId,\n batchSize: options.batchSize ?? 50,\n batchIntervalMs: options.batchIntervalMs ?? 2e3,\n maxRetries: options.maxRetries ?? 5,\n fetchImpl: options.fetchImpl ?? fetch.bind(globalThis),\n newBatchId: options.newBatchId ?? (() => newId("batch")),\n appId: options.appId ?? null,\n candidate: options.candidate ?? (() => void 0)\n };\n }\n /** Replaces the lifecycle handlers. The Uploader keeps a single set; pass `{}` to clear. */\n on(events) {\n this.events = events;\n }\n /** Starts the periodic drain timer. No-op if already started or stopped. */\n start() {\n if (this.timer || this.stopped) return;\n this.timer = setInterval(() => {\n void this.drain();\n }, this.opts.batchIntervalMs);\n }\n /**\n * Drains the queue in batches until empty, no progress was made, or\n * a send fails. Re-entrant calls are guarded — only one drain runs\n * at a time even under concurrent invocations.\n */\n async drain() {\n if (this.draining || this.stopped) return;\n this.draining = true;\n try {\n while (!this.stopped) {\n const events = await this.opts.queue.peek(this.opts.batchSize);\n if (events.length === 0) return;\n const sizeBefore = await this.opts.queue.size();\n const result = await this.sendBatch(events, { keepalive: false });\n if (!result.progress) return;\n const sizeAfter = await this.opts.queue.size();\n if (sizeAfter >= sizeBefore) return;\n }\n } finally {\n this.draining = false;\n }\n }\n /**\n * Sends one batch. With `keepalive: true` the request survives page\n * navigation but is capped by the browser to ~64KB total in-flight;\n * we therefore send at most one batch and do not retry on failure.\n */\n async flush(options) {\n const events = await this.opts.queue.peek(this.opts.batchSize);\n if (events.length === 0) return;\n await this.sendBatch(events, { keepalive: options.keepalive, noRetry: options.keepalive });\n }\n /**\n * Prove that the real ingest route accepts an event before SDK readiness is\n * announced. This uses the same request builder, auth headers, response\n * validation, and retry path as normal queue delivery. It is intentionally\n * not configurable by SDK consumers.\n */\n async verifyDelivery(event, timeoutMs) {\n const result = await this.sendBatch([event], {\n keepalive: false,\n ackQueue: false,\n maxAttempts: 2,\n timeoutMs\n });\n if (result.accepted.includes(event.id)) return;\n if (result.rejected.includes(event.id)) {\n throw new DeliveryReadinessError(\n "ingest-rejected",\n "The evidence ingest route rejected the delivery canary.",\n { status: result.status }\n );\n }\n if (result.timedOut) {\n throw new DeliveryReadinessError(\n "ingest-timeout",\n "Timed out while verifying evidence delivery.",\n { cause: result.error }\n );\n }\n if (result.status === 401 || result.status === 403) {\n throw new DeliveryReadinessError(\n "ingest-not-authorized",\n "The evidence ingest route did not authorize this application and origin.",\n { status: result.status, cause: result.error }\n );\n }\n if (result.status !== void 0 && result.status >= 400 && result.status < 500) {\n throw new DeliveryReadinessError(\n "ingest-rejected",\n "The evidence ingest route rejected the delivery canary.",\n { status: result.status, cause: result.error }\n );\n }\n if (result.invalidResponse) {\n throw new DeliveryReadinessError(\n "ingest-invalid-response",\n "The evidence ingest route returned an invalid acknowledgement.",\n { cause: result.error }\n );\n }\n throw new DeliveryReadinessError(\n "ingest-unreachable",\n "The evidence ingest route could not be reached.",\n { cause: result.error, status: result.status }\n );\n }\n /** Stops the drain timer and aborts any in-flight non-keepalive request. */\n async stop() {\n this.stopped = true;\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.controller?.abort();\n }\n async sendBatch(events, {\n keepalive,\n noRetry = false,\n ackQueue = true,\n maxAttempts = this.opts.maxRetries,\n timeoutMs\n }) {\n const batchId = this.opts.newBatchId();\n const candidate = this.opts.candidate();\n const body = {\n batchId,\n sessionId: this.opts.sessionId,\n events,\n ...candidate ? { candidate } : {}\n };\n const controller = keepalive ? null : new AbortController();\n this.controller = controller;\n const signal = controller?.signal;\n let timedOut = false;\n const deadlineAt = timeoutMs === void 0 ? void 0 : Date.now() + timeoutMs;\n const timeout = controller && timeoutMs !== void 0 ? setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, timeoutMs) : null;\n let lastError;\n let lastStatus;\n let invalidResponse = false;\n try {\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n if (this.stopped && !keepalive) {\n return { progress: false, accepted: [], rejected: [] };\n }\n let res;\n let parsedResponse;\n let parseError;\n try {\n const attemptTimeoutMs = deadlineAt === void 0 ? EVENT_REQUEST_TIMEOUT_MS : Math.max(1, Math.min(EVENT_REQUEST_TIMEOUT_MS, deadlineAt - Date.now()));\n const response = keepalive ? await this.opts.fetchImpl(this.opts.ingestUrl, {\n method: "POST",\n headers: {\n "content-type": "application/json",\n "idempotency-key": batchId,\n ...this.opts.appId ? { "x-app-id": this.opts.appId } : {}\n },\n body: JSON.stringify(body),\n keepalive\n }) : await withRequestDeadline(\n "event-ingest",\n attemptTimeoutMs,\n async (requestSignal) => {\n const request = await this.opts.fetchImpl(this.opts.ingestUrl, {\n method: "POST",\n headers: {\n "content-type": "application/json",\n "idempotency-key": batchId,\n ...this.opts.appId ? { "x-app-id": this.opts.appId } : {}\n },\n body: JSON.stringify(body),\n keepalive: false,\n signal: requestSignal\n });\n if (request.ok) {\n try {\n parsedResponse = await request.json();\n } catch (error) {\n parseError = error instanceof Error ? error : new Error(String(error));\n }\n }\n return request;\n },\n signal\n );\n res = response;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n lastError = error;\n if (error instanceof RequestDeadlineError) timedOut = true;\n if (error.name === "AbortError") break;\n this.events.onUploadFailed?.(batchId, attempt, error);\n if (noRetry || attempt === maxAttempts) break;\n await sleep(backoffMs(attempt), signal);\n continue;\n }\n lastStatus = res.status;\n timedOut = false;\n if (res.ok) {\n let parsed;\n if (keepalive) {\n try {\n parsed = await res.json();\n } catch (error) {\n parseError = error instanceof Error ? error : new Error(String(error));\n parsed = { batchId, accepted: [], rejected: [] };\n }\n } else {\n parsed = parsedResponse ?? { batchId, accepted: [], rejected: [] };\n }\n if (parseError) {\n invalidResponse = true;\n lastError = parseError;\n this.events.onUploadFailed?.(batchId, attempt, lastError);\n if (noRetry || attempt === maxAttempts) break;\n await sleep(backoffMs(attempt), signal);\n continue;\n }\n const accepted = Array.isArray(parsed.accepted) ? parsed.accepted : [];\n const rejected = Array.isArray(parsed.rejected) ? parsed.rejected : [];\n if (accepted.length === 0 && rejected.length === 0) {\n invalidResponse = true;\n lastError = new Error("malformed response: empty accepted and rejected");\n this.events.onUploadFailed?.(batchId, attempt, lastError);\n } else {\n const toAck = [...accepted, ...rejected];\n if (ackQueue) await this.opts.queue.ack(toAck);\n this.events.onUploaded?.(batchId, accepted.length, accepted, rejected);\n return {\n progress: toAck.length > 0,\n accepted,\n rejected,\n status: res.status\n };\n }\n } else if (res.status >= 400 && res.status < 500 && res.status !== 408 && res.status !== 429) {\n lastError = new Error(`non-retryable ${res.status}`);\n this.events.onUploadFailed?.(batchId, attempt, lastError);\n return {\n progress: false,\n accepted: [],\n rejected: [],\n error: lastError,\n status: res.status\n };\n } else {\n lastError = new Error(`retryable ${res.status}`);\n this.events.onUploadFailed?.(batchId, attempt, lastError);\n }\n if (noRetry || attempt === maxAttempts) break;\n await sleep(backoffMs(attempt), signal);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n lastError = error;\n if (error.name !== "AbortError" || timedOut) {\n this.events.onUploadFailed?.(batchId, Math.max(1, maxAttempts), error);\n }\n } finally {\n if (timeout) clearTimeout(timeout);\n if (this.controller === controller) this.controller = null;\n }\n return {\n progress: false,\n accepted: [],\n rejected: [],\n ...lastError ? { error: lastError } : {},\n ...lastStatus !== void 0 ? { status: lastStatus } : {},\n ...timedOut ? { timedOut: true } : {},\n ...invalidResponse ? { invalidResponse: true } : {}\n };\n }\n}\nfunction backoffMs(attempt) {\n const base = Math.min(3e4, 500 * Math.pow(2, attempt - 1));\n const jitter = Math.random() * base * 0.25;\n return base + jitter;\n}\nfunction sleep(ms, signal) {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n const id = setTimeout(resolve, ms);\n signal?.addEventListener(\n "abort",\n () => {\n clearTimeout(id);\n resolve();\n },\n { once: true }\n );\n });\n}\nconst SDK_VERSION = "0.2.1";\nconst SDK_BUILD_SHA = "03bc2909b70164d21dfa7be02df4f4dc5bef8691";\nconst SDK_BUILD_INFO = Object.freeze({\n sdkVersion: SDK_VERSION,\n buildSha: SDK_BUILD_SHA\n});\nconst DELIVERY_CANARY_TIMEOUT_MS = 8e3;\nclass WorkerCore {\n constructor(host, deps = {}) {\n this.host = host;\n this.deps = {\n queueFactory: deps.queueFactory ?? ((sessionId) => new EventQueue({ dbName: sessionDbName(sessionId) })),\n uploaderFactory: deps.uploaderFactory ?? ((queue, config) => new Uploader({\n queue,\n ingestUrl: config.ingestUrl,\n sessionId: config.sessionId,\n appId: config.appId,\n candidate: () => this.candidate,\n batchSize: config.batchSize,\n batchIntervalMs: config.batchIntervalMs,\n maxRetries: config.maxRetries\n })),\n newEventId: deps.newEventId ?? (() => newId("evt")),\n now: deps.now ?? Date.now,\n deliveryCanaryTimeoutMs: deps.deliveryCanaryTimeoutMs ?? DELIVERY_CANARY_TIMEOUT_MS\n };\n this.host.onMessage((msg) => {\n void this.handle(msg);\n });\n }\n queue = null;\n uploader = null;\n config = null;\n candidate;\n deps;\n async handle(msg) {\n switch (msg.type) {\n case "init":\n await this.init(msg.config);\n return;\n case "identify":\n this.candidate = msg.candidate;\n return;\n case "emit":\n await this.emit(msg.event);\n return;\n case "flush":\n await this.uploader?.flush({ keepalive: true });\n return;\n case "stop":\n await this.stop();\n return;\n }\n }\n async init(config) {\n try {\n this.config = config;\n this.queue = this.deps.queueFactory(config.sessionId);\n await this.queue.open();\n this.uploader = this.deps.uploaderFactory(this.queue, config);\n this.uploader.on({\n onUploaded: (batchId, count, accepted, rejected) => this.host.postMessage({\n type: "uploaded",\n batchId,\n count,\n accepted,\n rejected\n }),\n onUploadFailed: (batchId, attempt, error) => this.host.postMessage({\n type: "upload-failed",\n batchId,\n attempt,\n error: error.message\n })\n });\n const deliveryCanary = this.createEvent({\n kind: "sdk.delivery.ready",\n payload: {\n phase: "startup",\n ...SDK_BUILD_INFO\n }\n });\n await this.uploader.verifyDelivery(deliveryCanary, this.deps.deliveryCanaryTimeoutMs);\n this.uploader.start();\n this.host.postMessage({ type: "ready" });\n if (this.queue.storageMode() === "memory") {\n this.host.postMessage({\n type: "storage-fallback",\n mode: "memory",\n reason: this.queue.storageFallbackReason() ?? "IndexedDB unavailable; using in-memory queue"\n });\n }\n void EventQueue.sweepStale(/* @__PURE__ */ new Set([sessionDbName(config.sessionId)]));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n await this.uploader?.stop().catch(() => void 0);\n await this.queue?.close().catch(() => void 0);\n this.config = null;\n this.queue = null;\n this.uploader = null;\n this.host.postMessage({\n type: "init-failed",\n error: message,\n ...err instanceof DeliveryReadinessError ? { code: err.code } : {}\n });\n }\n }\n async emit(event) {\n if (!this.queue || !this.config) return;\n const stored = this.createEvent(event);\n const { dropped } = await this.queue.enqueue(stored);\n this.host.postMessage({ type: "queued", eventId: stored.id });\n if (dropped > 0) {\n this.host.postMessage({ type: "dropped", reason: "overflow", count: dropped });\n }\n }\n createEvent(event) {\n if (!this.config) {\n throw new Error("worker is not configured");\n }\n return {\n id: event.id ?? this.deps.newEventId(),\n sessionId: this.config.sessionId,\n kind: event.kind,\n timestamp: event.timestamp ?? this.deps.now(),\n ...event.payload !== void 0 ? { payload: event.payload } : {},\n // Stamp the per-device fingerprint on every event so the\n // server can render multi-device timelines. The\n // fingerprint is computed once on the main thread and\n // forwarded via the init message; the worker never\n // recomputes it because every event in a single SDK\n // session has the same device id by definition.\n ...this.config.fingerprintId !== void 0 ? { fingerprintId: this.config.fingerprintId } : {}\n };\n }\n async stop() {\n await this.uploader?.drain();\n await this.uploader?.stop();\n const pending = await this.queue?.size() ?? 0;\n if (this.queue && pending === 0) {\n await this.queue.destroy();\n } else {\n await this.queue?.close();\n }\n this.host.postMessage({ type: "stopped" });\n }\n}\nconst ctx = self;\nnew WorkerCore({\n postMessage: (msg) => ctx.postMessage(msg),\n onMessage: (handler) => {\n ctx.addEventListener("message", (event) => {\n handler(event.data);\n });\n }\n});\n';
24304
24391
  class BlobWorker {
24305
24392
  url;
24306
24393
  worker;
@@ -24876,6 +24963,17 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
24876
24963
  );
24877
24964
  const preflightEngineOptions = computed(() => {
24878
24965
  const options = buildPreflightEngineOptions(resolvedPolicy.value, detectFace.value);
24966
+ const workload = recordingReadinessWorkload(resolvedPolicy.value);
24967
+ if (attempt.value && workload && options.system?.connection !== false) {
24968
+ options.connectionReadiness = () => measureRecordingDeliveryReadiness({
24969
+ sessionId: attempt.value.sessionId,
24970
+ ingestUrl: resolvedIngestUrl.value,
24971
+ ...props.appId ? { appId: props.appId } : {},
24972
+ payloadBytes: workload.payloadBytes,
24973
+ completionWindowMs: workload.completionWindowMs,
24974
+ samples: 3
24975
+ });
24976
+ }
24879
24977
  if (finalStepHandlesRuntimeScreenShare.value) {
24880
24978
  options.media = {
24881
24979
  ...options.media ?? {},
@@ -218,6 +218,16 @@ export declare function resolveProctoringPolicyForPage(args: {
218
218
  policyOverrides?: ProctoringPolicyInput;
219
219
  }): ProctoringPolicy;
220
220
  export declare function buildPreflightEngineOptions(policy: ProctoringPolicy, detectFace?: DetectFace): Omit<SystemCheckOptions, "mode">;
221
+ export interface RecordingReadinessWorkload {
222
+ payloadBytes: number;
223
+ completionWindowMs: number;
224
+ }
225
+ /**
226
+ * Convert the enabled continuous recorders into one representative upload.
227
+ * The payload contains the bytes produced across the shortest recorder window;
228
+ * requiring it to complete in half that window provides 2x delivery headroom.
229
+ */
230
+ export declare function recordingReadinessWorkload(policy: ProctoringPolicy): RecordingReadinessWorkload | null;
221
231
  export declare function buildSdkObservers(policy: ProctoringPolicy): DomObserversConfig;
222
232
  export declare function shouldRunPreflight(policy: ProctoringPolicy): boolean;
223
233
  /** Device ids persisted by the wizard, as stored. */
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/proctored-assessment/policy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/proctored-assessment/policy.ts"],"names":[],"mappings":"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"}
@@ -37,6 +37,11 @@ export declare const usePreflightCheck: (options?: UsePreflightCheckOptions) =>
37
37
  uploadMbps?: number | undefined;
38
38
  latencyMs?: number | undefined;
39
39
  jitterMs?: number | undefined;
40
+ recordingUploadMode?: "direct" | "segments" | "post" | undefined;
41
+ readinessPayloadBytes?: number | undefined;
42
+ readinessMedianMs?: number | undefined;
43
+ readinessWindowMs?: number | undefined;
44
+ readinessSampleCount?: number | undefined;
40
45
  band?: import("@a4anthony/proctorkit-sdk").ConnectionBand | undefined;
41
46
  }[], CheckRow[] | {
42
47
  kind: CheckKind;
@@ -60,6 +65,11 @@ export declare const usePreflightCheck: (options?: UsePreflightCheckOptions) =>
60
65
  uploadMbps?: number | undefined;
61
66
  latencyMs?: number | undefined;
62
67
  jitterMs?: number | undefined;
68
+ recordingUploadMode?: "direct" | "segments" | "post" | undefined;
69
+ readinessPayloadBytes?: number | undefined;
70
+ readinessMedianMs?: number | undefined;
71
+ readinessWindowMs?: number | undefined;
72
+ readinessSampleCount?: number | undefined;
63
73
  band?: import("@a4anthony/proctorkit-sdk").ConnectionBand | undefined;
64
74
  }[]>;
65
75
  isRunning: import("vue").Ref<boolean, boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"usePreflightCheck.d.ts","sourceRoot":"","sources":["../src/usePreflightCheck.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,WAAW,EACX,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;AAE1D,eAAO,MAAM,iBAAiB,GAAI,UAAS,wBAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAuC1C,OAAO,CAAC,eAAe,CAAC;4BAoBzC,oBAAoB,EAAE,KAC9B,OAAO,CAAC,eAAe,CAAC;iBA6BH,OAAO,CAAC,eAAe,CAAC;0BAef,OAAO,CAAC,IAAI,CAAC;4BAWX,OAAO,CAAC,IAAI,CAAC;0BAIb,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;wBAG1B,OAAO,CAAC,IAAI,CAAC;6BAW/B,MAAM,mBACA;QAAE,YAAY,EAAE,gBAAgB,CAAA;KAAE;;;kCAaX,OAAO,KAAU,OAAO,CAAC,IAAI,CAAC;CAsBzE,CAAC;AAIF,YAAY,EACV,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,kBAAkB,GACnB,CAAC"}
1
+ {"version":3,"file":"usePreflightCheck.d.ts","sourceRoot":"","sources":["../src/usePreflightCheck.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,WAAW,EACX,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;AAE1D,eAAO,MAAM,iBAAiB,GAAI,UAAS,wBAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAuC1C,OAAO,CAAC,eAAe,CAAC;4BAoBzC,oBAAoB,EAAE,KAC9B,OAAO,CAAC,eAAe,CAAC;iBA6BH,OAAO,CAAC,eAAe,CAAC;0BAef,OAAO,CAAC,IAAI,CAAC;4BAWX,OAAO,CAAC,IAAI,CAAC;0BAIb,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;wBAG1B,OAAO,CAAC,IAAI,CAAC;6BAW/B,MAAM,mBACA;QAAE,YAAY,EAAE,gBAAgB,CAAA;KAAE;;;kCAaX,OAAO,KAAU,OAAO,CAAC,IAAI,CAAC;CAsBzE,CAAC;AAIF,YAAY,EACV,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,kBAAkB,GACnB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SystemStep.vue.d.ts","sourceRoot":"","sources":["../../src/wizard/SystemStep.vue"],"names":[],"mappings":"AA6dA,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAQrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAU9D,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC9B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;;;;;;;;AAkuBF,wBAOG"}
1
+ {"version":3,"file":"SystemStep.vue.d.ts","sourceRoot":"","sources":["../../src/wizard/SystemStep.vue"],"names":[],"mappings":"AAodA,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAOrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAU9D,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC9B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;;;;;;;;AA0tBF,wBAOG"}
@@ -1 +1 @@
1
- {"version":3,"file":"usePreflightTelemetry.d.ts","sourceRoot":"","sources":["../../src/wizard/usePreflightTelemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAiC,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAC9D,OAAO,KAAK,EACV,QAAQ,EACR,SAAS,EAGV,MAAM,2BAA2B,CAAC;AAMnC,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACV,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,CAAC;IACF;;;OAGG;IACH,IAAI,EAAE,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgBD,eAAO,MAAM,qBAAqB,GAChC,SAAS,4BAA4B,KACpC;IACD,qEAAqE;IACrE,IAAI,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACnE,+DAA+D;IAC/D,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;4DACwD;IACxD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAgO5B,CAAC"}
1
+ {"version":3,"file":"usePreflightTelemetry.d.ts","sourceRoot":"","sources":["../../src/wizard/usePreflightTelemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAiC,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAC9D,OAAO,KAAK,EACV,QAAQ,EACR,SAAS,EAGV,MAAM,2BAA2B,CAAC;AAMnC,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACV,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,CAAC;IACF;;;OAGG;IACH,IAAI,EAAE,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgBD,eAAO,MAAM,qBAAqB,GAChC,SAAS,4BAA4B,KACpC;IACD,qEAAqE;IACrE,IAAI,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACnE,+DAA+D;IAC/D,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;4DACwD;IACxD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CA+O5B,CAAC"}
@@ -64,6 +64,11 @@ export declare const useWizardSteps: (options?: UseWizardOptions) => {
64
64
  uploadMbps?: number | undefined;
65
65
  latencyMs?: number | undefined;
66
66
  jitterMs?: number | undefined;
67
+ recordingUploadMode?: "direct" | "segments" | "post" | undefined;
68
+ readinessPayloadBytes?: number | undefined;
69
+ readinessMedianMs?: number | undefined;
70
+ readinessWindowMs?: number | undefined;
71
+ readinessSampleCount?: number | undefined;
67
72
  band?: import("@a4anthony/proctorkit-sdk").ConnectionBand | undefined;
68
73
  }[], import("@a4anthony/proctorkit-sdk").CheckRow[] | {
69
74
  kind: import("@a4anthony/proctorkit-sdk").CheckKind;
@@ -87,6 +92,11 @@ export declare const useWizardSteps: (options?: UseWizardOptions) => {
87
92
  uploadMbps?: number | undefined;
88
93
  latencyMs?: number | undefined;
89
94
  jitterMs?: number | undefined;
95
+ recordingUploadMode?: "direct" | "segments" | "post" | undefined;
96
+ readinessPayloadBytes?: number | undefined;
97
+ readinessMedianMs?: number | undefined;
98
+ readinessWindowMs?: number | undefined;
99
+ readinessSampleCount?: number | undefined;
90
100
  band?: import("@a4anthony/proctorkit-sdk").ConnectionBand | undefined;
91
101
  }[]>;
92
102
  isRunning: Ref<boolean, boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"useWizardSteps.d.ts","sourceRoot":"","sources":["../../src/wizard/useWizardSteps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAwB,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAErD,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGtE,MAAM,WAAW,gBAAiB,SAAQ,wBAAwB;IAChE;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc,GAAI,UAAS,gBAAqB;;;;;mBA0CvC,IAAI;iBAYJ,UAAU,KAAG,IAAI;iBAqBnB,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAevB,CAAC;AAEF,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"useWizardSteps.d.ts","sourceRoot":"","sources":["../../src/wizard/useWizardSteps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAwB,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAErD,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGtE,MAAM,WAAW,gBAAiB,SAAQ,wBAAwB;IAChE;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc,GAAI,UAAS,gBAAqB;;;;;mBA0CvC,IAAI;iBAYJ,UAAU,KAAG,IAAI;iBAqBnB,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAevB,CAAC;AAEF,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a4anthony/proctorkit-vue",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Vue 3 components for the proctoring SDK — pre-flight system check wizard.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,8 +24,8 @@
24
24
  "@lucide/vue": "^1.16.0",
25
25
  "@ricky0123/vad-web": "^0.0.30",
26
26
  "vue-i18n": "^11.1.0",
27
- "@a4anthony/proctorkit-content": "0.0.1",
28
- "@a4anthony/proctorkit-sdk": "0.1.1"
27
+ "@a4anthony/proctorkit-content": "0.1.0",
28
+ "@a4anthony/proctorkit-sdk": "0.2.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@storybook/vue3-vite": "^10.4.0",