@arcware-cloud/pixelstreaming-websdk 1.2.18 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs.js +1184 -727
- package/index.esm.js +1226 -762
- package/index.umd.js +1184 -727
- package/package.json +1 -1
- package/types/lib/ArcwareApplication.d.ts +4 -0
- package/types/lib/ArcwareConfig.d.ts +1 -1
- package/types/lib/ArcwarePixelStreaming.d.ts +30 -1
- package/types/lib/features/ArcwareEventUtil.d.ts +28 -0
- package/types/lib/features/ArcwareFileTransferUtil.d.ts +13 -0
- package/types/lib/features/common.d.ts +13 -0
- /package/types/lib/{DiagnosticsCollector.d.ts → features/DiagnosticsCollector.d.ts} +0 -0
package/index.cjs.js
CHANGED
|
@@ -22843,7 +22843,7 @@ function UrlBuilder(input, urlFlags) {
|
|
|
22843
22843
|
flags.split("&").forEach((val) => {
|
|
22844
22844
|
const [key, value] = val.split("=");
|
|
22845
22845
|
// Ensure the value is encoded
|
|
22846
|
-
params.
|
|
22846
|
+
params.set(key, value);
|
|
22847
22847
|
});
|
|
22848
22848
|
}
|
|
22849
22849
|
return url.toString();
|
|
@@ -22881,6 +22881,9 @@ const ArcwarePixelStreamingApplicationStyles_1 = __webpack_require__(2299);
|
|
|
22881
22881
|
const AudioButton_1 = __webpack_require__(7734);
|
|
22882
22882
|
const MicButton_1 = __webpack_require__(2293);
|
|
22883
22883
|
const StopButton_1 = __webpack_require__(9684);
|
|
22884
|
+
const ArcwareEventUtil_1 = __webpack_require__(471);
|
|
22885
|
+
const ArcwareFileTransferUtil_1 = __webpack_require__(2768);
|
|
22886
|
+
const common_1 = __webpack_require__(2483);
|
|
22884
22887
|
const DEBUG = false;
|
|
22885
22888
|
const TextKeyRegex = /^(\['([a-zA-Z 0-9-_]+)'\] )/;
|
|
22886
22889
|
function findElementByTextContent(root, selector) {
|
|
@@ -22930,7 +22933,7 @@ const removals = {
|
|
|
22930
22933
|
// By default the UI settings should be disabled, since we have a custom method for them.
|
|
22931
22934
|
"['UI'] section.settingsContainer:not([id])": true,
|
|
22932
22935
|
// Hide option of start audio muted or not
|
|
22933
|
-
"#StartVideoMuted": true
|
|
22936
|
+
"#StartVideoMuted": true
|
|
22934
22937
|
};
|
|
22935
22938
|
if (DEBUG)
|
|
22936
22939
|
Object.keys(removals).forEach((key) => {
|
|
@@ -22956,6 +22959,8 @@ class ArcwareApplication extends lib_pixelstreamingfrontend_ui_ue5_5_1.Applicati
|
|
|
22956
22959
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
22957
22960
|
super(options);
|
|
22958
22961
|
this.responseCallback = null;
|
|
22962
|
+
this.analyticsEventCallback = null;
|
|
22963
|
+
this.fileDownloadCallback = null;
|
|
22959
22964
|
this.ArcwareSection = this.configUI.buildSectionWithHeading(this.settingsPanel.settingsContentElement, "Arcware Cloud");
|
|
22960
22965
|
this.stream = options === null || options === void 0 ? void 0 : options.stream;
|
|
22961
22966
|
this.emitUIInteraction = this.emitUIInteraction.bind(this);
|
|
@@ -22968,7 +22973,7 @@ class ArcwareApplication extends lib_pixelstreamingfrontend_ui_ue5_5_1.Applicati
|
|
|
22968
22973
|
this.parentElement = (_b = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _b === void 0 ? void 0 : _b.parentElement;
|
|
22969
22974
|
this.webRtcController = (_c = this === null || this === void 0 ? void 0 : this.stream) === null || _c === void 0 ? void 0 : _c["_webRtcController"];
|
|
22970
22975
|
this.addLoveLetterhandler();
|
|
22971
|
-
(_d = this === null || this === void 0 ? void 0 : this.stream) === null || _d === void 0 ? void 0 : _d.addResponseEventListener("ue-response", (response) => this
|
|
22976
|
+
(_d = this === null || this === void 0 ? void 0 : this.stream) === null || _d === void 0 ? void 0 : _d.addResponseEventListener("ue-response-internal", (response) => this.applicationResponse(response));
|
|
22972
22977
|
(_f = (_e = this === null || this === void 0 ? void 0 : this.stream) === null || _e === void 0 ? void 0 : _e.sessionIdHandler) === null || _f === void 0 ? void 0 : _f.add((sessionId) => {
|
|
22973
22978
|
var _a;
|
|
22974
22979
|
(_a = this === null || this === void 0 ? void 0 : this.statsPanel) === null || _a === void 0 ? void 0 : _a.addOrUpdateSessionStat("sessionId", "SessionId", sessionId);
|
|
@@ -22997,6 +23002,8 @@ class ArcwareApplication extends lib_pixelstreamingfrontend_ui_ue5_5_1.Applicati
|
|
|
22997
23002
|
this.uiElementsVisibility(false);
|
|
22998
23003
|
this.addTextToConnectOverlay();
|
|
22999
23004
|
this.preventDefaultKeyboardEvents();
|
|
23005
|
+
this.analyticsEventCallback = this.analyticsEvent;
|
|
23006
|
+
this.fileDownloadCallback = this.fileDownload;
|
|
23000
23007
|
}
|
|
23001
23008
|
addLoveLetterhandler() {
|
|
23002
23009
|
var _a, _b;
|
|
@@ -23227,8 +23234,26 @@ class ArcwareApplication extends lib_pixelstreamingfrontend_ui_ue5_5_1.Applicati
|
|
|
23227
23234
|
});
|
|
23228
23235
|
}
|
|
23229
23236
|
applicationResponse(response) {
|
|
23230
|
-
|
|
23231
|
-
|
|
23237
|
+
var _a, _b;
|
|
23238
|
+
let obj = null;
|
|
23239
|
+
try {
|
|
23240
|
+
obj = (0, common_1.parseUnknownToObject)(response, { allowJsonish: true });
|
|
23241
|
+
}
|
|
23242
|
+
catch (_c) {
|
|
23243
|
+
// If not parseable, fall through to generic callback
|
|
23244
|
+
}
|
|
23245
|
+
const t = (0, common_1.normalizeType)(obj["type"]);
|
|
23246
|
+
// route to exactly one callback
|
|
23247
|
+
if (t === "event") {
|
|
23248
|
+
(_a = this.analyticsEventCallback) === null || _a === void 0 ? void 0 : _a.call(this, response);
|
|
23249
|
+
return;
|
|
23250
|
+
}
|
|
23251
|
+
if (t === "filetransfer" || t === "createscreenshot") {
|
|
23252
|
+
(_b = this.fileDownloadCallback) === null || _b === void 0 ? void 0 : _b.call(this, response);
|
|
23253
|
+
return;
|
|
23254
|
+
}
|
|
23255
|
+
if (this.responseCallback) {
|
|
23256
|
+
this.responseCallback(response);
|
|
23232
23257
|
}
|
|
23233
23258
|
}
|
|
23234
23259
|
applyArcwareStyles() {
|
|
@@ -23267,6 +23292,49 @@ class ArcwareApplication extends lib_pixelstreamingfrontend_ui_ue5_5_1.Applicati
|
|
|
23267
23292
|
}
|
|
23268
23293
|
}
|
|
23269
23294
|
}
|
|
23295
|
+
analyticsEvent(response) {
|
|
23296
|
+
var _a;
|
|
23297
|
+
const event = (0, ArcwareEventUtil_1.toAnalyticsEvent)(response, { maxPayloadBytes: 512, allowJsonish: true });
|
|
23298
|
+
if (event.ok === false) {
|
|
23299
|
+
console.warn("Invalid AnalyticsEvent:", event.error, response);
|
|
23300
|
+
return;
|
|
23301
|
+
}
|
|
23302
|
+
(_a = this.stream) === null || _a === void 0 ? void 0 : _a.send(event.value); // send the sanitized object
|
|
23303
|
+
}
|
|
23304
|
+
fileDownload(response) {
|
|
23305
|
+
var _a;
|
|
23306
|
+
let msg;
|
|
23307
|
+
try {
|
|
23308
|
+
msg = (0, ArcwareFileTransferUtil_1.parseControl)(response, ArcwareFileTransferUtil_1.ZFileTransfer);
|
|
23309
|
+
}
|
|
23310
|
+
catch (e) {
|
|
23311
|
+
console.warn("Invalid control message:", e);
|
|
23312
|
+
return;
|
|
23313
|
+
}
|
|
23314
|
+
const file = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.file;
|
|
23315
|
+
if (!file || !file.data || !file.mimetype)
|
|
23316
|
+
return;
|
|
23317
|
+
const ext = (0, common_1.extFromMime)(file.mimetype);
|
|
23318
|
+
const base = msg.filename && msg.filename.trim() ? (0, common_1.sanitizeFilename)(msg.filename) : (0, common_1.randomHash)();
|
|
23319
|
+
const name = base + ext;
|
|
23320
|
+
try {
|
|
23321
|
+
// ✅ Make safe Blob parts (clone each chunk to ensure regular ArrayBuffer)
|
|
23322
|
+
const chunks = file.data; // <-- remove the generic
|
|
23323
|
+
const safeParts = chunks.map((u8) => u8.slice()); // fresh ArrayBuffers
|
|
23324
|
+
const blob = new Blob(safeParts, { type: file.mimetype });
|
|
23325
|
+
const url = URL.createObjectURL(blob);
|
|
23326
|
+
const a = document.createElement("a");
|
|
23327
|
+
a.href = url;
|
|
23328
|
+
a.download = name;
|
|
23329
|
+
document.body.appendChild(a);
|
|
23330
|
+
a.click();
|
|
23331
|
+
document.body.removeChild(a);
|
|
23332
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
23333
|
+
}
|
|
23334
|
+
catch (err) {
|
|
23335
|
+
console.error("Download failed:", err);
|
|
23336
|
+
}
|
|
23337
|
+
}
|
|
23270
23338
|
}
|
|
23271
23339
|
ArcwareApplication.Flags = (_a = class {
|
|
23272
23340
|
},
|
|
@@ -23351,7 +23419,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
|
|
|
23351
23419
|
if (!config.initialSettings.ss)
|
|
23352
23420
|
config.initialSettings.ss = exports.DefaultUrl;
|
|
23353
23421
|
super(config);
|
|
23354
|
-
this.VERSION = "1.
|
|
23422
|
+
this.VERSION = "1.3.1";
|
|
23355
23423
|
this.settings = settings;
|
|
23356
23424
|
this.session = new Session_1.Session();
|
|
23357
23425
|
this._initialSettings = config.initialSettings;
|
|
@@ -23503,8 +23571,75 @@ const LoveLetters_1 = __webpack_require__(4572);
|
|
|
23503
23571
|
const ArcwareLogoLoader_1 = __webpack_require__(6469);
|
|
23504
23572
|
const MicrophoneOverlay_1 = __webpack_require__(3613);
|
|
23505
23573
|
const ConnectionIdentifier_1 = __webpack_require__(5999);
|
|
23506
|
-
const DiagnosticsCollector_1 = __webpack_require__(
|
|
23574
|
+
const DiagnosticsCollector_1 = __webpack_require__(8429);
|
|
23507
23575
|
class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStreaming {
|
|
23576
|
+
bindTransportEvents() {
|
|
23577
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
23578
|
+
const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
|
|
23579
|
+
if (!current || current === this._boundTransport)
|
|
23580
|
+
return;
|
|
23581
|
+
// Unbind from previous
|
|
23582
|
+
if (this._boundTransport) {
|
|
23583
|
+
if (this._onWsOpen)
|
|
23584
|
+
(_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
|
|
23585
|
+
if (this._onWsClose)
|
|
23586
|
+
(_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
|
|
23587
|
+
}
|
|
23588
|
+
// Define (or reuse) callbacks
|
|
23589
|
+
if (!this._onWsOpen) {
|
|
23590
|
+
this._onWsOpen = () => {
|
|
23591
|
+
this.flushOutbox();
|
|
23592
|
+
// fallback nudge for videoInitialized
|
|
23593
|
+
if (!this.videoInitializedSent)
|
|
23594
|
+
setTimeout(() => this.sendVideoInitializedOnce(), 150);
|
|
23595
|
+
};
|
|
23596
|
+
}
|
|
23597
|
+
if (!this._onWsClose) {
|
|
23598
|
+
this._onWsClose = (evt) => {
|
|
23599
|
+
// Bubble to your public close handler
|
|
23600
|
+
EventHandler_1.EventHandler.Emit(this.websocketOnCloseHandler, evt);
|
|
23601
|
+
};
|
|
23602
|
+
}
|
|
23603
|
+
// Bind to current
|
|
23604
|
+
(_f = current.addEventListener) === null || _f === void 0 ? void 0 : _f.call(current, "open", this._onWsOpen);
|
|
23605
|
+
(_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "close", this._onWsClose);
|
|
23606
|
+
this._boundTransport = current;
|
|
23607
|
+
}
|
|
23608
|
+
startTransportWatcher() {
|
|
23609
|
+
// Rebind if the transport object reference changes (cheap safety net)
|
|
23610
|
+
if (this._transportWatchTimer)
|
|
23611
|
+
return;
|
|
23612
|
+
this._transportWatchTimer = window.setInterval(() => {
|
|
23613
|
+
var _a;
|
|
23614
|
+
const cur = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
|
|
23615
|
+
if (cur && cur !== this._boundTransport)
|
|
23616
|
+
this.bindTransportEvents();
|
|
23617
|
+
}, 3000); // light-touch; adjust if you like
|
|
23618
|
+
}
|
|
23619
|
+
stopTransportWatcher() {
|
|
23620
|
+
if (this._transportWatchTimer) {
|
|
23621
|
+
window.clearInterval(this._transportWatchTimer);
|
|
23622
|
+
this._transportWatchTimer = undefined;
|
|
23623
|
+
}
|
|
23624
|
+
}
|
|
23625
|
+
bindVideoElPlayingOnce() {
|
|
23626
|
+
var _a, _b, _c;
|
|
23627
|
+
const videoEl = (_c = (_b = (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
23628
|
+
if (!videoEl || videoEl === this._boundVideoEl)
|
|
23629
|
+
return;
|
|
23630
|
+
// Unbind older one if replaced
|
|
23631
|
+
if (this._boundVideoEl && this._onVideoPlaying) {
|
|
23632
|
+
this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
|
|
23633
|
+
}
|
|
23634
|
+
this._onVideoPlaying = () => this.sendVideoInitializedOnce();
|
|
23635
|
+
videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
|
|
23636
|
+
this._boundVideoEl = videoEl;
|
|
23637
|
+
}
|
|
23638
|
+
get isWsOpen() {
|
|
23639
|
+
var _a, _b;
|
|
23640
|
+
const ws = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.webSocket;
|
|
23641
|
+
return !!ws && ws.readyState === WebSocket.OPEN;
|
|
23642
|
+
}
|
|
23508
23643
|
/** Returns a list of WebSocketStates of all PixelStreaming Instances generated. */
|
|
23509
23644
|
get WebsocketStates() {
|
|
23510
23645
|
return ConnectionIdentifier_1.ConnectionIdentifier.Instance.GetWebSocketStates();
|
|
@@ -23520,11 +23655,18 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
|
|
|
23520
23655
|
return state !== undefined ? state : WebSocket.CLOSED;
|
|
23521
23656
|
}
|
|
23522
23657
|
constructor(config, overrides) {
|
|
23658
|
+
var _a, _b, _c;
|
|
23523
23659
|
/** As soon as upstream is fixed, we got to adjust the url building process. */
|
|
23524
23660
|
(0, ApplyUrlHack_1.ApplyUrlHack)();
|
|
23525
23661
|
super(config, overrides);
|
|
23526
23662
|
this.loveLettersQueue = [];
|
|
23527
23663
|
this.isProcessingQueue = false;
|
|
23664
|
+
// --- reliable send / idempotence ---
|
|
23665
|
+
this.outbox = [];
|
|
23666
|
+
this.retryTimers = new Map(); // reserved if you later add ACKs
|
|
23667
|
+
this.videoInitializedSent = false;
|
|
23668
|
+
this.versionReplyInFlight = false;
|
|
23669
|
+
this.nextMsgId = 1;
|
|
23528
23670
|
// Externalized
|
|
23529
23671
|
/** On ping the session creation timestamp will be updated. */
|
|
23530
23672
|
this.queueHandler = new EventHandler_1.EventHandler();
|
|
@@ -23547,13 +23689,29 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
|
|
|
23547
23689
|
// const signallingServerUrl = this.config.getTextSettingValue(TextParameters.SignallingServerUrl);
|
|
23548
23690
|
// return signallingServerUrl + "?" + this.config.urlFlags;
|
|
23549
23691
|
// });
|
|
23692
|
+
const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
|
|
23693
|
+
(_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
|
|
23694
|
+
this.flushOutbox();
|
|
23695
|
+
});
|
|
23696
|
+
(_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
|
|
23697
|
+
// Bubble to your public close handler if you expose one
|
|
23698
|
+
if (this.websocketOnCloseHandler) {
|
|
23699
|
+
EventHandler_1.EventHandler.Emit(this.websocketOnCloseHandler, evt);
|
|
23700
|
+
}
|
|
23701
|
+
});
|
|
23702
|
+
this.setupVideoInitFallbacks();
|
|
23550
23703
|
// Set override config.
|
|
23551
23704
|
this.config = config;
|
|
23552
23705
|
this.loveLettersList = [];
|
|
23553
23706
|
this.microphoneOverlay = new MicrophoneOverlay_1.MicrophoneOverlay(this);
|
|
23554
23707
|
this.diagnosticsCollector = new DiagnosticsCollector_1.DiagnosticsCollector({
|
|
23555
|
-
enableBandwidthProbe: false
|
|
23708
|
+
enableBandwidthProbe: false
|
|
23556
23709
|
});
|
|
23710
|
+
// after super(...) and once webRtcController is available
|
|
23711
|
+
this.bindTransportEvents();
|
|
23712
|
+
this.startTransportWatcher();
|
|
23713
|
+
// ensure video 'playing' fallback is attached to the current element
|
|
23714
|
+
this.bindVideoElPlayingOnce();
|
|
23557
23715
|
// this.loveLettersContainer = null;
|
|
23558
23716
|
this.wrapWebSocketOnCloseHandler();
|
|
23559
23717
|
// Bind the event listener function to the class instance
|
|
@@ -23580,7 +23738,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
|
|
|
23580
23738
|
this.webRtcController.streamMessageController.registerMessageHandler(0, // MessageDirection.ToStreamer,
|
|
23581
23739
|
"TextboxEntry", (messageData) => {
|
|
23582
23740
|
try {
|
|
23583
|
-
this.webRtcController.sendMessageController.sendMessageToStreamer(
|
|
23741
|
+
this.webRtcController.sendMessageController.sendMessageToStreamer("TextboxEntry", messageData);
|
|
23584
23742
|
}
|
|
23585
23743
|
catch (e) {
|
|
23586
23744
|
console.error(`Error: ToStreamer.TextboxEntry`, e);
|
|
@@ -23611,10 +23769,26 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
|
|
|
23611
23769
|
* * * * * * *
|
|
23612
23770
|
*/
|
|
23613
23771
|
/** On version requested, the version of the WebSDK would be returned. */
|
|
23614
|
-
onVersion(
|
|
23772
|
+
onVersion(_msg) {
|
|
23773
|
+
var _a, _b;
|
|
23615
23774
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
23616
|
-
|
|
23617
|
-
|
|
23775
|
+
let diagnostics;
|
|
23776
|
+
try {
|
|
23777
|
+
diagnostics = yield this.diagnosticsCollector.collect();
|
|
23778
|
+
}
|
|
23779
|
+
catch (e) {
|
|
23780
|
+
(_a = lib_pixelstreamingfrontend_ue5_5_1.Logger.Warning) === null || _a === void 0 ? void 0 : _a.call(lib_pixelstreamingfrontend_ue5_5_1.Logger, `Diagnostics collection failed: ${(_b = e === null || e === void 0 ? void 0 : e.message) !== null && _b !== void 0 ? _b : e}`);
|
|
23781
|
+
}
|
|
23782
|
+
finally {
|
|
23783
|
+
// Build payload with required fields only; append diagnostics if available
|
|
23784
|
+
const payload = {
|
|
23785
|
+
type: "version",
|
|
23786
|
+
version: this.config.VERSION
|
|
23787
|
+
};
|
|
23788
|
+
if (diagnostics !== undefined)
|
|
23789
|
+
payload.diagnostics = diagnostics;
|
|
23790
|
+
this.send(payload); // uses your buffered send
|
|
23791
|
+
}
|
|
23618
23792
|
});
|
|
23619
23793
|
}
|
|
23620
23794
|
/** On ping the session creation timestamp will be updated. */
|
|
@@ -23681,16 +23855,67 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
|
|
|
23681
23855
|
this.session.set(message.sessionId);
|
|
23682
23856
|
EventHandler_1.EventHandler.Emit(this.sessionIdHandler, message.sessionId);
|
|
23683
23857
|
}
|
|
23858
|
+
sendVideoInitializedOnce() {
|
|
23859
|
+
if (this.videoInitializedSent)
|
|
23860
|
+
return;
|
|
23861
|
+
this.videoInitializedSent = true;
|
|
23862
|
+
// Use withId if you plan to support idempotence on the server
|
|
23863
|
+
this.send(/* this.withId( */ { type: "onVideoInitialized" } /* ) */);
|
|
23864
|
+
if (this.videoInitializedHandler) {
|
|
23865
|
+
EventHandler_1.EventHandler.Emit(this.videoInitializedHandler, undefined);
|
|
23866
|
+
}
|
|
23867
|
+
}
|
|
23868
|
+
// Attach fallbacks once (call this in constructor after transport wiring)
|
|
23869
|
+
setupVideoInitFallbacks() {
|
|
23870
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
23871
|
+
// Fallback #1: HTMLVideoElement 'playing'
|
|
23872
|
+
const videoEl = (_c = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
23873
|
+
(_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => this.sendVideoInitializedOnce(), { once: true });
|
|
23874
|
+
// Fallback #2: stats hook (if you emit one)
|
|
23875
|
+
(_e = this.addEventListener) === null || _e === void 0 ? void 0 : _e.call(this, "statsReceived", (e) => {
|
|
23876
|
+
var _a, _b;
|
|
23877
|
+
const stats = e === null || e === void 0 ? void 0 : e.detail;
|
|
23878
|
+
if (!this.videoInitializedSent && ((_b = (_a = stats === null || stats === void 0 ? void 0 : stats.video) === null || _a === void 0 ? void 0 : _a.framesDecoded) !== null && _b !== void 0 ? _b : 0) > 0) {
|
|
23879
|
+
this.sendVideoInitializedOnce();
|
|
23880
|
+
}
|
|
23881
|
+
});
|
|
23882
|
+
// Fallback #3: after socket opens, give it a tick
|
|
23883
|
+
const transport = (_f = this.webRtcController) === null || _f === void 0 ? void 0 : _f.transport;
|
|
23884
|
+
(_g = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _g === void 0 ? void 0 : _g.call(transport, "open", () => {
|
|
23885
|
+
if (!this.videoInitializedSent) {
|
|
23886
|
+
setTimeout(() => this.sendVideoInitializedOnce(), 150);
|
|
23887
|
+
}
|
|
23888
|
+
});
|
|
23889
|
+
}
|
|
23684
23890
|
onVideoInitialized() {
|
|
23685
|
-
|
|
23686
|
-
|
|
23687
|
-
this.
|
|
23688
|
-
|
|
23689
|
-
|
|
23690
|
-
|
|
23691
|
-
|
|
23692
|
-
|
|
23693
|
-
|
|
23891
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
23892
|
+
// send early and once
|
|
23893
|
+
this.sendVideoInitializedOnce();
|
|
23894
|
+
// keep side-effects guarded so they can't break the send
|
|
23895
|
+
try {
|
|
23896
|
+
(_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
23897
|
+
}
|
|
23898
|
+
catch (_h) { }
|
|
23899
|
+
try {
|
|
23900
|
+
(_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
23901
|
+
}
|
|
23902
|
+
catch (_j) { }
|
|
23903
|
+
try {
|
|
23904
|
+
(_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
|
|
23905
|
+
}
|
|
23906
|
+
catch (_k) { }
|
|
23907
|
+
try {
|
|
23908
|
+
(_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
|
|
23909
|
+
}
|
|
23910
|
+
catch (_l) { }
|
|
23911
|
+
try {
|
|
23912
|
+
(_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
|
|
23913
|
+
}
|
|
23914
|
+
catch (_m) { }
|
|
23915
|
+
try {
|
|
23916
|
+
(_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
|
|
23917
|
+
}
|
|
23918
|
+
catch (_o) { }
|
|
23694
23919
|
}
|
|
23695
23920
|
/** Adding a zod-safe handler. */
|
|
23696
23921
|
addMessageHandler(type, zod, boundMethod) {
|
|
@@ -23705,7 +23930,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
|
|
|
23705
23930
|
lib_pixelstreamingfrontend_ue5_5_1.Logger.Error(error.message);
|
|
23706
23931
|
}
|
|
23707
23932
|
if (type === "error") {
|
|
23708
|
-
this.disconnect();
|
|
23933
|
+
//this.disconnect();
|
|
23709
23934
|
}
|
|
23710
23935
|
});
|
|
23711
23936
|
}
|
|
@@ -23719,19 +23944,48 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
|
|
|
23719
23944
|
// This cast has to be done, since Frontend does not use typescript-strict setting.
|
|
23720
23945
|
this.send(message);
|
|
23721
23946
|
}
|
|
23722
|
-
send(
|
|
23723
|
-
|
|
23724
|
-
|
|
23725
|
-
|
|
23726
|
-
|
|
23727
|
-
|
|
23728
|
-
|
|
23729
|
-
|
|
23730
|
-
lib_pixelstreamingfrontend_ue5_5_1.Logger.Error(`
|
|
23947
|
+
send(a, b) {
|
|
23948
|
+
var _a, _b;
|
|
23949
|
+
const msg = typeof a === "string" ? Object.assign({ type: a }, (b !== null && b !== void 0 ? b : {})) : a;
|
|
23950
|
+
// Optional zod validation if you have schemas for this type
|
|
23951
|
+
const schema = (_a = shared_pixelstreaming_websdk_1.Messages.Send) === null || _a === void 0 ? void 0 : _a[msg.type];
|
|
23952
|
+
if (schema) {
|
|
23953
|
+
const result = schema.safeParse(msg);
|
|
23954
|
+
if (!result.success) {
|
|
23955
|
+
(_b = lib_pixelstreamingfrontend_ue5_5_1.Logger.Error) === null || _b === void 0 ? void 0 : _b.call(lib_pixelstreamingfrontend_ue5_5_1.Logger, `Send validation failed for ${msg.type}: ${result.error}`);
|
|
23956
|
+
return;
|
|
23731
23957
|
}
|
|
23958
|
+
this._dispatchOrBuffer(result.data);
|
|
23732
23959
|
}
|
|
23733
23960
|
else {
|
|
23734
|
-
this.
|
|
23961
|
+
this._dispatchOrBuffer(msg);
|
|
23962
|
+
}
|
|
23963
|
+
}
|
|
23964
|
+
_dispatchOrBuffer(message) {
|
|
23965
|
+
if (this.isWsOpen) {
|
|
23966
|
+
try {
|
|
23967
|
+
this.signallingProtocol.sendMessage(message);
|
|
23968
|
+
return;
|
|
23969
|
+
}
|
|
23970
|
+
catch (_a) {
|
|
23971
|
+
// fallthrough to buffer
|
|
23972
|
+
}
|
|
23973
|
+
}
|
|
23974
|
+
this.outbox.push(message);
|
|
23975
|
+
}
|
|
23976
|
+
flushOutbox() {
|
|
23977
|
+
if (!this.isWsOpen || this.outbox.length === 0)
|
|
23978
|
+
return;
|
|
23979
|
+
const batch = this.outbox.splice(0, this.outbox.length);
|
|
23980
|
+
for (const m of batch) {
|
|
23981
|
+
try {
|
|
23982
|
+
this.signallingProtocol.sendMessage(m);
|
|
23983
|
+
}
|
|
23984
|
+
catch (_a) {
|
|
23985
|
+
// if we fail mid-flush, put remaining back and bail
|
|
23986
|
+
this.outbox.unshift(m, ...batch.slice(batch.indexOf(m) + 1));
|
|
23987
|
+
break;
|
|
23988
|
+
}
|
|
23735
23989
|
}
|
|
23736
23990
|
}
|
|
23737
23991
|
handleResolutionChange() {
|
|
@@ -23795,7 +24049,18 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
|
|
|
23795
24049
|
}
|
|
23796
24050
|
}
|
|
23797
24051
|
removePlayer() {
|
|
23798
|
-
|
|
24052
|
+
var _a, _b, _c, _d;
|
|
24053
|
+
this.stopTransportWatcher();
|
|
24054
|
+
// Optional: unbind handlers
|
|
24055
|
+
if (this._boundTransport) {
|
|
24056
|
+
if (this._onWsOpen)
|
|
24057
|
+
(_b = (_a = this._boundTransport).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, "open", this._onWsOpen);
|
|
24058
|
+
if (this._onWsClose)
|
|
24059
|
+
(_d = (_c = this._boundTransport).removeEventListener) === null || _d === void 0 ? void 0 : _d.call(_c, "close", this._onWsClose);
|
|
24060
|
+
}
|
|
24061
|
+
if (this._boundVideoEl && this._onVideoPlaying) {
|
|
24062
|
+
this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
|
|
24063
|
+
}
|
|
23799
24064
|
this.disconnect();
|
|
23800
24065
|
}
|
|
23801
24066
|
handleMouseLock() {
|
|
@@ -23893,11 +24158,11 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
|
|
|
23893
24158
|
(_a = this === null || this === void 0 ? void 0 : this.config) === null || _a === void 0 ? void 0 : _a.setFlagEnabled(lib_pixelstreamingfrontend_ue5_5_1.Flags.UseMic, enable);
|
|
23894
24159
|
if (!isDefault) {
|
|
23895
24160
|
(_b = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _b === void 0 ? void 0 : _b.toggleMessage(enable);
|
|
24161
|
+
setTimeout(() => { var _a; return (_a = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _a === void 0 ? void 0 : _a.toggleVisibility(true); }, 200);
|
|
23896
24162
|
setTimeout(() => {
|
|
23897
|
-
|
|
23898
|
-
|
|
23899
|
-
|
|
23900
|
-
setTimeout(() => {
|
|
24163
|
+
this.videoInitializedSent = false; // <-- reset before a real media restart
|
|
24164
|
+
this.bindVideoElPlayingOnce(); // in case a new element will appear
|
|
24165
|
+
this.bindTransportEvents(); // cheap rebind now
|
|
23901
24166
|
this.reconnect();
|
|
23902
24167
|
}, 1000);
|
|
23903
24168
|
}
|
|
@@ -23949,767 +24214,959 @@ exports.ArcwarePixelStreaming = ArcwarePixelStreaming;
|
|
|
23949
24214
|
|
|
23950
24215
|
/***/ }),
|
|
23951
24216
|
|
|
23952
|
-
/***/
|
|
24217
|
+
/***/ 5602:
|
|
23953
24218
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
23954
24219
|
|
|
23955
24220
|
|
|
23956
|
-
/**
|
|
23957
|
-
* DiagnosticsCollector.ts
|
|
23958
|
-
* Lightweight, privacy-aware client diagnostics for troubleshooting + analytics.
|
|
23959
|
-
* WebRTC collection intentionally omitted (to add later).
|
|
23960
|
-
*
|
|
23961
|
-
* Notes:
|
|
23962
|
-
* - Some fields are best-effort due to browser restrictions; they're nullable.
|
|
23963
|
-
* - Bandwidth probe requires a small binary served with:
|
|
23964
|
-
* Content-Type: application/octet-stream
|
|
23965
|
-
* Content-Encoding: identity
|
|
23966
|
-
* Cache-Control: no-store
|
|
23967
|
-
* Default location: /diag/probe.bin
|
|
23968
|
-
*/
|
|
23969
24221
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
23970
|
-
exports.
|
|
23971
|
-
const
|
|
23972
|
-
|
|
23973
|
-
|
|
23974
|
-
|
|
23975
|
-
|
|
23976
|
-
|
|
23977
|
-
|
|
23978
|
-
|
|
23979
|
-
|
|
23980
|
-
|
|
23981
|
-
|
|
23982
|
-
|
|
23983
|
-
/**
|
|
23984
|
-
|
|
23985
|
-
*/
|
|
23986
|
-
|
|
23987
|
-
|
|
23988
|
-
|
|
23989
|
-
|
|
23990
|
-
|
|
23991
|
-
|
|
23992
|
-
|
|
23993
|
-
|
|
23994
|
-
|
|
23995
|
-
|
|
24222
|
+
exports.ArcwareSettingsSchema = void 0;
|
|
24223
|
+
const zod_1 = __webpack_require__(8754);
|
|
24224
|
+
const shared_pixelstreaming_websdk_1 = __webpack_require__(7910);
|
|
24225
|
+
/** Arcware Settings. */
|
|
24226
|
+
exports.ArcwareSettingsSchema = zod_1.z.object({
|
|
24227
|
+
/** Overwrites the Session-Tool and uses the provided session instead. */
|
|
24228
|
+
session: zod_1.z.string().optional(),
|
|
24229
|
+
/** Can be used to be added to the request in order to verify access to private projects.
|
|
24230
|
+
* For internal use only. => Preview page.
|
|
24231
|
+
*/
|
|
24232
|
+
token: zod_1.z.string().optional(),
|
|
24233
|
+
/** @deprecated in there for legacy use. Can only be used when token is provided. */
|
|
24234
|
+
bypass: zod_1.z.boolean().optional(),
|
|
24235
|
+
// /** Configure DirectFlow Token. */
|
|
24236
|
+
// directFlow: z.string().optional(),
|
|
24237
|
+
/** Handler for server side error messages. */
|
|
24238
|
+
errorHandler: zod_1.z.function().args(shared_pixelstreaming_websdk_1.Messages.ZErrorMessage).returns(zod_1.z.void()).optional(),
|
|
24239
|
+
/** Handler for queue events. */
|
|
24240
|
+
queueHandler: zod_1.z.function().args(shared_pixelstreaming_websdk_1.Messages.ZQueue).returns(zod_1.z.void()).optional(),
|
|
24241
|
+
/** Handler for sessionId message. */
|
|
24242
|
+
sessionIdHandler: zod_1.z.function().args(zod_1.z.string()).returns(zod_1.z.void()).optional(),
|
|
24243
|
+
/** Handler for love letters.
|
|
24244
|
+
* "LoveLetters" are send from backend to the SDK to state what phase the connection currently is in. */
|
|
24245
|
+
loveLetterHandler: zod_1.z.function().args(shared_pixelstreaming_websdk_1.Messages.ZLoveLetter).returns(zod_1.z.void()).optional(),
|
|
24246
|
+
/** Show or hide the fullscreen button. */
|
|
24247
|
+
fullscreenButton: zod_1.z.boolean().optional(),
|
|
24248
|
+
/** Show or hide the settings button. */
|
|
24249
|
+
settingsButton: zod_1.z.boolean().optional(),
|
|
24250
|
+
/** Show or hide the info button. */
|
|
24251
|
+
infoButton: zod_1.z.boolean().optional(),
|
|
24252
|
+
/** Show or hide the audio button. */
|
|
24253
|
+
audioButton: zod_1.z.boolean().optional(),
|
|
24254
|
+
/** Show or hide the microphone button. */
|
|
24255
|
+
micButton: zod_1.z.boolean().optional(),
|
|
24256
|
+
/** Show or hide the microphone button. */
|
|
24257
|
+
stopButton: zod_1.z.boolean().optional(),
|
|
24258
|
+
/** Show or hide the connectionStrengthIcon button. */
|
|
24259
|
+
connectionStrengthIcon: zod_1.z.boolean().optional(),
|
|
24260
|
+
/** ShareId, used for sharing your project.
|
|
24261
|
+
* Using ArcwareInit will set this required property for you. */
|
|
24262
|
+
shareId: zod_1.z.string().startsWith("share-").optional(),
|
|
24263
|
+
/** Id of your project, only required if your shareId refers to multiple projects.
|
|
24264
|
+
* Using ArcwareInit will set this required property for you. */
|
|
24265
|
+
projectId: zod_1.z.string().optional(),
|
|
24266
|
+
/** Enable/Disable LoveLetter logging to the console. */
|
|
24267
|
+
loveLetterLogging: zod_1.z.boolean().optional(),
|
|
24268
|
+
/** Enable/Disable Connection Identifier logging to the console. */
|
|
24269
|
+
connectionIdentifierLoggingDisabled: zod_1.z.boolean().optional(),
|
|
24270
|
+
/** Width with which instance should be started */
|
|
24271
|
+
startWidth: zod_1.z.number().optional(),
|
|
24272
|
+
/** Height with which instance should be started */
|
|
24273
|
+
startHeight: zod_1.z.number().optional()
|
|
24274
|
+
});
|
|
24275
|
+
|
|
24276
|
+
|
|
24277
|
+
/***/ }),
|
|
24278
|
+
|
|
24279
|
+
/***/ 5999:
|
|
24280
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
24281
|
+
|
|
24282
|
+
|
|
24283
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24284
|
+
exports.ConnectionIdentifier = exports.WebsocketState = void 0;
|
|
24285
|
+
var WebsocketState;
|
|
24286
|
+
(function (WebsocketState) {
|
|
24287
|
+
// Socket has been created. The connection is not yet open.
|
|
24288
|
+
WebsocketState[WebsocketState["CONNECTING"] = 0] = "CONNECTING";
|
|
24289
|
+
// The connection is open and ready to communicate.
|
|
24290
|
+
WebsocketState[WebsocketState["OPEN"] = 1] = "OPEN";
|
|
24291
|
+
// The connection is in the process of closing.
|
|
24292
|
+
WebsocketState[WebsocketState["CLOSING"] = 2] = "CLOSING";
|
|
24293
|
+
// The connection is closed or couldn't be opened.
|
|
24294
|
+
WebsocketState[WebsocketState["CLOSED"] = 3] = "CLOSED";
|
|
24295
|
+
})(WebsocketState = exports.WebsocketState || (exports.WebsocketState = {}));
|
|
24296
|
+
class ConnectionIdentifier {
|
|
24297
|
+
static get Instance() {
|
|
24298
|
+
if (!this.instance) {
|
|
24299
|
+
this.instance = new ConnectionIdentifier();
|
|
24300
|
+
}
|
|
24301
|
+
return this.instance;
|
|
24302
|
+
}
|
|
24303
|
+
get WebsocketStates() {
|
|
24304
|
+
return this.aps.map((ps) => ps.websocketState);
|
|
24305
|
+
}
|
|
24306
|
+
constructor() {
|
|
24307
|
+
this.aps = [];
|
|
24308
|
+
this.enabled = true;
|
|
24309
|
+
}
|
|
24310
|
+
register(ps) {
|
|
24311
|
+
var _a;
|
|
24312
|
+
if (!this.aps.includes(ps)) {
|
|
24313
|
+
this.aps.push(ps);
|
|
24314
|
+
if ((_a = ps.config.settings) === null || _a === void 0 ? void 0 : _a.connectionIdentifierLoggingDisabled)
|
|
24315
|
+
this.disable();
|
|
24316
|
+
}
|
|
24317
|
+
if (!this.interval)
|
|
24318
|
+
this.interval = setInterval(this.connectionWatcher.bind(this), 10 * 1000);
|
|
24319
|
+
}
|
|
24320
|
+
GetWebSocketStates() {
|
|
24321
|
+
return this.aps.map((ps) => ps.websocketState);
|
|
24322
|
+
}
|
|
24323
|
+
ActiveInstances() {
|
|
24324
|
+
return this.GetWebSocketStates().filter((state) => state <= WebsocketState.OPEN).length;
|
|
24325
|
+
}
|
|
24326
|
+
disable() {
|
|
24327
|
+
this.enabled = false;
|
|
23996
24328
|
}
|
|
23997
24329
|
/**
|
|
23998
|
-
*
|
|
24330
|
+
* The purpose of this method is to periodically tell the developer the amount of connected instances.
|
|
24331
|
+
* This way the developer can figure out, when they messed up the implementation and there's shadow instances still running.
|
|
24332
|
+
* Or when they accidentally set up multiple connections!
|
|
24333
|
+
* Things like that can happen, for example if the React.useEffect was not setup perfectly!
|
|
23999
24334
|
*/
|
|
24000
|
-
|
|
24001
|
-
|
|
24002
|
-
|
|
24003
|
-
|
|
24004
|
-
|
|
24005
|
-
|
|
24006
|
-
|
|
24007
|
-
|
|
24008
|
-
|
|
24009
|
-
|
|
24010
|
-
};
|
|
24011
|
-
}
|
|
24012
|
-
const collectedAt = Date.now();
|
|
24013
|
-
const [uaInfo, codecSupport, measuredDownlinkMbps] = yield Promise.all([
|
|
24014
|
-
this.getUAInfo(),
|
|
24015
|
-
this.getCodecSupport(),
|
|
24016
|
-
this.maybeMeasureBandwidth()
|
|
24017
|
-
]);
|
|
24018
|
-
return {
|
|
24019
|
-
device: {
|
|
24020
|
-
type: this.inferDeviceType(),
|
|
24021
|
-
vendor: null,
|
|
24022
|
-
model: uaInfo.model,
|
|
24023
|
-
architecture: uaInfo.architecture,
|
|
24024
|
-
bitness: uaInfo.bitness,
|
|
24025
|
-
touchSupport: this.hasTouch(),
|
|
24026
|
-
hardwareConcurrency: (_a = navigator.hardwareConcurrency) !== null && _a !== void 0 ? _a : null,
|
|
24027
|
-
deviceMemory: (_b = navigator.deviceMemory) !== null && _b !== void 0 ? _b : null,
|
|
24028
|
-
orientation: this.getOrientation(),
|
|
24029
|
-
webgl: this.hasWebGL(),
|
|
24030
|
-
codecs: codecSupport
|
|
24031
|
-
},
|
|
24032
|
-
runtime: {
|
|
24033
|
-
browser: { family: uaInfo.browserFamily, version: uaInfo.browserVersion },
|
|
24034
|
-
os: { family: uaInfo.osFamily, version: uaInfo.osVersion }
|
|
24035
|
-
},
|
|
24036
|
-
powerHints: this.getPowerHints(),
|
|
24037
|
-
network: this.getNetworkInfo(measuredDownlinkMbps),
|
|
24038
|
-
timestamps: { collectedAt }
|
|
24039
|
-
};
|
|
24040
|
-
});
|
|
24335
|
+
connectionWatcher() {
|
|
24336
|
+
if (!this.enabled)
|
|
24337
|
+
return;
|
|
24338
|
+
const activeStates = this.GetWebSocketStates().filter((state) => state <= WebsocketState.OPEN);
|
|
24339
|
+
if (activeStates.length === 1) {
|
|
24340
|
+
console.log(`PixelStreaming Instance is connected.`);
|
|
24341
|
+
}
|
|
24342
|
+
else if (activeStates.length !== 0) {
|
|
24343
|
+
console.warn(`${activeStates.length} PixelStreaming Instances are connected!`);
|
|
24344
|
+
}
|
|
24041
24345
|
}
|
|
24042
|
-
|
|
24043
|
-
|
|
24044
|
-
|
|
24045
|
-
|
|
24046
|
-
|
|
24047
|
-
|
|
24048
|
-
|
|
24049
|
-
|
|
24050
|
-
|
|
24051
|
-
|
|
24052
|
-
|
|
24053
|
-
|
|
24054
|
-
|
|
24055
|
-
|
|
24056
|
-
|
|
24057
|
-
|
|
24058
|
-
|
|
24059
|
-
|
|
24060
|
-
|
|
24061
|
-
|
|
24062
|
-
|
|
24063
|
-
localCandidateType: (_b = local === null || local === void 0 ? void 0 : local.candidateType) !== null && _b !== void 0 ? _b : null,
|
|
24064
|
-
remoteCandidateType: (_c = remote === null || remote === void 0 ? void 0 : remote.candidateType) !== null && _c !== void 0 ? _c : null,
|
|
24065
|
-
protocol: (_d = local === null || local === void 0 ? void 0 : local.protocol) !== null && _d !== void 0 ? _d : null,
|
|
24066
|
-
networkType: (_e = local === null || local === void 0 ? void 0 : local.networkType) !== null && _e !== void 0 ? _e : null,
|
|
24067
|
-
dtlsCipher: (_f = transport === null || transport === void 0 ? void 0 : transport.dtlsCipher) !== null && _f !== void 0 ? _f : null
|
|
24068
|
-
};
|
|
24069
|
-
}
|
|
24070
|
-
catch (_g) {
|
|
24071
|
-
return {};
|
|
24072
|
-
}
|
|
24073
|
-
});
|
|
24346
|
+
}
|
|
24347
|
+
exports.ConnectionIdentifier = ConnectionIdentifier;
|
|
24348
|
+
|
|
24349
|
+
|
|
24350
|
+
/***/ }),
|
|
24351
|
+
|
|
24352
|
+
/***/ 3379:
|
|
24353
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
24354
|
+
|
|
24355
|
+
|
|
24356
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24357
|
+
exports.EventHandler = void 0;
|
|
24358
|
+
/** A helper class to spread the event to additional event handlers added from external sources. */
|
|
24359
|
+
class EventHandler {
|
|
24360
|
+
/** Returns the added callback on success or null, if something went wrong. */
|
|
24361
|
+
add(callback) {
|
|
24362
|
+
const cb = this.callbacks.find((cb) => cb === callback);
|
|
24363
|
+
if (cb)
|
|
24364
|
+
return null;
|
|
24365
|
+
this.callbacks.push(callback);
|
|
24366
|
+
return callback;
|
|
24074
24367
|
}
|
|
24075
|
-
/**
|
|
24076
|
-
|
|
24077
|
-
|
|
24078
|
-
|
|
24079
|
-
|
|
24080
|
-
|
|
24081
|
-
const webrtc = pc ? yield this.collectWebRTC(pc) : undefined;
|
|
24082
|
-
const ext = webrtc ? { diag: Object.assign(Object.assign({}, diag), { webrtc }) } : { diag };
|
|
24083
|
-
return Object.assign(Object.assign({}, base), { ext });
|
|
24084
|
-
});
|
|
24368
|
+
/** Returns true if the input callback has been found and removed and false if not. */
|
|
24369
|
+
remove(callback) {
|
|
24370
|
+
const cb = this.callbacks.find((cb) => cb === callback);
|
|
24371
|
+
if (cb)
|
|
24372
|
+
this.callbacks.splice(this.callbacks.indexOf(cb), 1);
|
|
24373
|
+
return !!cb;
|
|
24085
24374
|
}
|
|
24086
|
-
|
|
24087
|
-
|
|
24088
|
-
if (this.opts.sampleRate >= 1)
|
|
24089
|
-
return true;
|
|
24090
|
-
return Math.random() < this.opts.sampleRate;
|
|
24375
|
+
constructor() {
|
|
24376
|
+
this.callbacks = new Array();
|
|
24091
24377
|
}
|
|
24092
|
-
|
|
24093
|
-
|
|
24094
|
-
|
|
24095
|
-
return "ontouchstart" in window || ((_a = nav.maxTouchPoints) !== null && _a !== void 0 ? _a : 0) > 0;
|
|
24378
|
+
/** Emits the event-data for each of the existing handlers. */
|
|
24379
|
+
static Emit(handler, event) {
|
|
24380
|
+
handler.callbacks.forEach((callback) => callback(event));
|
|
24096
24381
|
}
|
|
24097
|
-
|
|
24098
|
-
|
|
24099
|
-
|
|
24100
|
-
|
|
24101
|
-
|
|
24102
|
-
|
|
24103
|
-
|
|
24104
|
-
|
|
24105
|
-
|
|
24106
|
-
|
|
24107
|
-
|
|
24108
|
-
|
|
24382
|
+
}
|
|
24383
|
+
exports.EventHandler = EventHandler;
|
|
24384
|
+
|
|
24385
|
+
|
|
24386
|
+
/***/ }),
|
|
24387
|
+
|
|
24388
|
+
/***/ 2469:
|
|
24389
|
+
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
24390
|
+
|
|
24391
|
+
|
|
24392
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24393
|
+
exports.Session = void 0;
|
|
24394
|
+
const addSeconds_1 = __webpack_require__(1973);
|
|
24395
|
+
const isBefore_1 = __webpack_require__(313);
|
|
24396
|
+
const zod_1 = __webpack_require__(8754);
|
|
24397
|
+
const ZSession = zod_1.z
|
|
24398
|
+
.object({
|
|
24399
|
+
id: zod_1.z.string().min(1),
|
|
24400
|
+
created: zod_1.z
|
|
24401
|
+
.date()
|
|
24402
|
+
.or(zod_1.z.string())
|
|
24403
|
+
.transform((arg) => new Date(arg)),
|
|
24404
|
+
expire: zod_1.z.boolean().default(false).optional(),
|
|
24405
|
+
})
|
|
24406
|
+
.strict();
|
|
24407
|
+
const ZOptions = zod_1.z.object({
|
|
24408
|
+
localStorageKey: zod_1.z.string().min(3).default("pxss"),
|
|
24409
|
+
keepSession: zod_1.z
|
|
24410
|
+
.number()
|
|
24411
|
+
.int()
|
|
24412
|
+
.min(3)
|
|
24413
|
+
/** Default keep is 10, since this is how long instances will be kept alive by default. */
|
|
24414
|
+
.default(10),
|
|
24415
|
+
});
|
|
24416
|
+
/** The sessionId is stored in the localStorage to allow for reconnection and
|
|
24417
|
+
* to prevent spamming start requests of instances, when smashing F5.
|
|
24418
|
+
*/
|
|
24419
|
+
class Session {
|
|
24420
|
+
get current() {
|
|
24421
|
+
return this._current;
|
|
24109
24422
|
}
|
|
24110
|
-
|
|
24111
|
-
|
|
24112
|
-
const canvas = document.createElement("canvas");
|
|
24113
|
-
return !!(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"));
|
|
24114
|
-
}
|
|
24115
|
-
catch (_a) {
|
|
24116
|
-
return false;
|
|
24117
|
-
}
|
|
24423
|
+
get noSession() {
|
|
24424
|
+
return new URLSearchParams(window.location.search).has("noSession");
|
|
24118
24425
|
}
|
|
24119
|
-
|
|
24120
|
-
|
|
24121
|
-
|
|
24122
|
-
|
|
24123
|
-
|
|
24124
|
-
|
|
24125
|
-
|
|
24126
|
-
|
|
24127
|
-
const minDim = Math.min(screen.width, screen.height);
|
|
24128
|
-
// 1. Explicit iPad / tablet detection via UA (iOS often lies in CH)
|
|
24129
|
-
if (/\b(iPad|Tablet)\b/i.test(ua)) {
|
|
24130
|
-
return Type.Tablet;
|
|
24131
|
-
}
|
|
24132
|
-
// 2. UA-CH mobile hint (Chromium only, often accurate for Android)
|
|
24133
|
-
if (isMobileCH) {
|
|
24134
|
-
if (minDim >= 600)
|
|
24135
|
-
return Type.Tablet;
|
|
24136
|
-
return Type.Mobile;
|
|
24137
|
-
}
|
|
24138
|
-
// 3. UA sniffing fallback for mobile
|
|
24139
|
-
if (/\b(iPhone|Android.*Mobile|Windows Phone)\b/i.test(ua)) {
|
|
24140
|
-
return Type.Mobile;
|
|
24426
|
+
get id() {
|
|
24427
|
+
// If the query-parameter "noSession" or "nosession" is set, it will be skipped.
|
|
24428
|
+
if (this.noSession)
|
|
24429
|
+
return null;
|
|
24430
|
+
const sessionString = window.localStorage.getItem(this.localStorageKey);
|
|
24431
|
+
// No session yet set.
|
|
24432
|
+
if (sessionString === null) {
|
|
24433
|
+
return null;
|
|
24141
24434
|
}
|
|
24142
|
-
|
|
24143
|
-
|
|
24144
|
-
|
|
24435
|
+
const parsed = ZSession.safeParse(JSON.parse(sessionString));
|
|
24436
|
+
// Clear the session if it's not valid.
|
|
24437
|
+
if (!parsed.success) {
|
|
24438
|
+
this.unset();
|
|
24439
|
+
return null;
|
|
24145
24440
|
}
|
|
24146
|
-
|
|
24147
|
-
|
|
24148
|
-
|
|
24149
|
-
|
|
24150
|
-
|
|
24151
|
-
const saveData = typeof (conn === null || conn === void 0 ? void 0 : conn.saveData) === "boolean" ? conn.saveData : null;
|
|
24152
|
-
let prefersReducedData = null;
|
|
24153
|
-
let prefersReducedMotion = null;
|
|
24154
|
-
if (typeof window.matchMedia === "function") {
|
|
24155
|
-
try {
|
|
24156
|
-
const mqData = window.matchMedia("(prefers-reduced-data: reduce)");
|
|
24157
|
-
if (typeof mqData.matches === "boolean") {
|
|
24158
|
-
prefersReducedData = mqData.matches;
|
|
24159
|
-
}
|
|
24160
|
-
}
|
|
24161
|
-
catch (_a) { }
|
|
24162
|
-
try {
|
|
24163
|
-
const mqMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
24164
|
-
if (typeof mqMotion.matches === "boolean") {
|
|
24165
|
-
prefersReducedMotion = mqMotion.matches;
|
|
24166
|
-
}
|
|
24167
|
-
}
|
|
24168
|
-
catch (_b) { }
|
|
24441
|
+
const session = parsed.data;
|
|
24442
|
+
const expirationTime = (0, addSeconds_1.default)(new Date(session.created), this.options.keepSession);
|
|
24443
|
+
if ((0, isBefore_1.default)(expirationTime, new Date())) {
|
|
24444
|
+
this.unset();
|
|
24445
|
+
return null;
|
|
24169
24446
|
}
|
|
24170
|
-
|
|
24171
|
-
|
|
24172
|
-
getNetworkInfo(measuredDownlinkMbps) {
|
|
24173
|
-
const conn = navigator.connection;
|
|
24174
|
-
return {
|
|
24175
|
-
type: typeof (conn === null || conn === void 0 ? void 0 : conn.type) === "string" ? conn.type : null,
|
|
24176
|
-
effectiveType: typeof (conn === null || conn === void 0 ? void 0 : conn.effectiveType) === "string" ? conn.effectiveType : null,
|
|
24177
|
-
downlinkMbps: typeof (conn === null || conn === void 0 ? void 0 : conn.downlink) === "number" ? conn.downlink : null,
|
|
24178
|
-
rttMs: typeof (conn === null || conn === void 0 ? void 0 : conn.rtt) === "number" ? conn.rtt : null,
|
|
24179
|
-
measuredDownlinkMbps
|
|
24180
|
-
};
|
|
24181
|
-
}
|
|
24182
|
-
maybeMeasureBandwidth() {
|
|
24183
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
24184
|
-
const conn = navigator.connection;
|
|
24185
|
-
const saveData = (conn === null || conn === void 0 ? void 0 : conn.saveData) === true;
|
|
24186
|
-
if (!this.opts.enableBandwidthProbe)
|
|
24187
|
-
return null;
|
|
24188
|
-
if (this.opts.respectSaveData && saveData)
|
|
24189
|
-
return null;
|
|
24190
|
-
try {
|
|
24191
|
-
const t0 = performance.now();
|
|
24192
|
-
const res = yield fetch(this.withCacheBuster(this.opts.probeUrl), {
|
|
24193
|
-
cache: "no-store",
|
|
24194
|
-
credentials: "omit"
|
|
24195
|
-
});
|
|
24196
|
-
const buf = yield res.arrayBuffer();
|
|
24197
|
-
const t1 = performance.now();
|
|
24198
|
-
const bits = buf.byteLength * 8;
|
|
24199
|
-
const seconds = (t1 - t0) / 1000;
|
|
24200
|
-
if (seconds <= 0.05)
|
|
24201
|
-
return null; // ignore unstable samples
|
|
24202
|
-
return +(bits / seconds / 1000000).toFixed(2);
|
|
24203
|
-
}
|
|
24204
|
-
catch (_a) {
|
|
24205
|
-
return null;
|
|
24206
|
-
}
|
|
24207
|
-
});
|
|
24447
|
+
// Return the sessionId.
|
|
24448
|
+
return session.id;
|
|
24208
24449
|
}
|
|
24209
|
-
|
|
24210
|
-
|
|
24211
|
-
const u = new URL(url, location.origin);
|
|
24212
|
-
const token = (_b = (_a = crypto === null || crypto === void 0 ? void 0 : crypto.randomUUID) === null || _a === void 0 ? void 0 : _a.call(crypto)) !== null && _b !== void 0 ? _b : String(Date.now());
|
|
24213
|
-
u.searchParams.set("cb", token);
|
|
24214
|
-
return u.toString();
|
|
24450
|
+
get localStorageKey() {
|
|
24451
|
+
return this.options.localStorageKey;
|
|
24215
24452
|
}
|
|
24216
|
-
|
|
24217
|
-
|
|
24218
|
-
const [h264, hevc] = yield Promise.all([
|
|
24219
|
-
this.supportsCodec('video/mp4; codecs="avc1.42E01E"'),
|
|
24220
|
-
this.supportsCodec('video/mp4; codecs="hvc1.1.6.L93.B0"')
|
|
24221
|
-
]);
|
|
24222
|
-
return { h264, hevc };
|
|
24223
|
-
});
|
|
24453
|
+
constructor(options) {
|
|
24454
|
+
this.options = ZOptions.parse(options || {});
|
|
24224
24455
|
}
|
|
24225
|
-
|
|
24226
|
-
|
|
24227
|
-
|
|
24228
|
-
|
|
24229
|
-
|
|
24230
|
-
|
|
24231
|
-
|
|
24232
|
-
|
|
24233
|
-
|
|
24234
|
-
|
|
24235
|
-
}
|
|
24236
|
-
}
|
|
24237
|
-
catch (_a) { }
|
|
24238
|
-
try {
|
|
24239
|
-
const v = document.createElement("video");
|
|
24240
|
-
return v.canPlayType(mime) !== "";
|
|
24241
|
-
}
|
|
24242
|
-
catch (_b) {
|
|
24243
|
-
return false;
|
|
24244
|
-
}
|
|
24245
|
-
});
|
|
24456
|
+
/** Set's the session with creation date for the given storage key to the localStorage. */
|
|
24457
|
+
set(sessionId) {
|
|
24458
|
+
ZSession.shape.id.parse(sessionId);
|
|
24459
|
+
this._current = sessionId;
|
|
24460
|
+
const session = {
|
|
24461
|
+
id: sessionId,
|
|
24462
|
+
created: new Date(),
|
|
24463
|
+
expire: false,
|
|
24464
|
+
};
|
|
24465
|
+
window.localStorage.setItem(this.localStorageKey, JSON.stringify(session));
|
|
24246
24466
|
}
|
|
24247
|
-
|
|
24248
|
-
|
|
24249
|
-
|
|
24250
|
-
return this.uaInfoCache;
|
|
24251
|
-
const nav = navigator;
|
|
24252
|
-
const uaData = nav.userAgentData;
|
|
24253
|
-
const ua = navigator.userAgent;
|
|
24254
|
-
let browserFamily = "Unknown";
|
|
24255
|
-
let browserVersion = null;
|
|
24256
|
-
let osFamily = "Unknown";
|
|
24257
|
-
let osVersion = null;
|
|
24258
|
-
let model = null;
|
|
24259
|
-
let architecture = null;
|
|
24260
|
-
let bitness = null;
|
|
24261
|
-
// --- UA-CH (modern browsers) ---
|
|
24262
|
-
if (uaData === null || uaData === void 0 ? void 0 : uaData.getHighEntropyValues) {
|
|
24263
|
-
try {
|
|
24264
|
-
const high = yield uaData.getHighEntropyValues([
|
|
24265
|
-
"platform",
|
|
24266
|
-
"platformVersion",
|
|
24267
|
-
"model",
|
|
24268
|
-
"architecture",
|
|
24269
|
-
"bitness",
|
|
24270
|
-
"fullVersionList"
|
|
24271
|
-
]);
|
|
24272
|
-
osFamily = high.platform || "Unknown";
|
|
24273
|
-
osVersion = high.platformVersion || null;
|
|
24274
|
-
model = high.model || null;
|
|
24275
|
-
architecture = high.architecture || null;
|
|
24276
|
-
bitness = high.bitness || null;
|
|
24277
|
-
const brands = high.fullVersionList || uaData.brands || [];
|
|
24278
|
-
const realBrand = brands.find((b) => {
|
|
24279
|
-
if (!b.brand)
|
|
24280
|
-
return false;
|
|
24281
|
-
const normalized = b.brand.replace(/[^a-zA-Z]/g, "").toLowerCase();
|
|
24282
|
-
return !normalized.includes("chromium") && !normalized.includes("notabrand");
|
|
24283
|
-
});
|
|
24284
|
-
if (realBrand) {
|
|
24285
|
-
browserFamily = realBrand.brand;
|
|
24286
|
-
browserVersion = realBrand.version;
|
|
24287
|
-
}
|
|
24288
|
-
}
|
|
24289
|
-
catch (_a) {
|
|
24290
|
-
// silently fail
|
|
24291
|
-
}
|
|
24292
|
-
}
|
|
24293
|
-
// --- Fallback to classic UA parsing if browser unknown ---
|
|
24294
|
-
if (!browserFamily || browserFamily === "Unknown") {
|
|
24295
|
-
const browserRegexes = [
|
|
24296
|
-
[/Edg\/(\S+)/, "Edge"],
|
|
24297
|
-
[/OPR\/(\S+)/, "Opera"],
|
|
24298
|
-
[/SamsungBrowser\/(\S+)/, "Samsung Internet"],
|
|
24299
|
-
[/Firefox\/(\S+)/, "Firefox"],
|
|
24300
|
-
[/Chrome\/(\S+)/, "Chrome"],
|
|
24301
|
-
[/Version\/(\S+).*Safari/, "Safari"]
|
|
24302
|
-
];
|
|
24303
|
-
for (const [regex, name] of browserRegexes) {
|
|
24304
|
-
const match = ua.match(regex);
|
|
24305
|
-
if (match) {
|
|
24306
|
-
browserFamily = name;
|
|
24307
|
-
browserVersion = match[1];
|
|
24308
|
-
break;
|
|
24309
|
-
}
|
|
24310
|
-
}
|
|
24311
|
-
}
|
|
24312
|
-
// --- OS detection (always run, iOS first) ---
|
|
24313
|
-
if (/iPhone|iPad|iPod/.test(ua)) {
|
|
24314
|
-
osFamily = "iOS";
|
|
24315
|
-
const match = ua.match(/OS (\d+[_\d]*)/);
|
|
24316
|
-
if (match)
|
|
24317
|
-
osVersion = match[1].replace(/_/g, ".");
|
|
24318
|
-
}
|
|
24319
|
-
else if (uaData === null || uaData === void 0 ? void 0 : uaData.platform) {
|
|
24320
|
-
osFamily = uaData.platform;
|
|
24321
|
-
}
|
|
24322
|
-
else if (/Windows/.test(ua)) {
|
|
24323
|
-
osFamily = "Windows";
|
|
24324
|
-
const match = ua.match(/Windows NT (\d+\.\d+)/);
|
|
24325
|
-
if (match)
|
|
24326
|
-
osVersion = match[1];
|
|
24327
|
-
}
|
|
24328
|
-
else if (/Mac OS X/.test(ua)) {
|
|
24329
|
-
osFamily = "macOS";
|
|
24330
|
-
const match = ua.match(/Mac OS X (\d+[_\d]*)/);
|
|
24331
|
-
if (match)
|
|
24332
|
-
osVersion = match[1].replace(/_/g, ".");
|
|
24333
|
-
}
|
|
24334
|
-
else if (/Android/.test(ua)) {
|
|
24335
|
-
osFamily = "Android";
|
|
24336
|
-
const match = ua.match(/Android (\d+(\.\d+)?)/);
|
|
24337
|
-
if (match)
|
|
24338
|
-
osVersion = match[1];
|
|
24339
|
-
}
|
|
24340
|
-
else if (/Linux/.test(ua)) {
|
|
24341
|
-
osFamily = "Linux";
|
|
24342
|
-
}
|
|
24343
|
-
const result = { browserFamily, browserVersion, osFamily, osVersion, model, architecture, bitness };
|
|
24344
|
-
this.uaInfoCache = result;
|
|
24345
|
-
return result;
|
|
24346
|
-
});
|
|
24467
|
+
/** Removes a session from the localStorage. */
|
|
24468
|
+
unset() {
|
|
24469
|
+
window.localStorage.removeItem(this.localStorageKey);
|
|
24347
24470
|
}
|
|
24348
24471
|
}
|
|
24349
|
-
exports.
|
|
24472
|
+
exports.Session = Session;
|
|
24473
|
+
|
|
24474
|
+
|
|
24475
|
+
/***/ }),
|
|
24476
|
+
|
|
24477
|
+
/***/ 9764:
|
|
24478
|
+
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
24479
|
+
|
|
24480
|
+
|
|
24481
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24482
|
+
exports.Stats = void 0;
|
|
24483
|
+
const shared_pixelstreaming_websdk_1 = __webpack_require__(7910);
|
|
24484
|
+
function Stats(stats) {
|
|
24485
|
+
const result = shared_pixelstreaming_websdk_1.Messages.ZStats.shape.stats.parse({
|
|
24486
|
+
/**
|
|
24487
|
+
* Other known properties.
|
|
24488
|
+
*/
|
|
24489
|
+
codecs: stats.codecs,
|
|
24490
|
+
candidatePair: stats.candidatePairs,
|
|
24491
|
+
localCandidates: stats.localCandidates,
|
|
24492
|
+
remoteCandidates: stats.remoteCandidates,
|
|
24493
|
+
DataChannelStats: stats.datachannelStats,
|
|
24494
|
+
// Received (last) for ticket
|
|
24495
|
+
bytesReceived: forceNumber(stats.inboundVideoStats.bytesReceived),
|
|
24496
|
+
// Packets Lost (last) for ticket
|
|
24497
|
+
packetsLost: forceNumber(stats.inboundVideoStats.packetsLost),
|
|
24498
|
+
// Video resolution: highest lowest average (portrait) and highest lowest average (landscape) for ticket
|
|
24499
|
+
frameWidth: forceNumber(stats.inboundVideoStats.frameWidth),
|
|
24500
|
+
// Video resolution: highest lowest average (portrait) and highest lowest average (landscape) for ticket
|
|
24501
|
+
frameHeight: forceNumber(stats.inboundVideoStats.frameHeight),
|
|
24502
|
+
// Frames decoded (Last) for ticket
|
|
24503
|
+
framesDecoded: forceNumber(stats.inboundVideoStats.framesDecoded),
|
|
24504
|
+
// Framerate (low / high, avg) for ticket
|
|
24505
|
+
framesPerSecond: forceNumber(stats.inboundVideoStats.framesPerSecond),
|
|
24506
|
+
// frames dropped (last) for ticket
|
|
24507
|
+
framesDropped: forceNumber(stats.inboundVideoStats.framesDropped),
|
|
24508
|
+
// Videocodec (once) for ticket
|
|
24509
|
+
videoCodec: stats.inboundVideoStats.codecId,
|
|
24510
|
+
// audiocodec (once) for ticket
|
|
24511
|
+
audioCodec: stats.inboundAudioStats.codecId,
|
|
24512
|
+
// browser type and version for ticket (arcware / addition)
|
|
24513
|
+
browserInfo: {
|
|
24514
|
+
// to be received!
|
|
24515
|
+
userAgent: navigator.userAgent,
|
|
24516
|
+
platform: navigator.oscpu || navigator.platform || null,
|
|
24517
|
+
language: navigator.language,
|
|
24518
|
+
},
|
|
24519
|
+
// Net RTT (low, high, avg)
|
|
24520
|
+
// BEGIN TW CHANGE
|
|
24521
|
+
currentRTT: calcRTT(stats.candidatePairs),
|
|
24522
|
+
// END TW CHANGE
|
|
24523
|
+
// Duration (last)
|
|
24524
|
+
sessionRunTime: stats.sessionStats.runTime,
|
|
24525
|
+
// Controls stream input (??)
|
|
24526
|
+
controlsStreamInput: stats.sessionStats.controlsStreamInput,
|
|
24527
|
+
// video quantization parameter (low / high / avg if applicable)
|
|
24528
|
+
videoEncoderAvgQP: forceNumber(stats.sessionStats.videoEncoderAvgQP),
|
|
24529
|
+
// Video bitrate (min / max / avg)
|
|
24530
|
+
videoBitrate: forceNumber(stats.inboundVideoStats.bitrate),
|
|
24531
|
+
// Audio bitrate (min / max / avg)
|
|
24532
|
+
audioBitrate: forceNumber(stats.inboundAudioStats.bitrate),
|
|
24533
|
+
});
|
|
24534
|
+
return result;
|
|
24535
|
+
}
|
|
24536
|
+
exports.Stats = Stats;
|
|
24537
|
+
/**
|
|
24538
|
+
* Given an array of candidate pairs this function will find the highest RTT for the selected pair
|
|
24539
|
+
* @param pairs - An array of candidate pairs
|
|
24540
|
+
* @returns The highest round trip time of a selected candidate pair
|
|
24541
|
+
*/
|
|
24542
|
+
function calcRTT(pairs) {
|
|
24543
|
+
let rtt = 0;
|
|
24544
|
+
pairs.forEach((pair) => {
|
|
24545
|
+
if (pair.selected && pair.currentRoundTripTime > rtt) {
|
|
24546
|
+
rtt = pair.currentRoundTripTime;
|
|
24547
|
+
}
|
|
24548
|
+
});
|
|
24549
|
+
return rtt;
|
|
24550
|
+
}
|
|
24551
|
+
/**
|
|
24552
|
+
* Takes a number and forces it to return a number. If the value passed in is NaN, 0 will be returned.
|
|
24553
|
+
* @param value - A number
|
|
24554
|
+
* @returns The number passed in as value or 0 if vlaue was NaN
|
|
24555
|
+
*/
|
|
24556
|
+
function forceNumber(value) {
|
|
24557
|
+
return isNaN(value) ? 0 : value;
|
|
24558
|
+
}
|
|
24350
24559
|
|
|
24351
24560
|
|
|
24352
24561
|
/***/ }),
|
|
24353
24562
|
|
|
24354
|
-
/***/
|
|
24563
|
+
/***/ 9580:
|
|
24564
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
24565
|
+
|
|
24566
|
+
|
|
24567
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24568
|
+
function debounce(func, wait) {
|
|
24569
|
+
let timeout;
|
|
24570
|
+
return function (...args) {
|
|
24571
|
+
clearTimeout(timeout);
|
|
24572
|
+
timeout = window.setTimeout(() => func(...args), wait);
|
|
24573
|
+
};
|
|
24574
|
+
}
|
|
24575
|
+
exports["default"] = debounce;
|
|
24576
|
+
|
|
24577
|
+
|
|
24578
|
+
/***/ }),
|
|
24579
|
+
|
|
24580
|
+
/***/ 471:
|
|
24355
24581
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
24356
24582
|
|
|
24357
24583
|
|
|
24358
24584
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24359
|
-
exports.
|
|
24585
|
+
exports.isAnalyticsEvent = exports.toAnalyticsEvent = void 0;
|
|
24586
|
+
// analytics.ts
|
|
24587
|
+
const common_1 = __webpack_require__(2483);
|
|
24588
|
+
/**
|
|
24589
|
+
* Build an AnalyticsEvent from unknown input.
|
|
24590
|
+
* - accepts object or JSON/JSON-ish string
|
|
24591
|
+
* - drops extra fields
|
|
24592
|
+
* - requires non-empty string `type` and `customName`
|
|
24593
|
+
* - accepts `payload` only if it's a string; truncates by **bytes**
|
|
24594
|
+
*/
|
|
24595
|
+
function toAnalyticsEvent(input, opts = {}) {
|
|
24596
|
+
var _a, _b, _c;
|
|
24597
|
+
const maxBytes = (_a = opts.maxPayloadBytes) !== null && _a !== void 0 ? _a : 512;
|
|
24598
|
+
let obj;
|
|
24599
|
+
try {
|
|
24600
|
+
obj = (0, common_1.parseUnknownToObject)(input, { allowJsonish: (_b = opts.allowJsonish) !== null && _b !== void 0 ? _b : true });
|
|
24601
|
+
}
|
|
24602
|
+
catch (e) {
|
|
24603
|
+
return { ok: false, error: (_c = e === null || e === void 0 ? void 0 : e.message) !== null && _c !== void 0 ? _c : "Invalid input" };
|
|
24604
|
+
}
|
|
24605
|
+
const typeVal = safeString(obj["type"]);
|
|
24606
|
+
const customNameVal = safeString(obj["customName"]);
|
|
24607
|
+
if (!typeVal)
|
|
24608
|
+
return { ok: false, error: "`type` must be a non-empty string." };
|
|
24609
|
+
if (!customNameVal)
|
|
24610
|
+
return { ok: false, error: "`customName` must be a non-empty string." };
|
|
24611
|
+
let payloadStr;
|
|
24612
|
+
if ("payload" in obj && typeof obj["payload"] === "string") {
|
|
24613
|
+
payloadStr = (0, common_1.truncateByBytes)(obj["payload"], maxBytes);
|
|
24614
|
+
}
|
|
24615
|
+
const value = payloadStr !== undefined
|
|
24616
|
+
? { type: typeVal, customName: customNameVal, payload: payloadStr }
|
|
24617
|
+
: { type: typeVal, customName: customNameVal };
|
|
24618
|
+
return { ok: true, value };
|
|
24619
|
+
}
|
|
24620
|
+
exports.toAnalyticsEvent = toAnalyticsEvent;
|
|
24621
|
+
/** Type guard */
|
|
24622
|
+
function isAnalyticsEvent(x) {
|
|
24623
|
+
return (!!x &&
|
|
24624
|
+
typeof x === "object" &&
|
|
24625
|
+
typeof x.type === "string" &&
|
|
24626
|
+
typeof x.customName === "string" &&
|
|
24627
|
+
(typeof x.payload === "string" || x.payload === undefined));
|
|
24628
|
+
}
|
|
24629
|
+
exports.isAnalyticsEvent = isAnalyticsEvent;
|
|
24630
|
+
function safeString(x) {
|
|
24631
|
+
if (typeof x !== "string")
|
|
24632
|
+
return undefined;
|
|
24633
|
+
const trimmed = x.trim();
|
|
24634
|
+
return trimmed.length ? trimmed : undefined;
|
|
24635
|
+
}
|
|
24636
|
+
|
|
24637
|
+
|
|
24638
|
+
/***/ }),
|
|
24639
|
+
|
|
24640
|
+
/***/ 2768:
|
|
24641
|
+
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
24642
|
+
|
|
24643
|
+
|
|
24644
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24645
|
+
exports.parseControl = exports.ZFileTransfer = void 0;
|
|
24646
|
+
// fileTransfer.ts
|
|
24360
24647
|
const zod_1 = __webpack_require__(8754);
|
|
24361
|
-
const
|
|
24362
|
-
|
|
24363
|
-
exports.
|
|
24364
|
-
|
|
24365
|
-
|
|
24366
|
-
/** Can be used to be added to the request in order to verify access to private projects.
|
|
24367
|
-
* For internal use only. => Preview page.
|
|
24368
|
-
*/
|
|
24369
|
-
token: zod_1.z.string().optional(),
|
|
24370
|
-
/** @deprecated in there for legacy use. Can only be used when token is provided. */
|
|
24371
|
-
bypass: zod_1.z.boolean().optional(),
|
|
24372
|
-
// /** Configure DirectFlow Token. */
|
|
24373
|
-
// directFlow: z.string().optional(),
|
|
24374
|
-
/** Handler for server side error messages. */
|
|
24375
|
-
errorHandler: zod_1.z.function().args(shared_pixelstreaming_websdk_1.Messages.ZErrorMessage).returns(zod_1.z.void()).optional(),
|
|
24376
|
-
/** Handler for queue events. */
|
|
24377
|
-
queueHandler: zod_1.z.function().args(shared_pixelstreaming_websdk_1.Messages.ZQueue).returns(zod_1.z.void()).optional(),
|
|
24378
|
-
/** Handler for sessionId message. */
|
|
24379
|
-
sessionIdHandler: zod_1.z.function().args(zod_1.z.string()).returns(zod_1.z.void()).optional(),
|
|
24380
|
-
/** Handler for love letters.
|
|
24381
|
-
* "LoveLetters" are send from backend to the SDK to state what phase the connection currently is in. */
|
|
24382
|
-
loveLetterHandler: zod_1.z.function().args(shared_pixelstreaming_websdk_1.Messages.ZLoveLetter).returns(zod_1.z.void()).optional(),
|
|
24383
|
-
/** Show or hide the fullscreen button. */
|
|
24384
|
-
fullscreenButton: zod_1.z.boolean().optional(),
|
|
24385
|
-
/** Show or hide the settings button. */
|
|
24386
|
-
settingsButton: zod_1.z.boolean().optional(),
|
|
24387
|
-
/** Show or hide the info button. */
|
|
24388
|
-
infoButton: zod_1.z.boolean().optional(),
|
|
24389
|
-
/** Show or hide the audio button. */
|
|
24390
|
-
audioButton: zod_1.z.boolean().optional(),
|
|
24391
|
-
/** Show or hide the microphone button. */
|
|
24392
|
-
micButton: zod_1.z.boolean().optional(),
|
|
24393
|
-
/** Show or hide the microphone button. */
|
|
24394
|
-
stopButton: zod_1.z.boolean().optional(),
|
|
24395
|
-
/** Show or hide the connectionStrengthIcon button. */
|
|
24396
|
-
connectionStrengthIcon: zod_1.z.boolean().optional(),
|
|
24397
|
-
/** ShareId, used for sharing your project.
|
|
24398
|
-
* Using ArcwareInit will set this required property for you. */
|
|
24399
|
-
shareId: zod_1.z.string().startsWith("share-").optional(),
|
|
24400
|
-
/** Id of your project, only required if your shareId refers to multiple projects.
|
|
24401
|
-
* Using ArcwareInit will set this required property for you. */
|
|
24402
|
-
projectId: zod_1.z.string().optional(),
|
|
24403
|
-
/** Enable/Disable LoveLetter logging to the console. */
|
|
24404
|
-
loveLetterLogging: zod_1.z.boolean().optional(),
|
|
24405
|
-
/** Enable/Disable Connection Identifier logging to the console. */
|
|
24406
|
-
connectionIdentifierLoggingDisabled: zod_1.z.boolean().optional(),
|
|
24407
|
-
/** Width with which instance should be started */
|
|
24408
|
-
startWidth: zod_1.z.number().optional(),
|
|
24409
|
-
/** Height with which instance should be started */
|
|
24410
|
-
startHeight: zod_1.z.number().optional()
|
|
24648
|
+
const common_1 = __webpack_require__(2483);
|
|
24649
|
+
// Schema
|
|
24650
|
+
exports.ZFileTransfer = zod_1.z.object({
|
|
24651
|
+
type: zod_1.z.literal("fileTransfer"),
|
|
24652
|
+
filename: zod_1.z.string().trim().optional()
|
|
24411
24653
|
});
|
|
24654
|
+
// Normalized parse + validate
|
|
24655
|
+
function parseControl(input, schema) {
|
|
24656
|
+
const obj = (0, common_1.parseUnknownToObject)(input, { allowJsonish: true });
|
|
24657
|
+
return schema.parse(obj);
|
|
24658
|
+
}
|
|
24659
|
+
exports.parseControl = parseControl;
|
|
24412
24660
|
|
|
24413
24661
|
|
|
24414
24662
|
/***/ }),
|
|
24415
24663
|
|
|
24416
|
-
/***/
|
|
24417
|
-
/***/ ((__unused_webpack_module, exports) => {
|
|
24664
|
+
/***/ 8429:
|
|
24665
|
+
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
24418
24666
|
|
|
24419
24667
|
|
|
24668
|
+
/**
|
|
24669
|
+
* DiagnosticsCollector.ts
|
|
24670
|
+
* Lightweight, privacy-aware client diagnostics for troubleshooting + analytics.
|
|
24671
|
+
* WebRTC collection intentionally omitted (to add later).
|
|
24672
|
+
*
|
|
24673
|
+
* Notes:
|
|
24674
|
+
* - Some fields are best-effort due to browser restrictions; they're nullable.
|
|
24675
|
+
* - Bandwidth probe requires a small binary served with:
|
|
24676
|
+
* Content-Type: application/octet-stream
|
|
24677
|
+
* Content-Encoding: identity
|
|
24678
|
+
* Cache-Control: no-store
|
|
24679
|
+
* Default location: /diag/probe.bin
|
|
24680
|
+
*/
|
|
24420
24681
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24421
|
-
exports.
|
|
24422
|
-
|
|
24423
|
-
|
|
24424
|
-
|
|
24425
|
-
|
|
24426
|
-
|
|
24427
|
-
|
|
24428
|
-
|
|
24429
|
-
|
|
24430
|
-
|
|
24431
|
-
|
|
24432
|
-
|
|
24433
|
-
|
|
24434
|
-
|
|
24435
|
-
|
|
24436
|
-
|
|
24437
|
-
|
|
24438
|
-
|
|
24682
|
+
exports.DiagnosticsCollector = exports.Type = exports.Orientation = void 0;
|
|
24683
|
+
const tslib_1 = __webpack_require__(655);
|
|
24684
|
+
var Orientation;
|
|
24685
|
+
(function (Orientation) {
|
|
24686
|
+
Orientation["Landscape"] = "landscape";
|
|
24687
|
+
Orientation["Portrait"] = "portrait";
|
|
24688
|
+
})(Orientation = exports.Orientation || (exports.Orientation = {}));
|
|
24689
|
+
var Type;
|
|
24690
|
+
(function (Type) {
|
|
24691
|
+
Type["Desktop"] = "desktop";
|
|
24692
|
+
Type["Mobile"] = "mobile";
|
|
24693
|
+
Type["Tablet"] = "tablet";
|
|
24694
|
+
})(Type = exports.Type || (exports.Type = {}));
|
|
24695
|
+
/**
|
|
24696
|
+
* DiagnosticsCollector
|
|
24697
|
+
*/
|
|
24698
|
+
class DiagnosticsCollector {
|
|
24699
|
+
constructor(opts = {}) {
|
|
24700
|
+
var _a, _b, _c, _d;
|
|
24701
|
+
this.uaInfoCache = null;
|
|
24702
|
+
this.opts = {
|
|
24703
|
+
enableBandwidthProbe: (_a = opts.enableBandwidthProbe) !== null && _a !== void 0 ? _a : true,
|
|
24704
|
+
probeUrl: (_b = opts.probeUrl) !== null && _b !== void 0 ? _b : "/diag/probe.bin",
|
|
24705
|
+
respectSaveData: (_c = opts.respectSaveData) !== null && _c !== void 0 ? _c : true,
|
|
24706
|
+
sampleRate: Math.max(0, Math.min(1, (_d = opts.sampleRate) !== null && _d !== void 0 ? _d : 1))
|
|
24707
|
+
};
|
|
24708
|
+
}
|
|
24709
|
+
/**
|
|
24710
|
+
* Collect the diagnostics payload.
|
|
24711
|
+
*/
|
|
24712
|
+
collect() {
|
|
24713
|
+
var _a, _b;
|
|
24714
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
24715
|
+
if (!this.shouldSample()) {
|
|
24716
|
+
return {
|
|
24717
|
+
device: { type: Type.Desktop, touchSupport: false },
|
|
24718
|
+
runtime: { browser: { family: "Unknown", version: null }, os: { family: "Unknown", version: null } },
|
|
24719
|
+
powerHints: { saveData: null, prefersReducedData: null, prefersReducedMotion: null },
|
|
24720
|
+
network: { type: null, effectiveType: null, downlinkMbps: null, rttMs: null, measuredDownlinkMbps: null },
|
|
24721
|
+
timestamps: { collectedAt: Date.now() }
|
|
24722
|
+
};
|
|
24723
|
+
}
|
|
24724
|
+
const collectedAt = Date.now();
|
|
24725
|
+
const [uaInfo, codecSupport, measuredDownlinkMbps] = yield Promise.all([
|
|
24726
|
+
this.getUAInfo(),
|
|
24727
|
+
this.getCodecSupport(),
|
|
24728
|
+
this.maybeMeasureBandwidth()
|
|
24729
|
+
]);
|
|
24730
|
+
return {
|
|
24731
|
+
device: {
|
|
24732
|
+
type: this.inferDeviceType(),
|
|
24733
|
+
vendor: null,
|
|
24734
|
+
model: uaInfo.model,
|
|
24735
|
+
architecture: uaInfo.architecture,
|
|
24736
|
+
bitness: uaInfo.bitness,
|
|
24737
|
+
touchSupport: this.hasTouch(),
|
|
24738
|
+
hardwareConcurrency: (_a = navigator.hardwareConcurrency) !== null && _a !== void 0 ? _a : null,
|
|
24739
|
+
deviceMemory: (_b = navigator.deviceMemory) !== null && _b !== void 0 ? _b : null,
|
|
24740
|
+
orientation: this.getOrientation(),
|
|
24741
|
+
webgl: this.hasWebGL(),
|
|
24742
|
+
codecs: codecSupport
|
|
24743
|
+
},
|
|
24744
|
+
runtime: {
|
|
24745
|
+
browser: { family: uaInfo.browserFamily, version: uaInfo.browserVersion },
|
|
24746
|
+
os: { family: uaInfo.osFamily, version: uaInfo.osVersion }
|
|
24747
|
+
},
|
|
24748
|
+
powerHints: this.getPowerHints(),
|
|
24749
|
+
network: this.getNetworkInfo(measuredDownlinkMbps),
|
|
24750
|
+
timestamps: { collectedAt }
|
|
24751
|
+
};
|
|
24752
|
+
});
|
|
24753
|
+
}
|
|
24754
|
+
/**
|
|
24755
|
+
* Collect a safe subset of WebRTC stats once PC is connected.
|
|
24756
|
+
*/
|
|
24757
|
+
collectWebRTC(pc) {
|
|
24758
|
+
var _a, _b, _c, _d, _e, _f;
|
|
24759
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
24760
|
+
try {
|
|
24761
|
+
const stats = yield pc.getStats();
|
|
24762
|
+
let selected, transport, local, remote;
|
|
24763
|
+
stats.forEach((r) => {
|
|
24764
|
+
if (r.type === "transport" && r.selectedCandidatePairId)
|
|
24765
|
+
transport = r;
|
|
24766
|
+
if (r.type === "candidate-pair" && (r.selected || r.nominated))
|
|
24767
|
+
selected = r;
|
|
24768
|
+
});
|
|
24769
|
+
if (selected) {
|
|
24770
|
+
local = stats.get(selected.localCandidateId);
|
|
24771
|
+
remote = stats.get(selected.remoteCandidateId);
|
|
24772
|
+
}
|
|
24773
|
+
return {
|
|
24774
|
+
candidatePairId: (_a = selected === null || selected === void 0 ? void 0 : selected.id) !== null && _a !== void 0 ? _a : null,
|
|
24775
|
+
localCandidateType: (_b = local === null || local === void 0 ? void 0 : local.candidateType) !== null && _b !== void 0 ? _b : null,
|
|
24776
|
+
remoteCandidateType: (_c = remote === null || remote === void 0 ? void 0 : remote.candidateType) !== null && _c !== void 0 ? _c : null,
|
|
24777
|
+
protocol: (_d = local === null || local === void 0 ? void 0 : local.protocol) !== null && _d !== void 0 ? _d : null,
|
|
24778
|
+
networkType: (_e = local === null || local === void 0 ? void 0 : local.networkType) !== null && _e !== void 0 ? _e : null,
|
|
24779
|
+
dtlsCipher: (_f = transport === null || transport === void 0 ? void 0 : transport.dtlsCipher) !== null && _f !== void 0 ? _f : null
|
|
24780
|
+
};
|
|
24781
|
+
}
|
|
24782
|
+
catch (_g) {
|
|
24783
|
+
return {};
|
|
24784
|
+
}
|
|
24785
|
+
});
|
|
24439
24786
|
}
|
|
24440
|
-
|
|
24441
|
-
|
|
24787
|
+
/**
|
|
24788
|
+
* Helper to embed diagnostics in a hello envelope.
|
|
24789
|
+
*/
|
|
24790
|
+
buildHelloEnvelope(base, pc) {
|
|
24791
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
24792
|
+
const diag = yield this.collect();
|
|
24793
|
+
const webrtc = pc ? yield this.collectWebRTC(pc) : undefined;
|
|
24794
|
+
const ext = webrtc ? { diag: Object.assign(Object.assign({}, diag), { webrtc }) } : { diag };
|
|
24795
|
+
return Object.assign(Object.assign({}, base), { ext });
|
|
24796
|
+
});
|
|
24442
24797
|
}
|
|
24443
|
-
|
|
24444
|
-
|
|
24445
|
-
this.
|
|
24798
|
+
// ---------- Internals ----------
|
|
24799
|
+
shouldSample() {
|
|
24800
|
+
if (this.opts.sampleRate >= 1)
|
|
24801
|
+
return true;
|
|
24802
|
+
return Math.random() < this.opts.sampleRate;
|
|
24446
24803
|
}
|
|
24447
|
-
|
|
24804
|
+
hasTouch() {
|
|
24448
24805
|
var _a;
|
|
24449
|
-
|
|
24450
|
-
|
|
24451
|
-
if ((_a = ps.config.settings) === null || _a === void 0 ? void 0 : _a.connectionIdentifierLoggingDisabled)
|
|
24452
|
-
this.disable();
|
|
24453
|
-
}
|
|
24454
|
-
if (!this.interval)
|
|
24455
|
-
this.interval = setInterval(this.connectionWatcher.bind(this), 10 * 1000);
|
|
24456
|
-
}
|
|
24457
|
-
GetWebSocketStates() {
|
|
24458
|
-
return this.aps.map((ps) => ps.websocketState);
|
|
24806
|
+
const nav = navigator;
|
|
24807
|
+
return "ontouchstart" in window || ((_a = nav.maxTouchPoints) !== null && _a !== void 0 ? _a : 0) > 0;
|
|
24459
24808
|
}
|
|
24460
|
-
|
|
24461
|
-
|
|
24809
|
+
getOrientation() {
|
|
24810
|
+
var _a;
|
|
24811
|
+
try {
|
|
24812
|
+
if ((_a = screen.orientation) === null || _a === void 0 ? void 0 : _a.type) {
|
|
24813
|
+
return screen.orientation.type.startsWith("portrait") ? Orientation.Portrait : Orientation.Landscape;
|
|
24814
|
+
}
|
|
24815
|
+
if (window.matchMedia) {
|
|
24816
|
+
return window.matchMedia("(orientation: portrait)").matches ? Orientation.Portrait : Orientation.Landscape;
|
|
24817
|
+
}
|
|
24818
|
+
}
|
|
24819
|
+
catch (_b) { }
|
|
24820
|
+
return null;
|
|
24462
24821
|
}
|
|
24463
|
-
|
|
24464
|
-
|
|
24822
|
+
hasWebGL() {
|
|
24823
|
+
try {
|
|
24824
|
+
const canvas = document.createElement("canvas");
|
|
24825
|
+
return !!(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"));
|
|
24826
|
+
}
|
|
24827
|
+
catch (_a) {
|
|
24828
|
+
return false;
|
|
24829
|
+
}
|
|
24465
24830
|
}
|
|
24466
24831
|
/**
|
|
24467
|
-
*
|
|
24468
|
-
*
|
|
24469
|
-
* Or when they accidentally set up multiple connections!
|
|
24470
|
-
* Things like that can happen, for example if the React.useEffect was not setup perfectly!
|
|
24832
|
+
* Heuristic device type: best-effort only.
|
|
24833
|
+
* Tries UA-CH, then UA fallback, then touch + screen size heuristics.
|
|
24471
24834
|
*/
|
|
24472
|
-
|
|
24473
|
-
|
|
24474
|
-
|
|
24475
|
-
const
|
|
24476
|
-
|
|
24477
|
-
|
|
24835
|
+
inferDeviceType() {
|
|
24836
|
+
const uaData = navigator.userAgentData;
|
|
24837
|
+
const ua = navigator.userAgent || "";
|
|
24838
|
+
const isMobileCH = (uaData === null || uaData === void 0 ? void 0 : uaData.mobile) === true;
|
|
24839
|
+
const minDim = Math.min(screen.width, screen.height);
|
|
24840
|
+
// 1. Explicit iPad / tablet detection via UA (iOS often lies in CH)
|
|
24841
|
+
if (/\b(iPad|Tablet)\b/i.test(ua)) {
|
|
24842
|
+
return Type.Tablet;
|
|
24478
24843
|
}
|
|
24479
|
-
|
|
24480
|
-
|
|
24844
|
+
// 2. UA-CH mobile hint (Chromium only, often accurate for Android)
|
|
24845
|
+
if (isMobileCH) {
|
|
24846
|
+
if (minDim >= 600)
|
|
24847
|
+
return Type.Tablet;
|
|
24848
|
+
return Type.Mobile;
|
|
24481
24849
|
}
|
|
24482
|
-
|
|
24483
|
-
|
|
24484
|
-
|
|
24485
|
-
|
|
24486
|
-
|
|
24487
|
-
/***/ }),
|
|
24488
|
-
|
|
24489
|
-
/***/ 3379:
|
|
24490
|
-
/***/ ((__unused_webpack_module, exports) => {
|
|
24491
|
-
|
|
24492
|
-
|
|
24493
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24494
|
-
exports.EventHandler = void 0;
|
|
24495
|
-
/** A helper class to spread the event to additional event handlers added from external sources. */
|
|
24496
|
-
class EventHandler {
|
|
24497
|
-
/** Returns the added callback on success or null, if something went wrong. */
|
|
24498
|
-
add(callback) {
|
|
24499
|
-
const cb = this.callbacks.find((cb) => cb === callback);
|
|
24500
|
-
if (cb)
|
|
24501
|
-
return null;
|
|
24502
|
-
this.callbacks.push(callback);
|
|
24503
|
-
return callback;
|
|
24504
|
-
}
|
|
24505
|
-
/** Returns true if the input callback has been found and removed and false if not. */
|
|
24506
|
-
remove(callback) {
|
|
24507
|
-
const cb = this.callbacks.find((cb) => cb === callback);
|
|
24508
|
-
if (cb)
|
|
24509
|
-
this.callbacks.splice(this.callbacks.indexOf(cb), 1);
|
|
24510
|
-
return !!cb;
|
|
24511
|
-
}
|
|
24512
|
-
constructor() {
|
|
24513
|
-
this.callbacks = new Array();
|
|
24514
|
-
}
|
|
24515
|
-
/** Emits the event-data for each of the existing handlers. */
|
|
24516
|
-
static Emit(handler, event) {
|
|
24517
|
-
handler.callbacks.forEach((callback) => callback(event));
|
|
24518
|
-
}
|
|
24519
|
-
}
|
|
24520
|
-
exports.EventHandler = EventHandler;
|
|
24521
|
-
|
|
24522
|
-
|
|
24523
|
-
/***/ }),
|
|
24524
|
-
|
|
24525
|
-
/***/ 2469:
|
|
24526
|
-
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
24527
|
-
|
|
24528
|
-
|
|
24529
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24530
|
-
exports.Session = void 0;
|
|
24531
|
-
const addSeconds_1 = __webpack_require__(1973);
|
|
24532
|
-
const isBefore_1 = __webpack_require__(313);
|
|
24533
|
-
const zod_1 = __webpack_require__(8754);
|
|
24534
|
-
const ZSession = zod_1.z
|
|
24535
|
-
.object({
|
|
24536
|
-
id: zod_1.z.string().min(1),
|
|
24537
|
-
created: zod_1.z
|
|
24538
|
-
.date()
|
|
24539
|
-
.or(zod_1.z.string())
|
|
24540
|
-
.transform((arg) => new Date(arg)),
|
|
24541
|
-
expire: zod_1.z.boolean().default(false).optional(),
|
|
24542
|
-
})
|
|
24543
|
-
.strict();
|
|
24544
|
-
const ZOptions = zod_1.z.object({
|
|
24545
|
-
localStorageKey: zod_1.z.string().min(3).default("pxss"),
|
|
24546
|
-
keepSession: zod_1.z
|
|
24547
|
-
.number()
|
|
24548
|
-
.int()
|
|
24549
|
-
.min(3)
|
|
24550
|
-
/** Default keep is 10, since this is how long instances will be kept alive by default. */
|
|
24551
|
-
.default(10),
|
|
24552
|
-
});
|
|
24553
|
-
/** The sessionId is stored in the localStorage to allow for reconnection and
|
|
24554
|
-
* to prevent spamming start requests of instances, when smashing F5.
|
|
24555
|
-
*/
|
|
24556
|
-
class Session {
|
|
24557
|
-
get current() {
|
|
24558
|
-
return this._current;
|
|
24559
|
-
}
|
|
24560
|
-
get noSession() {
|
|
24561
|
-
return new URLSearchParams(window.location.search).has("noSession");
|
|
24562
|
-
}
|
|
24563
|
-
get id() {
|
|
24564
|
-
// If the query-parameter "noSession" or "nosession" is set, it will be skipped.
|
|
24565
|
-
if (this.noSession)
|
|
24566
|
-
return null;
|
|
24567
|
-
const sessionString = window.localStorage.getItem(this.localStorageKey);
|
|
24568
|
-
// No session yet set.
|
|
24569
|
-
if (sessionString === null) {
|
|
24570
|
-
return null;
|
|
24850
|
+
// 3. UA sniffing fallback for mobile
|
|
24851
|
+
if (/\b(iPhone|Android.*Mobile|Windows Phone)\b/i.test(ua)) {
|
|
24852
|
+
return Type.Mobile;
|
|
24571
24853
|
}
|
|
24572
|
-
|
|
24573
|
-
|
|
24574
|
-
|
|
24575
|
-
this.unset();
|
|
24576
|
-
return null;
|
|
24854
|
+
// 4. Touch-capable with "tablet-like" dimensions
|
|
24855
|
+
if (("ontouchstart" in window || navigator.maxTouchPoints > 0) && minDim >= 600 && minDim <= 1100) {
|
|
24856
|
+
return Type.Tablet;
|
|
24577
24857
|
}
|
|
24578
|
-
|
|
24579
|
-
|
|
24580
|
-
|
|
24581
|
-
|
|
24582
|
-
|
|
24858
|
+
// 5. Default fallback
|
|
24859
|
+
return Type.Desktop;
|
|
24860
|
+
}
|
|
24861
|
+
getPowerHints() {
|
|
24862
|
+
const conn = navigator.connection;
|
|
24863
|
+
const saveData = typeof (conn === null || conn === void 0 ? void 0 : conn.saveData) === "boolean" ? conn.saveData : null;
|
|
24864
|
+
let prefersReducedData = null;
|
|
24865
|
+
let prefersReducedMotion = null;
|
|
24866
|
+
if (typeof window.matchMedia === "function") {
|
|
24867
|
+
try {
|
|
24868
|
+
const mqData = window.matchMedia("(prefers-reduced-data: reduce)");
|
|
24869
|
+
if (typeof mqData.matches === "boolean") {
|
|
24870
|
+
prefersReducedData = mqData.matches;
|
|
24871
|
+
}
|
|
24872
|
+
}
|
|
24873
|
+
catch (_a) { }
|
|
24874
|
+
try {
|
|
24875
|
+
const mqMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
24876
|
+
if (typeof mqMotion.matches === "boolean") {
|
|
24877
|
+
prefersReducedMotion = mqMotion.matches;
|
|
24878
|
+
}
|
|
24879
|
+
}
|
|
24880
|
+
catch (_b) { }
|
|
24583
24881
|
}
|
|
24584
|
-
|
|
24585
|
-
|
|
24882
|
+
return { saveData, prefersReducedData, prefersReducedMotion };
|
|
24883
|
+
}
|
|
24884
|
+
getNetworkInfo(measuredDownlinkMbps) {
|
|
24885
|
+
const conn = navigator.connection;
|
|
24886
|
+
return {
|
|
24887
|
+
type: typeof (conn === null || conn === void 0 ? void 0 : conn.type) === "string" ? conn.type : null,
|
|
24888
|
+
effectiveType: typeof (conn === null || conn === void 0 ? void 0 : conn.effectiveType) === "string" ? conn.effectiveType : null,
|
|
24889
|
+
downlinkMbps: typeof (conn === null || conn === void 0 ? void 0 : conn.downlink) === "number" ? conn.downlink : null,
|
|
24890
|
+
rttMs: typeof (conn === null || conn === void 0 ? void 0 : conn.rtt) === "number" ? conn.rtt : null,
|
|
24891
|
+
measuredDownlinkMbps
|
|
24892
|
+
};
|
|
24893
|
+
}
|
|
24894
|
+
maybeMeasureBandwidth() {
|
|
24895
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
24896
|
+
const conn = navigator.connection;
|
|
24897
|
+
const saveData = (conn === null || conn === void 0 ? void 0 : conn.saveData) === true;
|
|
24898
|
+
if (!this.opts.enableBandwidthProbe)
|
|
24899
|
+
return null;
|
|
24900
|
+
if (this.opts.respectSaveData && saveData)
|
|
24901
|
+
return null;
|
|
24902
|
+
try {
|
|
24903
|
+
const t0 = performance.now();
|
|
24904
|
+
const res = yield fetch(this.withCacheBuster(this.opts.probeUrl), {
|
|
24905
|
+
cache: "no-store",
|
|
24906
|
+
credentials: "omit"
|
|
24907
|
+
});
|
|
24908
|
+
const buf = yield res.arrayBuffer();
|
|
24909
|
+
const t1 = performance.now();
|
|
24910
|
+
const bits = buf.byteLength * 8;
|
|
24911
|
+
const seconds = (t1 - t0) / 1000;
|
|
24912
|
+
if (seconds <= 0.05)
|
|
24913
|
+
return null; // ignore unstable samples
|
|
24914
|
+
return +(bits / seconds / 1000000).toFixed(2);
|
|
24915
|
+
}
|
|
24916
|
+
catch (_a) {
|
|
24917
|
+
return null;
|
|
24918
|
+
}
|
|
24919
|
+
});
|
|
24586
24920
|
}
|
|
24587
|
-
|
|
24588
|
-
|
|
24921
|
+
withCacheBuster(url) {
|
|
24922
|
+
var _a, _b;
|
|
24923
|
+
const u = new URL(url, location.origin);
|
|
24924
|
+
const token = (_b = (_a = crypto === null || crypto === void 0 ? void 0 : crypto.randomUUID) === null || _a === void 0 ? void 0 : _a.call(crypto)) !== null && _b !== void 0 ? _b : String(Date.now());
|
|
24925
|
+
u.searchParams.set("cb", token);
|
|
24926
|
+
return u.toString();
|
|
24589
24927
|
}
|
|
24590
|
-
|
|
24591
|
-
this
|
|
24928
|
+
getCodecSupport() {
|
|
24929
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
24930
|
+
const [h264, hevc] = yield Promise.all([
|
|
24931
|
+
this.supportsCodec('video/mp4; codecs="avc1.42E01E"'),
|
|
24932
|
+
this.supportsCodec('video/mp4; codecs="hvc1.1.6.L93.B0"')
|
|
24933
|
+
]);
|
|
24934
|
+
return { h264, hevc };
|
|
24935
|
+
});
|
|
24592
24936
|
}
|
|
24593
|
-
|
|
24594
|
-
|
|
24595
|
-
|
|
24596
|
-
|
|
24597
|
-
|
|
24598
|
-
|
|
24599
|
-
|
|
24600
|
-
|
|
24601
|
-
|
|
24602
|
-
|
|
24937
|
+
supportsCodec(mime) {
|
|
24938
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
24939
|
+
try {
|
|
24940
|
+
if ("mediaCapabilities" in navigator) {
|
|
24941
|
+
// @ts-ignore
|
|
24942
|
+
const res = yield navigator.mediaCapabilities.decodingInfo({
|
|
24943
|
+
type: "file",
|
|
24944
|
+
video: { contentType: mime, width: 1920, height: 1080, bitrate: 5000000, framerate: 30 }
|
|
24945
|
+
});
|
|
24946
|
+
return !!(res === null || res === void 0 ? void 0 : res.supported);
|
|
24947
|
+
}
|
|
24948
|
+
}
|
|
24949
|
+
catch (_a) { }
|
|
24950
|
+
try {
|
|
24951
|
+
const v = document.createElement("video");
|
|
24952
|
+
return v.canPlayType(mime) !== "";
|
|
24953
|
+
}
|
|
24954
|
+
catch (_b) {
|
|
24955
|
+
return false;
|
|
24956
|
+
}
|
|
24957
|
+
});
|
|
24603
24958
|
}
|
|
24604
|
-
|
|
24605
|
-
|
|
24606
|
-
|
|
24959
|
+
getUAInfo() {
|
|
24960
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
24961
|
+
if (this.uaInfoCache)
|
|
24962
|
+
return this.uaInfoCache;
|
|
24963
|
+
const nav = navigator;
|
|
24964
|
+
const uaData = nav.userAgentData;
|
|
24965
|
+
const ua = navigator.userAgent;
|
|
24966
|
+
let browserFamily = "Unknown";
|
|
24967
|
+
let browserVersion = null;
|
|
24968
|
+
let osFamily = "Unknown";
|
|
24969
|
+
let osVersion = null;
|
|
24970
|
+
let model = null;
|
|
24971
|
+
let architecture = null;
|
|
24972
|
+
let bitness = null;
|
|
24973
|
+
// --- UA-CH (modern browsers) ---
|
|
24974
|
+
if (uaData === null || uaData === void 0 ? void 0 : uaData.getHighEntropyValues) {
|
|
24975
|
+
try {
|
|
24976
|
+
const high = yield uaData.getHighEntropyValues([
|
|
24977
|
+
"platform",
|
|
24978
|
+
"platformVersion",
|
|
24979
|
+
"model",
|
|
24980
|
+
"architecture",
|
|
24981
|
+
"bitness",
|
|
24982
|
+
"fullVersionList"
|
|
24983
|
+
]);
|
|
24984
|
+
osFamily = high.platform || "Unknown";
|
|
24985
|
+
osVersion = high.platformVersion || null;
|
|
24986
|
+
model = high.model || null;
|
|
24987
|
+
architecture = high.architecture || null;
|
|
24988
|
+
bitness = high.bitness || null;
|
|
24989
|
+
const brands = high.fullVersionList || uaData.brands || [];
|
|
24990
|
+
const realBrand = brands.find((b) => {
|
|
24991
|
+
if (!b.brand)
|
|
24992
|
+
return false;
|
|
24993
|
+
const normalized = b.brand.replace(/[^a-zA-Z]/g, "").toLowerCase();
|
|
24994
|
+
return !normalized.includes("chromium") && !normalized.includes("notabrand");
|
|
24995
|
+
});
|
|
24996
|
+
if (realBrand) {
|
|
24997
|
+
browserFamily = realBrand.brand;
|
|
24998
|
+
browserVersion = realBrand.version;
|
|
24999
|
+
}
|
|
25000
|
+
}
|
|
25001
|
+
catch (_a) {
|
|
25002
|
+
// silently fail
|
|
25003
|
+
}
|
|
25004
|
+
}
|
|
25005
|
+
// --- Fallback to classic UA parsing if browser unknown ---
|
|
25006
|
+
if (!browserFamily || browserFamily === "Unknown") {
|
|
25007
|
+
const browserRegexes = [
|
|
25008
|
+
[/Edg\/(\S+)/, "Edge"],
|
|
25009
|
+
[/OPR\/(\S+)/, "Opera"],
|
|
25010
|
+
[/SamsungBrowser\/(\S+)/, "Samsung Internet"],
|
|
25011
|
+
[/Firefox\/(\S+)/, "Firefox"],
|
|
25012
|
+
[/Chrome\/(\S+)/, "Chrome"],
|
|
25013
|
+
[/Version\/(\S+).*Safari/, "Safari"]
|
|
25014
|
+
];
|
|
25015
|
+
for (const [regex, name] of browserRegexes) {
|
|
25016
|
+
const match = ua.match(regex);
|
|
25017
|
+
if (match) {
|
|
25018
|
+
browserFamily = name;
|
|
25019
|
+
browserVersion = match[1];
|
|
25020
|
+
break;
|
|
25021
|
+
}
|
|
25022
|
+
}
|
|
25023
|
+
}
|
|
25024
|
+
// --- OS detection (always run, iOS first) ---
|
|
25025
|
+
if (/iPhone|iPad|iPod/.test(ua)) {
|
|
25026
|
+
osFamily = "iOS";
|
|
25027
|
+
const match = ua.match(/OS (\d+[_\d]*)/);
|
|
25028
|
+
if (match)
|
|
25029
|
+
osVersion = match[1].replace(/_/g, ".");
|
|
25030
|
+
}
|
|
25031
|
+
else if (uaData === null || uaData === void 0 ? void 0 : uaData.platform) {
|
|
25032
|
+
osFamily = uaData.platform;
|
|
25033
|
+
}
|
|
25034
|
+
else if (/Windows/.test(ua)) {
|
|
25035
|
+
osFamily = "Windows";
|
|
25036
|
+
const match = ua.match(/Windows NT (\d+\.\d+)/);
|
|
25037
|
+
if (match)
|
|
25038
|
+
osVersion = match[1];
|
|
25039
|
+
}
|
|
25040
|
+
else if (/Mac OS X/.test(ua)) {
|
|
25041
|
+
osFamily = "macOS";
|
|
25042
|
+
const match = ua.match(/Mac OS X (\d+[_\d]*)/);
|
|
25043
|
+
if (match)
|
|
25044
|
+
osVersion = match[1].replace(/_/g, ".");
|
|
25045
|
+
}
|
|
25046
|
+
else if (/Android/.test(ua)) {
|
|
25047
|
+
osFamily = "Android";
|
|
25048
|
+
const match = ua.match(/Android (\d+(\.\d+)?)/);
|
|
25049
|
+
if (match)
|
|
25050
|
+
osVersion = match[1];
|
|
25051
|
+
}
|
|
25052
|
+
else if (/Linux/.test(ua)) {
|
|
25053
|
+
osFamily = "Linux";
|
|
25054
|
+
}
|
|
25055
|
+
const result = { browserFamily, browserVersion, osFamily, osVersion, model, architecture, bitness };
|
|
25056
|
+
this.uaInfoCache = result;
|
|
25057
|
+
return result;
|
|
25058
|
+
});
|
|
24607
25059
|
}
|
|
24608
25060
|
}
|
|
24609
|
-
exports.
|
|
25061
|
+
exports.DiagnosticsCollector = DiagnosticsCollector;
|
|
24610
25062
|
|
|
24611
25063
|
|
|
24612
25064
|
/***/ }),
|
|
24613
25065
|
|
|
24614
|
-
/***/
|
|
24615
|
-
/***/ ((__unused_webpack_module, exports
|
|
25066
|
+
/***/ 2483:
|
|
25067
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
24616
25068
|
|
|
24617
25069
|
|
|
24618
25070
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
24619
|
-
exports.
|
|
24620
|
-
|
|
24621
|
-
function
|
|
24622
|
-
|
|
24623
|
-
|
|
24624
|
-
|
|
24625
|
-
|
|
24626
|
-
|
|
24627
|
-
|
|
24628
|
-
|
|
24629
|
-
|
|
24630
|
-
|
|
24631
|
-
|
|
24632
|
-
|
|
24633
|
-
|
|
24634
|
-
|
|
24635
|
-
|
|
24636
|
-
|
|
24637
|
-
|
|
24638
|
-
|
|
24639
|
-
|
|
24640
|
-
|
|
24641
|
-
|
|
24642
|
-
framesPerSecond: forceNumber(stats.inboundVideoStats.framesPerSecond),
|
|
24643
|
-
// frames dropped (last) for ticket
|
|
24644
|
-
framesDropped: forceNumber(stats.inboundVideoStats.framesDropped),
|
|
24645
|
-
// Videocodec (once) for ticket
|
|
24646
|
-
videoCodec: stats.inboundVideoStats.codecId,
|
|
24647
|
-
// audiocodec (once) for ticket
|
|
24648
|
-
audioCodec: stats.inboundAudioStats.codecId,
|
|
24649
|
-
// browser type and version for ticket (arcware / addition)
|
|
24650
|
-
browserInfo: {
|
|
24651
|
-
// to be received!
|
|
24652
|
-
userAgent: navigator.userAgent,
|
|
24653
|
-
platform: navigator.oscpu || navigator.platform || null,
|
|
24654
|
-
language: navigator.language,
|
|
24655
|
-
},
|
|
24656
|
-
// Net RTT (low, high, avg)
|
|
24657
|
-
// BEGIN TW CHANGE
|
|
24658
|
-
currentRTT: calcRTT(stats.candidatePairs),
|
|
24659
|
-
// END TW CHANGE
|
|
24660
|
-
// Duration (last)
|
|
24661
|
-
sessionRunTime: stats.sessionStats.runTime,
|
|
24662
|
-
// Controls stream input (??)
|
|
24663
|
-
controlsStreamInput: stats.sessionStats.controlsStreamInput,
|
|
24664
|
-
// video quantization parameter (low / high / avg if applicable)
|
|
24665
|
-
videoEncoderAvgQP: forceNumber(stats.sessionStats.videoEncoderAvgQP),
|
|
24666
|
-
// Video bitrate (min / max / avg)
|
|
24667
|
-
videoBitrate: forceNumber(stats.inboundVideoStats.bitrate),
|
|
24668
|
-
// Audio bitrate (min / max / avg)
|
|
24669
|
-
audioBitrate: forceNumber(stats.inboundAudioStats.bitrate),
|
|
24670
|
-
});
|
|
24671
|
-
return result;
|
|
24672
|
-
}
|
|
24673
|
-
exports.Stats = Stats;
|
|
24674
|
-
/**
|
|
24675
|
-
* Given an array of candidate pairs this function will find the highest RTT for the selected pair
|
|
24676
|
-
* @param pairs - An array of candidate pairs
|
|
24677
|
-
* @returns The highest round trip time of a selected candidate pair
|
|
24678
|
-
*/
|
|
24679
|
-
function calcRTT(pairs) {
|
|
24680
|
-
let rtt = 0;
|
|
24681
|
-
pairs.forEach((pair) => {
|
|
24682
|
-
if (pair.selected && pair.currentRoundTripTime > rtt) {
|
|
24683
|
-
rtt = pair.currentRoundTripTime;
|
|
25071
|
+
exports.normalizeType = exports.randomHash = exports.extFromMime = exports.sanitizeFilename = exports.truncateByBytes = exports.parseUnknownToObject = void 0;
|
|
25072
|
+
/** Conservative normalizer: accepts object, strict JSON string, or JSON-ish like {foo: "bar"} */
|
|
25073
|
+
function parseUnknownToObject(input, opts = { allowJsonish: true }) {
|
|
25074
|
+
if (input && typeof input === "object")
|
|
25075
|
+
return input;
|
|
25076
|
+
if (typeof input === "string") {
|
|
25077
|
+
try {
|
|
25078
|
+
const parsed = JSON.parse(input);
|
|
25079
|
+
if (parsed && typeof parsed === "object")
|
|
25080
|
+
return parsed;
|
|
25081
|
+
}
|
|
25082
|
+
catch (_a) { }
|
|
25083
|
+
if (opts.allowJsonish) {
|
|
25084
|
+
const repaired = input
|
|
25085
|
+
.trim()
|
|
25086
|
+
.replace(/'/g, '"')
|
|
25087
|
+
.replace(/([{,]\s*)([A-Za-z_][$\w-]*)(\s*:)/g, '$1"$2"$3');
|
|
25088
|
+
try {
|
|
25089
|
+
const parsed = JSON.parse(repaired);
|
|
25090
|
+
if (parsed && typeof parsed === "object")
|
|
25091
|
+
return parsed;
|
|
25092
|
+
}
|
|
25093
|
+
catch (_b) { }
|
|
24684
25094
|
}
|
|
24685
|
-
}
|
|
24686
|
-
|
|
24687
|
-
}
|
|
24688
|
-
/**
|
|
24689
|
-
* Takes a number and forces it to return a number. If the value passed in is NaN, 0 will be returned.
|
|
24690
|
-
* @param value - A number
|
|
24691
|
-
* @returns The number passed in as value or 0 if vlaue was NaN
|
|
24692
|
-
*/
|
|
24693
|
-
function forceNumber(value) {
|
|
24694
|
-
return isNaN(value) ? 0 : value;
|
|
25095
|
+
}
|
|
25096
|
+
throw new Error("Input must be an object or a JSON string of an object.");
|
|
24695
25097
|
}
|
|
24696
|
-
|
|
24697
|
-
|
|
24698
|
-
|
|
24699
|
-
|
|
24700
|
-
|
|
24701
|
-
|
|
24702
|
-
|
|
24703
|
-
|
|
24704
|
-
|
|
24705
|
-
|
|
24706
|
-
|
|
24707
|
-
|
|
24708
|
-
|
|
24709
|
-
|
|
25098
|
+
exports.parseUnknownToObject = parseUnknownToObject;
|
|
25099
|
+
/** Byte-safe string truncation (no broken unicode) */
|
|
25100
|
+
function truncateByBytes(input, maxBytes) {
|
|
25101
|
+
const enc = new TextEncoder();
|
|
25102
|
+
const dec = new TextDecoder();
|
|
25103
|
+
const bytes = enc.encode(input);
|
|
25104
|
+
if (bytes.byteLength <= maxBytes)
|
|
25105
|
+
return input;
|
|
25106
|
+
// Back off until decode works
|
|
25107
|
+
for (let cut = maxBytes; cut > 0; cut--) {
|
|
25108
|
+
try {
|
|
25109
|
+
return dec.decode(bytes.subarray(0, cut), { stream: false });
|
|
25110
|
+
}
|
|
25111
|
+
catch (_a) { }
|
|
25112
|
+
}
|
|
25113
|
+
return "";
|
|
25114
|
+
}
|
|
25115
|
+
exports.truncateByBytes = truncateByBytes;
|
|
25116
|
+
/** Cross-platform safe filename */
|
|
25117
|
+
function sanitizeFilename(input) {
|
|
25118
|
+
let name = input.replace(/\s+/g, " ").trim();
|
|
25119
|
+
name = name.replace(/[\\\/:\*\?"<>\|\u0000-\u001F]+/g, "");
|
|
25120
|
+
name = name.replace(/^\.+/, ""); // avoid hidden files
|
|
25121
|
+
const reserved = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\..*)?$/i;
|
|
25122
|
+
if (reserved.test(name) || !name)
|
|
25123
|
+
name = randomHash();
|
|
25124
|
+
if (name.length > 100)
|
|
25125
|
+
name = name.slice(0, 100);
|
|
25126
|
+
return name;
|
|
25127
|
+
}
|
|
25128
|
+
exports.sanitizeFilename = sanitizeFilename;
|
|
25129
|
+
/** MIME -> extension */
|
|
25130
|
+
function extFromMime(mime) {
|
|
25131
|
+
const map = {
|
|
25132
|
+
"image/png": ".png",
|
|
25133
|
+
"image/jpeg": ".jpg",
|
|
25134
|
+
"image/jpg": ".jpg",
|
|
25135
|
+
"image/webp": ".webp",
|
|
25136
|
+
"image/gif": ".gif",
|
|
25137
|
+
"image/bmp": ".bmp",
|
|
25138
|
+
"image/tiff": ".tiff",
|
|
25139
|
+
"video/mp4": ".mp4",
|
|
25140
|
+
"video/webm": ".webm",
|
|
25141
|
+
"video/ogg": ".ogv",
|
|
25142
|
+
"audio/mpeg": ".mp3",
|
|
25143
|
+
"audio/ogg": ".ogg",
|
|
25144
|
+
"audio/wav": ".wav",
|
|
25145
|
+
"audio/webm": ".weba",
|
|
25146
|
+
"application/pdf": ".pdf",
|
|
25147
|
+
"application/zip": ".zip",
|
|
25148
|
+
"application/x-zip-compressed": ".zip",
|
|
25149
|
+
"application/json": ".json",
|
|
25150
|
+
"text/plain": ".txt",
|
|
25151
|
+
"text/csv": ".csv"
|
|
24710
25152
|
};
|
|
25153
|
+
if (map[mime])
|
|
25154
|
+
return map[mime];
|
|
25155
|
+
if (mime.startsWith("image/") || mime.startsWith("video/") || mime.startsWith("audio/")) {
|
|
25156
|
+
return "." + mime.split("/")[1];
|
|
25157
|
+
}
|
|
25158
|
+
return "";
|
|
24711
25159
|
}
|
|
24712
|
-
exports
|
|
25160
|
+
exports.extFromMime = extFromMime;
|
|
25161
|
+
/** Short random fallback */
|
|
25162
|
+
function randomHash() {
|
|
25163
|
+
return Math.random().toString(36).slice(2, 8);
|
|
25164
|
+
}
|
|
25165
|
+
exports.randomHash = randomHash;
|
|
25166
|
+
function normalizeType(v) {
|
|
25167
|
+
return typeof v === "string" ? v.trim().toLowerCase() : "";
|
|
25168
|
+
}
|
|
25169
|
+
exports.normalizeType = normalizeType;
|
|
24713
25170
|
|
|
24714
25171
|
|
|
24715
25172
|
/***/ }),
|