@arcware-cloud/pixelstreaming-websdk 1.2.15 → 1.2.17

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/README.md CHANGED
@@ -80,6 +80,10 @@ For more detailed examples and advanced usage, please refer to our documentation
80
80
 
81
81
  # Changelog
82
82
 
83
+ ### 1.2.16
84
+
85
+ - Added "diagnostics collector" module
86
+
83
87
  ### 1.2.13
84
88
 
85
89
  - Replaced "moment" by "date-fns"
package/index.cjs.js CHANGED
@@ -23351,7 +23351,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23351
23351
  if (!config.initialSettings.ss)
23352
23352
  config.initialSettings.ss = exports.DefaultUrl;
23353
23353
  super(config);
23354
- this.VERSION = "1.2.15";
23354
+ this.VERSION = "1.2.17";
23355
23355
  this.settings = settings;
23356
23356
  this.session = new Session_1.Session();
23357
23357
  this._initialSettings = config.initialSettings;
@@ -23967,17 +23967,29 @@ exports.ArcwarePixelStreaming = ArcwarePixelStreaming;
23967
23967
  * Default location: /diag/probe.bin
23968
23968
  */
23969
23969
  Object.defineProperty(exports, "__esModule", ({ value: true }));
23970
- exports.DiagnosticsCollector = void 0;
23970
+ exports.DiagnosticsCollector = exports.Type = exports.Orientation = void 0;
23971
23971
  const tslib_1 = __webpack_require__(655);
23972
+ var Orientation;
23973
+ (function (Orientation) {
23974
+ Orientation["Landscape"] = "landscape";
23975
+ Orientation["Portrait"] = "portrait";
23976
+ })(Orientation = exports.Orientation || (exports.Orientation = {}));
23977
+ var Type;
23978
+ (function (Type) {
23979
+ Type["Desktop"] = "desktop";
23980
+ Type["Mobile"] = "mobile";
23981
+ Type["Tablet"] = "tablet";
23982
+ })(Type = exports.Type || (exports.Type = {}));
23972
23983
  /**
23973
23984
  * DiagnosticsCollector
23974
23985
  */
