@titan-os/sdk 1.7.0 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/sdk.js CHANGED
@@ -112,6 +112,17 @@ class LogSubscriptionManager {
112
112
  if (this.logBuffer.length > this.maxBufferSize) {
113
113
  this.logBuffer.shift();
114
114
  }
115
+ const isGatewayEntry = entry.metadata?.source === "Gateway" || entry.metadata?.tunneled === true;
116
+ if (isGatewayEntry && entry.level === "error") {
117
+ const callerInfo = entry.metadata?.caller || "[Gateway]";
118
+ const consoleArgs = formatConsoleOutput(
119
+ entry.module,
120
+ entry.message,
121
+ entry.args || [],
122
+ callerInfo
123
+ );
124
+ outputToConsole("error", consoleArgs);
125
+ }
115
126
  this.subscriptions.forEach((subscription) => {
116
127
  if (this.shouldNotifySubscription(subscription, entry)) {
117
128
  try {
@@ -183,9 +194,28 @@ class LogSubscriptionManager {
183
194
  return [...filtered];
184
195
  }
185
196
  }
197
+ function formatConsoleOutput(module, message, args, callerInfo) {
198
+ const prefix = `[TitanSDK][${module}]`;
199
+ return [`${prefix} ${message}`, ...args, "\n", callerInfo];
200
+ }
201
+ function outputToConsole(level, consoleArgs) {
202
+ switch (level) {
203
+ case "debug":
204
+ console.debug(...consoleArgs);
205
+ break;
206
+ case "info":
207
+ console.info(...consoleArgs);
208
+ break;
209
+ case "warn":
210
+ console.warn(...consoleArgs);
211
+ break;
212
+ case "error":
213
+ console.error(...consoleArgs);
214
+ break;
215
+ }
216
+ }
186
217
  const globalLogManager = new LogSubscriptionManager();
187
218
  function createEnhancedLogger(module) {
188
- const prefix = `[TitanSDK] [${module}]`;
189
219
  const getStackDetails = (callerInfo) => {
190
220
  let fnName = "";
191
221
  let fnPath = "";
@@ -248,28 +278,15 @@ function createEnhancedLogger(module) {
248
278
  }
249
279
  };
250
280
  globalLogManager.addLogEntry(entry);
251
- const shouldLogToConsole = globalLogManager.isDebugMode() || level === "warn" || level === "error";
281
+ const shouldLogToConsole = globalLogManager.isDebugMode() || level === "error";
252
282
  if (shouldLogToConsole) {
253
- const consoleArgs = [
254
- `${prefix} ${message}`,
255
- ...args,
256
- "\n",
283
+ const consoleArgs = formatConsoleOutput(
284
+ module,
285
+ message,
286
+ args,
257
287
  formattedCallerInfo
258
- ];
259
- switch (level) {
260
- case "debug":
261
- console.debug(...consoleArgs);
262
- break;
263
- case "info":
264
- console.info(...consoleArgs);
265
- break;
266
- case "warn":
267
- console.warn(...consoleArgs);
268
- break;
269
- case "error":
270
- console.error(...consoleArgs);
271
- break;
272
- }
288
+ );
289
+ outputToConsole(level, consoleArgs);
273
290
  }
274
291
  };
275
292
  return {
@@ -914,14 +931,17 @@ class BaseBridge {
914
931
  this.initReject = reject;
915
932
  log$u.debug("bridge: starting initialization process");
916
933
  window.addEventListener("message", this.handleMessage.bind(this));
934
+ let isResolved = false;
917
935
  const handleIframeLoad = () => {
918
- if (this.aborted) return;
936
+ if (this.aborted || isResolved) return;
937
+ isResolved = true;
919
938
  this.isInitialized = true;
920
939
  log$u.debug("bridge initialized successfully");
921
940
  resolve(true);
922
941
  };
923
942
  const handleIframeError = () => {
924
- if (this.aborted) return;
943
+ if (this.aborted || isResolved) return;
944
+ isResolved = true;
925
945
  log$u.error("Bridge iframe failed to load or initialize.");
926
946
  this.isInitialized = false;
927
947
  reject(new Error("Bridge iframe failed to load or initialize."));
@@ -929,7 +949,17 @@ class BaseBridge {
929
949
  (async () => {
930
950
  try {
931
951
  await this.setupIframe(handleIframeLoad, handleIframeError);
952
+ if (!isResolved) {
953
+ isResolved = true;
954
+ log$u.warn(
955
+ "Bridge initialization timeout - setupIframe completed but LAUNCHER_READY not received"
956
+ );
957
+ this.isInitialized = false;
958
+ resolve(false);
959
+ }
932
960
  } catch (error) {
961
+ if (isResolved) return;
962
+ isResolved = true;
933
963
  log$u.error("Failed to setup iframe:", error);
934
964
  this.isInitialized = false;
935
965
  reject(error);
@@ -1329,10 +1359,29 @@ __publicField(_CSPDetector, "violations", []);
1329
1359
  let CSPDetector = _CSPDetector;
1330
1360
  const log$s = getLogger("EnhancedBridge");
1331
1361
  function isBridgeCspViolation(violation, src) {
1332
- if (violation.directive !== "frame-src" || !violation.blockedURI || !src) {
1362
+ const relevantDirectives = ["frame-src", "child-src", "connect-src"];
1363
+ if (!relevantDirectives.includes(violation.directive) || !violation.blockedURI || !src) {
1333
1364
  return false;
1334
1365
  }
1335
- return src.includes(violation.blockedURI) || violation.blockedURI.includes(src);
1366
+ const blockedURI = violation.blockedURI;
1367
+ const normalizeUrl = (url) => {
1368
+ return url.replace(/\/+$/, "").toLowerCase();
1369
+ };
1370
+ const normalizedBlocked = normalizeUrl(blockedURI);
1371
+ const normalizedSrc = normalizeUrl(src);
1372
+ const getDomain = (url) => {
1373
+ try {
1374
+ const urlObj = new URL(url);
1375
+ return urlObj.hostname;
1376
+ } catch {
1377
+ const match = url.match(/^(?:https?:\/\/)?([^\/]+)/);
1378
+ return match ? match[1] : "";
1379
+ }
1380
+ };
1381
+ const blockedDomain = getDomain(blockedURI);
1382
+ const srcDomain = getDomain(src);
1383
+ const isGatewayRelated = normalizedSrc.includes(normalizedBlocked) || normalizedBlocked.includes(normalizedSrc) || blockedDomain && srcDomain && blockedDomain === srcDomain || blockedURI.includes("titanos.tv") && src.includes("titanos.tv") || blockedURI.includes("localhost") && src.includes("localhost");
1384
+ return isGatewayRelated;
1336
1385
  }
1337
1386
  class EnhancedBaseBridge extends BaseBridge {
1338
1387
  constructor(config) {
@@ -1345,20 +1394,42 @@ class EnhancedBaseBridge extends BaseBridge {
1345
1394
  cspViolations: []
1346
1395
  });
1347
1396
  __publicField(this, "cspUnsubscribe");
1397
+ __publicField(this, "cspViolationDetected", false);
1398
+ __publicField(this, "cspViolationPromise");
1399
+ __publicField(this, "cspViolationResolver", null);
1348
1400
  this.bridgeHealthStatus.gatewayUrl = this.src;
1401
+ this.cspViolationPromise = new Promise((resolve) => {
1402
+ this.cspViolationResolver = resolve;
1403
+ });
1349
1404
  this.setupCspViolationListener();
1350
1405
  }
1351
1406
  setupCspViolationListener() {
1352
1407
  this.cspUnsubscribe = CSPDetector.onViolation(
1353
1408
  (violation) => {
1409
+ log$s.debug("CSP violation received in EnhancedBaseBridge:", {
1410
+ directive: violation.directive,
1411
+ blockedURI: violation.blockedURI,
1412
+ gatewayUrl: this.src,
1413
+ isBridgeViolation: isBridgeCspViolation(violation, this.src)
1414
+ });
1354
1415
  if (isBridgeCspViolation(violation, this.src)) {
1416
+ const violationString = `${violation.directive}: ${violation.blockedURI || "unknown"}`;
1417
+ if (!this.bridgeHealthStatus.cspViolations.includes(violationString)) {
1418
+ this.bridgeHealthStatus.cspViolations.push(violationString);
1419
+ }
1355
1420
  log$s.warn("CSP violation detected for bridge:", {
1356
1421
  directive: violation.directive,
1357
1422
  blockedURI: violation.blockedURI,
1358
1423
  gatewayUrl: this.src
1359
1424
  });
1360
1425
  this.bridgeHealthStatus.cspBlocked = true;
1361
- this.bridgeHealthStatus.lastError = `CSP blocked: ${violation.directive}`;
1426
+ this.bridgeHealthStatus.lastError = `CSP ${violation.directive} blocked: ${violation.blockedURI || "unknown"}`;
1427
+ if (!this.cspViolationDetected && this.cspViolationResolver) {
1428
+ this.cspViolationDetected = true;
1429
+ log$s.debug("Resolving CSP violation Promise");
1430
+ this.cspViolationResolver();
1431
+ this.cspViolationResolver = null;
1432
+ }
1362
1433
  }
1363
1434
  }
1364
1435
  );
@@ -1392,6 +1463,10 @@ class EnhancedBaseBridge extends BaseBridge {
1392
1463
  this.cspUnsubscribe();
1393
1464
  this.cspUnsubscribe = void 0;
1394
1465
  }
1466
+ this.cspViolationDetected = false;
1467
+ this.cspViolationPromise = new Promise((resolve) => {
1468
+ this.cspViolationResolver = resolve;
1469
+ });
1395
1470
  this.bridgeHealthStatus = {
1396
1471
  connected: false,
1397
1472
  cspBlocked: false,
@@ -1451,6 +1526,50 @@ class EnhancedBaseBridge extends BaseBridge {
1451
1526
  error: health.lastError
1452
1527
  };
1453
1528
  }
1529
+ /**
1530
+ * Waits for bridge initialization attempt to complete (success or failure).
1531
+ * This method resolves when the bridge has finished attempting to initialize,
1532
+ * allowing callers to check the initialization status without relying on timeouts.
1533
+ */
1534
+ async waitForInitializationAttempt() {
1535
+ if (this.isConnected()) {
1536
+ log$s.debug("Bridge already initialized, no need to wait");
1537
+ return;
1538
+ }
1539
+ const bridge = this;
1540
+ if (bridge.initializationPromise) {
1541
+ log$s.debug("Bridge initialization in progress, waiting for completion...");
1542
+ try {
1543
+ await bridge.initializationPromise;
1544
+ log$s.debug("Bridge initialization attempt completed");
1545
+ } catch {
1546
+ log$s.debug("Bridge initialization attempt completed (with error)");
1547
+ }
1548
+ } else {
1549
+ log$s.debug(
1550
+ "No bridge initialization in progress, starting new attempt..."
1551
+ );
1552
+ try {
1553
+ await this.initialize();
1554
+ log$s.debug("Bridge initialization attempt completed");
1555
+ } catch {
1556
+ log$s.debug("Bridge initialization attempt completed (with error)");
1557
+ }
1558
+ }
1559
+ if (this.bridgeHealthStatus.iframeCreated && !this.isConnected()) {
1560
+ if (this.cspViolationDetected || this.bridgeHealthStatus.cspBlocked) {
1561
+ log$s.debug("CSP violation already detected, no need to wait");
1562
+ } else {
1563
+ log$s.debug(
1564
+ "Iframe created but connection not established, waiting for CSP violation detection..."
1565
+ );
1566
+ await this.cspViolationPromise;
1567
+ log$s.debug(
1568
+ "CSP violation detection completed (or connection established)"
1569
+ );
1570
+ }
1571
+ }
1572
+ }
1454
1573
  }
1455
1574
  class VestelBridge extends EnhancedBaseBridge {
1456
1575
  constructor(config) {
@@ -3884,357 +4003,721 @@ function requireLzString() {
3884
4003
  return lzString.exports;
3885
4004
  }
3886
4005
  var lzStringExports = requireLzString();
3887
- const VERSION = "1.7.0";
3888
- const log$l = getLogger("TVPlatform");
3889
- class TVPlatform extends BasePlatform {
3890
- // 7 days
3891
- constructor(config, bridge) {
3892
- super(config);
3893
- __publicField(this, "DEFAULT_DEVICE_INFO", {});
3894
- __publicField(this, "bridge");
3895
- __publicField(this, "isInitialized", false);
3896
- __publicField(this, "CACHE_KEY", "titansdk");
3897
- __publicField(this, "CACHE_EXPIRY", 7 * 24 * 60 * 60 * 1e3);
3898
- if (bridge) {
3899
- this.bridge = bridge;
3900
- } else {
3901
- const bridgeConfig = {
3902
- gatewayUrl: this.config.gatewayUrl
3903
- };
3904
- this.bridge = new EnhancedBaseBridge(bridgeConfig);
3905
- }
3906
- this.initializeBridgeSafely();
4006
+ const VERSION = "1.7.2";
4007
+ const logger$2 = getLogger("RollbarClient");
4008
+ const IGNORED_ERROR_PATTERNS = [
4009
+ "chrome://userjs/",
4010
+ "chrome-extension://",
4011
+ "moz-extension://",
4012
+ "getJWTString",
4013
+ "getjwtstring",
4014
+ "user.js",
4015
+ "userscript",
4016
+ "tampermonkey",
4017
+ "greasemonkey",
4018
+ "can't find variable getjwtstring",
4019
+ "referenceerror: can't find variable: getjwtstring",
4020
+ "unexpected end of json input",
4021
+ "jsonparse"
4022
+ ];
4023
+ class RollbarClient {
4024
+ constructor() {
4025
+ __publicField(this, "rollbar", null);
4026
+ __publicField(this, "config", null);
4027
+ __publicField(this, "windowWrapper", new WindowWrapper());
3907
4028
  }
3908
- async initializeBridgeSafely() {
3909
- try {
3910
- const success = await this.bridge.initialize();
3911
- if (success) {
3912
- this.isInitialized = true;
3913
- }
3914
- } catch (error) {
3915
- log$l.warn("Bridge initialization failed:", error);
3916
- }
3917
- this.waitReadyResolver(true);
4029
+ isSDKError(error) {
4030
+ return error instanceof SDKError || error instanceof Error && error.name === "SDKError";
3918
4031
  }
3919
- getFromLocalStorage() {
3920
- try {
3921
- if (typeof localStorage === "undefined") {
3922
- return null;
3923
- }
3924
- if (!localStorage.getItem) {
3925
- return null;
3926
- }
3927
- const cached = localStorage.getItem(this.CACHE_KEY);
3928
- if (!cached) {
3929
- return null;
3930
- }
3931
- const parsed = JSON.parse(cached);
3932
- if (Date.now() - parsed.timestamp > this.CACHE_EXPIRY || parsed.lastVersion !== VERSION) {
3933
- localStorage.removeItem(this.CACHE_KEY);
3934
- return null;
3935
- }
3936
- log$l.debug("Device info loaded from localStorage cache");
3937
- return parsed;
3938
- } catch (error) {
3939
- log$l.warn("Failed to load device info from localStorage:", error);
3940
- return null;
4032
+ initialize(config) {
4033
+ if (!config.enabled || !config.accessToken) {
4034
+ logger$2.warn("Rollbar not initialized - disabled or missing access token");
4035
+ return;
3941
4036
  }
3942
- }
3943
- getFromURL() {
3944
4037
  try {
3945
- const urlParams = new URLSearchParams(window.location.search);
3946
- const titansdkParam = urlParams.get("titandata");
3947
- if (!titansdkParam) {
3948
- return null;
3949
- }
3950
- let decoded = null;
3951
- const windowWrapper2 = new WindowWrapper();
3952
- try {
3953
- decoded = lzStringExports.decompressFromEncodedURIComponent(titansdkParam);
3954
- if (decoded) {
3955
- log$l.debug("Device info loaded from URL parameter (lz-string)");
3956
- }
3957
- } catch (lzError) {
3958
- log$l.debug("lz-string decompression failed, trying base64");
3959
- }
3960
- if (!decoded) {
3961
- try {
3962
- const atobFunc = windowWrapper2.get("atob");
3963
- if (atobFunc) {
3964
- const urlDecoded = decodeURIComponent(titansdkParam);
3965
- decoded = atobFunc(urlDecoded);
3966
- log$l.debug("Device info loaded from URL parameter (base64)");
3967
- } else {
3968
- log$l.warn("atob function not available");
3969
- return null;
4038
+ this.config = config;
4039
+ this.rollbar = new Rollbar({
4040
+ accessToken: config.accessToken,
4041
+ environment: config.environment || getEnvironment(),
4042
+ captureUncaught: true,
4043
+ captureUnhandledRejections: true,
4044
+ verbose: false,
4045
+ reportLevel: "error",
4046
+ captureIp: false,
4047
+ captureUsername: false,
4048
+ captureEmail: false,
4049
+ maxItems: 100,
4050
+ itemsPerMinute: 60,
4051
+ captureLambdaTimeouts: false,
4052
+ endpoint: `${getLogsDomain()}/logs/`,
4053
+ autoInstrument: {
4054
+ network: false,
4055
+ log: false,
4056
+ dom: false,
4057
+ navigation: false,
4058
+ connectivity: false
4059
+ },
4060
+ payload: {
4061
+ client: {
4062
+ javascript: {
4063
+ code_version: "unknown",
4064
+ source_map_enabled: true
4065
+ }
3970
4066
  }
3971
- } catch (base64Error) {
3972
- log$l.warn("Both lz-string and base64 decoding failed");
3973
- return null;
4067
+ },
4068
+ transform: (payload) => {
4069
+ if (payload.context) {
4070
+ payload.context = `hephaestus-${payload.context}`;
4071
+ }
4072
+ },
4073
+ checkIgnore: (_isUncaught, args, _payload) => {
4074
+ const error = args[0];
4075
+ const errorMessage = typeof error === "string" ? error : error?.message;
4076
+ const errorStack = typeof error === "object" && error ? error.stack : "";
4077
+ const errorString = String(error).toLowerCase();
4078
+ const ignoredPatterns = IGNORED_ERROR_PATTERNS;
4079
+ return ignoredPatterns.some(
4080
+ (pattern) => errorMessage?.toLowerCase().includes(pattern.toLowerCase()) || errorStack?.toLowerCase().includes(pattern.toLowerCase()) || errorString.includes(pattern.toLowerCase())
4081
+ );
3974
4082
  }
3975
- }
3976
- if (!decoded) {
3977
- log$l.warn("Failed to decode URL parameter");
3978
- return null;
3979
- }
3980
- const parsed = JSON.parse(decoded);
3981
- return parsed;
4083
+ });
4084
+ this.setupGlobalErrorHandlers();
4085
+ logger$2.info("Rollbar initialized successfully", {
4086
+ environment: config.environment
4087
+ });
3982
4088
  } catch (error) {
3983
- log$l.warn("Failed to load device info from URL parameter:", error);
3984
- return null;
4089
+ logger$2.error("Failed to initialize Rollbar", { error, config });
3985
4090
  }
3986
4091
  }
3987
- saveToLocalStorage(data) {
3988
- try {
3989
- if (typeof localStorage === "undefined") {
3990
- return;
3991
- }
3992
- if (!data || !data.deviceId || !data.brand || !data.model) {
3993
- log$l.warn("Skipping cache save - invalid or empty device info");
3994
- return;
3995
- }
3996
- const cacheData = {
3997
- data,
3998
- timestamp: Date.now(),
3999
- lastVersion: VERSION
4000
- };
4001
- localStorage.setItem(this.CACHE_KEY, JSON.stringify(cacheData));
4002
- log$l.debug("Device info saved to localStorage cache");
4003
- } catch (error) {
4004
- log$l.warn("Failed to save device info to localStorage:", error);
4005
- }
4092
+ shouldIgnoreError(error) {
4093
+ if (!error) return true;
4094
+ const errorMessage = typeof error === "string" ? error : error.message || "";
4095
+ const errorStack = typeof error === "object" ? error.stack || "" : "";
4096
+ const errorString = String(error).toLowerCase();
4097
+ const ignoredPatterns = IGNORED_ERROR_PATTERNS;
4098
+ return ignoredPatterns.some(
4099
+ (pattern) => errorMessage?.toLowerCase().includes(pattern.toLowerCase()) || errorStack?.toLowerCase().includes(pattern.toLowerCase()) || errorString.includes(pattern.toLowerCase())
4100
+ );
4006
4101
  }
4007
- async getBaseDeviceInfo() {
4008
- const urlData = this.getFromURL();
4009
- if (urlData) {
4010
- this.saveToLocalStorage(urlData);
4011
- this.waitReadyResolver(true);
4012
- return {
4013
- deviceInfo: urlData,
4014
- tts: DEFAULT_TTS_SETTINGS,
4015
- tm: DEFAULT_TM_SETTINGS
4016
- };
4102
+ async reportError(error, additionalData, severity = "error") {
4103
+ if (!this.rollbar || !this.config?.enabled || !error) {
4104
+ return Promise.resolve(null);
4017
4105
  }
4018
- if (this.config.useCache !== false) {
4019
- const localStorageData = this.getFromLocalStorage();
4020
- if (localStorageData) {
4021
- this.waitReadyResolver(true);
4022
- return {
4023
- deviceInfo: localStorageData.data,
4024
- tts: DEFAULT_TTS_SETTINGS,
4025
- tm: DEFAULT_TM_SETTINGS
4026
- };
4027
- }
4028
- } else if (this.config.debug) {
4029
- log$l.debug("Debug mode: skipping cache, fetching fresh data from iframe");
4106
+ if (!this.isSDKError(error)) {
4107
+ return Promise.resolve(null);
4030
4108
  }
4031
- try {
4032
- await this.waitReady;
4033
- return await this.bridge.executeWithFallback(
4034
- async () => {
4035
- const deviceInfo = await this.bridge.getDeviceInfo();
4036
- if (!deviceInfo) {
4037
- throw new Error("Failed to get device info");
4038
- }
4039
- if (deviceInfo.deviceInfo) {
4040
- this.saveToLocalStorage(deviceInfo.deviceInfo);
4041
- }
4042
- return deviceInfo;
4043
- },
4044
- async () => {
4045
- log$l.warn("Bridge unavailable, returning fallback device info");
4046
- const fallbackData = {
4047
- deviceInfo: null,
4048
- tts: DEFAULT_TTS_SETTINGS,
4049
- tm: DEFAULT_TM_SETTINGS
4109
+ if (this.shouldIgnoreError(error)) {
4110
+ return Promise.resolve(null);
4111
+ }
4112
+ return new Promise((resolve) => {
4113
+ this.getDeviceContext().then((deviceContext) => {
4114
+ try {
4115
+ const allLogs = LogManager.getHistory().filter(
4116
+ (log2) => !log2.module.includes("RollbarClient") && !log2.message.includes("Rollbar") && log2.level !== "debug"
4117
+ ).slice(-20);
4118
+ const logsString = allLogs.map(
4119
+ (log2) => `[${log2.timestamp}] ${log2.module}: ${log2.message}${log2.args && log2.args.length > 0 ? "\n Args: " + JSON.stringify(log2.args) : ""}`
4120
+ ).join("\n");
4121
+ const context = {
4122
+ logs: logsString,
4123
+ component: additionalData?.component || "SDK",
4124
+ operation: additionalData?.operation,
4125
+ requestId: additionalData?.requestId,
4126
+ timestamp: Date.now(),
4127
+ url: typeof window !== "undefined" ? window.location?.href : void 0,
4128
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "unknown",
4129
+ sessionId: this.generateSessionId(),
4130
+ errorStack: typeof error === "object" ? error.stack : void 0,
4131
+ version: typeof window !== "undefined" ? this.windowWrapper.get("TitanSDK")?.VERSION || "unknown" : "unknown",
4132
+ ...deviceContext,
4133
+ ...additionalData
4050
4134
  };
4051
- return fallbackData;
4135
+ const rollbarMethod = severity === "critical" ? "critical" : "error";
4136
+ const errorType = severity === "critical" ? "critical_error_with_logs" : "error_with_logs";
4137
+ this.rollbar?.[rollbarMethod](
4138
+ error,
4139
+ {
4140
+ custom: {
4141
+ type: errorType,
4142
+ context,
4143
+ logCount: allLogs.length
4144
+ }
4145
+ },
4146
+ (err, data) => {
4147
+ if (err) {
4148
+ if (!this.shouldIgnoreError(err)) {
4149
+ logger$2.error(
4150
+ `Failed to send ${severity} error to Rollbar`,
4151
+ {
4152
+ error: err,
4153
+ originalError: error
4154
+ }
4155
+ );
4156
+ }
4157
+ resolve(null);
4158
+ } else {
4159
+ const rollbarId = data ? data.uuid || data.result?.uuid || null : null;
4160
+ logger$2.info(
4161
+ `${severity === "critical" ? "Critical error" : "Error"} sent to Rollbar`,
4162
+ {
4163
+ message: typeof error === "string" ? error : error?.message || "Unknown error",
4164
+ component: context.component,
4165
+ rollbarId,
4166
+ logCount: allLogs.length
4167
+ }
4168
+ );
4169
+ resolve(rollbarId);
4170
+ }
4171
+ }
4172
+ );
4173
+ } catch (rollbarError) {
4174
+ logger$2.error(`Failed to send ${severity} error to Rollbar`, {
4175
+ error: rollbarError,
4176
+ originalError: error
4177
+ });
4178
+ resolve(null);
4052
4179
  }
4053
- );
4180
+ }).catch((deviceError) => {
4181
+ logger$2.error(`Failed to get device context for ${severity} error`, {
4182
+ error: deviceError
4183
+ });
4184
+ resolve(null);
4185
+ });
4186
+ });
4187
+ }
4188
+ collectSDKUsage(functionName, result, success, component) {
4189
+ if (!this.rollbar || !this.config?.enabled) return;
4190
+ try {
4191
+ const logLevel = success ? "info" : "warning";
4192
+ this.rollbar[logLevel](`SDK function execution: ${functionName}`, {
4193
+ custom: {
4194
+ type: "sdk_function_execution",
4195
+ functionName,
4196
+ success,
4197
+ component,
4198
+ result: success ? result : void 0,
4199
+ error: !success ? result : void 0,
4200
+ timestamp: Date.now(),
4201
+ url: typeof window !== "undefined" ? window.location?.href : void 0
4202
+ }
4203
+ });
4204
+ logger$2.info("SDK function execution logged", {
4205
+ functionName,
4206
+ success,
4207
+ component
4208
+ });
4054
4209
  } catch (error) {
4055
- log$l.warn("Failed to get device info from bridge:", error);
4210
+ logger$2.error("Failed to log SDK function execution", {
4211
+ error,
4212
+ functionName,
4213
+ component
4214
+ });
4215
+ }
4216
+ }
4217
+ generateSessionId() {
4218
+ return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
4219
+ }
4220
+ async getDeviceContext() {
4221
+ try {
4222
+ if (window?.TitanSDK) {
4223
+ try {
4224
+ const deviceInfo = await window?.TitanSDK?.deviceInfo?.getDeviceInfo?.();
4225
+ return {
4226
+ deviceInfo: deviceInfo ? JSON.stringify(deviceInfo) : "unavailable"
4227
+ };
4228
+ } catch (sdkError) {
4229
+ }
4230
+ }
4056
4231
  return {
4057
- deviceInfo: null,
4058
- tts: DEFAULT_TTS_SETTINGS,
4059
- tm: DEFAULT_TM_SETTINGS
4232
+ deviceInfo: `OS: ${navigator?.platform || "unknown"}, Browser: ${this.detectBrowserEngine()}, Storage: ${"localStorage" in (window || {})}`
4060
4233
  };
4234
+ } catch (error) {
4235
+ return {};
4061
4236
  }
4062
4237
  }
4063
- isTV() {
4064
- return typeof window !== "undefined" && (navigator.userAgent.includes("TV") || navigator.userAgent.includes("SmartTV") || navigator.userAgent.includes("SMART-TV") || window.location.href.includes("file://"));
4238
+ detectBrowserEngine() {
4239
+ if (typeof navigator === "undefined") return "unknown";
4240
+ const userAgent = navigator.userAgent;
4241
+ if (userAgent.includes("Chrome")) return "Blink";
4242
+ if (userAgent.includes("Firefox")) return "Gecko";
4243
+ if (userAgent.includes("Safari") && !userAgent.includes("Chrome"))
4244
+ return "WebKit";
4245
+ if (userAgent.includes("Edge")) return "EdgeHTML";
4246
+ return "unknown";
4065
4247
  }
4066
- }
4067
- const oipfWindow = new WindowWrapper();
4068
- const windowStorage = new WindowWrapper();
4069
- function detectStreamingSupport() {
4070
- const video = document.createElement("video");
4071
- if (!!video.canPlayType && typeof video.canPlayType === "function") {
4072
- return {
4073
- supportAppleHLS: video.canPlayType("application/vnd.apple.mpegURL") !== "" || video.canPlayType("audio/mpegurl") !== "",
4074
- supportMSSmoothStreaming: video.canPlayType("application/vnd.ms-sstr+xml") !== "",
4075
- supportMSSInitiator: video.canPlayType("application/vnd.ms-playready.initiator+xml") !== "",
4076
- supportMPEG_DASH: video.canPlayType("application/dash+xml") !== "" || "unknown"
4248
+ setupGlobalErrorHandlers() {
4249
+ if (typeof window === "undefined") return;
4250
+ const originalConsoleError = console.error;
4251
+ console.error = (...args) => {
4252
+ originalConsoleError.apply(console, args);
4253
+ const errorArg = args.find(
4254
+ (arg) => arg instanceof Error || typeof arg === "string" && arg.includes("Error")
4255
+ );
4256
+ if (errorArg && this.isSDKError(errorArg) && !this.shouldIgnoreError(errorArg)) {
4257
+ this.reportError(errorArg, {
4258
+ component: "SDK",
4259
+ operation: "console.error"
4260
+ });
4261
+ }
4077
4262
  };
4263
+ if (typeof window !== "undefined") {
4264
+ window.addEventListener("error", (event) => {
4265
+ if (this.isSDKError(event.error) && !this.shouldIgnoreError(event.error)) {
4266
+ this.reportError(event.error || event.message, {
4267
+ component: "SDK",
4268
+ operation: "window.onerror"
4269
+ });
4270
+ }
4271
+ });
4272
+ window.addEventListener("unhandledrejection", (event) => {
4273
+ if (this.isSDKError(event.reason) && !this.shouldIgnoreError(event.reason)) {
4274
+ this.reportError(event.reason, {
4275
+ component: "SDK",
4276
+ operation: "unhandledrejection"
4277
+ });
4278
+ }
4279
+ });
4280
+ }
4078
4281
  }
4079
- return {
4080
- supportAppleHLS: false,
4081
- supportMSSmoothStreaming: false,
4082
- supportMSSInitiator: false,
4083
- supportMPEG_DASH: "unknown"
4084
- };
4085
- }
4086
- function detect3DUHDSupport() {
4087
- try {
4088
- const sysinfoElement = document.createElement("object");
4089
- sysinfoElement.setAttribute("id", "sysinfo");
4090
- sysinfoElement.setAttribute("type", "systeminfoobject");
4091
- document.body.appendChild(sysinfoElement);
4092
- const sysinfo = sysinfoElement;
4093
- const result = {
4094
- support3d: Boolean(sysinfo.has3D),
4095
- supportUHD: sysinfo.panelinfo?.toLowerCase() === "3840x2160"
4096
- };
4097
- return { ...result, supportFHD: true };
4098
- } catch (error) {
4099
- return {
4100
- support3d: false,
4101
- supportUHD: false,
4102
- supportFHD: true
4103
- };
4282
+ isInitialized() {
4283
+ return this.rollbar !== null && this.config?.enabled === true;
4104
4284
  }
4105
4285
  }
4106
- function detectOIPFSupport() {
4107
- try {
4108
- if (oipfWindow.get("oipfObjectFactory") !== void 0) {
4109
- return { supportOIPF: true };
4286
+ const rollbarClient = new RollbarClient();
4287
+ const lastReportedAtByCode = {};
4288
+ const REPORT_THROTTLE_MS = 5e3;
4289
+ function redactAndTrimContext(context) {
4290
+ const result = {};
4291
+ const SENSITIVE_KEYS = /jwt|token|authorization|cookie|password|secret/i;
4292
+ const trimValue = (value) => {
4293
+ if (typeof value === "string") {
4294
+ return value.length > 500 ? `${value.slice(0, 500)}…` : value;
4295
+ }
4296
+ if (Array.isArray(value)) {
4297
+ const limited = value.slice(-50);
4298
+ return limited.map(
4299
+ (v) => typeof v === "string" && v.length > 500 ? `${v.slice(0, 500)}…` : v
4300
+ );
4110
4301
  }
4111
- const testObject = document.createElement("object");
4112
- testObject.type = "application/oipfdrmagent";
4113
- const agent = testObject;
4114
- if (typeof agent.sendDRMMessage === "function") {
4115
- return { supportOIPF: true };
4302
+ return value;
4303
+ };
4304
+ Object.keys(context).forEach((key) => {
4305
+ const raw = context[key];
4306
+ if (SENSITIVE_KEYS.test(key)) {
4307
+ result[key] = "[REDACTED]";
4308
+ } else {
4309
+ result[key] = trimValue(raw);
4116
4310
  }
4117
- return { supportOIPF: false };
4118
- } catch (e) {
4119
- return { supportOIPF: false };
4120
- }
4311
+ });
4312
+ return result;
4121
4313
  }
4122
- function detectBrowserCapabilities() {
4314
+ function reportCriticalCode(code, component, operation, context = {}) {
4123
4315
  try {
4124
- const navigatorWrapper = new WindowWrapper();
4125
- const navigatorObj = navigatorWrapper.get("navigator");
4126
- const hasRequestMediaKeySystemAccess = navigatorObj !== void 0 && typeof navigatorObj.requestMediaKeySystemAccess === "function";
4127
- const hasMSMediaKeys = windowStorage.has("MSMediaKeys");
4128
- return {
4129
- supportWebSocket: windowStorage.has("WebSocket"),
4130
- supportEME: hasRequestMediaKeySystemAccess || hasMSMediaKeys,
4131
- hasStorage: windowStorage.has("localStorage") && windowStorage.has("sessionStorage")
4132
- };
4133
- } catch (e) {
4134
- return {
4135
- supportWebSocket: false,
4136
- supportEME: false,
4137
- hasStorage: false
4316
+ const now = Date.now();
4317
+ const last = lastReportedAtByCode[code] || 0;
4318
+ if (now - last < REPORT_THROTTLE_MS) {
4319
+ return Promise.resolve(null);
4320
+ }
4321
+ lastReportedAtByCode[code] = now;
4322
+ const enriched = {
4323
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "unknown",
4324
+ component,
4325
+ operation,
4326
+ context: context ? redactAndTrimContext(context) : void 0,
4327
+ version: VERSION
4138
4328
  };
4329
+ logger$2.error("SDK_CRITICAL", {
4330
+ code,
4331
+ component,
4332
+ operation,
4333
+ ...enriched.context ? { context: enriched.context } : {}
4334
+ });
4335
+ const err = new SDKError(code, ErrorCode.UNKNOWN, {
4336
+ component,
4337
+ operation,
4338
+ ...enriched.context ? { context: enriched.context } : {}
4339
+ });
4340
+ return rollbarClient.reportError(err, enriched, "critical");
4341
+ } catch {
4342
+ return Promise.resolve(null);
4139
4343
  }
4140
4344
  }
4141
- const mediaKeyWindow = new WindowWrapper();
4142
- function detectDRMMethodSupport() {
4143
- let returnString = "";
4144
- returnString = checkOIPFDRMAgentObj();
4145
- try {
4146
- const hasMediaKeys = mediaKeyWindow.has("MediaKeys");
4147
- const hasWebKitMediaKeys = mediaKeyWindow.has("WebKitMediaKeys");
4148
- const hasMSMediaKeys = mediaKeyWindow.has("MSMediaKeys");
4149
- const eme = hasMediaKeys || hasWebKitMediaKeys || hasMSMediaKeys;
4150
- returnString = eme ? "EME" : returnString;
4151
- return { drmMethod: returnString };
4152
- } catch (e) {
4153
- return { drmMethod: "" };
4154
- }
4155
- }
4156
- function checkOIPFDRMAgentObj() {
4157
- try {
4158
- const testObject = document.createElement("object");
4159
- testObject.type = "application/oipfdrmagent";
4160
- const agent = testObject;
4161
- if (typeof agent.sendDRMMessage === "function") {
4162
- return "OIPF";
4345
+ const rollbarClient$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
4346
+ __proto__: null,
4347
+ reportCriticalCode,
4348
+ rollbarClient
4349
+ }, Symbol.toStringTag, { value: "Module" }));
4350
+ const log$l = getLogger("TVPlatform");
4351
+ class TVPlatform extends BasePlatform {
4352
+ // 7 days
4353
+ constructor(config, bridge) {
4354
+ super(config);
4355
+ __publicField(this, "DEFAULT_DEVICE_INFO", {});
4356
+ __publicField(this, "bridge");
4357
+ __publicField(this, "isInitialized", false);
4358
+ __publicField(this, "CACHE_KEY", "titansdk");
4359
+ __publicField(this, "CACHE_EXPIRY", 7 * 24 * 60 * 60 * 1e3);
4360
+ if (bridge) {
4361
+ this.bridge = bridge;
4163
4362
  } else {
4164
- return "";
4363
+ const bridgeConfig = {
4364
+ gatewayUrl: this.config.gatewayUrl
4365
+ };
4366
+ this.bridge = new EnhancedBaseBridge(bridgeConfig);
4165
4367
  }
4166
- } catch (e) {
4167
- return "";
4368
+ this.initializeBridgeSafely();
4168
4369
  }
4169
- }
4170
- function detectEMESupport() {
4171
- try {
4172
- const hasMediaKeys = mediaKeyWindow.has("MediaKeys");
4173
- const hasWebKitMediaKeys = mediaKeyWindow.has("WebKitMediaKeys");
4174
- const hasMSMediaKeys = mediaKeyWindow.has("MSMediaKeys");
4175
- return { supportEME: hasMediaKeys || hasWebKitMediaKeys || hasMSMediaKeys };
4176
- } catch (e) {
4177
- return { supportEME: false };
4370
+ async initializeBridgeSafely() {
4371
+ try {
4372
+ const success = await this.bridge.initialize();
4373
+ if (success) {
4374
+ this.isInitialized = true;
4375
+ }
4376
+ } catch (error) {
4377
+ log$l.warn("Bridge initialization failed:", error);
4378
+ }
4379
+ this.waitReadyResolver(true);
4178
4380
  }
4179
- }
4180
- const log$k = getLogger("PhilipsCapabilities");
4181
- function checkPlayreadySupport() {
4182
- const config = [
4183
- {
4184
- initDataTypes: ["cenc"],
4185
- audioCapabilities: [
4186
- {
4187
- contentType: 'audio/mp4;codecs="mp4a.40.2"'
4381
+ getFromLocalStorage() {
4382
+ try {
4383
+ if (typeof localStorage === "undefined") {
4384
+ return null;
4385
+ }
4386
+ if (!localStorage.getItem) {
4387
+ return null;
4388
+ }
4389
+ const cached = localStorage.getItem(this.CACHE_KEY);
4390
+ if (!cached) {
4391
+ return null;
4392
+ }
4393
+ const parsed = JSON.parse(cached);
4394
+ if (Date.now() - parsed.timestamp > this.CACHE_EXPIRY || parsed.lastVersion !== VERSION) {
4395
+ localStorage.removeItem(this.CACHE_KEY);
4396
+ return null;
4397
+ }
4398
+ log$l.debug("Device info loaded from localStorage cache");
4399
+ return parsed;
4400
+ } catch (error) {
4401
+ log$l.warn("Failed to load device info from localStorage:", error);
4402
+ return null;
4403
+ }
4404
+ }
4405
+ getFromURL() {
4406
+ try {
4407
+ const urlParams = new URLSearchParams(window.location.search);
4408
+ const titansdkParam = urlParams.get("titandata");
4409
+ if (!titansdkParam) {
4410
+ return null;
4411
+ }
4412
+ let decoded = null;
4413
+ const windowWrapper2 = new WindowWrapper();
4414
+ try {
4415
+ decoded = lzStringExports.decompressFromEncodedURIComponent(titansdkParam);
4416
+ if (decoded) {
4417
+ log$l.debug("Device info loaded from URL parameter (lz-string)");
4188
4418
  }
4189
- ],
4190
- videoCapabilities: [
4191
- {
4192
- contentType: 'video/mp4;codecs="avc1.42E01E"'
4419
+ } catch (lzError) {
4420
+ log$l.debug("lz-string decompression failed, trying base64");
4421
+ }
4422
+ if (!decoded) {
4423
+ try {
4424
+ const atobFunc = windowWrapper2.get("atob");
4425
+ if (atobFunc) {
4426
+ const urlDecoded = decodeURIComponent(titansdkParam);
4427
+ decoded = atobFunc(urlDecoded);
4428
+ log$l.debug("Device info loaded from URL parameter (base64)");
4429
+ } else {
4430
+ log$l.warn("atob function not available");
4431
+ return null;
4432
+ }
4433
+ } catch (base64Error) {
4434
+ log$l.warn("Both lz-string and base64 decoding failed");
4435
+ return null;
4193
4436
  }
4194
- ]
4437
+ }
4438
+ if (!decoded) {
4439
+ log$l.warn("Failed to decode URL parameter");
4440
+ return null;
4441
+ }
4442
+ const parsed = JSON.parse(decoded);
4443
+ return parsed;
4444
+ } catch (error) {
4445
+ log$l.warn("Failed to load device info from URL parameter:", error);
4446
+ return null;
4195
4447
  }
4196
- ];
4197
- return new Promise((resolve) => {
4448
+ }
4449
+ saveToLocalStorage(data) {
4198
4450
  try {
4199
- navigator.requestMediaKeySystemAccess("com.microsoft.playready", config).then(() => {
4200
- resolve(true);
4201
- }).catch(() => {
4202
- resolve(false);
4203
- });
4204
- } catch (e) {
4205
- resolve(false);
4451
+ if (typeof localStorage === "undefined") {
4452
+ return;
4453
+ }
4454
+ if (!data || !data.deviceId || !data.brand || !data.model) {
4455
+ log$l.warn("Skipping cache save - invalid or empty device info");
4456
+ return;
4457
+ }
4458
+ const cacheData = {
4459
+ data,
4460
+ timestamp: Date.now(),
4461
+ lastVersion: VERSION
4462
+ };
4463
+ localStorage.setItem(this.CACHE_KEY, JSON.stringify(cacheData));
4464
+ log$l.debug("Device info saved to localStorage cache");
4465
+ } catch (error) {
4466
+ log$l.warn("Failed to save device info to localStorage:", error);
4206
4467
  }
4207
- });
4208
- }
4209
- function checkWidevineSupport() {
4210
- const config = [
4211
- {
4212
- initDataTypes: ["cenc"],
4213
- audioCapabilities: [
4214
- {
4215
- contentType: 'audio/mp4;codecs="mp4a.40.2"'
4468
+ }
4469
+ async getBaseDeviceInfo() {
4470
+ const urlData = this.getFromURL();
4471
+ if (urlData) {
4472
+ this.saveToLocalStorage(urlData);
4473
+ this.waitReadyResolver(true);
4474
+ return {
4475
+ deviceInfo: urlData,
4476
+ tts: DEFAULT_TTS_SETTINGS,
4477
+ tm: DEFAULT_TM_SETTINGS
4478
+ };
4479
+ }
4480
+ if (this.config.useCache !== false) {
4481
+ const localStorageData = this.getFromLocalStorage();
4482
+ if (localStorageData) {
4483
+ this.waitReadyResolver(true);
4484
+ return {
4485
+ deviceInfo: localStorageData.data,
4486
+ tts: DEFAULT_TTS_SETTINGS,
4487
+ tm: DEFAULT_TM_SETTINGS
4488
+ };
4489
+ }
4490
+ } else if (this.config.debug) {
4491
+ log$l.debug("Debug mode: skipping cache, fetching fresh data from iframe");
4492
+ }
4493
+ try {
4494
+ await this.waitReady;
4495
+ return await this.bridge.executeWithFallback(
4496
+ async () => {
4497
+ const deviceInfo = await this.bridge.getDeviceInfo();
4498
+ if (!deviceInfo) {
4499
+ throw new Error("Failed to get device info");
4500
+ }
4501
+ if (deviceInfo.deviceInfo) {
4502
+ this.saveToLocalStorage(deviceInfo.deviceInfo);
4503
+ }
4504
+ return deviceInfo;
4505
+ },
4506
+ async () => {
4507
+ log$l.warn("Bridge unavailable, returning fallback device info");
4508
+ const fallbackData = {
4509
+ deviceInfo: null,
4510
+ tts: DEFAULT_TTS_SETTINGS,
4511
+ tm: DEFAULT_TM_SETTINGS
4512
+ };
4513
+ void reportCriticalCode(
4514
+ "SDK_BRIDGE_FALLBACK",
4515
+ "SDK",
4516
+ "bridge.executeWithFallback",
4517
+ {
4518
+ reason: "bridge unavailable",
4519
+ platformId: this.getId(),
4520
+ isInitialized: this.isInitialized
4521
+ }
4522
+ );
4523
+ return fallbackData;
4216
4524
  }
4217
- ],
4218
- videoCapabilities: [
4525
+ );
4526
+ } catch (error) {
4527
+ log$l.warn("Failed to get device info from bridge:", error);
4528
+ void reportCriticalCode(
4529
+ "SDK_BRIDGE_FALLBACK",
4530
+ "SDK",
4531
+ "bridge.executeWithFallback",
4219
4532
  {
4220
- contentType: 'video/mp4;codecs="avc1.42E01E"'
4533
+ reason: "bridge exception",
4534
+ platformId: this.getId(),
4535
+ isInitialized: this.isInitialized,
4536
+ error: error instanceof Error ? error.message : String(error)
4221
4537
  }
4222
- ]
4223
- }
4224
- ];
4225
- return new Promise((resolve) => {
4226
- try {
4227
- navigator.requestMediaKeySystemAccess("com.widevine.alpha", config).then(() => {
4228
- resolve(true);
4229
- }).catch(() => {
4230
- resolve(false);
4231
- });
4232
- } catch (e) {
4233
- resolve(false);
4538
+ );
4539
+ return {
4540
+ deviceInfo: null,
4541
+ tts: DEFAULT_TTS_SETTINGS,
4542
+ tm: DEFAULT_TM_SETTINGS
4543
+ };
4234
4544
  }
4235
- });
4236
- }
4237
- async function getCapabilities$1(_platform) {
4545
+ }
4546
+ isTV() {
4547
+ return typeof window !== "undefined" && (navigator.userAgent.includes("TV") || navigator.userAgent.includes("SmartTV") || navigator.userAgent.includes("SMART-TV") || window.location.href.includes("file://"));
4548
+ }
4549
+ }
4550
+ const oipfWindow = new WindowWrapper();
4551
+ const windowStorage = new WindowWrapper();
4552
+ function detectStreamingSupport() {
4553
+ const video = document.createElement("video");
4554
+ if (!!video.canPlayType && typeof video.canPlayType === "function") {
4555
+ return {
4556
+ supportAppleHLS: video.canPlayType("application/vnd.apple.mpegURL") !== "" || video.canPlayType("audio/mpegurl") !== "",
4557
+ supportMSSmoothStreaming: video.canPlayType("application/vnd.ms-sstr+xml") !== "",
4558
+ supportMSSInitiator: video.canPlayType("application/vnd.ms-playready.initiator+xml") !== "",
4559
+ supportMPEG_DASH: video.canPlayType("application/dash+xml") !== "" || "unknown"
4560
+ };
4561
+ }
4562
+ return {
4563
+ supportAppleHLS: false,
4564
+ supportMSSmoothStreaming: false,
4565
+ supportMSSInitiator: false,
4566
+ supportMPEG_DASH: "unknown"
4567
+ };
4568
+ }
4569
+ function detect3DUHDSupport() {
4570
+ try {
4571
+ const sysinfoElement = document.createElement("object");
4572
+ sysinfoElement.setAttribute("id", "sysinfo");
4573
+ sysinfoElement.setAttribute("type", "systeminfoobject");
4574
+ document.body.appendChild(sysinfoElement);
4575
+ const sysinfo = sysinfoElement;
4576
+ const result = {
4577
+ support3d: Boolean(sysinfo.has3D),
4578
+ supportUHD: sysinfo.panelinfo?.toLowerCase() === "3840x2160"
4579
+ };
4580
+ return { ...result, supportFHD: true };
4581
+ } catch (error) {
4582
+ return {
4583
+ support3d: false,
4584
+ supportUHD: false,
4585
+ supportFHD: true
4586
+ };
4587
+ }
4588
+ }
4589
+ function detectOIPFSupport() {
4590
+ try {
4591
+ if (oipfWindow.get("oipfObjectFactory") !== void 0) {
4592
+ return { supportOIPF: true };
4593
+ }
4594
+ const testObject = document.createElement("object");
4595
+ testObject.type = "application/oipfdrmagent";
4596
+ const agent = testObject;
4597
+ if (typeof agent.sendDRMMessage === "function") {
4598
+ return { supportOIPF: true };
4599
+ }
4600
+ return { supportOIPF: false };
4601
+ } catch (e) {
4602
+ return { supportOIPF: false };
4603
+ }
4604
+ }
4605
+ function detectBrowserCapabilities() {
4606
+ try {
4607
+ const navigatorWrapper = new WindowWrapper();
4608
+ const navigatorObj = navigatorWrapper.get("navigator");
4609
+ const hasRequestMediaKeySystemAccess = navigatorObj !== void 0 && typeof navigatorObj.requestMediaKeySystemAccess === "function";
4610
+ const hasMSMediaKeys = windowStorage.has("MSMediaKeys");
4611
+ return {
4612
+ supportWebSocket: windowStorage.has("WebSocket"),
4613
+ supportEME: hasRequestMediaKeySystemAccess || hasMSMediaKeys,
4614
+ hasStorage: windowStorage.has("localStorage") && windowStorage.has("sessionStorage")
4615
+ };
4616
+ } catch (e) {
4617
+ return {
4618
+ supportWebSocket: false,
4619
+ supportEME: false,
4620
+ hasStorage: false
4621
+ };
4622
+ }
4623
+ }
4624
+ const mediaKeyWindow = new WindowWrapper();
4625
+ function detectDRMMethodSupport() {
4626
+ let returnString = "";
4627
+ returnString = checkOIPFDRMAgentObj();
4628
+ try {
4629
+ const hasMediaKeys = mediaKeyWindow.has("MediaKeys");
4630
+ const hasWebKitMediaKeys = mediaKeyWindow.has("WebKitMediaKeys");
4631
+ const hasMSMediaKeys = mediaKeyWindow.has("MSMediaKeys");
4632
+ const eme = hasMediaKeys || hasWebKitMediaKeys || hasMSMediaKeys;
4633
+ returnString = eme ? "EME" : returnString;
4634
+ return { drmMethod: returnString };
4635
+ } catch (e) {
4636
+ return { drmMethod: "" };
4637
+ }
4638
+ }
4639
+ function checkOIPFDRMAgentObj() {
4640
+ try {
4641
+ const testObject = document.createElement("object");
4642
+ testObject.type = "application/oipfdrmagent";
4643
+ const agent = testObject;
4644
+ if (typeof agent.sendDRMMessage === "function") {
4645
+ return "OIPF";
4646
+ } else {
4647
+ return "";
4648
+ }
4649
+ } catch (e) {
4650
+ return "";
4651
+ }
4652
+ }
4653
+ function detectEMESupport() {
4654
+ try {
4655
+ const hasMediaKeys = mediaKeyWindow.has("MediaKeys");
4656
+ const hasWebKitMediaKeys = mediaKeyWindow.has("WebKitMediaKeys");
4657
+ const hasMSMediaKeys = mediaKeyWindow.has("MSMediaKeys");
4658
+ return { supportEME: hasMediaKeys || hasWebKitMediaKeys || hasMSMediaKeys };
4659
+ } catch (e) {
4660
+ return { supportEME: false };
4661
+ }
4662
+ }
4663
+ const log$k = getLogger("PhilipsCapabilities");
4664
+ function checkPlayreadySupport() {
4665
+ const config = [
4666
+ {
4667
+ initDataTypes: ["cenc"],
4668
+ audioCapabilities: [
4669
+ {
4670
+ contentType: 'audio/mp4;codecs="mp4a.40.2"'
4671
+ }
4672
+ ],
4673
+ videoCapabilities: [
4674
+ {
4675
+ contentType: 'video/mp4;codecs="avc1.42E01E"'
4676
+ }
4677
+ ]
4678
+ }
4679
+ ];
4680
+ return new Promise((resolve) => {
4681
+ try {
4682
+ navigator.requestMediaKeySystemAccess("com.microsoft.playready", config).then(() => {
4683
+ resolve(true);
4684
+ }).catch(() => {
4685
+ resolve(false);
4686
+ });
4687
+ } catch (e) {
4688
+ resolve(false);
4689
+ }
4690
+ });
4691
+ }
4692
+ function checkWidevineSupport() {
4693
+ const config = [
4694
+ {
4695
+ initDataTypes: ["cenc"],
4696
+ audioCapabilities: [
4697
+ {
4698
+ contentType: 'audio/mp4;codecs="mp4a.40.2"'
4699
+ }
4700
+ ],
4701
+ videoCapabilities: [
4702
+ {
4703
+ contentType: 'video/mp4;codecs="avc1.42E01E"'
4704
+ }
4705
+ ]
4706
+ }
4707
+ ];
4708
+ return new Promise((resolve) => {
4709
+ try {
4710
+ navigator.requestMediaKeySystemAccess("com.widevine.alpha", config).then(() => {
4711
+ resolve(true);
4712
+ }).catch(() => {
4713
+ resolve(false);
4714
+ });
4715
+ } catch (e) {
4716
+ resolve(false);
4717
+ }
4718
+ });
4719
+ }
4720
+ async function getCapabilities$1(_platform) {
4238
4721
  const playreadySupported = await checkPlayreadySupport();
4239
4722
  const widevineSupported = await checkWidevineSupport();
4240
4723
  const capabilities = {
@@ -4418,6 +4901,16 @@ class PhilipsCompat extends TVPlatform {
4418
4901
  legacyInfo.Product.platform = platform;
4419
4902
  legacyInfo.Product.language = data.deviceInfo.language;
4420
4903
  legacyInfo.Product.mac = data.deviceInfo.mac;
4904
+ if (!legacyInfo.Product.mac) {
4905
+ void reportCriticalCode(
4906
+ "SDK_BRIDGE_NO_MAC",
4907
+ "SDK",
4908
+ "formatBridgeResponse",
4909
+ {
4910
+ deviceInfo: data.deviceInfo
4911
+ }
4912
+ );
4913
+ }
4421
4914
  legacyInfo.Product.ifa = data.deviceInfo.ifa || "";
4422
4915
  legacyInfo.Product.ifaType = data.deviceInfo.ifaType || "";
4423
4916
  legacyInfo.Product.year = data.deviceInfo.year || "";
@@ -4970,7 +5463,7 @@ function getCapabilities(_platform) {
4970
5463
  };
4971
5464
  if (_platform === "MB191") {
4972
5465
  capabilities.supportHDR_DV = false;
4973
- capabilities.supportHDR_HDR10 = false;
5466
+ capabilities.supportHDR_HDR10 = true;
4974
5467
  capabilities.supportDolbyAtmos = false;
4975
5468
  }
4976
5469
  return {
@@ -5037,32 +5530,26 @@ class VestelCompat extends TVPlatform {
5037
5530
  }
5038
5531
  async fetchDeviceInfoInternal() {
5039
5532
  try {
5040
- if (await this.waitReady) {
5041
- const bridgeInfo = await this.getBaseDeviceInfo();
5042
- const legacyInfo = {
5043
- Channel: this.DEFAULT_DEVICE_INFO.Channel,
5044
- Product: this.DEFAULT_DEVICE_INFO.Product
5045
- };
5046
- const infoWithProduct = this.formatBridgeResponse(
5047
- bridgeInfo,
5048
- legacyInfo
5049
- );
5050
- const platform = infoWithProduct.Product.platform;
5051
- const capabilities = getCapabilities(platform);
5052
- return {
5053
- ...infoWithProduct,
5054
- Capability: capabilities
5055
- };
5056
- }
5533
+ const bridgeInfo = await this.getBaseDeviceInfo();
5534
+ const legacyInfo = {
5535
+ Channel: this.DEFAULT_DEVICE_INFO.Channel,
5536
+ Product: this.DEFAULT_DEVICE_INFO.Product
5537
+ };
5538
+ const infoWithProduct = this.formatBridgeResponse(bridgeInfo, legacyInfo);
5539
+ const platform = infoWithProduct.Product.platform;
5540
+ const capabilities = getCapabilities(platform);
5541
+ return {
5542
+ ...infoWithProduct,
5543
+ Capability: capabilities
5544
+ };
5545
+ } catch (error) {
5546
+ log$c.error("Error getting device info:", error);
5057
5547
  const fallbackCapabilities = getCapabilities();
5058
5548
  return {
5059
5549
  Channel: this.DEFAULT_DEVICE_INFO.Channel,
5060
5550
  Product: this.DEFAULT_DEVICE_INFO.Product,
5061
5551
  Capability: fallbackCapabilities
5062
5552
  };
5063
- } catch (error) {
5064
- log$c.error("Error getting device info:", error);
5065
- throw error;
5066
5553
  }
5067
5554
  }
5068
5555
  formatBridgeResponse(data, legacyInfo) {
@@ -5420,7 +5907,7 @@ class BrowserAccessibilityService {
5420
5907
  log$8.info("TM settings updated:", this.tmSettings);
5421
5908
  }
5422
5909
  }
5423
- const logger$2 = getLogger("BrowserPlatform");
5910
+ const logger$1 = getLogger("BrowserPlatform");
5424
5911
  class BrowserCompat extends BasePlatform {
5425
5912
  constructor(config) {
5426
5913
  super(config);
@@ -5436,7 +5923,7 @@ class BrowserCompat extends BasePlatform {
5436
5923
  return true;
5437
5924
  }
5438
5925
  async getDeviceInfo() {
5439
- logger$2.debug("Getting default device info for browser");
5926
+ logger$1.debug("Getting default device info for browser");
5440
5927
  return this.getDefaultDeviceInfo();
5441
5928
  }
5442
5929
  getDefaultDeviceInfo() {
@@ -5740,7 +6227,7 @@ class PhilipsOldAccessibilityService {
5740
6227
  return false;
5741
6228
  }
5742
6229
  }
5743
- const logger$1 = getLogger("PhilipsOldPlatform");
6230
+ const logger = getLogger("PhilipsOldPlatform");
5744
6231
  class PhilipsOldCompat extends BasePlatform {
5745
6232
  constructor(config) {
5746
6233
  super(config);
@@ -5778,484 +6265,206 @@ class PhilipsOldCompat extends BasePlatform {
5778
6265
  }
5779
6266
  const userAgent = navigator.userAgent.toLowerCase();
5780
6267
  const philipsPatterns = ["philips", "saphi", "nettv", "tpvision"];
5781
- return philipsPatterns.some((pattern) => userAgent.includes(pattern));
5782
- }
5783
- async getDeviceInfo() {
5784
- if (this.deviceInfo) {
5785
- return this.deviceInfo;
5786
- }
5787
- if (this.deviceInfoPromise) {
5788
- return await this.deviceInfoPromise;
5789
- }
5790
- this.deviceInfoPromise = this.fetchDeviceInfoInternal();
5791
- try {
5792
- const result = await this.deviceInfoPromise;
5793
- this.deviceInfo = result;
5794
- return result;
5795
- } catch (error) {
5796
- this.deviceInfoPromise = null;
5797
- throw error;
5798
- }
5799
- }
5800
- async fetchDeviceInfoInternal() {
5801
- try {
5802
- if (await this.waitReady) {
5803
- const bridgeInfo = await this.fetchDeviceInfo();
5804
- const legacyInfo = {
5805
- Channel: this.DEFAULT_DEVICE_INFO.Channel,
5806
- Product: this.DEFAULT_DEVICE_INFO.Product
5807
- };
5808
- if (!bridgeInfo) {
5809
- const capabilities3 = await getCapabilities$1();
5810
- return {
5811
- ...legacyInfo,
5812
- Capability: capabilities3
5813
- };
5814
- }
5815
- const formatted = this.formatBridgeResponse(
5816
- {
5817
- deviceInfo: bridgeInfo,
5818
- tts: DEFAULT_TTS_SETTINGS,
5819
- tm: DEFAULT_TM_SETTINGS
5820
- },
5821
- legacyInfo
5822
- );
5823
- const platform = formatted.Product.platform;
5824
- const capabilities2 = await getCapabilities$1(platform);
5825
- return {
5826
- ...formatted,
5827
- Capability: capabilities2
5828
- };
5829
- }
5830
- const capabilities = await getCapabilities$1();
5831
- return {
5832
- Channel: this.DEFAULT_DEVICE_INFO.Channel,
5833
- Product: this.DEFAULT_DEVICE_INFO.Product,
5834
- Capability: capabilities
5835
- };
5836
- } catch (error) {
5837
- logger$1.warn("Error getting device info:", error);
5838
- throw error;
5839
- }
5840
- }
5841
- async fetchDeviceInfo() {
5842
- try {
5843
- const domain = "app.titanos.tv";
5844
- const backendInfo = await Promise.race([
5845
- getDeviceInfoFromBackend(
5846
- null,
5847
- domain,
5848
- "zeasn"
5849
- ),
5850
- new Promise((resolve) => {
5851
- setTimeout(() => {
5852
- logger$1.warn("Zeasn backend device info request timed out");
5853
- resolve(null);
5854
- }, this.timeout);
5855
- })
5856
- ]);
5857
- if (!backendInfo || !backendInfo.datas?.cookies) {
5858
- return null;
5859
- }
5860
- const profileId = backendInfo.datas.cookies.profileid;
5861
- const deviceInfo = {
5862
- profileId,
5863
- deviceId: decodeURIComponent(backendInfo.datas.cookies.deviceid || ""),
5864
- model: backendInfo.datas.cookies.deviceYear || "",
5865
- year: backendInfo.datas.cookies.deviceYear || "",
5866
- firmwareVersion: backendInfo.datas.cookies.ufversion || "",
5867
- country: backendInfo.datas.cookies.country || "",
5868
- language: getBrowserLanguage("en"),
5869
- brand: PlatformName.PHILIPS,
5870
- platformName: PlatformName.PHILIPS,
5871
- mac: decodeURIComponent(backendInfo.datas.cookies.mac || ""),
5872
- ifa: "",
5873
- ifaType: ""
5874
- };
5875
- return deviceInfo;
5876
- } catch (error) {
5877
- logger$1.warn("Error fetching device info from backend", error);
5878
- return null;
5879
- }
5880
- }
5881
- formatBridgeResponse(data, legacyInfo) {
5882
- let platform = "TitanOS";
5883
- let firmwareComponentID = "unknown";
5884
- if (!data.deviceInfo) {
5885
- return legacyInfo;
5886
- }
5887
- if (data.deviceInfo.profileId) {
5888
- platform = data.deviceInfo.platformName;
5889
- if (data.deviceInfo.profileId) {
5890
- var profileInfo = data.deviceInfo.profileId.split("_");
5891
- platform = (profileInfo[1] || platform).replace(/\d+$/, "");
5892
- firmwareComponentID = profileInfo[1] ? decodeURIComponent(profileInfo[1]) : "unknown";
5893
- }
5894
- }
5895
- legacyInfo.Product.firmwareVersion = data.deviceInfo.firmwareVersion;
5896
- legacyInfo.Product.country = data.deviceInfo.country;
5897
- legacyInfo.Product.deviceID = data.deviceInfo.deviceId;
5898
- legacyInfo.Product.platform = platform;
5899
- legacyInfo.Product.language = data.deviceInfo.language;
5900
- legacyInfo.Product.mac = data.deviceInfo.mac;
5901
- legacyInfo.Product.ifa = data.deviceInfo.ifa || "";
5902
- legacyInfo.Product.ifaType = data.deviceInfo.ifaType || "";
5903
- legacyInfo.Product.year = data.deviceInfo.year || "";
5904
- legacyInfo.Product.firmwareComponentID = firmwareComponentID;
5905
- return legacyInfo;
5906
- }
5907
- getPriority() {
5908
- return 100;
5909
- }
5910
- getId() {
5911
- return "philips";
5912
- }
5913
- }
5914
- class PhilipsOldDeviceInfoService {
5915
- constructor(config) {
5916
- __publicField(this, "platform");
5917
- __publicField(this, "info");
5918
- this.platform = new PhilipsOldCompat(config);
5919
- this.info = null;
5920
- }
5921
- async getDeviceInfo() {
5922
- const legacyInfo = await this.platform.getDeviceInfo();
5923
- this.info = legacyInfo;
5924
- return this.info;
5925
- }
5926
- async getCapabilities() {
5927
- if (!this.info) {
5928
- this.info = await this.getDeviceInfo();
5929
- }
5930
- return this.info.Capability;
5931
- }
5932
- }
5933
- class PhilipsOldAppControlService {
5934
- async launch(_appId, _deepLink) {
5935
- return false;
5936
- }
5937
- }
5938
- class PhilipsOldSDK {
5939
- constructor(options) {
5940
- __publicField(this, "accessibilityService");
5941
- __publicField(this, "deviceInfoService");
5942
- __publicField(this, "appControlService");
5943
- __publicField(this, "deviceInfo", {
5944
- getDeviceInfo: () => this.deviceInfoService.getDeviceInfo(),
5945
- getCapabilities: () => this.deviceInfoService.getCapabilities()
5946
- });
5947
- __publicField(this, "accessibility", {
5948
- enableReader: (config) => this.accessibilityService.enableReader(config),
5949
- disableReader: () => this.accessibilityService.disableReader(),
5950
- isTTSSupported: () => this.accessibilityService.isTTSSupported(),
5951
- isTTSEnabled: () => this.accessibilityService.isTTSEnabled(),
5952
- isTMEnabled: () => this.accessibilityService.isTMEnabled(),
5953
- isTextMagnificationSupported: () => this.accessibilityService.isTextMagnificationSupported(),
5954
- getTTSSettings: async () => convertToPublicSettings(await this.accessibilityService.getTTSSettings()),
5955
- getTMSettings: async () => convertToPublicSettings(await this.accessibilityService.getTMSettings()),
5956
- startSpeaking: (text) => this.accessibilityService.startSpeaking(text),
5957
- stopSpeaking: () => this.accessibilityService.stopSpeaking(),
5958
- onTTSSettingsChange: (_callback) => {
5959
- return () => {
5960
- };
5961
- },
5962
- onTMSettingsChange: (_callback) => {
5963
- return () => {
5964
- };
5965
- }
5966
- });
5967
- __publicField(this, "apps", {
5968
- launch: (appId, deepLink) => this.appControlService.launch(appId, deepLink)
5969
- });
5970
- this.accessibilityService = new PhilipsOldAccessibilityService();
5971
- this.deviceInfoService = new PhilipsOldDeviceInfoService(options);
5972
- this.appControlService = new PhilipsOldAppControlService();
5973
- }
5974
- get logging() {
5975
- return new LoggingService();
5976
- }
5977
- async init() {
5978
- return true;
5979
- }
5980
- }
5981
- const logger = getLogger("RollbarClient");
5982
- const IGNORED_ERROR_PATTERNS = [
5983
- "chrome://userjs/",
5984
- "chrome-extension://",
5985
- "moz-extension://",
5986
- "getJWTString",
5987
- "getjwtstring",
5988
- "user.js",
5989
- "userscript",
5990
- "tampermonkey",
5991
- "greasemonkey",
5992
- "can't find variable getjwtstring",
5993
- "referenceerror: can't find variable: getjwtstring",
5994
- "unexpected end of json input",
5995
- "jsonparse"
5996
- ];
5997
- class RollbarClient {
5998
- constructor() {
5999
- __publicField(this, "rollbar", null);
6000
- __publicField(this, "config", null);
6001
- __publicField(this, "windowWrapper", new WindowWrapper());
6002
- }
6003
- initialize(config) {
6004
- if (!config.enabled || !config.accessToken) {
6005
- logger.warn("Rollbar not initialized - disabled or missing access token");
6006
- return;
6007
- }
6008
- try {
6009
- this.config = config;
6010
- this.rollbar = new Rollbar({
6011
- accessToken: config.accessToken,
6012
- environment: config.environment || getEnvironment(),
6013
- captureUncaught: true,
6014
- captureUnhandledRejections: true,
6015
- verbose: false,
6016
- reportLevel: "error",
6017
- captureIp: false,
6018
- captureUsername: false,
6019
- captureEmail: false,
6020
- maxItems: 100,
6021
- itemsPerMinute: 60,
6022
- captureLambdaTimeouts: false,
6023
- endpoint: `${getLogsDomain()}/logs/`,
6024
- autoInstrument: {
6025
- network: false,
6026
- log: false,
6027
- dom: false,
6028
- navigation: false,
6029
- connectivity: false
6030
- },
6031
- payload: {
6032
- client: {
6033
- javascript: {
6034
- code_version: "unknown",
6035
- source_map_enabled: true
6036
- }
6037
- }
6038
- },
6039
- transform: (payload) => {
6040
- if (payload.context) {
6041
- payload.context = `hephaestus-${payload.context}`;
6042
- }
6043
- },
6044
- checkIgnore: (_isUncaught, args, _payload) => {
6045
- const error = args[0];
6046
- const errorMessage = typeof error === "string" ? error : error?.message;
6047
- const errorStack = typeof error === "object" && error ? error.stack : "";
6048
- const errorString = String(error).toLowerCase();
6049
- const ignoredPatterns = IGNORED_ERROR_PATTERNS;
6050
- return ignoredPatterns.some(
6051
- (pattern) => errorMessage?.toLowerCase().includes(pattern.toLowerCase()) || errorStack?.toLowerCase().includes(pattern.toLowerCase()) || errorString.includes(pattern.toLowerCase())
6052
- );
6053
- }
6054
- });
6055
- this.setupGlobalErrorHandlers();
6056
- logger.info("Rollbar initialized successfully", {
6057
- environment: config.environment
6058
- });
6059
- } catch (error) {
6060
- logger.error("Failed to initialize Rollbar", { error, config });
6061
- }
6062
- }
6063
- shouldIgnoreError(error) {
6064
- if (!error) return true;
6065
- const errorMessage = typeof error === "string" ? error : error.message || "";
6066
- const errorStack = typeof error === "object" ? error.stack || "" : "";
6067
- const errorString = String(error).toLowerCase();
6068
- const ignoredPatterns = IGNORED_ERROR_PATTERNS;
6069
- return ignoredPatterns.some(
6070
- (pattern) => errorMessage?.toLowerCase().includes(pattern.toLowerCase()) || errorStack?.toLowerCase().includes(pattern.toLowerCase()) || errorString.includes(pattern.toLowerCase())
6071
- );
6072
- }
6073
- async reportError(error, additionalData, severity = "error") {
6074
- if (!this.rollbar || !this.config?.enabled || !error) {
6075
- return Promise.resolve(null);
6076
- }
6077
- if (this.shouldIgnoreError(error)) {
6078
- return Promise.resolve(null);
6079
- }
6080
- return new Promise((resolve) => {
6081
- this.getDeviceContext().then((deviceContext) => {
6082
- try {
6083
- const allLogs = LogManager.getHistory().filter(
6084
- (log2) => !log2.module.includes("RollbarClient") && !log2.message.includes("Rollbar") && log2.level !== "debug"
6085
- ).slice(-20);
6086
- const logsString = allLogs.map(
6087
- (log2) => `[${log2.timestamp}] ${log2.module}: ${log2.message}${log2.args && log2.args.length > 0 ? "\n Args: " + JSON.stringify(log2.args) : ""}`
6088
- ).join("\n");
6089
- const context = {
6090
- logs: logsString,
6091
- component: additionalData?.component || "SDK",
6092
- operation: additionalData?.operation,
6093
- requestId: additionalData?.requestId,
6094
- timestamp: Date.now(),
6095
- url: typeof window !== "undefined" ? window.location?.href : void 0,
6096
- userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "unknown",
6097
- sessionId: this.generateSessionId(),
6098
- errorStack: typeof error === "object" ? error.stack : void 0,
6099
- version: typeof window !== "undefined" ? this.windowWrapper.get("TitanSDK")?.VERSION || "unknown" : "unknown",
6100
- ...deviceContext,
6101
- ...additionalData
6102
- };
6103
- const rollbarMethod = severity === "critical" ? "critical" : "error";
6104
- const errorType = severity === "critical" ? "critical_error_with_logs" : "error_with_logs";
6105
- this.rollbar?.[rollbarMethod](
6106
- error,
6107
- {
6108
- custom: {
6109
- type: errorType,
6110
- context,
6111
- logCount: allLogs.length
6112
- }
6113
- },
6114
- (err, data) => {
6115
- if (err) {
6116
- if (!this.shouldIgnoreError(err)) {
6117
- logger.error(
6118
- `Failed to send ${severity} error to Rollbar`,
6119
- {
6120
- error: err,
6121
- originalError: error
6122
- }
6123
- );
6124
- }
6125
- resolve(null);
6126
- } else {
6127
- const rollbarId = data ? data.uuid || data.result?.uuid || null : null;
6128
- logger.info(
6129
- `${severity === "critical" ? "Critical error" : "Error"} sent to Rollbar`,
6130
- {
6131
- message: typeof error === "string" ? error : error?.message || "Unknown error",
6132
- component: context.component,
6133
- rollbarId,
6134
- logCount: allLogs.length
6135
- }
6136
- );
6137
- resolve(rollbarId);
6138
- }
6139
- }
6140
- );
6141
- } catch (rollbarError) {
6142
- logger.error(`Failed to send ${severity} error to Rollbar`, {
6143
- error: rollbarError,
6144
- originalError: error
6145
- });
6146
- resolve(null);
6147
- }
6148
- }).catch((deviceError) => {
6149
- logger.error(`Failed to get device context for ${severity} error`, {
6150
- error: deviceError
6151
- });
6152
- resolve(null);
6153
- });
6154
- });
6268
+ return philipsPatterns.some((pattern) => userAgent.includes(pattern));
6155
6269
  }
6156
- collectSDKUsage(functionName, result, success, component) {
6157
- if (!this.rollbar || !this.config?.enabled) return;
6270
+ async getDeviceInfo() {
6271
+ if (this.deviceInfo) {
6272
+ return this.deviceInfo;
6273
+ }
6274
+ if (this.deviceInfoPromise) {
6275
+ return await this.deviceInfoPromise;
6276
+ }
6277
+ this.deviceInfoPromise = this.fetchDeviceInfoInternal();
6158
6278
  try {
6159
- const logLevel = success ? "info" : "warning";
6160
- this.rollbar[logLevel](`SDK function execution: ${functionName}`, {
6161
- custom: {
6162
- type: "sdk_function_execution",
6163
- functionName,
6164
- success,
6165
- component,
6166
- result: success ? result : void 0,
6167
- error: !success ? result : void 0,
6168
- timestamp: Date.now(),
6169
- url: typeof window !== "undefined" ? window.location?.href : void 0
6170
- }
6171
- });
6172
- logger.info("SDK function execution logged", {
6173
- functionName,
6174
- success,
6175
- component
6176
- });
6279
+ const result = await this.deviceInfoPromise;
6280
+ this.deviceInfo = result;
6281
+ return result;
6177
6282
  } catch (error) {
6178
- logger.error("Failed to log SDK function execution", {
6179
- error,
6180
- functionName,
6181
- component
6182
- });
6283
+ this.deviceInfoPromise = null;
6284
+ throw error;
6183
6285
  }
6184
6286
  }
6185
- generateSessionId() {
6186
- return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
6187
- }
6188
- async getDeviceContext() {
6287
+ async fetchDeviceInfoInternal() {
6189
6288
  try {
6190
- if (window?.TitanSDK) {
6191
- try {
6192
- const deviceInfo = await window?.TitanSDK?.deviceInfo?.getDeviceInfo?.();
6289
+ if (await this.waitReady) {
6290
+ const bridgeInfo = await this.fetchDeviceInfo();
6291
+ const legacyInfo = {
6292
+ Channel: this.DEFAULT_DEVICE_INFO.Channel,
6293
+ Product: this.DEFAULT_DEVICE_INFO.Product
6294
+ };
6295
+ if (!bridgeInfo) {
6296
+ const capabilities3 = await getCapabilities$1();
6193
6297
  return {
6194
- deviceInfo: deviceInfo ? JSON.stringify(deviceInfo) : "unavailable"
6298
+ ...legacyInfo,
6299
+ Capability: capabilities3
6195
6300
  };
6196
- } catch (sdkError) {
6197
6301
  }
6302
+ const formatted = this.formatBridgeResponse(
6303
+ {
6304
+ deviceInfo: bridgeInfo,
6305
+ tts: DEFAULT_TTS_SETTINGS,
6306
+ tm: DEFAULT_TM_SETTINGS
6307
+ },
6308
+ legacyInfo
6309
+ );
6310
+ const platform = formatted.Product.platform;
6311
+ const capabilities2 = await getCapabilities$1(platform);
6312
+ return {
6313
+ ...formatted,
6314
+ Capability: capabilities2
6315
+ };
6198
6316
  }
6317
+ const capabilities = await getCapabilities$1();
6199
6318
  return {
6200
- deviceInfo: `OS: ${navigator?.platform || "unknown"}, Browser: ${this.detectBrowserEngine()}, Storage: ${"localStorage" in (window || {})}`
6319
+ Channel: this.DEFAULT_DEVICE_INFO.Channel,
6320
+ Product: this.DEFAULT_DEVICE_INFO.Product,
6321
+ Capability: capabilities
6201
6322
  };
6202
6323
  } catch (error) {
6203
- return {};
6324
+ logger.warn("Error getting device info:", error);
6325
+ throw error;
6204
6326
  }
6205
6327
  }
6206
- detectBrowserEngine() {
6207
- if (typeof navigator === "undefined") return "unknown";
6208
- const userAgent = navigator.userAgent;
6209
- if (userAgent.includes("Chrome")) return "Blink";
6210
- if (userAgent.includes("Firefox")) return "Gecko";
6211
- if (userAgent.includes("Safari") && !userAgent.includes("Chrome"))
6212
- return "WebKit";
6213
- if (userAgent.includes("Edge")) return "EdgeHTML";
6214
- return "unknown";
6328
+ async fetchDeviceInfo() {
6329
+ try {
6330
+ const domain = "app.titanos.tv";
6331
+ const backendInfo = await Promise.race([
6332
+ getDeviceInfoFromBackend(
6333
+ null,
6334
+ domain,
6335
+ "zeasn"
6336
+ ),
6337
+ new Promise((resolve) => {
6338
+ setTimeout(() => {
6339
+ logger.warn("Zeasn backend device info request timed out");
6340
+ resolve(null);
6341
+ }, this.timeout);
6342
+ })
6343
+ ]);
6344
+ if (!backendInfo || !backendInfo.datas?.cookies) {
6345
+ return null;
6346
+ }
6347
+ const profileId = backendInfo.datas.cookies.profileid;
6348
+ const deviceInfo = {
6349
+ profileId,
6350
+ deviceId: decodeURIComponent(backendInfo.datas.cookies.deviceid || ""),
6351
+ model: backendInfo.datas.cookies.deviceYear || "",
6352
+ year: backendInfo.datas.cookies.deviceYear || "",
6353
+ firmwareVersion: backendInfo.datas.cookies.ufversion || "",
6354
+ country: backendInfo.datas.cookies.country || "",
6355
+ language: getBrowserLanguage("en"),
6356
+ brand: PlatformName.PHILIPS,
6357
+ platformName: PlatformName.PHILIPS,
6358
+ mac: decodeURIComponent(backendInfo.datas.cookies.mac || ""),
6359
+ ifa: "",
6360
+ ifaType: ""
6361
+ };
6362
+ return deviceInfo;
6363
+ } catch (error) {
6364
+ logger.warn("Error fetching device info from backend", error);
6365
+ return null;
6366
+ }
6215
6367
  }
6216
- setupGlobalErrorHandlers() {
6217
- if (typeof window === "undefined") return;
6218
- const originalConsoleError = console.error;
6219
- console.error = (...args) => {
6220
- originalConsoleError.apply(console, args);
6221
- const errorArg = args.find(
6222
- (arg) => arg instanceof Error || typeof arg === "string" && arg.includes("Error")
6223
- );
6224
- if (errorArg && !this.shouldIgnoreError(errorArg)) {
6225
- this.reportError(errorArg, {
6226
- component: "SDK",
6227
- operation: "console.error"
6228
- });
6368
+ formatBridgeResponse(data, legacyInfo) {
6369
+ let platform = "TitanOS";
6370
+ let firmwareComponentID = "unknown";
6371
+ if (!data.deviceInfo) {
6372
+ return legacyInfo;
6373
+ }
6374
+ if (data.deviceInfo.profileId) {
6375
+ platform = data.deviceInfo.platformName;
6376
+ if (data.deviceInfo.profileId) {
6377
+ var profileInfo = data.deviceInfo.profileId.split("_");
6378
+ platform = (profileInfo[1] || platform).replace(/\d+$/, "");
6379
+ firmwareComponentID = profileInfo[1] ? decodeURIComponent(profileInfo[1]) : "unknown";
6229
6380
  }
6230
- };
6231
- if (typeof window !== "undefined") {
6232
- window.addEventListener("error", (event) => {
6233
- if (!this.shouldIgnoreError(event.error)) {
6234
- this.reportError(event.error || event.message, {
6235
- component: "SDK",
6236
- operation: "window.onerror"
6237
- });
6238
- }
6239
- });
6240
- window.addEventListener("unhandledrejection", (event) => {
6241
- if (!this.shouldIgnoreError(event.reason)) {
6242
- this.reportError(event.reason, {
6243
- component: "SDK",
6244
- operation: "unhandledrejection"
6245
- });
6246
- }
6247
- });
6248
6381
  }
6382
+ legacyInfo.Product.firmwareVersion = data.deviceInfo.firmwareVersion;
6383
+ legacyInfo.Product.country = data.deviceInfo.country;
6384
+ legacyInfo.Product.deviceID = data.deviceInfo.deviceId;
6385
+ legacyInfo.Product.platform = platform;
6386
+ legacyInfo.Product.language = data.deviceInfo.language;
6387
+ legacyInfo.Product.mac = data.deviceInfo.mac;
6388
+ legacyInfo.Product.ifa = data.deviceInfo.ifa || "";
6389
+ legacyInfo.Product.ifaType = data.deviceInfo.ifaType || "";
6390
+ legacyInfo.Product.year = data.deviceInfo.year || "";
6391
+ legacyInfo.Product.firmwareComponentID = firmwareComponentID;
6392
+ return legacyInfo;
6249
6393
  }
6250
- isInitialized() {
6251
- return this.rollbar !== null && this.config?.enabled === true;
6394
+ getPriority() {
6395
+ return 100;
6396
+ }
6397
+ getId() {
6398
+ return "philips";
6399
+ }
6400
+ }
6401
+ class PhilipsOldDeviceInfoService {
6402
+ constructor(config) {
6403
+ __publicField(this, "platform");
6404
+ __publicField(this, "info");
6405
+ this.platform = new PhilipsOldCompat(config);
6406
+ this.info = null;
6407
+ }
6408
+ async getDeviceInfo() {
6409
+ const legacyInfo = await this.platform.getDeviceInfo();
6410
+ this.info = legacyInfo;
6411
+ return this.info;
6412
+ }
6413
+ async getCapabilities() {
6414
+ if (!this.info) {
6415
+ this.info = await this.getDeviceInfo();
6416
+ }
6417
+ return this.info.Capability;
6418
+ }
6419
+ }
6420
+ class PhilipsOldAppControlService {
6421
+ async launch(_appId, _deepLink) {
6422
+ return false;
6423
+ }
6424
+ }
6425
+ class PhilipsOldSDK {
6426
+ constructor(options) {
6427
+ __publicField(this, "accessibilityService");
6428
+ __publicField(this, "deviceInfoService");
6429
+ __publicField(this, "appControlService");
6430
+ __publicField(this, "deviceInfo", {
6431
+ getDeviceInfo: () => this.deviceInfoService.getDeviceInfo(),
6432
+ getCapabilities: () => this.deviceInfoService.getCapabilities()
6433
+ });
6434
+ __publicField(this, "accessibility", {
6435
+ enableReader: (config) => this.accessibilityService.enableReader(config),
6436
+ disableReader: () => this.accessibilityService.disableReader(),
6437
+ isTTSSupported: () => this.accessibilityService.isTTSSupported(),
6438
+ isTTSEnabled: () => this.accessibilityService.isTTSEnabled(),
6439
+ isTMEnabled: () => this.accessibilityService.isTMEnabled(),
6440
+ isTextMagnificationSupported: () => this.accessibilityService.isTextMagnificationSupported(),
6441
+ getTTSSettings: async () => convertToPublicSettings(await this.accessibilityService.getTTSSettings()),
6442
+ getTMSettings: async () => convertToPublicSettings(await this.accessibilityService.getTMSettings()),
6443
+ startSpeaking: (text) => this.accessibilityService.startSpeaking(text),
6444
+ stopSpeaking: () => this.accessibilityService.stopSpeaking(),
6445
+ onTTSSettingsChange: (_callback) => {
6446
+ return () => {
6447
+ };
6448
+ },
6449
+ onTMSettingsChange: (_callback) => {
6450
+ return () => {
6451
+ };
6452
+ }
6453
+ });
6454
+ __publicField(this, "apps", {
6455
+ launch: (appId, deepLink) => this.appControlService.launch(appId, deepLink)
6456
+ });
6457
+ this.accessibilityService = new PhilipsOldAccessibilityService();
6458
+ this.deviceInfoService = new PhilipsOldDeviceInfoService(options);
6459
+ this.appControlService = new PhilipsOldAppControlService();
6460
+ }
6461
+ get logging() {
6462
+ return new LoggingService();
6463
+ }
6464
+ async init() {
6465
+ return true;
6252
6466
  }
6253
6467
  }
6254
- const rollbarClient = new RollbarClient();
6255
- const rollbarClient$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
6256
- __proto__: null,
6257
- rollbarClient
6258
- }, Symbol.toStringTag, { value: "Module" }));
6259
6468
  const log$3 = getLogger("SmartTvA_API");
6260
6469
  const initializeSmartTvAPI = async (sdk) => {
6261
6470
  log$3.info("Initializing SmartTvA_API with TitanSDK");
@@ -6639,10 +6848,7 @@ let sdkInstance = null;
6639
6848
  let sdkResult = null;
6640
6849
  let initPromise = null;
6641
6850
  let cachedDeviceInfo = null;
6642
- rollbarClient.initialize({
6643
- accessToken: "",
6644
- enabled: false
6645
- });
6851
+ let rollbarInitialized = false;
6646
6852
  const ensureInitialized = async () => {
6647
6853
  if (!sdkInstance) {
6648
6854
  throw new SDKError(
@@ -6672,6 +6878,15 @@ const getTitanSDK = (options) => {
6672
6878
  ...options
6673
6879
  };
6674
6880
  globalLogManager.setDebugMode(finalOptions.debug ?? false);
6881
+ if (!rollbarInitialized) {
6882
+ const rollbarToken = "";
6883
+ const rollbarEnabled = false;
6884
+ rollbarClient.initialize({
6885
+ accessToken: rollbarToken,
6886
+ enabled: rollbarEnabled
6887
+ });
6888
+ rollbarInitialized = true;
6889
+ }
6675
6890
  const platformResult = platformDetector.detectPlatform(finalOptions);
6676
6891
  const platformType = platformResult.platform;
6677
6892
  log.info("Platform detected:", platformType);