@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.
- package/dist/ProctoredAssessment.vue.d.ts.map +1 -1
- package/dist/ProctoringSystemCheck.vue.d.ts.map +1 -1
- package/dist/index.js +151 -53
- package/dist/proctored-assessment/policy.d.ts +10 -0
- package/dist/proctored-assessment/policy.d.ts.map +1 -1
- package/dist/usePreflightCheck.d.ts +10 -0
- package/dist/usePreflightCheck.d.ts.map +1 -1
- package/dist/wizard/SystemStep.vue.d.ts.map +1 -1
- package/dist/wizard/usePreflightTelemetry.d.ts.map +1 -1
- package/dist/wizard/useWizardSteps.d.ts +10 -0
- package/dist/wizard/useWizardSteps.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProctoredAssessment.vue.d.ts","sourceRoot":"","sources":["../src/ProctoredAssessment.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProctoredAssessment.vue.d.ts","sourceRoot":"","sources":["../src/ProctoredAssessment.vue"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProctoringSystemCheck.vue.d.ts","sourceRoot":"","sources":["../src/ProctoringSystemCheck.vue"],"names":[],"mappings":"
|
|
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,
|
|
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: "
|
|
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: "
|
|
1297
|
-
"slow-connection": "
|
|
1298
|
-
"speed-test-failed": "We couldn't
|
|
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: "
|
|
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: "
|
|
1550
|
-
slowUploadMessage: "
|
|
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: "
|
|
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: "
|
|
1746
|
-
"slow-connection": "
|
|
1747
|
-
"speed-test-failed": "Nous n'avons pas pu
|
|
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: "
|
|
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: "
|
|
1999
|
-
slowUploadMessage: "
|
|
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$
|
|
2226
|
-
function buildSchemaDefinitions(messages, numericNames = numericPlaceholders$
|
|
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$
|
|
2382
|
-
const localeKeys$
|
|
2383
|
-
if (sourceKeys$
|
|
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
|
-
|
|
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$
|
|
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$
|
|
2410
|
-
const sourceKeys$
|
|
2411
|
-
const localeKeys$
|
|
2412
|
-
if (sourceKeys$
|
|
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
|
|
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
|
|
2439
|
-
const sourceKeys = Object.keys(
|
|
2440
|
-
const localeKeys = Object.keys(
|
|
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
|
|
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 =
|
|
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-
|
|
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:
|
|
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:
|
|
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
|
|
16686
|
-
|
|
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"
|
|
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
|
|
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":"
|
|
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;
|
|
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
|
|
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.
|
|
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
|
|
28
|
-
"@a4anthony/proctorkit-sdk": "0.
|
|
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",
|