23975
23986
  class DiagnosticsCollector {
23976
23987
  constructor(opts = {}) {
23977
23988
  var _a, _b, _c, _d;
23989
+ this.uaInfoCache = null;
23978
23990
  this.opts = {
23979
23991
  enableBandwidthProbe: (_a = opts.enableBandwidthProbe) !== null && _a !== void 0 ? _a : true,
23980
- probeUrl: (_b = opts.probeUrl) !== null && _b !== void 0 ? _b : '/diag/probe.bin',
23992
+ probeUrl: (_b = opts.probeUrl) !== null && _b !== void 0 ? _b : "/diag/probe.bin",
23981
23993
  respectSaveData: (_c = opts.respectSaveData) !== null && _c !== void 0 ? _c : true,
23982
23994
  sampleRate: Math.max(0, Math.min(1, (_d = opts.sampleRate) !== null && _d !== void 0 ? _d : 1))
23983
23995
  };
@@ -23990,8 +24002,8 @@ class DiagnosticsCollector {
23990
24002
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
23991
24003
  if (!this.shouldSample()) {
23992
24004
  return {
23993
- device: { type: 'desktop', touchSupport: false },
23994
- runtime: { browser: { family: 'Unknown', version: null }, os: { family: 'Unknown', version: null } },
24005
+ device: { type: Type.Desktop, touchSupport: false },
24006
+ runtime: { browser: { family: "Unknown", version: null }, os: { family: "Unknown", version: null } },
23995
24007
  powerHints: { saveData: null, prefersReducedData: null, prefersReducedMotion: null },
23996
24008
  network: { type: null, effectiveType: null, downlinkMbps: null, rttMs: null, measuredDownlinkMbps: null },
23997
24009
  timestamps: { collectedAt: Date.now() }
@@ -24037,9 +24049,9 @@ class DiagnosticsCollector {
24037
24049
  const stats = yield pc.getStats();
24038
24050
  let selected, transport, local, remote;
24039
24051
  stats.forEach((r) => {
24040
- if (r.type === 'transport' && r.selectedCandidatePairId)
24052
+ if (r.type === "transport" && r.selectedCandidatePairId)
24041
24053
  transport = r;
24042
- if (r.type === 'candidate-pair' && (r.selected || r.nominated))
24054
+ if (r.type === "candidate-pair" && (r.selected || r.nominated))
24043
24055
  selected = r;
24044
24056
  });
24045
24057
  if (selected) {
@@ -24080,16 +24092,16 @@ class DiagnosticsCollector {
24080
24092
  hasTouch() {
24081
24093
  var _a;
24082
24094
  const nav = navigator;
24083
- return 'ontouchstart' in window || ((_a = nav.maxTouchPoints) !== null && _a !== void 0 ? _a : 0) > 0;
24095
+ return "ontouchstart" in window || ((_a = nav.maxTouchPoints) !== null && _a !== void 0 ? _a : 0) > 0;
24084
24096
  }
24085
24097
  getOrientation() {
24086
24098
  var _a;
24087
24099
  try {
24088
24100
  if ((_a = screen.orientation) === null || _a === void 0 ? void 0 : _a.type) {
24089
- return screen.orientation.type.startsWith('portrait') ? 'portrait' : 'landscape';
24101
+ return screen.orientation.type.startsWith("portrait") ? Orientation.Portrait : Orientation.Landscape;
24090
24102
  }
24091
24103
  if (window.matchMedia) {
24092
- return window.matchMedia('(orientation: portrait)').matches ? 'portrait' : 'landscape';
24104
+ return window.matchMedia("(orientation: portrait)").matches ? Orientation.Portrait : Orientation.Landscape;
24093
24105
  }
24094
24106
  }
24095
24107
  catch (_b) { }
@@ -24097,8 +24109,8 @@ class DiagnosticsCollector {
24097
24109
  }
24098
24110
  hasWebGL() {
24099
24111
  try {
24100
- const canvas = document.createElement('canvas');
24101
- return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
24112
+ const canvas = document.createElement("canvas");
24113
+ return !!(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"));
24102
24114
  }
24103
24115
  catch (_a) {
24104
24116
  return false;
@@ -24106,37 +24118,50 @@ class DiagnosticsCollector {
24106
24118
  }
24107
24119
  /**
24108
24120
  * Heuristic device type: best-effort only.
24121
+ * Tries UA-CH, then UA fallback, then touch + screen size heuristics.
24109
24122
  */
24110
24123
  inferDeviceType() {
24111
24124
  const uaData = navigator.userAgentData;
24125
+ const ua = navigator.userAgent || "";
24112
24126
  const isMobileCH = (uaData === null || uaData === void 0 ? void 0 : uaData.mobile) === true;
24113
24127
  const minDim = Math.min(screen.width, screen.height);
24114
- if (isMobileCH && minDim >= 600)
24115
- return 'tablet';
24116
- if (isMobileCH)
24117
- return 'mobile';
24118
- if (/\b(iPad|Tablet)\b/i.test(navigator.userAgent))
24119
- return 'tablet';
24120
- if (('ontouchstart' in window) && minDim >= 600 && minDim <= 1100)
24121
- return 'tablet';
24122
- return 'desktop';
24128
+ // 1. Explicit iPad / tablet detection via UA (iOS often lies in CH)
24129
+ if (/\b(iPad|Tablet)\b/i.test(ua)) {
24130
+ return Type.Tablet;
24131
+ }
24132
+ // 2. UA-CH mobile hint (Chromium only, often accurate for Android)
24133
+ if (isMobileCH) {
24134
+ if (minDim >= 600)
24135
+ return Type.Tablet;
24136
+ return Type.Mobile;
24137
+ }
24138
+ // 3. UA sniffing fallback for mobile
24139
+ if (/\b(iPhone|Android.*Mobile|Windows Phone)\b/i.test(ua)) {
24140
+ return Type.Mobile;
24141
+ }
24142
+ // 4. Touch-capable with "tablet-like" dimensions
24143
+ if (("ontouchstart" in window || navigator.maxTouchPoints > 0) && minDim >= 600 && minDim <= 1100) {
24144
+ return Type.Tablet;
24145
+ }
24146
+ // 5. Default fallback
24147
+ return Type.Desktop;
24123
24148
  }
24124
24149
  getPowerHints() {
24125
24150
  const conn = navigator.connection;
24126
- const saveData = typeof (conn === null || conn === void 0 ? void 0 : conn.saveData) === 'boolean' ? conn.saveData : null;
24151
+ const saveData = typeof (conn === null || conn === void 0 ? void 0 : conn.saveData) === "boolean" ? conn.saveData : null;
24127
24152
  let prefersReducedData = null;
24128
24153
  let prefersReducedMotion = null;
24129
- if (typeof window.matchMedia === 'function') {
24154
+ if (typeof window.matchMedia === "function") {
24130
24155
  try {
24131
- const mqData = window.matchMedia('(prefers-reduced-data: reduce)');
24132
- if (typeof mqData.matches === 'boolean') {
24156
+ const mqData = window.matchMedia("(prefers-reduced-data: reduce)");
24157
+ if (typeof mqData.matches === "boolean") {
24133
24158
  prefersReducedData = mqData.matches;
24134
24159
  }
24135
24160
  }
24136
24161
  catch (_a) { }
24137
24162
  try {
24138
- const mqMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
24139
- if (typeof mqMotion.matches === 'boolean') {
24163
+ const mqMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
24164
+ if (typeof mqMotion.matches === "boolean") {
24140
24165
  prefersReducedMotion = mqMotion.matches;
24141
24166
  }
24142
24167
  }
@@ -24147,10 +24172,10 @@ class DiagnosticsCollector {
24147
24172
  getNetworkInfo(measuredDownlinkMbps) {
24148
24173
  const conn = navigator.connection;
24149
24174
  return {
24150
- type: (typeof (conn === null || conn === void 0 ? void 0 : conn.type) === 'string') ? conn.type : null,
24151
- effectiveType: (typeof (conn === null || conn === void 0 ? void 0 : conn.effectiveType) === 'string') ? conn.effectiveType : null,
24152
- downlinkMbps: (typeof (conn === null || conn === void 0 ? void 0 : conn.downlink) === 'number') ? conn.downlink : null,
24153
- rttMs: (typeof (conn === null || conn === void 0 ? void 0 : conn.rtt) === 'number') ? conn.rtt : null,
24175
+ type: typeof (conn === null || conn === void 0 ? void 0 : conn.type) === "string" ? conn.type : null,
24176
+ effectiveType: typeof (conn === null || conn === void 0 ? void 0 : conn.effectiveType) === "string" ? conn.effectiveType : null,
24177
+ downlinkMbps: typeof (conn === null || conn === void 0 ? void 0 : conn.downlink) === "number" ? conn.downlink : null,
24178
+ rttMs: typeof (conn === null || conn === void 0 ? void 0 : conn.rtt) === "number" ? conn.rtt : null,
24154
24179
  measuredDownlinkMbps
24155
24180
  };
24156
24181
  }
@@ -24165,8 +24190,8 @@ class DiagnosticsCollector {
24165
24190
  try {
24166
24191
  const t0 = performance.now();
24167
24192
  const res = yield fetch(this.withCacheBuster(this.opts.probeUrl), {
24168
- cache: 'no-store',
24169
- credentials: 'omit'
24193
+ cache: "no-store",
24194
+ credentials: "omit"
24170
24195
  });
24171
24196
  const buf = yield res.arrayBuffer();
24172
24197
  const t1 = performance.now();
@@ -24174,7 +24199,7 @@ class DiagnosticsCollector {
24174
24199
  const seconds = (t1 - t0) / 1000;
24175
24200
  if (seconds <= 0.05)
24176
24201
  return null; // ignore unstable samples
24177
- return +((bits / seconds) / 1000000).toFixed(2);
24202
+ return +(bits / seconds / 1000000).toFixed(2);
24178
24203
  }
24179
24204
  catch (_a) {
24180
24205
  return null;
@@ -24185,7 +24210,7 @@ class DiagnosticsCollector {
24185
24210
  var _a, _b;
24186
24211
  const u = new URL(url, location.origin);
24187
24212
  const token = (_b = (_a = crypto === null || crypto === void 0 ? void 0 : crypto.randomUUID) === null || _a === void 0 ? void 0 : _a.call(crypto)) !== null && _b !== void 0 ? _b : String(Date.now());
24188
- u.searchParams.set('cb', token);
24213
+ u.searchParams.set("cb", token);
24189
24214
  return u.toString();
24190
24215
  }
24191
24216
  getCodecSupport() {
@@ -24200,10 +24225,10 @@ class DiagnosticsCollector {
24200
24225
  supportsCodec(mime) {
24201
24226
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
24202
24227
  try {
24203
- if ('mediaCapabilities' in navigator) {
24228
+ if ("mediaCapabilities" in navigator) {
24204
24229
  // @ts-ignore
24205
24230
  const res = yield navigator.mediaCapabilities.decodingInfo({
24206
- type: 'file',
24231
+ type: "file",
24207
24232
  video: { contentType: mime, width: 1920, height: 1080, bitrate: 5000000, framerate: 30 }
24208
24233
  });
24209
24234
  return !!(res === null || res === void 0 ? void 0 : res.supported);
@@ -24211,8 +24236,8 @@ class DiagnosticsCollector {
24211
24236
  }
24212
24237
  catch (_a) { }
24213
24238
  try {
24214
- const v = document.createElement('video');
24215
- return v.canPlayType(mime) !== '';
24239
+ const v = document.createElement("video");
24240
+ return v.canPlayType(mime) !== "";
24216
24241
  }
24217
24242
  catch (_b) {
24218
24243
  return false;
@@ -24220,60 +24245,104 @@ class DiagnosticsCollector {
24220
24245
  });
24221
24246
  }
24222
24247
  getUAInfo() {
24223
- var _a, _b;
24224
24248
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
24249
+ if (this.uaInfoCache)
24250
+ return this.uaInfoCache;
24225
24251
  const nav = navigator;
24226
24252
  const uaData = nav.userAgentData;
24227
- let browserFamily = 'Unknown', browserVersion = null;
24228
- let osFamily = 'Unknown', osVersion = null;
24229
- let model = null, architecture = null, bitness = null;
24253
+ const ua = navigator.userAgent;
24254
+ let browserFamily = "Unknown";
24255
+ let browserVersion = null;
24256
+ let osFamily = "Unknown";
24257
+ let osVersion = null;
24258
+ let model = null;
24259
+ let architecture = null;
24260
+ let bitness = null;
24261
+ // --- UA-CH (modern browsers) ---
24230
24262
  if (uaData === null || uaData === void 0 ? void 0 : uaData.getHighEntropyValues) {
24231
24263
  try {
24232
24264
  const high = yield uaData.getHighEntropyValues([
24233
- 'platform', 'platformVersion', 'model', 'architecture', 'bitness', 'fullVersionList'
24265
+ "platform",
24266
+ "platformVersion",
24267
+ "model",
24268
+ "architecture",
24269
+ "bitness",
24270
+ "fullVersionList"
24234
24271
  ]);
24235
- osFamily = high.platform || 'Unknown';
24272
+ osFamily = high.platform || "Unknown";
24236
24273
  osVersion = high.platformVersion || null;
24237
24274
  model = high.model || null;
24238
24275
  architecture = high.architecture || null;
24239
24276
  bitness = high.bitness || null;
24240
24277
  const brands = high.fullVersionList || uaData.brands || [];
24241
- const real = brands.find(b => b.brand && !/Chromium|Not:?A-?Brand/i.test(b.brand));
24242
- browserFamily = (real === null || real === void 0 ? void 0 : real.brand) || ((_a = brands[0]) === null || _a === void 0 ? void 0 : _a.brand) || 'Unknown';
24243
- browserVersion = (real === null || real === void 0 ? void 0 : real.version) || ((_b = brands[0]) === null || _b === void 0 ? void 0 : _b.version) || null;
24244
- }
24245
- catch (_c) { }
24246
- }
24247
- if (browserFamily === 'Unknown') {
24248
- const ua = navigator.userAgent;
24249
- if (/Firefox\/(\S+)/.test(ua)) {
24250
- browserFamily = 'Firefox';
24251
- browserVersion = RegExp.$1;
24252
- }
24253
- else if (/Edg\/(\S+)/.test(ua)) {
24254
- browserFamily = 'Edge';
24255
- browserVersion = RegExp.$1;
24278
+ const realBrand = brands.find((b) => {
24279
+ if (!b.brand)
24280
+ return false;
24281
+ const normalized = b.brand.replace(/[^a-zA-Z]/g, "").toLowerCase();
24282
+ return !normalized.includes("chromium") && !normalized.includes("notabrand");
24283
+ });
24284
+ if (realBrand) {
24285
+ browserFamily = realBrand.brand;
24286
+ browserVersion = realBrand.version;
24287
+ }
24256
24288
  }
24257
- else if (/Chrome\/(\S+)/.test(ua)) {
24258
- browserFamily = 'Chrome';
24259
- browserVersion = RegExp.$1;
24289
+ catch (_a) {
24290
+ // silently fail
24260
24291
  }
24261
- else if (/Version\/(\S+).*Safari/.test(ua)) {
24262
- browserFamily = 'Safari';
24263
- browserVersion = RegExp.$1;
24292
+ }
24293
+ // --- Fallback to classic UA parsing if browser unknown ---
24294
+ if (!browserFamily || browserFamily === "Unknown") {
24295
+ const browserRegexes = [
24296
+ [/Edg\/(\S+)/, "Edge"],
24297
+ [/OPR\/(\S+)/, "Opera"],
24298
+ [/SamsungBrowser\/(\S+)/, "Samsung Internet"],
24299
+ [/Firefox\/(\S+)/, "Firefox"],
24300
+ [/Chrome\/(\S+)/, "Chrome"],
24301
+ [/Version\/(\S+).*Safari/, "Safari"]
24302
+ ];
24303
+ for (const [regex, name] of browserRegexes) {
24304
+ const match = ua.match(regex);
24305
+ if (match) {
24306
+ browserFamily = name;
24307
+ browserVersion = match[1];
24308
+ break;
24309
+ }
24264
24310
  }
24265
- if (/Windows/.test(ua))
24266
- osFamily = 'Windows';
24267
- else if (/Mac OS X/.test(ua))
24268
- osFamily = 'macOS';
24269
- else if (/Android/.test(ua))
24270
- osFamily = 'Android';
24271
- else if (/iPhone|iPad|iPod/.test(ua))
24272
- osFamily = 'iOS';
24273
- else if (/Linux/.test(ua))
24274
- osFamily = 'Linux';
24275
- }
24276
- return { browserFamily, browserVersion, osFamily, osVersion, model, architecture, bitness };
24311
+ }
24312
+ // --- OS detection (always run, iOS first) ---
24313
+ if (/iPhone|iPad|iPod/.test(ua)) {
24314
+ osFamily = "iOS";
24315
+ const match = ua.match(/OS (\d+[_\d]*)/);
24316
+ if (match)
24317
+ osVersion = match[1].replace(/_/g, ".");
24318
+ }
24319
+ else if (uaData === null || uaData === void 0 ? void 0 : uaData.platform) {
24320
+ osFamily = uaData.platform;
24321
+ }
24322
+ else if (/Windows/.test(ua)) {
24323
+ osFamily = "Windows";
24324
+ const match = ua.match(/Windows NT (\d+\.\d+)/);
24325
+ if (match)
24326
+ osVersion = match[1];
24327
+ }
24328
+ else if (/Mac OS X/.test(ua)) {
24329
+ osFamily = "macOS";
24330
+ const match = ua.match(/Mac OS X (\d+[_\d]*)/);
24331
+ if (match)
24332
+ osVersion = match[1].replace(/_/g, ".");
24333
+ }
24334
+ else if (/Android/.test(ua)) {
24335
+ osFamily = "Android";
24336
+ const match = ua.match(/Android (\d+(\.\d+)?)/);
24337
+ if (match)
24338
+ osVersion = match[1];
24339
+ }
24340
+ else if (/Linux/.test(ua)) {
24341
+ osFamily = "Linux";
24342
+ }
24343
+ const result = { browserFamily, browserVersion, osFamily, osVersion, model, architecture, bitness };
24344
+ this.uaInfoCache = result;
24345
+ return result;
24277
24346
  });
24278
24347
  }
24279
24348
  }
package/index.esm.js CHANGED
@@ -23356,7 +23356,7 @@ class ArcwareConfig extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBP
23356
23356
  if (!config.initialSettings.ss)
23357
23357
  config.initialSettings.ss = DefaultUrl;
23358
23358
  super(config);
23359
- this.VERSION = "1.2.15";
23359
+ this.VERSION = "1.2.17";
23360
23360
  this.settings = settings;
23361
23361
  this.session = new _domain_Session__WEBPACK_IMPORTED_MODULE_0__.Session();
23362
23362
  this._initialSettings = config.initialSettings;
@@ -23502,18 +23502,18 @@ __webpack_require__.r(__webpack_exports__);
23502
23502
  /* harmony export */ });
23503
23503
  /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(655);
23504
23504
  /* harmony import */ var _arcware_cloud_shared_pixelstreaming_websdk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7910);
23505
- /* harmony import */ var _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(516);
23505
+ /* harmony import */ var _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(516);
23506
23506
  /* harmony import */ var _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(7800);
23507
23507
  /* harmony import */ var _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(7463);
23508
- /* harmony import */ var _ApplyUrlHack__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4790);
23509
- /* harmony import */ var _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(3379);
23508
+ /* harmony import */ var _ApplyUrlHack__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4790);
23509
+ /* harmony import */ var _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(3379);
23510
23510
  /* harmony import */ var _domain_Stats__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9764);
23511
23511
  /* harmony import */ var _domain_debounce__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(9580);
23512
23512
  /* harmony import */ var _ui_LoveLetters__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(4572);
23513
23513
  /* harmony import */ var _ui_ArcwareLogoLoader__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(6469);
23514
- /* harmony import */ var _ui_MicrophoneOverlay__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(3613);
23514
+ /* harmony import */ var _ui_MicrophoneOverlay__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(3613);
23515
23515
  /* harmony import */ var _domain_ConnectionIdentifier__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5999);
23516
- /* harmony import */ var _DiagnosticsCollector__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(6478);
23516
+ /* harmony import */ var _DiagnosticsCollector__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6478);
23517
23517
 
23518
23518
 
23519
23519
 
@@ -23526,7 +23526,7 @@ __webpack_require__.r(__webpack_exports__);
23526
23526
 
23527
23527
 
23528
23528
 
23529
- class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_3__.PixelStreaming {
23529
+ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_4__.PixelStreaming {
23530
23530
  /** Returns a list of WebSocketStates of all PixelStreaming Instances generated. */
23531
23531
  get WebsocketStates() {
23532
23532
  return _domain_ConnectionIdentifier__WEBPACK_IMPORTED_MODULE_2__.ConnectionIdentifier.Instance.GetWebSocketStates();
@@ -23543,24 +23543,24 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23543
23543
  }
23544
23544
  constructor(config, overrides) {
23545
23545
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23546
- (0,_ApplyUrlHack__WEBPACK_IMPORTED_MODULE_4__.ApplyUrlHack)();
23546
+ (0,_ApplyUrlHack__WEBPACK_IMPORTED_MODULE_5__.ApplyUrlHack)();
23547
23547
  super(config, overrides);
23548
23548
  this.loveLettersQueue = [];
23549
23549
  this.isProcessingQueue = false;
23550
23550
  // Externalized
23551
23551
  /** On ping the session creation timestamp will be updated. */
23552
- this.queueHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23552
+ this.queueHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23553
23553
  /** Error receiver. */
23554
- this.errorHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23554
+ this.errorHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23555
23555
  /** LoveLetter */
23556
- this.loveLetterHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23556
+ this.loveLetterHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23557
23557
  /** SessionId */
23558
- this.sessionIdHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23558
+ this.sessionIdHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23559
23559
  /** VideoInitialized */
23560
- this.videoInitializedHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23560
+ this.videoInitializedHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23561
23561
  // Internal
23562
23562
  /** WebSocket Close */
23563
- this.websocketOnCloseHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23563
+ this.websocketOnCloseHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23564
23564
  /** 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
23565
  * Instead we use ApplyUrlHack();
23566
23566
  */
@@ -23572,8 +23572,8 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23572
23572
  // Set override config.
23573
23573
  this.config = config;
23574
23574
  this.loveLettersList = [];
23575
- this.microphoneOverlay = new _ui_MicrophoneOverlay__WEBPACK_IMPORTED_MODULE_6__.MicrophoneOverlay(this);
23576
- this.diagnosticsCollector = new _DiagnosticsCollector__WEBPACK_IMPORTED_MODULE_7__.DiagnosticsCollector({
23575
+ this.microphoneOverlay = new _ui_MicrophoneOverlay__WEBPACK_IMPORTED_MODULE_7__.MicrophoneOverlay(this);
23576
+ this.diagnosticsCollector = new _DiagnosticsCollector__WEBPACK_IMPORTED_MODULE_3__.DiagnosticsCollector({
23577
23577
  enableBandwidthProbe: false,
23578
23578
  });
23579
23579
  // this.loveLettersContainer = null;
@@ -23684,30 +23684,30 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23684
23684
  }
23685
23685
  onQueue(message) {
23686
23686
  _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Info(`QueueInfo received.`);
23687
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.queueHandler, message);
23687
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.queueHandler, message);
23688
23688
  }
23689
23689
  onError(error) {
23690
23690
  _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Error(error.type);
23691
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.errorHandler, error);
23691
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.errorHandler, error);
23692
23692
  }
23693
23693
  onLoveLetter(loveLetter) {
23694
23694
  // Logger.Info(Logger.GetStackTrace(), loveLetter.reason);
23695
23695
  if (this.config.settings.loveLetterLogging)
23696
23696
  console.info(loveLetter.reason);
23697
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.loveLetterHandler, loveLetter);
23697
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.loveLetterHandler, loveLetter);
23698
23698
  this.pushLetter(loveLetter.reason);
23699
23699
  }
23700
23700
  onSessionId(message) {
23701
23701
  _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Info(message.sessionId);
23702
23702
  // console.info(`Session: ${message.sessionId}`);
23703
23703
  this.session.set(message.sessionId);
23704
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.sessionIdHandler, message.sessionId);
23704
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.sessionIdHandler, message.sessionId);
23705
23705
  }
23706
23706
  onVideoInitialized() {
23707
23707
  /** The videoInitialized event is important for the Arcware Cloud BAckend, since without that event the instance will be cleaned up (killed). */
23708
23708
  this.handleMouseLock();
23709
23709
  this.send({ type: "onVideoInitialized" });
23710
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.videoInitializedHandler, undefined);
23710
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.videoInitializedHandler, undefined);
23711
23711
  this.handleResolutionChange();
23712
23712
  this.handleRemoveLoveLetters();
23713
23713
  this.microphoneOverlay.toggleVisibility(false);
@@ -23928,7 +23928,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23928
23928
  var _a, _b;
23929
23929
  let self = this;
23930
23930
  (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.addEventListener("close", (event) => {
23931
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(self.websocketOnCloseHandler, event);
23931
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(self.websocketOnCloseHandler, event);
23932
23932
  });
23933
23933
  }
23934
23934
  onStreamingStateChange(callback) {
@@ -23975,7 +23975,9 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23975
23975
 
23976
23976
  __webpack_require__.r(__webpack_exports__);
23977
23977
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
23978
- /* harmony export */ "DiagnosticsCollector": () => (/* binding */ DiagnosticsCollector)
23978
+ /* harmony export */ "DiagnosticsCollector": () => (/* binding */ DiagnosticsCollector),
23979
+ /* harmony export */ "Orientation": () => (/* binding */ Orientation),
23980
+ /* harmony export */ "Type": () => (/* binding */ Type)
23979
23981
  /* harmony export */ });
23980
23982
  /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(655);
23981
23983
  /**
@@ -23992,15 +23994,27 @@ __webpack_require__.r(__webpack_exports__);
23992
23994
  * Default location: /diag/probe.bin
23993
23995
  */
23994
23996
 
23997
+ var Orientation;
23998
+ (function (Orientation) {
23999
+ Orientation["Landscape"] = "landscape";
24000
+ Orientation["Portrait"] = "portrait";
24001
+ })(Orientation || (Orientation = {}));
24002
+ var Type;
24003
+ (function (Type) {
24004
+ Type["Desktop"] = "desktop";
24005
+ Type["Mobile"] = "mobile";
24006
+ Type["Tablet"] = "tablet";
24007
+ })(Type || (Type = {}));
23995
24008
  /**
23996
24009
  * DiagnosticsCollector
23997
24010
  */
23998
24011
  class DiagnosticsCollector {
23999
24012
  constructor(opts = {}) {
24000
24013
  var _a, _b, _c, _d;
24014
+ this.uaInfoCache = null;
24001
24015
  this.opts = {
24002
24016
  enableBandwidthProbe: (_a = opts.enableBandwidthProbe) !== null && _a !== void 0 ? _a : true,
24003
- probeUrl: (_b = opts.probeUrl) !== null && _b !== void 0 ? _b : '/diag/probe.bin',
24017
+ probeUrl: (_b = opts.probeUrl) !== null && _b !== void 0 ? _b : "/diag/probe.bin",
24004
24018
  respectSaveData: (_c = opts.respectSaveData) !== null && _c !== void 0 ? _c : true,
24005
24019
  sampleRate: Math.max(0, Math.min(1, (_d = opts.sampleRate) !== null && _d !== void 0 ? _d : 1))
24006
24020
  };
@@ -24013,8 +24027,8 @@ class DiagnosticsCollector {
24013
24027
  return (0,tslib__WEBPACK_IMPORTED_MODULE_0__.__awaiter)(this, void 0, void 0, function* () {
24014
24028
  if (!this.shouldSample()) {
24015
24029
  return {
24016
- device: { type: 'desktop', touchSupport: false },
24017
- runtime: { browser: { family: 'Unknown', version: null }, os: { family: 'Unknown', version: null } },
24030
+ device: { type: Type.Desktop, touchSupport: false },
24031
+ runtime: { browser: { family: "Unknown", version: null }, os: { family: "Unknown", version: null } },
24018
24032
  powerHints: { saveData: null, prefersReducedData: null, prefersReducedMotion: null },
24019
24033
  network: { type: null, effectiveType: null, downlinkMbps: null, rttMs: null, measuredDownlinkMbps: null },
24020
24034
  timestamps: { collectedAt: Date.now() }
@@ -24060,9 +24074,9 @@ class DiagnosticsCollector {
24060
24074
  const stats = yield pc.getStats();
24061
24075
  let selected, transport, local, remote;
24062
24076
  stats.forEach((r) => {
24063
- if (r.type === 'transport' && r.selectedCandidatePairId)
24077
+ if (r.type === "transport" && r.selectedCandidatePairId)
24064
24078
  transport = r;
24065
- if (r.type === 'candidate-pair' && (r.selected || r.nominated))
24079
+ if (r.type === "candidate-pair" && (r.selected || r.nominated))
24066
24080
  selected = r;
24067
24081
  });
24068
24082
  if (selected) {
@@ -24103,16 +24117,16 @@ class DiagnosticsCollector {
24103
24117
  hasTouch() {
24104
24118
  var _a;
24105
24119
  const nav = navigator;
24106
- return 'ontouchstart' in window || ((_a = nav.maxTouchPoints) !== null && _a !== void 0 ? _a : 0) > 0;
24120
+ return "ontouchstart" in window || ((_a = nav.maxTouchPoints) !== null && _a !== void 0 ? _a : 0) > 0;
24107
24121
  }
24108
24122
  getOrientation() {
24109
24123
  var _a;
24110
24124
  try {
24111
24125
  if ((_a = screen.orientation) === null || _a === void 0 ? void 0 : _a.type) {
24112
- return screen.orientation.type.startsWith('portrait') ? 'portrait' : 'landscape';
24126
+ return screen.orientation.type.startsWith("portrait") ? Orientation.Portrait : Orientation.Landscape;
24113
24127
  }
24114
24128
  if (window.matchMedia) {
24115
- return window.matchMedia('(orientation: portrait)').matches ? 'portrait' : 'landscape';
24129
+ return window.matchMedia("(orientation: portrait)").matches ? Orientation.Portrait : Orientation.Landscape;
24116
24130
  }
24117
24131
  }
24118
24132
  catch (_b) { }
@@ -24120,8 +24134,8 @@ class DiagnosticsCollector {
24120
24134
  }
24121
24135
  hasWebGL() {
24122
24136
  try {
24123
- const canvas = document.createElement('canvas');
24124
- return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
24137
+ const canvas = document.createElement("canvas");
24138
+ return !!(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"));
24125
24139
  }
24126
24140
  catch (_a) {
24127
24141
  return false;
@@ -24129,37 +24143,50 @@ class DiagnosticsCollector {
24129
24143
  }
24130
24144
  /**
24131
24145
  * Heuristic device type: best-effort only.
24146
+ * Tries UA-CH, then UA fallback, then touch + screen size heuristics.
24132
24147
  */
24133
24148
  inferDeviceType() {
24134
24149
  const uaData = navigator.userAgentData;
24150
+ const ua = navigator.userAgent || "";
24135
24151
  const isMobileCH = (uaData === null || uaData === void 0 ? void 0 : uaData.mobile) === true;
24136
24152
  const minDim = Math.min(screen.width, screen.height);
24137
- if (isMobileCH && minDim >= 600)
24138
- return 'tablet';
24139
- if (isMobileCH)
24140
- return 'mobile';
24141
- if (/\b(iPad|Tablet)\b/i.test(navigator.userAgent))
24142
- return 'tablet';
24143
- if (('ontouchstart' in window) && minDim >= 600 && minDim <= 1100)
24144
- return 'tablet';
24145
- return 'desktop';
24153
+ // 1. Explicit iPad / tablet detection via UA (iOS often lies in CH)
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;
24170
+ }
24171
+ // 5. Default fallback
24172
+ return Type.Desktop;
24146
24173
  }
24147
24174
  getPowerHints() {
24148
24175
  const conn = navigator.connection;
24149
- const saveData = typeof (conn === null || conn === void 0 ? void 0 : conn.saveData) === 'boolean' ? conn.saveData : null;
24176
+ const saveData = typeof (conn === null || conn === void 0 ? void 0 : conn.saveData) === "boolean" ? conn.saveData : null;
24150
24177
  let prefersReducedData = null;
24151
24178
  let prefersReducedMotion = null;
24152
- if (typeof window.matchMedia === 'function') {
24179
+ if (typeof window.matchMedia === "function") {
24153
24180
  try {
24154
- const mqData = window.matchMedia('(prefers-reduced-data: reduce)');
24155
- if (typeof mqData.matches === 'boolean') {
24181
+ const mqData = window.matchMedia("(prefers-reduced-data: reduce)");
24182
+ if (typeof mqData.matches === "boolean") {
24156
24183
  prefersReducedData = mqData.matches;
24157
24184
  }
24158
24185
  }
24159
24186
  catch (_a) { }
24160
24187
  try {
24161
- const mqMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
24162
- if (typeof mqMotion.matches === 'boolean') {
24188
+ const mqMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
24189
+ if (typeof mqMotion.matches === "boolean") {
24163
24190
  prefersReducedMotion = mqMotion.matches;
24164
24191
  }
24165
24192
  }
@@ -24170,10 +24197,10 @@ class DiagnosticsCollector {
24170
24197
  getNetworkInfo(measuredDownlinkMbps) {
24171
24198
  const conn = navigator.connection;
24172
24199
  return {
24173
- type: (typeof (conn === null || conn === void 0 ? void 0 : conn.type) === 'string') ? conn.type : null,
24174
- effectiveType: (typeof (conn === null || conn === void 0 ? void 0 : conn.effectiveType) === 'string') ? conn.effectiveType : null,
24175
- downlinkMbps: (typeof (conn === null || conn === void 0 ? void 0 : conn.downlink) === 'number') ? conn.downlink : null,
24176
- rttMs: (typeof (conn === null || conn === void 0 ? void 0 : conn.rtt) === 'number') ? conn.rtt : null,
24200
+ type: typeof (conn === null || conn === void 0 ? void 0 : conn.type) === "string" ? conn.type : null,
24201
+ effectiveType: typeof (conn === null || conn === void 0 ? void 0 : conn.effectiveType) === "string" ? conn.effectiveType : null,
24202
+ downlinkMbps: typeof (conn === null || conn === void 0 ? void 0 : conn.downlink) === "number" ? conn.downlink : null,
24203
+ rttMs: typeof (conn === null || conn === void 0 ? void 0 : conn.rtt) === "number" ? conn.rtt : null,
24177
24204
  measuredDownlinkMbps
24178
24205
  };
24179
24206
  }
@@ -24188,8 +24215,8 @@ class DiagnosticsCollector {
24188
24215
  try {
24189
24216
  const t0 = performance.now();
24190
24217
  const res = yield fetch(this.withCacheBuster(this.opts.probeUrl), {
24191
- cache: 'no-store',
24192
- credentials: 'omit'
24218
+ cache: "no-store",
24219
+ credentials: "omit"
24193
24220
  });
24194
24221
  const buf = yield res.arrayBuffer();
24195
24222
  const t1 = performance.now();
@@ -24197,7 +24224,7 @@ class DiagnosticsCollector {
24197
24224
  const seconds = (t1 - t0) / 1000;
24198
24225
  if (seconds <= 0.05)
24199
24226
  return null; // ignore unstable samples
24200
- return +((bits / seconds) / 1000000).toFixed(2);
24227
+ return +(bits / seconds / 1000000).toFixed(2);
24201
24228
  }
24202
24229
  catch (_a) {
24203
24230
  return null;
@@ -24208,7 +24235,7 @@ class DiagnosticsCollector {
24208
24235
  var _a, _b;
24209
24236
  const u = new URL(url, location.origin);
24210
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());
24211
- u.searchParams.set('cb', token);
24238
+ u.searchParams.set("cb", token);
24212
24239
  return u.toString();
24213
24240
  }
24214
24241
  getCodecSupport() {
@@ -24223,10 +24250,10 @@ class DiagnosticsCollector {
24223
24250
  supportsCodec(mime) {
24224
24251
  return (0,tslib__WEBPACK_IMPORTED_MODULE_0__.__awaiter)(this, void 0, void 0, function* () {
24225
24252
  try {
24226
- if ('mediaCapabilities' in navigator) {
24253
+ if ("mediaCapabilities" in navigator) {
24227
24254
  // @ts-ignore
24228
24255
  const res = yield navigator.mediaCapabilities.decodingInfo({
24229
- type: 'file',
24256
+ type: "file",
24230
24257
  video: { contentType: mime, width: 1920, height: 1080, bitrate: 5000000, framerate: 30 }
24231
24258
  });
24232
24259
  return !!(res === null || res === void 0 ? void 0 : res.supported);
@@ -24234,8 +24261,8 @@ class DiagnosticsCollector {
24234
24261
  }
24235
24262
  catch (_a) { }
24236
24263
  try {
24237
- const v = document.createElement('video');
24238
- return v.canPlayType(mime) !== '';
24264
+ const v = document.createElement("video");
24265
+ return v.canPlayType(mime) !== "";
24239
24266
  }
24240
24267
  catch (_b) {
24241
24268
  return false;
@@ -24243,60 +24270,104 @@ class DiagnosticsCollector {
24243
24270
  });
24244
24271
  }
24245
24272
  getUAInfo() {
24246
- var _a, _b;
24247
24273
  return (0,tslib__WEBPACK_IMPORTED_MODULE_0__.__awaiter)(this, void 0, void 0, function* () {
24274
+ if (this.uaInfoCache)
24275
+ return this.uaInfoCache;
24248
24276
  const nav = navigator;
24249
24277
  const uaData = nav.userAgentData;
24250
- let browserFamily = 'Unknown', browserVersion = null;
24251
- let osFamily = 'Unknown', osVersion = null;
24252
- let model = null, architecture = null, bitness = null;
24278
+ const ua = navigator.userAgent;
24279
+ let browserFamily = "Unknown";
24280
+ let browserVersion = null;
24281
+ let osFamily = "Unknown";
24282
+ let osVersion = null;
24283
+ let model = null;
24284
+ let architecture = null;
24285
+ let bitness = null;
24286
+ // --- UA-CH (modern browsers) ---
24253
24287
  if (uaData === null || uaData === void 0 ? void 0 : uaData.getHighEntropyValues) {
24254
24288
  try {
24255
24289
  const high = yield uaData.getHighEntropyValues([
24256
- 'platform', 'platformVersion', 'model', 'architecture', 'bitness', 'fullVersionList'
24290
+ "platform",
24291
+ "platformVersion",
24292
+ "model",
24293
+ "architecture",
24294
+ "bitness",
24295
+ "fullVersionList"
24257
24296
  ]);
24258
- osFamily = high.platform || 'Unknown';
24297
+ osFamily = high.platform || "Unknown";
24259
24298
  osVersion = high.platformVersion || null;
24260
24299
  model = high.model || null;
24261
24300
  architecture = high.architecture || null;
24262
24301
  bitness = high.bitness || null;
24263
24302
  const brands = high.fullVersionList || uaData.brands || [];
24264
- const real = brands.find(b => b.brand && !/Chromium|Not:?A-?Brand/i.test(b.brand));
24265
- browserFamily = (real === null || real === void 0 ? void 0 : real.brand) || ((_a = brands[0]) === null || _a === void 0 ? void 0 : _a.brand) || 'Unknown';
24266
- browserVersion = (real === null || real === void 0 ? void 0 : real.version) || ((_b = brands[0]) === null || _b === void 0 ? void 0 : _b.version) || null;
24267
- }
24268
- catch (_c) { }
24269
- }
24270
- if (browserFamily === 'Unknown') {
24271
- const ua = navigator.userAgent;
24272
- if (/Firefox\/(\S+)/.test(ua)) {
24273
- browserFamily = 'Firefox';
24274
- browserVersion = RegExp.$1;
24275
- }
24276
- else if (/Edg\/(\S+)/.test(ua)) {
24277
- browserFamily = 'Edge';
24278
- browserVersion = RegExp.$1;
24303
+ const realBrand = brands.find((b) => {
24304
+ if (!b.brand)
24305
+ return false;
24306
+ const normalized = b.brand.replace(/[^a-zA-Z]/g, "").toLowerCase();
24307
+ return !normalized.includes("chromium") && !normalized.includes("notabrand");
24308
+ });
24309
+ if (realBrand) {
24310
+ browserFamily = realBrand.brand;
24311
+ browserVersion = realBrand.version;
24312
+ }
24279
24313
  }
24280
- else if (/Chrome\/(\S+)/.test(ua)) {
24281
- browserFamily = 'Chrome';
24282
- browserVersion = RegExp.$1;
24314
+ catch (_a) {
24315
+ // silently fail
24283
24316
  }
24284
- else if (/Version\/(\S+).*Safari/.test(ua)) {
24285
- browserFamily = 'Safari';
24286
- browserVersion = RegExp.$1;
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
+ }
24287
24335
  }
24288
- if (/Windows/.test(ua))
24289
- osFamily = 'Windows';
24290
- else if (/Mac OS X/.test(ua))
24291
- osFamily = 'macOS';
24292
- else if (/Android/.test(ua))
24293
- osFamily = 'Android';
24294
- else if (/iPhone|iPad|iPod/.test(ua))
24295
- osFamily = 'iOS';
24296
- else if (/Linux/.test(ua))
24297
- osFamily = 'Linux';
24298
- }
24299
- return { browserFamily, browserVersion, osFamily, osVersion, model, architecture, bitness };
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;
24300
24371
  });
24301
24372
  }
24302
24373
  }
package/index.umd.js CHANGED
@@ -23361,7 +23361,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23361
23361
  if (!config.initialSettings.ss)
23362
23362
  config.initialSettings.ss = exports.DefaultUrl;
23363
23363
  super(config);
23364
- this.VERSION = "1.2.15";
23364
+ this.VERSION = "1.2.17";
23365
23365
  this.settings = settings;
23366
23366
  this.session = new Session_1.Session();
23367
23367
  this._initialSettings = config.initialSettings;
@@ -23977,17 +23977,29 @@ exports.ArcwarePixelStreaming = ArcwarePixelStreaming;
23977
23977
  * Default location: /diag/probe.bin
23978
23978
  */
23979
23979
  Object.defineProperty(exports, "__esModule", ({ value: true }));
23980
- exports.DiagnosticsCollector = void 0;
23980
+ exports.DiagnosticsCollector = exports.Type = exports.Orientation = void 0;
23981
23981
  const tslib_1 = __webpack_require__(655);
23982
+ var Orientation;
23983
+ (function (Orientation) {
23984
+ Orientation["Landscape"] = "landscape";
23985
+ Orientation["Portrait"] = "portrait";
23986
+ })(Orientation = exports.Orientation || (exports.Orientation = {}));
23987
+ var Type;
23988
+ (function (Type) {
23989
+ Type["Desktop"] = "desktop";
23990
+ Type["Mobile"] = "mobile";
23991
+ Type["Tablet"] = "tablet";
23992
+ })(Type = exports.Type || (exports.Type = {}));
23982
23993
  /**
23983
23994
  * DiagnosticsCollector
23984
23995
  */
23985
23996
  class DiagnosticsCollector {
23986
23997
  constructor(opts = {}) {
23987
23998
  var _a, _b, _c, _d;
23999
+ this.uaInfoCache = null;
23988
24000
  this.opts = {
23989
24001
  enableBandwidthProbe: (_a = opts.enableBandwidthProbe) !== null && _a !== void 0 ? _a : true,
23990
- probeUrl: (_b = opts.probeUrl) !== null && _b !== void 0 ? _b : '/diag/probe.bin',
24002
+ probeUrl: (_b = opts.probeUrl) !== null && _b !== void 0 ? _b : "/diag/probe.bin",
23991
24003
  respectSaveData: (_c = opts.respectSaveData) !== null && _c !== void 0 ? _c : true,
23992
24004
  sampleRate: Math.max(0, Math.min(1, (_d = opts.sampleRate) !== null && _d !== void 0 ? _d : 1))
23993
24005
  };
@@ -24000,8 +24012,8 @@ class DiagnosticsCollector {
24000
24012
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
24001
24013
  if (!this.shouldSample()) {
24002
24014
  return {
24003
- device: { type: 'desktop', touchSupport: false },
24004
- runtime: { browser: { family: 'Unknown', version: null }, os: { family: 'Unknown', version: null } },
24015
+ device: { type: Type.Desktop, touchSupport: false },
24016
+ runtime: { browser: { family: "Unknown", version: null }, os: { family: "Unknown", version: null } },
24005
24017
  powerHints: { saveData: null, prefersReducedData: null, prefersReducedMotion: null },
24006
24018
  network: { type: null, effectiveType: null, downlinkMbps: null, rttMs: null, measuredDownlinkMbps: null },
24007
24019
  timestamps: { collectedAt: Date.now() }
@@ -24047,9 +24059,9 @@ class DiagnosticsCollector {
24047
24059
  const stats = yield pc.getStats();
24048
24060
  let selected, transport, local, remote;
24049
24061
  stats.forEach((r) => {
24050
- if (r.type === 'transport' && r.selectedCandidatePairId)
24062
+ if (r.type === "transport" && r.selectedCandidatePairId)
24051
24063
  transport = r;
24052
- if (r.type === 'candidate-pair' && (r.selected || r.nominated))
24064
+ if (r.type === "candidate-pair" && (r.selected || r.nominated))
24053
24065
  selected = r;
24054
24066
  });
24055
24067
  if (selected) {
@@ -24090,16 +24102,16 @@ class DiagnosticsCollector {
24090
24102
  hasTouch() {
24091
24103
  var _a;
24092
24104
  const nav = navigator;
24093
- return 'ontouchstart' in window || ((_a = nav.maxTouchPoints) !== null && _a !== void 0 ? _a : 0) > 0;
24105
+ return "ontouchstart" in window || ((_a = nav.maxTouchPoints) !== null && _a !== void 0 ? _a : 0) > 0;
24094
24106
  }
24095
24107
  getOrientation() {
24096
24108
  var _a;
24097
24109
  try {
24098
24110
  if ((_a = screen.orientation) === null || _a === void 0 ? void 0 : _a.type) {
24099
- return screen.orientation.type.startsWith('portrait') ? 'portrait' : 'landscape';
24111
+ return screen.orientation.type.startsWith("portrait") ? Orientation.Portrait : Orientation.Landscape;
24100
24112
  }
24101
24113
  if (window.matchMedia) {
24102
- return window.matchMedia('(orientation: portrait)').matches ? 'portrait' : 'landscape';
24114
+ return window.matchMedia("(orientation: portrait)").matches ? Orientation.Portrait : Orientation.Landscape;
24103
24115
  }
24104
24116
  }
24105
24117
  catch (_b) { }
@@ -24107,8 +24119,8 @@ class DiagnosticsCollector {
24107
24119
  }
24108
24120
  hasWebGL() {
24109
24121
  try {
24110
- const canvas = document.createElement('canvas');
24111
- return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
24122
+ const canvas = document.createElement("canvas");
24123
+ return !!(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"));
24112
24124
  }
24113
24125
  catch (_a) {
24114
24126
  return false;
@@ -24116,37 +24128,50 @@ class DiagnosticsCollector {
24116
24128
  }
24117
24129
  /**
24118
24130
  * Heuristic device type: best-effort only.
24131
+ * Tries UA-CH, then UA fallback, then touch + screen size heuristics.
24119
24132
  */
24120
24133
  inferDeviceType() {
24121
24134
  const uaData = navigator.userAgentData;
24135
+ const ua = navigator.userAgent || "";
24122
24136
  const isMobileCH = (uaData === null || uaData === void 0 ? void 0 : uaData.mobile) === true;
24123
24137
  const minDim = Math.min(screen.width, screen.height);
24124
- if (isMobileCH && minDim >= 600)
24125
- return 'tablet';
24126
- if (isMobileCH)
24127
- return 'mobile';
24128
- if (/\b(iPad|Tablet)\b/i.test(navigator.userAgent))
24129
- return 'tablet';
24130
- if (('ontouchstart' in window) && minDim >= 600 && minDim <= 1100)
24131
- return 'tablet';
24132
- return 'desktop';
24138
+ // 1. Explicit iPad / tablet detection via UA (iOS often lies in CH)
24139
+ if (/\b(iPad|Tablet)\b/i.test(ua)) {
24140
+ return Type.Tablet;
24141
+ }
24142
+ // 2. UA-CH mobile hint (Chromium only, often accurate for Android)
24143
+ if (isMobileCH) {
24144
+ if (minDim >= 600)
24145
+ return Type.Tablet;
24146
+ return Type.Mobile;
24147
+ }
24148
+ // 3. UA sniffing fallback for mobile
24149
+ if (/\b(iPhone|Android.*Mobile|Windows Phone)\b/i.test(ua)) {
24150
+ return Type.Mobile;
24151
+ }
24152
+ // 4. Touch-capable with "tablet-like" dimensions
24153
+ if (("ontouchstart" in window || navigator.maxTouchPoints > 0) && minDim >= 600 && minDim <= 1100) {
24154
+ return Type.Tablet;
24155
+ }
24156
+ // 5. Default fallback
24157
+ return Type.Desktop;
24133
24158
  }
24134
24159
  getPowerHints() {
24135
24160
  const conn = navigator.connection;
24136
- const saveData = typeof (conn === null || conn === void 0 ? void 0 : conn.saveData) === 'boolean' ? conn.saveData : null;
24161
+ const saveData = typeof (conn === null || conn === void 0 ? void 0 : conn.saveData) === "boolean" ? conn.saveData : null;
24137
24162
  let prefersReducedData = null;
24138
24163
  let prefersReducedMotion = null;
24139
- if (typeof window.matchMedia === 'function') {
24164
+ if (typeof window.matchMedia === "function") {
24140
24165
  try {
24141
- const mqData = window.matchMedia('(prefers-reduced-data: reduce)');
24142
- if (typeof mqData.matches === 'boolean') {
24166
+ const mqData = window.matchMedia("(prefers-reduced-data: reduce)");
24167
+ if (typeof mqData.matches === "boolean") {
24143
24168
  prefersReducedData = mqData.matches;
24144
24169
  }
24145
24170
  }
24146
24171
  catch (_a) { }
24147
24172
  try {
24148
- const mqMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
24149
- if (typeof mqMotion.matches === 'boolean') {
24173
+ const mqMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
24174
+ if (typeof mqMotion.matches === "boolean") {
24150
24175
  prefersReducedMotion = mqMotion.matches;
24151
24176
  }
24152
24177
  }
@@ -24157,10 +24182,10 @@ class DiagnosticsCollector {
24157
24182
  getNetworkInfo(measuredDownlinkMbps) {
24158
24183
  const conn = navigator.connection;
24159
24184
  return {
24160
- type: (typeof (conn === null || conn === void 0 ? void 0 : conn.type) === 'string') ? conn.type : null,
24161
- effectiveType: (typeof (conn === null || conn === void 0 ? void 0 : conn.effectiveType) === 'string') ? conn.effectiveType : null,
24162
- downlinkMbps: (typeof (conn === null || conn === void 0 ? void 0 : conn.downlink) === 'number') ? conn.downlink : null,
24163
- rttMs: (typeof (conn === null || conn === void 0 ? void 0 : conn.rtt) === 'number') ? conn.rtt : null,
24185
+ type: typeof (conn === null || conn === void 0 ? void 0 : conn.type) === "string" ? conn.type : null,
24186
+ effectiveType: typeof (conn === null || conn === void 0 ? void 0 : conn.effectiveType) === "string" ? conn.effectiveType : null,
24187
+ downlinkMbps: typeof (conn === null || conn === void 0 ? void 0 : conn.downlink) === "number" ? conn.downlink : null,
24188
+ rttMs: typeof (conn === null || conn === void 0 ? void 0 : conn.rtt) === "number" ? conn.rtt : null,
24164
24189
  measuredDownlinkMbps
24165
24190
  };
24166
24191
  }
@@ -24175,8 +24200,8 @@ class DiagnosticsCollector {
24175
24200
  try {
24176
24201
  const t0 = performance.now();
24177
24202
  const res = yield fetch(this.withCacheBuster(this.opts.probeUrl), {
24178
- cache: 'no-store',
24179
- credentials: 'omit'
24203
+ cache: "no-store",
24204
+ credentials: "omit"
24180
24205
  });
24181
24206
  const buf = yield res.arrayBuffer();
24182
24207
  const t1 = performance.now();
@@ -24184,7 +24209,7 @@ class DiagnosticsCollector {
24184
24209
  const seconds = (t1 - t0) / 1000;
24185
24210
  if (seconds <= 0.05)
24186
24211
  return null; // ignore unstable samples
24187
- return +((bits / seconds) / 1000000).toFixed(2);
24212
+ return +(bits / seconds / 1000000).toFixed(2);
24188
24213
  }
24189
24214
  catch (_a) {
24190
24215
  return null;
@@ -24195,7 +24220,7 @@ class DiagnosticsCollector {
24195
24220
  var _a, _b;
24196
24221
  const u = new URL(url, location.origin);
24197
24222
  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());
24198
- u.searchParams.set('cb', token);
24223
+ u.searchParams.set("cb", token);
24199
24224
  return u.toString();
24200
24225
  }
24201
24226
  getCodecSupport() {
@@ -24210,10 +24235,10 @@ class DiagnosticsCollector {
24210
24235
  supportsCodec(mime) {
24211
24236
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
24212
24237
  try {
24213
- if ('mediaCapabilities' in navigator) {
24238
+ if ("mediaCapabilities" in navigator) {
24214
24239
  // @ts-ignore
24215
24240
  const res = yield navigator.mediaCapabilities.decodingInfo({
24216
- type: 'file',
24241
+ type: "file",
24217
24242
  video: { contentType: mime, width: 1920, height: 1080, bitrate: 5000000, framerate: 30 }
24218
24243
  });
24219
24244
  return !!(res === null || res === void 0 ? void 0 : res.supported);
@@ -24221,8 +24246,8 @@ class DiagnosticsCollector {
24221
24246
  }
24222
24247
  catch (_a) { }
24223
24248
  try {
24224
- const v = document.createElement('video');
24225
- return v.canPlayType(mime) !== '';
24249
+ const v = document.createElement("video");
24250
+ return v.canPlayType(mime) !== "";
24226
24251
  }
24227
24252
  catch (_b) {
24228
24253
  return false;
@@ -24230,60 +24255,104 @@ class DiagnosticsCollector {
24230
24255
  });
24231
24256
  }
24232
24257
  getUAInfo() {
24233
- var _a, _b;
24234
24258
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
24259
+ if (this.uaInfoCache)
24260
+ return this.uaInfoCache;
24235
24261
  const nav = navigator;
24236
24262
  const uaData = nav.userAgentData;
24237
- let browserFamily = 'Unknown', browserVersion = null;
24238
- let osFamily = 'Unknown', osVersion = null;
24239
- let model = null, architecture = null, bitness = null;
24263
+ const ua = navigator.userAgent;
24264
+ let browserFamily = "Unknown";
24265
+ let browserVersion = null;
24266
+ let osFamily = "Unknown";
24267
+ let osVersion = null;
24268
+ let model = null;
24269
+ let architecture = null;
24270
+ let bitness = null;
24271
+ // --- UA-CH (modern browsers) ---
24240
24272
  if (uaData === null || uaData === void 0 ? void 0 : uaData.getHighEntropyValues) {
24241
24273
  try {
24242
24274
  const high = yield uaData.getHighEntropyValues([
24243
- 'platform', 'platformVersion', 'model', 'architecture', 'bitness', 'fullVersionList'
24275
+ "platform",
24276
+ "platformVersion",
24277
+ "model",
24278
+ "architecture",
24279
+ "bitness",
24280
+ "fullVersionList"
24244
24281
  ]);
24245
- osFamily = high.platform || 'Unknown';
24282
+ osFamily = high.platform || "Unknown";
24246
24283
  osVersion = high.platformVersion || null;
24247
24284
  model = high.model || null;
24248
24285
  architecture = high.architecture || null;
24249
24286
  bitness = high.bitness || null;
24250
24287
  const brands = high.fullVersionList || uaData.brands || [];
24251
- const real = brands.find(b => b.brand && !/Chromium|Not:?A-?Brand/i.test(b.brand));
24252
- browserFamily = (real === null || real === void 0 ? void 0 : real.brand) || ((_a = brands[0]) === null || _a === void 0 ? void 0 : _a.brand) || 'Unknown';
24253
- browserVersion = (real === null || real === void 0 ? void 0 : real.version) || ((_b = brands[0]) === null || _b === void 0 ? void 0 : _b.version) || null;
24254
- }
24255
- catch (_c) { }
24256
- }
24257
- if (browserFamily === 'Unknown') {
24258
- const ua = navigator.userAgent;
24259
- if (/Firefox\/(\S+)/.test(ua)) {
24260
- browserFamily = 'Firefox';
24261
- browserVersion = RegExp.$1;
24262
- }
24263
- else if (/Edg\/(\S+)/.test(ua)) {
24264
- browserFamily = 'Edge';
24265
- browserVersion = RegExp.$1;
24288
+ const realBrand = brands.find((b) => {
24289
+ if (!b.brand)
24290
+ return false;
24291
+ const normalized = b.brand.replace(/[^a-zA-Z]/g, "").toLowerCase();
24292
+ return !normalized.includes("chromium") && !normalized.includes("notabrand");
24293
+ });
24294
+ if (realBrand) {
24295
+ browserFamily = realBrand.brand;
24296
+ browserVersion = realBrand.version;
24297
+ }
24266
24298
  }
24267
- else if (/Chrome\/(\S+)/.test(ua)) {
24268
- browserFamily = 'Chrome';
24269
- browserVersion = RegExp.$1;
24299
+ catch (_a) {
24300
+ // silently fail
24270
24301
  }
24271
- else if (/Version\/(\S+).*Safari/.test(ua)) {
24272
- browserFamily = 'Safari';
24273
- browserVersion = RegExp.$1;
24302
+ }
24303
+ // --- Fallback to classic UA parsing if browser unknown ---
24304
+ if (!browserFamily || browserFamily === "Unknown") {
24305
+ const browserRegexes = [
24306
+ [/Edg\/(\S+)/, "Edge"],
24307
+ [/OPR\/(\S+)/, "Opera"],
24308
+ [/SamsungBrowser\/(\S+)/, "Samsung Internet"],
24309
+ [/Firefox\/(\S+)/, "Firefox"],
24310
+ [/Chrome\/(\S+)/, "Chrome"],
24311
+ [/Version\/(\S+).*Safari/, "Safari"]
24312
+ ];
24313
+ for (const [regex, name] of browserRegexes) {
24314
+ const match = ua.match(regex);
24315
+ if (match) {
24316
+ browserFamily = name;
24317
+ browserVersion = match[1];
24318
+ break;
24319
+ }
24274
24320
  }
24275
- if (/Windows/.test(ua))
24276
- osFamily = 'Windows';
24277
- else if (/Mac OS X/.test(ua))
24278
- osFamily = 'macOS';
24279
- else if (/Android/.test(ua))
24280
- osFamily = 'Android';
24281
- else if (/iPhone|iPad|iPod/.test(ua))
24282
- osFamily = 'iOS';
24283
- else if (/Linux/.test(ua))
24284
- osFamily = 'Linux';
24285
- }
24286
- return { browserFamily, browserVersion, osFamily, osVersion, model, architecture, bitness };
24321
+ }
24322
+ // --- OS detection (always run, iOS first) ---
24323
+ if (/iPhone|iPad|iPod/.test(ua)) {
24324
+ osFamily = "iOS";
24325
+ const match = ua.match(/OS (\d+[_\d]*)/);
24326
+ if (match)
24327
+ osVersion = match[1].replace(/_/g, ".");
24328
+ }
24329
+ else if (uaData === null || uaData === void 0 ? void 0 : uaData.platform) {
24330
+ osFamily = uaData.platform;
24331
+ }
24332
+ else if (/Windows/.test(ua)) {
24333
+ osFamily = "Windows";
24334
+ const match = ua.match(/Windows NT (\d+\.\d+)/);
24335
+ if (match)
24336
+ osVersion = match[1];
24337
+ }
24338
+ else if (/Mac OS X/.test(ua)) {
24339
+ osFamily = "macOS";
24340
+ const match = ua.match(/Mac OS X (\d+[_\d]*)/);
24341
+ if (match)
24342
+ osVersion = match[1].replace(/_/g, ".");
24343
+ }
24344
+ else if (/Android/.test(ua)) {
24345
+ osFamily = "Android";
24346
+ const match = ua.match(/Android (\d+(\.\d+)?)/);
24347
+ if (match)
24348
+ osVersion = match[1];
24349
+ }
24350
+ else if (/Linux/.test(ua)) {
24351
+ osFamily = "Linux";
24352
+ }
24353
+ const result = { browserFamily, browserVersion, osFamily, osVersion, model, architecture, bitness };
24354
+ this.uaInfoCache = result;
24355
+ return result;
24287
24356
  });
24288
24357
  }
24289
24358
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arcware-cloud/pixelstreaming-websdk",
3
3
  "description": "WebSDK for easy implementation of pixel streaming with Arcware Cloud Services. Heavily based on the '@epicgames-ps' library.",
4
- "version": "1.2.15",
4
+ "version": "1.2.17",
5
5
  "type": "commonjs",
6
6
  "main": "./index.umd.js",
7
7
  "module": "./index.umd.js",
@@ -15,7 +15,7 @@
15
15
  ],
16
16
  "author": {
17
17
  "name": "Arcware GmbH",
18
- "email": "info@arcware.com",
18
+ "email": "sales@arcware.com",
19
19
  "url": "https://www.arcware.com"
20
20
  },
21
21
  "license": "MIT",