@getlimelight/sdk 0.7.4 → 0.7.9

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.9" : "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,361 @@ 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
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1410
+ responseChunks.push(buf);
1411
+ responseSize += buf.length;
1412
+ }
1413
+ });
1414
+ res.on("end", () => {
1415
+ if (responseSent) return;
1416
+ responseSent = true;
1417
+ const endTime = Date.now();
1418
+ const duration = endTime - startTime;
1419
+ const responseHeaders = {};
1420
+ if (res.headers) {
1421
+ for (const [key, value] of Object.entries(res.headers)) {
1422
+ if (value) {
1423
+ responseHeaders[key.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
1424
+ }
1425
+ }
1426
+ }
1427
+ const contentType = responseHeaders["content-type"] || "";
1428
+ let responseBodyStr;
1429
+ if (responseChunks.length > 0) {
1430
+ if (isBinaryContentType(contentType)) {
1431
+ responseBodyStr = `[Binary Data: ${contentType}]`;
1432
+ } else {
1433
+ const full = Buffer.concat(responseChunks);
1434
+ responseBodyStr = full.length > MAX_BODY_SIZE ? full.toString("utf-8", 0, MAX_BODY_SIZE) + "...[truncated]" : full.toString("utf-8");
1435
+ }
1436
+ }
1437
+ const responseBody = serializeBody(
1438
+ responseBodyStr,
1439
+ self2.config?.disableBodyCapture
1440
+ );
1441
+ const statusCode = res.statusCode ?? 0;
1442
+ let responseEvent = {
1443
+ id: requestId,
1444
+ traceId,
1445
+ sessionId: self2.getSessionId(),
1446
+ timestamp: endTime,
1447
+ phase: "RESPONSE" /* RESPONSE */,
1448
+ networkType: "http" /* HTTP */,
1449
+ status: statusCode,
1450
+ statusText: res.statusMessage || "",
1451
+ headers: redactSensitiveHeaders(responseHeaders),
1452
+ body: responseBody,
1453
+ duration,
1454
+ responseSize: responseBody?.size ?? 0,
1455
+ redirected: false,
1456
+ ok: statusCode >= 200 && statusCode < 300
1457
+ };
1458
+ if (self2.config?.beforeSend) {
1459
+ const modifiedEvent = self2.config.beforeSend(responseEvent);
1460
+ if (!modifiedEvent) return;
1461
+ if (modifiedEvent.phase !== "RESPONSE" /* RESPONSE */) {
1462
+ console.error("[Limelight] beforeSend must return same event type");
1463
+ return;
1464
+ }
1465
+ responseEvent = modifiedEvent;
1466
+ }
1467
+ self2.sendMessage(responseEvent);
1468
+ });
1469
+ });
1470
+ req.on("error", (err) => {
1471
+ if (responseSent) return;
1472
+ responseSent = true;
1473
+ let errorEvent = {
1474
+ id: requestId,
1475
+ traceId,
1476
+ sessionId: self2.getSessionId(),
1477
+ timestamp: Date.now(),
1478
+ phase: "ERROR" /* ERROR */,
1479
+ networkType: "http" /* HTTP */,
1480
+ errorMessage: err.message || "Network request failed",
1481
+ stack: err.stack
1482
+ };
1483
+ if (self2.config?.beforeSend) {
1484
+ const modifiedEvent = self2.config.beforeSend(errorEvent);
1485
+ if (modifiedEvent && (modifiedEvent.phase === "ERROR" /* ERROR */ || modifiedEvent.phase === "ABORT" /* ABORT */)) {
1486
+ errorEvent = modifiedEvent;
1487
+ }
1488
+ }
1489
+ self2.sendMessage(errorEvent);
1490
+ });
1491
+ req.on("timeout", () => {
1492
+ if (responseSent) return;
1493
+ responseSent = true;
1494
+ let errorEvent = {
1495
+ id: requestId,
1496
+ traceId,
1497
+ sessionId: self2.getSessionId(),
1498
+ timestamp: Date.now(),
1499
+ phase: "ERROR" /* ERROR */,
1500
+ networkType: "http" /* HTTP */,
1501
+ errorMessage: "Request timeout"
1502
+ };
1503
+ if (self2.config?.beforeSend) {
1504
+ const modifiedEvent = self2.config.beforeSend(errorEvent);
1505
+ if (modifiedEvent && (modifiedEvent.phase === "ERROR" /* ERROR */ || modifiedEvent.phase === "ABORT" /* ABORT */)) {
1506
+ errorEvent = modifiedEvent;
1507
+ }
1508
+ }
1509
+ self2.sendMessage(errorEvent);
1510
+ });
1511
+ req.on("close", () => {
1512
+ if (responseSent) return;
1513
+ if (!req.destroyed) return;
1514
+ responseSent = true;
1515
+ let errorEvent = {
1516
+ id: requestId,
1517
+ traceId,
1518
+ sessionId: self2.getSessionId(),
1519
+ timestamp: Date.now(),
1520
+ phase: "ABORT" /* ABORT */,
1521
+ networkType: "http" /* HTTP */,
1522
+ errorMessage: "Request aborted"
1523
+ };
1524
+ if (self2.config?.beforeSend) {
1525
+ const modifiedEvent = self2.config.beforeSend(errorEvent);
1526
+ if (modifiedEvent && (modifiedEvent.phase === "ERROR" /* ERROR */ || modifiedEvent.phase === "ABORT" /* ABORT */)) {
1527
+ errorEvent = modifiedEvent;
1528
+ }
1529
+ }
1530
+ self2.sendMessage(errorEvent);
1531
+ });
1532
+ return req;
1533
+ }
1534
+ cleanup() {
1535
+ if (!this.isSetup) {
1536
+ if (this.config?.enableInternalLogging) {
1537
+ console.warn("[Limelight] HTTP interceptor not set up");
1538
+ }
1539
+ return;
1540
+ }
1541
+ this.isSetup = false;
1542
+ if (this.httpModule && this.originalHttpRequest) {
1543
+ this.httpModule.request = this.originalHttpRequest;
1544
+ }
1545
+ if (this.httpModule && this.originalHttpGet) {
1546
+ this.httpModule.get = this.originalHttpGet;
1547
+ }
1548
+ if (this.httpsModule && this.originalHttpsRequest) {
1549
+ this.httpsModule.request = this.originalHttpsRequest;
1550
+ }
1551
+ if (this.httpsModule && this.originalHttpsGet) {
1552
+ this.httpsModule.get = this.originalHttpsGet;
1553
+ }
1554
+ }
1555
+ };
1556
+
1171
1557
  // src/limelight/interceptors/RenderInterceptor.ts
