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