@getlimelight/sdk 0.7.4 → 0.7.8

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/index.mjs CHANGED
@@ -1,3 +1,8 @@
1
+ // Bridge Node CJS require to globalThis so runtime dynamic requires work
2
+ // in environments like ts-node where require is module-scoped only.
3
+ // In ESM or browser contexts typeof require is 'undefined', so this is a no-op.
4
+ if (typeof require === "function" && typeof globalThis !== "undefined" && typeof globalThis.require === "undefined" && typeof process !== "undefined" && process.versions && process.versions.node) { Object.defineProperty(globalThis, "require", { value: require, configurable: true, writable: true, enumerable: false }); }
5
+
1
6
  // src/types/console.ts
2
7
  var ConsoleLevel = /* @__PURE__ */ ((ConsoleLevel2) => {
3
8
  ConsoleLevel2["LOG"] = "log";
@@ -30,6 +35,7 @@ var NetworkType = /* @__PURE__ */ ((NetworkType2) => {
30
35
  NetworkType2["XHR"] = "xhr";
31
36
  NetworkType2["GRAPHQL"] = "graphql";
32
37
  NetworkType2["INCOMING"] = "incoming";
38
+ NetworkType2["HTTP"] = "http";
33
39
  return NetworkType2;
34
40
  })(NetworkType || {});
35
41
  var NetworkPhase = /* @__PURE__ */ ((NetworkPhase2) => {
@@ -50,17 +56,17 @@ var BodyFormat = /* @__PURE__ */ ((BodyFormat2) => {
50
56
  BodyFormat2["UNSERIALIZABLE"] = "UNSERIALIZABLE";
51
57
  return BodyFormat2;
52
58
  })(BodyFormat || {});
53
- var HttpMethod = /* @__PURE__ */ ((HttpMethod6) => {
54
- HttpMethod6["GET"] = "GET";
55
- HttpMethod6["POST"] = "POST";
56
- HttpMethod6["PUT"] = "PUT";
57
- HttpMethod6["PATCH"] = "PATCH";
58
- HttpMethod6["DELETE"] = "DELETE";
59
- HttpMethod6["HEAD"] = "HEAD";
60
- HttpMethod6["OPTIONS"] = "OPTIONS";
61
- HttpMethod6["TRACE"] = "TRACE";
62
- HttpMethod6["CONNECT"] = "CONNECT";
63
- return HttpMethod6;
59
+ var HttpMethod = /* @__PURE__ */ ((HttpMethod7) => {
60
+ HttpMethod7["GET"] = "GET";
61
+ HttpMethod7["POST"] = "POST";
62
+ HttpMethod7["PUT"] = "PUT";
63
+ HttpMethod7["PATCH"] = "PATCH";
64
+ HttpMethod7["DELETE"] = "DELETE";
65
+ HttpMethod7["HEAD"] = "HEAD";
66
+ HttpMethod7["OPTIONS"] = "OPTIONS";
67
+ HttpMethod7["TRACE"] = "TRACE";
68
+ HttpMethod7["CONNECT"] = "CONNECT";
69
+ return HttpMethod7;
64
70
  })(HttpMethod || {});
65
71
  var HttpStatusClass = /* @__PURE__ */ ((HttpStatusClass2) => {
66
72
  HttpStatusClass2[HttpStatusClass2["INFORMATIONAL"] = 100] = "INFORMATIONAL";
@@ -250,7 +256,7 @@ var LIMELIGHT_WEB_WSS_URL = "wss://api.getlimelight.io";
250
256
  var LIMELIGHT_DESKTOP_WSS_URL = "ws://localhost:8484";
251
257
  var LIMELIGHT_MCP_WS_URL = "ws://localhost:9229";
252
258
  var WS_PATH = "/limelight";
253
- var SDK_VERSION = true ? "0.7.4" : "test-version";
259
+ var SDK_VERSION = true ? "0.7.8" : "test-version";
254
260
  var RENDER_THRESHOLDS = {
255
261
  HOT_VELOCITY: 5,
256
262
  HIGH_RENDER_COUNT: 50,
@@ -264,6 +270,16 @@ var RENDER_THRESHOLDS = {
264
270
  TOP_PROPS_TO_REPORT: 5
265
271
  // Only report top N changed props
266
272
  };
273
+ var BINARY_CONTENT_TYPES = [
274
+ "image/",
275
+ "audio/",
276
+ "video/",
277
+ "application/octet-stream",
278
+ "application/pdf",
279
+ "application/zip",
280
+ "application/gzip"
281
+ ];
282
+ var MAX_BODY_SIZE = 1024 * 1024;
267
283
 
268
284
  // src/helpers/safety/redactSensitiveHeaders.ts
269
285
  var redactSensitiveHeaders = (headers) => {
@@ -543,6 +559,21 @@ var getCurrentTransactionId = () => {
543
559
  return globalGetTransactionId?.() ?? null;
544
560
  };
545
561
 
562
+ // src/helpers/http/resolveUrl.ts
563
+ var resolveUrl = (protocol, options) => {
564
+ const host = options.hostname || options.host || "localhost";
565
+ const port = options.port ? `:${options.port}` : "";
566
+ const path = options.path || "/";
567
+ return `${protocol}//${host}${port}${path}`;
568
+ };
569
+
570
+ // src/helpers/http/isBinaryContentType.ts
571
+ var isBinaryContentType = (contentType) => {
572
+ return BINARY_CONTENT_TYPES.some(
573
+ (type) => contentType.toLowerCase().includes(type)
574
+ );
575
+ };
576
+
546
577
  // src/limelight/interceptors/ConsoleInterceptor.ts
547
578
  var ConsoleInterceptor = class {
548
579
  constructor(sendMessage, getSessionId) {
@@ -1168,6 +1199,360 @@ var XHRInterceptor = class {
1168
1199
  }
1169
1200
  };
1170
1201
 
1202
+ // src/limelight/interceptors/HttpInterceptor.ts
1203
+ var HttpInterceptor = class {
1204
+ constructor(sendMessage, getSessionId) {
1205
+ this.sendMessage = sendMessage;
1206
+ this.getSessionId = getSessionId;
1207
+ try {
1208
+ const _require = globalThis["require"];
1209
+ this.httpModule = _require("http");
1210
+ this.httpsModule = _require("https");
1211
+ this.originalHttpRequest = this.httpModule.request;
1212
+ this.originalHttpGet = this.httpModule.get;
1213
+ this.originalHttpsRequest = this.httpsModule.request;
1214
+ this.originalHttpsGet = this.httpsModule.get;
1215
+ } catch {
1216
+ }
1217
+ }
1218
+ originalHttpRequest = null;
1219
+ originalHttpGet = null;
1220
+ originalHttpsRequest = null;
1221
+ originalHttpsGet = null;
1222
+ httpModule = null;
1223
+ httpsModule = null;
1224
+ config = null;
1225
+ isSetup = false;
1226
+ setup(config) {
1227
+ if (this.isSetup) {
1228
+ if (this.config?.enableInternalLogging) {
1229
+ console.warn("[Limelight] HTTP interceptor already set up");
1230
+ }
1231
+ return;
1232
+ }
1233
+ if (!this.httpModule || !this.httpsModule) {
1234
+ if (config?.enableInternalLogging) {
1235
+ console.warn(
1236
+ "[Limelight] Node http module not available, skipping HTTP interception"
1237
+ );
1238
+ }
1239
+ return;
1240
+ }
1241
+ this.isSetup = true;
1242
+ this.config = config;
1243
+ const self2 = this;
1244
+ const httpMod = this.httpModule;
1245
+ const httpsMod = this.httpsModule;
1246
+ httpMod.request = (...args) => {
1247
+ return self2.interceptRequest(
1248
+ "http:",
1249
+ self2.originalHttpRequest,
1250
+ httpMod,
1251
+ args
1252
+ );
1253
+ };
1254
+ httpMod.get = (...args) => {
1255
+ const req = self2.interceptRequest(
1256
+ "http:",
1257
+ self2.originalHttpRequest,
1258
+ httpMod,
1259
+ args
1260
+ );
1261
+ req.end();
1262
+ return req;
1263
+ };
1264
+ httpsMod.request = (...args) => {
1265
+ return self2.interceptRequest(
1266
+ "https:",
1267
+ self2.originalHttpsRequest,
1268
+ httpsMod,
1269
+ args
1270
+ );
1271
+ };
1272
+ httpsMod.get = (...args) => {
1273
+ const req = self2.interceptRequest(
1274
+ "https:",
1275
+ self2.originalHttpsRequest,
1276
+ httpsMod,
1277
+ args
1278
+ );
1279
+ req.end();
1280
+ return req;
1281
+ };
1282
+ }
1283
+ interceptRequest(protocol, originalMethod, module, args) {
1284
+ let url;
1285
+ let options;
1286
+ let callback;
1287
+ if (typeof args[0] === "string" || args[0] instanceof URL) {
1288
+ url = args[0];
1289
+ if (typeof args[1] === "function") {
1290
+ options = {};
1291
+ callback = args[1];
1292
+ } else {
1293
+ options = args[1] || {};
1294
+ callback = args[2];
1295
+ }
1296
+ } else {
1297
+ options = args[0] || {};
1298
+ callback = args[1];
1299
+ }
1300
+ let resolvedUrl;
1301
+ if (url) {
1302
+ resolvedUrl = url.toString();
1303
+ } else {
1304
+ resolvedUrl = resolveUrl(protocol, options);
1305
+ }
1306
+ const limelightServerUrl = this.config?.serverUrl || "";
1307
+ if (limelightServerUrl && resolvedUrl.includes(limelightServerUrl)) {
1308
+ return originalMethod.apply(module, args);
1309
+ }
1310
+ const self2 = this;
1311
+ const requestId = generateRequestId();
1312
+ const startTime = Date.now();
1313
+ const initiator = getInitiator();
1314
+ const traceHeaderName = this.config?.traceHeaderName ?? "x-limelight-trace-id";
1315
+ const existingTraceId = getTraceContext()?.getStore()?.traceId;
1316
+ const traceId = existingTraceId || generateRequestId();
1317
+ if (!options.headers) {
1318
+ options.headers = {};
1319
+ }
1320
+ options.headers[traceHeaderName] = traceId;
1321
+ const method = (options.method || "GET").toUpperCase();
1322
+ let patchedArgs;
1323
+ if (url) {
1324
+ patchedArgs = callback ? [url, options, callback] : [url, options];
1325
+ } else {
1326
+ patchedArgs = callback ? [options, callback] : [options];
1327
+ }
1328
+ const req = originalMethod.apply(
1329
+ module,
1330
+ patchedArgs
1331
+ );
1332
+ const bodyChunks = [];
1333
+ let totalBodySize = 0;
1334
+ let requestEventSent = false;
1335
+ const originalWrite = req.write.bind(req);
1336
+ const originalEnd = req.end.bind(req);
1337
+ req.write = (chunk, encodingOrCallback, callback2) => {
1338
+ if (chunk && totalBodySize < MAX_BODY_SIZE) {
1339
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1340
+ bodyChunks.push(buf);
1341
+ totalBodySize += buf.length;
1342
+ }
1343
+ return originalWrite(chunk, encodingOrCallback, callback2);
1344
+ };
1345
+ req.end = (chunk, encodingOrCallback, callback2) => {
1346
+ if (chunk && typeof chunk !== "function" && totalBodySize < MAX_BODY_SIZE) {
1347
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1348
+ bodyChunks.push(buf);
1349
+ totalBodySize += buf.length;
1350
+ }
1351
+ if (!requestEventSent) {
1352
+ requestEventSent = true;
1353
+ const fullBody = bodyChunks.length > 0 ? Buffer.concat(bodyChunks).toString("utf-8") : void 0;
1354
+ const headers = {};
1355
+ const rawHeaders = req.getHeaders();
1356
+ for (const [key, value] of Object.entries(rawHeaders)) {
1357
+ if (value !== void 0) {
1358
+ headers[key.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
1359
+ }
1360
+ }
1361
+ const requestBody = serializeBody(
1362
+ fullBody,
1363
+ self2.config?.disableBodyCapture
1364
+ );
1365
+ let requestEvent = {
1366
+ id: requestId,
1367
+ traceId,
1368
+ sessionId: self2.getSessionId(),
1369
+ timestamp: startTime,
1370
+ phase: "REQUEST" /* REQUEST */,
1371
+ networkType: "http" /* HTTP */,
1372
+ url: resolvedUrl,
1373
+ method,
1374
+ headers: redactSensitiveHeaders(headers),
1375
+ body: requestBody,
1376
+ name: formatRequestName(resolvedUrl),
1377
+ initiator,
1378
+ requestSize: requestBody?.size ?? 0
1379
+ };
1380
+ if (self2.config?.beforeSend) {
1381
+ const modifiedEvent = self2.config.beforeSend(requestEvent);
1382
+ if (!modifiedEvent) {
1383
+ return originalEnd(
1384
+ chunk,
1385
+ encodingOrCallback,
1386
+ callback2
1387
+ );
1388
+ }
1389
+ if (modifiedEvent.phase !== "REQUEST" /* REQUEST */) {
1390
+ console.error("[Limelight] beforeSend must return same event type");
1391
+ return originalEnd(
1392
+ chunk,
1393
+ encodingOrCallback,
1394
+ callback2
1395
+ );
1396
+ }
1397
+ requestEvent = modifiedEvent;
1398
+ }
1399
+ self2.sendMessage(requestEvent);
1400
+ }
1401
+ return originalEnd(chunk, encodingOrCallback, callback2);
1402
+ };
1403
+ let responseSent = false;
1404
+ req.on("response", (res) => {
1405
+ const responseChunks = [];
1406
+ let responseSize = 0;
1407
+ res.on("data", (chunk) => {
1408
+ if (responseSize < MAX_BODY_SIZE) {
1409
+ responseChunks.push(chunk);
1410
+ responseSize += chunk.length;
1411
+ }
1412
+ });
1413
+ res.on("end", () => {
1414
+ if (responseSent) return;
1415
+ responseSent = true;
1416
+ const endTime = Date.now();
1417
+ const duration = endTime - startTime;
1418
+ const responseHeaders = {};
1419
+ if (res.headers) {
1420
+ for (const [key, value] of Object.entries(res.headers)) {
1421
+ if (value) {
1422
+ responseHeaders[key.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
1423
+ }
1424
+ }
1425
+ }
1426
+ const contentType = responseHeaders["content-type"] || "";
1427
+ let responseBodyStr;
1428
+ if (responseChunks.length > 0) {
1429
+ if (isBinaryContentType(contentType)) {
1430
+ responseBodyStr = `[Binary Data: ${contentType}]`;
1431
+ } else {
1432
+ const full = Buffer.concat(responseChunks);
1433
+ responseBodyStr = full.length > MAX_BODY_SIZE ? full.toString("utf-8", 0, MAX_BODY_SIZE) + "...[truncated]" : full.toString("utf-8");
1434
+ }
1435
+ }
1436
+ const responseBody = serializeBody(
1437
+ responseBodyStr,
1438
+ self2.config?.disableBodyCapture
1439
+ );
1440
+ const statusCode = res.statusCode ?? 0;
1441
+ let responseEvent = {
1442
+ id: requestId,
1443
+ traceId,
1444
+ sessionId: self2.getSessionId(),
1445
+ timestamp: endTime,
1446
+ phase: "RESPONSE" /* RESPONSE */,
1447
+ networkType: "http" /* HTTP */,
1448
+ status: statusCode,
1449
+ statusText: res.statusMessage || "",
1450
+ headers: redactSensitiveHeaders(responseHeaders),
1451
+ body: responseBody,
1452
+ duration,
1453
+ responseSize: responseBody?.size ?? 0,
1454
+ redirected: false,
1455
+ ok: statusCode >= 200 && statusCode < 300
1456
+ };
1457
+ if (self2.config?.beforeSend) {
1458
+ const modifiedEvent = self2.config.beforeSend(responseEvent);
1459
+ if (!modifiedEvent) return;
1460
+ if (modifiedEvent.phase !== "RESPONSE" /* RESPONSE */) {
1461
+ console.error("[Limelight] beforeSend must return same event type");
1462
+ return;
1463
+ }
1464
+ responseEvent = modifiedEvent;
1465
+ }
1466
+ self2.sendMessage(responseEvent);
1467
+ });
1468
+ });
1469
+ req.on("error", (err) => {
1470
+ if (responseSent) return;
1471
+ responseSent = true;
1472
+ let errorEvent = {
1473
+ id: requestId,
1474
+ traceId,
1475
+ sessionId: self2.getSessionId(),
1476
+ timestamp: Date.now(),
1477
+ phase: "ERROR" /* ERROR */,
1478
+ networkType: "http" /* HTTP */,
1479
+ errorMessage: err.message || "Network request failed",
1480
+ stack: err.stack
1481
+ };
1482
+ if (self2.config?.beforeSend) {
1483
+ const modifiedEvent = self2.config.beforeSend(errorEvent);
1484
+ if (modifiedEvent && (modifiedEvent.phase === "ERROR" /* ERROR */ || modifiedEvent.phase === "ABORT" /* ABORT */)) {
1485
+ errorEvent = modifiedEvent;
1486
+ }
1487
+ }
1488
+ self2.sendMessage(errorEvent);
1489
+ });
1490
+ req.on("timeout", () => {
1491
+ if (responseSent) return;
1492
+ responseSent = true;
1493
+ let errorEvent = {
1494
+ id: requestId,
1495
+ traceId,
1496
+ sessionId: self2.getSessionId(),
1497
+ timestamp: Date.now(),
1498
+ phase: "ERROR" /* ERROR */,
1499
+ networkType: "http" /* HTTP */,
1500
+ errorMessage: "Request timeout"
1501
+ };
1502
+ if (self2.config?.beforeSend) {
1503
+ const modifiedEvent = self2.config.beforeSend(errorEvent);
1504
+ if (modifiedEvent && (modifiedEvent.phase === "ERROR" /* ERROR */ || modifiedEvent.phase === "ABORT" /* ABORT */)) {
1505
+ errorEvent = modifiedEvent;
1506
+ }
1507
+ }
1508
+ self2.sendMessage(errorEvent);
1509
+ });
1510
+ req.on("close", () => {
1511
+ if (responseSent) return;
1512
+ if (!req.destroyed) return;
1513
+ responseSent = true;
1514
+ let errorEvent = {
1515
+ id: requestId,
1516
+ traceId,
1517
+ sessionId: self2.getSessionId(),
1518
+ timestamp: Date.now(),
1519
+ phase: "ABORT" /* ABORT */,
1520
+ networkType: "http" /* HTTP */,
1521
+ errorMessage: "Request aborted"
1522
+ };
1523
+ if (self2.config?.beforeSend) {
1524
+ const modifiedEvent = self2.config.beforeSend(errorEvent);
1525
+ if (modifiedEvent && (modifiedEvent.phase === "ERROR" /* ERROR */ || modifiedEvent.phase === "ABORT" /* ABORT */)) {
1526
+ errorEvent = modifiedEvent;
1527
+ }
1528
+ }
1529
+ self2.sendMessage(errorEvent);
1530
+ });
1531
+ return req;
1532
+ }
1533
+ cleanup() {
1534
+ if (!this.isSetup) {
1535
+ if (this.config?.enableInternalLogging) {
1536
+ console.warn("[Limelight] HTTP interceptor not set up");
1537
+ }
1538
+ return;
1539
+ }
1540
+ this.isSetup = false;
1541
+ if (this.httpModule && this.originalHttpRequest) {
1542
+ this.httpModule.request = this.originalHttpRequest;
1543
+ }
1544
+ if (this.httpModule && this.originalHttpGet) {
1545
+ this.httpModule.get = this.originalHttpGet;
1546
+ }
1547
+ if (this.httpsModule && this.originalHttpsRequest) {
1548
+ this.httpsModule.request = this.originalHttpsRequest;
1549
+ }
1550
+ if (this.httpsModule && this.originalHttpsGet) {
1551
+ this.httpsModule.get = this.originalHttpsGet;
1552
+ }
1553
+ }
1554
+ };
1555
+
1171
1556
  // src/limelight/interceptors/RenderInterceptor.ts
1172
1557
  var RenderInterceptor = class {
1173
1558
  sendMessage;
@@ -2537,6 +2922,7 @@ var LimelightClient = class {
2537
2922
  maxQueueSize = 100;
2538
2923
  networkInterceptor;
2539
2924
  xhrInterceptor;
2925
+ httpInterceptor;
2540
2926
  consoleInterceptor;
2541
2927
  renderInterceptor;
2542
2928
  stateInterceptor;
@@ -2552,6 +2938,10 @@ var LimelightClient = class {
2552
2938
  this.sendMessage.bind(this),
2553
2939
  () => this.sessionId
2554
2940
  );
2941
+ this.httpInterceptor = new HttpInterceptor(
2942
+ this.sendMessage.bind(this),
2943
+ () => this.sessionId
2944
+ );
2555
2945
  this.consoleInterceptor = new ConsoleInterceptor(
2556
2946
  this.sendMessage.bind(this),
2557
2947
  () => this.sessionId
@@ -2612,6 +3002,9 @@ var LimelightClient = class {
2612
3002
  if (typeof XMLHttpRequest !== "undefined") {
2613
3003
  this.xhrInterceptor.setup(this.config);
2614
3004
  }
3005
+ if (!hasDOM()) {
3006
+ this.httpInterceptor.setup(this.config);
3007
+ }
2615
3008
  }
2616
3009
  if (this.config.enableConsole) {
2617
3010
  this.consoleInterceptor.setup(this.config);
@@ -2837,6 +3230,7 @@ var LimelightClient = class {
2837
3230
  }
2838
3231
  this.networkInterceptor.cleanup();
2839
3232
  this.xhrInterceptor.cleanup();
3233
+ this.httpInterceptor.cleanup();
2840
3234
  this.consoleInterceptor.cleanup();
2841
3235
  this.errorInterceptor.cleanup();
2842
3236
  this.renderInterceptor.cleanup();