1172
1558
  var RenderInterceptor = class {
1173
1559
  sendMessage;
@@ -2537,6 +2923,7 @@ var LimelightClient = class {
2537
2923
  maxQueueSize = 100;
2538
2924
  networkInterceptor;
2539
2925
  xhrInterceptor;
2926
+ httpInterceptor;
2540
2927
  consoleInterceptor;
2541
2928
  renderInterceptor;
2542
2929
  stateInterceptor;
@@ -2552,6 +2939,10 @@ var LimelightClient = class {
2552
2939
  this.sendMessage.bind(this),
2553
2940
  () => this.sessionId
2554
2941
  );
2942
+ this.httpInterceptor = new HttpInterceptor(
2943
+ this.sendMessage.bind(this),
2944
+ () => this.sessionId
2945
+ );
2555
2946
  this.consoleInterceptor = new ConsoleInterceptor(
2556
2947
  this.sendMessage.bind(this),
2557
2948
  () => this.sessionId
@@ -2612,6 +3003,9 @@ var LimelightClient = class {
2612
3003
  if (typeof XMLHttpRequest !== "undefined") {
2613
3004
  this.xhrInterceptor.setup(this.config);
2614
3005
  }
3006
+ if (!hasDOM()) {
3007
+ this.httpInterceptor.setup(this.config);
3008
+ }
2615
3009
  }
2616
3010
  if (this.config.enableConsole) {
2617
3011
  this.consoleInterceptor.setup(this.config);
@@ -2837,6 +3231,7 @@ var LimelightClient = class {
2837
3231
  }
2838
3232
  this.networkInterceptor.cleanup();
2839
3233
  this.xhrInterceptor.cleanup();
3234
+ this.httpInterceptor.cleanup();
2840
3235
  this.consoleInterceptor.cleanup();
2841
3236
  this.errorInterceptor.cleanup();
2842
3237
  this.renderInterceptor.cleanup();