@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/README.md CHANGED
@@ -128,6 +128,15 @@ export default Limelight.withLimelight((req, res) => {
128
128
 
129
129
  Both methods automatically capture request/response headers, bodies, status codes, and timing — and propagate a trace ID (`x-limelight-trace-id`) for full-stack tracing.
130
130
 
131
+ **Outbound HTTP interception** is automatic in Node.js environments. When `enableNetworkInspector` is `true` (the default), the SDK patches `http.request` and `https.request` to capture all outgoing calls your server makes — API calls to other services, auth servers, databases over HTTP, etc. Combined with the incoming middleware, this gives you full end-to-end tracing:
132
+
133
+ ```
134
+ Client (fetch) → Your Server (middleware) → Downstream Service (http interceptor)
135
+ ↑ same trace ID propagated across all three ↑
136
+ ```
137
+
138
+ No additional setup is required — just connect the SDK and add the middleware.
139
+
131
140
  ## Learn More
132
141
 
133
142
  - [Quick Start Guide](https://docs.getlimelight.io/quickstart)
package/dist/index.d.mts CHANGED
@@ -5,7 +5,8 @@ declare enum NetworkType {
5
5
  FETCH = "fetch",
6
6
  XHR = "xhr",
7
7
  GRAPHQL = "graphql",
8
- INCOMING = "incoming"
8
+ INCOMING = "incoming",
9
+ HTTP = "http"
9
10
  }
10
11
  declare enum NetworkPhase {
11
12
  CONNECT = "CONNECT",
@@ -572,6 +573,7 @@ declare class LimelightClient {
572
573
  private maxQueueSize;
573
574
  private networkInterceptor;
574
575
  private xhrInterceptor;
576
+ private httpInterceptor;
575
577
  private consoleInterceptor;
576
578
  private renderInterceptor;
577
579
  private stateInterceptor;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,8 @@ declare enum NetworkType {
5
5
  FETCH = "fetch",
6
6
  XHR = "xhr",
7
7
  GRAPHQL = "graphql",
8
- INCOMING = "incoming"
8
+ INCOMING = "incoming",
9
+ HTTP = "http"
9
10
  }
10
11
  declare enum NetworkPhase {
11
12
  CONNECT = "CONNECT",
@@ -572,6 +573,7 @@ declare class LimelightClient {
572
573
  private maxQueueSize;
573
574
  private networkInterceptor;
574
575
  private xhrInterceptor;
576
+ private httpInterceptor;
575
577
  private consoleInterceptor;
576
578
  private renderInterceptor;
577
579
  private stateInterceptor;
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
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 }); }
1
5
  "use strict";
2
6
  var __defProp = Object.defineProperty;
3
7
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -67,6 +71,7 @@ var NetworkType = /* @__PURE__ */ ((NetworkType2) => {
67
71
  NetworkType2["XHR"] = "xhr";
68
72
  NetworkType2["GRAPHQL"] = "graphql";
69
73
  NetworkType2["INCOMING"] = "incoming";
74
+ NetworkType2["HTTP"] = "http";
70
75
  return NetworkType2;
71
76
  })(NetworkType || {});
72
77
  var NetworkPhase = /* @__PURE__ */ ((NetworkPhase2) => {
@@ -87,17 +92,17 @@ var BodyFormat = /* @__PURE__ */ ((BodyFormat2) => {
87
92
  BodyFormat2["UNSERIALIZABLE"] = "UNSERIALIZABLE";
88
93
  return BodyFormat2;
89
94
  })(BodyFormat || {});
90
- var HttpMethod = /* @__PURE__ */ ((HttpMethod6) => {
91
- HttpMethod6["GET"] = "GET";
92
- HttpMethod6["POST"] = "POST";
93
- HttpMethod6["PUT"] = "PUT";
94
- HttpMethod6["PATCH"] = "PATCH";
95
- HttpMethod6["DELETE"] = "DELETE";
96
- HttpMethod6["HEAD"] = "HEAD";
97
- HttpMethod6["OPTIONS"] = "OPTIONS";
98
- HttpMethod6["TRACE"] = "TRACE";
99
- HttpMethod6["CONNECT"] = "CONNECT";
100
- return HttpMethod6;
95
+ var HttpMethod = /* @__PURE__ */ ((HttpMethod7) => {
96
+ HttpMethod7["GET"] = "GET";
97
+ HttpMethod7["POST"] = "POST";
98
+ HttpMethod7["PUT"] = "PUT";
99
+ HttpMethod7["PATCH"] = "PATCH";
100
+ HttpMethod7["DELETE"] = "DELETE";
101
+ HttpMethod7["HEAD"] = "HEAD";
102
+ HttpMethod7["OPTIONS"] = "OPTIONS";
103
+ HttpMethod7["TRACE"] = "TRACE";
104
+ HttpMethod7["CONNECT"] = "CONNECT";
105
+ return HttpMethod7;
101
106
  })(HttpMethod || {});
102
107
  var HttpStatusClass = /* @__PURE__ */ ((HttpStatusClass2) => {
103
108
  HttpStatusClass2[HttpStatusClass2["INFORMATIONAL"] = 100] = "INFORMATIONAL";
@@ -287,7 +292,7 @@ var LIMELIGHT_WEB_WSS_URL = "wss://api.getlimelight.io";
287
292
  var LIMELIGHT_DESKTOP_WSS_URL = "ws://localhost:8484";
288
293
  var LIMELIGHT_MCP_WS_URL = "ws://localhost:9229";
289
294
  var WS_PATH = "/limelight";
290
- var SDK_VERSION = true ? "0.7.4" : "test-version";
295
+ var SDK_VERSION = true ? "0.7.9" : "test-version";
291
296
  var RENDER_THRESHOLDS = {
292
297
  HOT_VELOCITY: 5,
293
298
  HIGH_RENDER_COUNT: 50,
@@ -301,6 +306,16 @@ var RENDER_THRESHOLDS = {
301
306
  TOP_PROPS_TO_REPORT: 5
302
307
  // Only report top N changed props
303
308
  };
309
+ var BINARY_CONTENT_TYPES = [
310
+ "image/",
311
+ "audio/",
312
+ "video/",
313
+ "application/octet-stream",
314
+ "application/pdf",
315
+ "application/zip",
316
+ "application/gzip"
317
+ ];
318
+ var MAX_BODY_SIZE = 1024 * 1024;
304
319
 
305
320
  // src/helpers/safety/redactSensitiveHeaders.ts
306
321
  var redactSensitiveHeaders = (headers) => {
@@ -580,6 +595,21 @@ var getCurrentTransactionId = () => {
580
595
  return globalGetTransactionId?.() ?? null;
581
596
  };
582
597
 
598
+ // src/helpers/http/resolveUrl.ts
599
+ var resolveUrl = (protocol, options) => {
600
+ const host = options.hostname || options.host || "localhost";
601
+ const port = options.port ? `:${options.port}` : "";
602
+ const path = options.path || "/";
603
+ return `${protocol}//${host}${port}${path}`;
604
+ };
605
+
606
+ // src/helpers/http/isBinaryContentType.ts
607
+ var isBinaryContentType = (contentType) => {
608
+ return BINARY_CONTENT_TYPES.some(
609
+ (type) => contentType.toLowerCase().includes(type)
610
+ );
611
+ };
612
+
583
613
  // src/limelight/interceptors/ConsoleInterceptor.ts
584
614
  var ConsoleInterceptor = class {
585
615
  constructor(sendMessage, getSessionId) {
@@ -1205,6 +1235,361 @@ var XHRInterceptor = class {
1205
1235
  }
1206
1236
  };
1207
1237
 
1238
+ // src/limelight/interceptors/HttpInterceptor.ts
1239
+ var HttpInterceptor = class {
1240
+ constructor(sendMessage, getSessionId) {
1241
+ this.sendMessage = sendMessage;
1242
+ this.getSessionId = getSessionId;
1243
+ try {
1244
+ const _require = globalThis["require"];
1245
+ this.httpModule = _require("http");
1246
+ this.httpsModule = _require("https");
1247
+ this.originalHttpRequest = this.httpModule.request;
1248
+ this.originalHttpGet = this.httpModule.get;
1249
+ this.originalHttpsRequest = this.httpsModule.request;
1250
+ this.originalHttpsGet = this.httpsModule.get;
1251
+ } catch {
1252
+ }
1253
+ }
1254
+ originalHttpRequest = null;
1255
+ originalHttpGet = null;
1256
+ originalHttpsRequest = null;
1257
+ originalHttpsGet = null;
1258
+ httpModule = null;
1259
+ httpsModule = null;
1260
+ config = null;
1261
+ isSetup = false;
1262
+ setup(config) {
1263
+ if (this.isSetup) {
1264
+ if (this.config?.enableInternalLogging) {
1265
+ console.warn("[Limelight] HTTP interceptor already set up");
1266
+ }
1267
+ return;
1268
+ }
1269
+ if (!this.httpModule || !this.httpsModule) {
1270
+ if (config?.enableInternalLogging) {
1271
+ console.warn(
1272
+ "[Limelight] Node http module not available, skipping HTTP interception"
1273
+ );
1274
+ }
1275
+ return;
1276
+ }
1277
+ this.isSetup = true;
1278
+ this.config = config;
1279
+ const self2 = this;
1280
+ const httpMod = this.httpModule;
1281
+ const httpsMod = this.httpsModule;
1282
+ httpMod.request = (...args) => {
1283
+ return self2.interceptRequest(
1284
+ "http:",
1285
+ self2.originalHttpRequest,
1286
+ httpMod,
1287
+ args
1288
+ );
1289
+ };
1290
+ httpMod.get = (...args) => {
1291
+ const req = self2.interceptRequest(
1292
+ "http:",
1293
+ self2.originalHttpRequest,
1294
+ httpMod,
1295
+ args
1296
+ );
1297
+ req.end();
1298
+ return req;
1299
+ };
1300
+ httpsMod.request = (...args) => {
1301
+ return self2.interceptRequest(
1302
+ "https:",
1303
+ self2.originalHttpsRequest,
1304
+ httpsMod,
1305
+ args
1306
+ );
1307
+ };
1308
+ httpsMod.get = (...args) => {
1309
+ const req = self2.interceptRequest(
1310
+ "https:",
1311
+ self2.originalHttpsRequest,
1312
+ httpsMod,
1313
+ args
1314
+ );
1315
+ req.end();
1316
+ return req;
1317
+ };
1318
+ }
1319
+ interceptRequest(protocol, originalMethod, module2, args) {
1320
+ let url;
1321
+ let options;
1322
+ let callback;
1323
+ if (typeof args[0] === "string" || args[0] instanceof URL) {
1324
+ url = args[0];
1325
+ if (typeof args[1] === "function") {
1326
+ options = {};
1327
+ callback = args[1];
1328
+ } else {
1329
+ options = args[1] || {};
1330
+ callback = args[2];
1331
+ }
1332
+ } else {
1333
+ options = args[0] || {};
1334
+ callback = args[1];
1335
+ }
1336
+ let resolvedUrl;
1337
+ if (url) {
1338
+ resolvedUrl = url.toString();
1339
+ } else {
1340
+ resolvedUrl = resolveUrl(protocol, options);
1341
+ }
1342
+ const limelightServerUrl = this.config?.serverUrl || "";
1343
+ if (limelightServerUrl && resolvedUrl.includes(limelightServerUrl)) {
1344
+ return originalMethod.apply(module2, args);
1345
+ }
1346
+ const self2 = this;
1347
+ const requestId = generateRequestId();
1348
+ const startTime = Date.now();
1349
+ const initiator = getInitiator();
1350
+ const traceHeaderName = this.config?.traceHeaderName ?? "x-limelight-trace-id";
1351
+ const existingTraceId = getTraceContext()?.getStore()?.traceId;
1352
+ const traceId = existingTraceId || generateRequestId();
1353
+ if (!options.headers) {
1354
+ options.headers = {};
1355
+ }
1356
+ options.headers[traceHeaderName] = traceId;
1357
+ const method = (options.method || "GET").toUpperCase();
1358
+ let patchedArgs;
1359
+ if (url) {
1360
+ patchedArgs = callback ? [url, options, callback] : [url, options];
1361
+ } else {
1362
+ patchedArgs = callback ? [options, callback] : [options];
1363
+ }
1364
+ const req = originalMethod.apply(
1365
+ module2,
1366
+ patchedArgs
1367
+ );
1368
+ const bodyChunks = [];
1369
+ let totalBodySize = 0;
1370
+ let requestEventSent = false;
1371
+ const originalWrite = req.write.bind(req);
1372
+ const originalEnd = req.end.bind(req);
1373
+ req.write = (chunk, encodingOrCallback, callback2) => {
1374
+ if (chunk && totalBodySize < MAX_BODY_SIZE) {
1375
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1376
+ bodyChunks.push(buf);
1377
+ totalBodySize += buf.length;
1378
+ }
1379
+ return originalWrite(chunk, encodingOrCallback, callback2);
1380
+ };
1381
+ req.end = (chunk, encodingOrCallback, callback2) => {
1382
+ if (chunk && typeof chunk !== "function" && totalBodySize < MAX_BODY_SIZE) {
1383
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1384
+ bodyChunks.push(buf);
1385
+ totalBodySize += buf.length;
1386
+ }
1387
+ if (!requestEventSent) {
1388
+ requestEventSent = true;
1389
+ const fullBody = bodyChunks.length > 0 ? Buffer.concat(bodyChunks).toString("utf-8") : void 0;
1390
+ const headers = {};
1391
+ const rawHeaders = req.getHeaders();
1392
+ for (const [key, value] of Object.entries(rawHeaders)) {
1393
+ if (value !== void 0) {
1394
+ headers[key.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
1395
+ }
1396
+ }
1397
+ const requestBody = serializeBody(
1398
+ fullBody,
1399
+ self2.config?.disableBodyCapture
1400
+ );
1401
+ let requestEvent = {
1402
+ id: requestId,
1403
+ traceId,
1404
+ sessionId: self2.getSessionId(),
1405
+ timestamp: startTime,
1406
+ phase: "REQUEST" /* REQUEST */,
1407
+ networkType: "http" /* HTTP */,
1408
+ url: resolvedUrl,
1409
+ method,
1410
+ headers: redactSensitiveHeaders(headers),
1411
+ body: requestBody,
1412
+ name: formatRequestName(resolvedUrl),
1413
+ initiator,
1414
+ requestSize: requestBody?.size ?? 0
1415
+ };
1416
+ if (self2.config?.beforeSend) {
1417
+ const modifiedEvent = self2.config.beforeSend(requestEvent);
1418
+ if (!modifiedEvent) {
1419
+ return originalEnd(
1420
+ chunk,
1421
+ encodingOrCallback,
1422
+ callback2
1423
+ );
1424
+ }
1425
+ if (modifiedEvent.phase !== "REQUEST" /* REQUEST */) {
1426
+ console.error("[Limelight] beforeSend must return same event type");
1427
+ return originalEnd(
1428
+ chunk,
1429
+ encodingOrCallback,
1430
+ callback2
1431
+ );
1432
+ }
1433
+ requestEvent = modifiedEvent;
1434
+ }
1435
+ self2.sendMessage(requestEvent);
1436
+ }
1437
+ return originalEnd(chunk, encodingOrCallback, callback2);
1438
+ };
1439
+ let responseSent = false;
1440
+ req.on("response", (res) => {
1441
+ const responseChunks = [];
1442
+ let responseSize = 0;
1443
+ res.on("data", (chunk) => {
1444
+ if (responseSize < MAX_BODY_SIZE) {
1445
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1446
+ responseChunks.push(buf);
1447
+ responseSize += buf.length;
1448
+ }
1449
+ });
1450
+ res.on("end", () => {
1451
+ if (responseSent) return;
1452
+ responseSent = true;
1453
+ const endTime = Date.now();
1454
+ const duration = endTime - startTime;
1455
+ const responseHeaders = {};
1456
+ if (res.headers) {
1457
+ for (const [key, value] of Object.entries(res.headers)) {
1458
+ if (value) {
1459
+ responseHeaders[key.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
1460
+ }
1461
+ }
1462
+ }
1463
+ const contentType = responseHeaders["content-type"] || "";
1464
+ let responseBodyStr;
1465
+ if (responseChunks.length > 0) {
1466
+ if (isBinaryContentType(contentType)) {
1467
+ responseBodyStr = `[Binary Data: ${contentType}]`;
1468
+ } else {
1469
+ const full = Buffer.concat(responseChunks);
1470
+ responseBodyStr = full.length > MAX_BODY_SIZE ? full.toString("utf-8", 0, MAX_BODY_SIZE) + "...[truncated]" : full.toString("utf-8");
1471
+ }
1472
+ }
1473
+ const responseBody = serializeBody(
1474
+ responseBodyStr,
1475
+ self2.config?.disableBodyCapture
1476
+ );
1477
+ const statusCode = res.statusCode ?? 0;
1478
+ let responseEvent = {
1479
+ id: requestId,
1480
+ traceId,
1481
+ sessionId: self2.getSessionId(),
1482
+ timestamp: endTime,
1483
+ phase: "RESPONSE" /* RESPONSE */,
1484
+ networkType: "http" /* HTTP */,
1485
+ status: statusCode,
1486
+ statusText: res.statusMessage || "",
1487
+ headers: redactSensitiveHeaders(responseHeaders),
1488
+ body: responseBody,
1489
+ duration,
1490
+ responseSize: responseBody?.size ?? 0,
1491
+ redirected: false,
1492
+ ok: statusCode >= 200 && statusCode < 300
1493
+ };
1494
+ if (self2.config?.beforeSend) {
1495
+ const modifiedEvent = self2.config.beforeSend(responseEvent);
1496
+ if (!modifiedEvent) return;
1497
+ if (modifiedEvent.phase !== "RESPONSE" /* RESPONSE */) {
1498
+ console.error("[Limelight] beforeSend must return same event type");
1499
+ return;
1500
+ }
1501
+ responseEvent = modifiedEvent;
1502
+ }
1503
+ self2.sendMessage(responseEvent);
1504
+ });
1505
+ });
1506
+ req.on("error", (err) => {
1507
+ if (responseSent) return;
1508
+ responseSent = true;
1509
+ let errorEvent = {
1510
+ id: requestId,
1511
+ traceId,
1512
+ sessionId: self2.getSessionId(),
1513
+ timestamp: Date.now(),
1514
+ phase: "ERROR" /* ERROR */,
1515
+ networkType: "http" /* HTTP */,
1516
+ errorMessage: err.message || "Network request failed",
1517
+ stack: err.stack
1518
+ };
1519
+ if (self2.config?.beforeSend) {
1520
+ const modifiedEvent = self2.config.beforeSend(errorEvent);
1521
+ if (modifiedEvent && (modifiedEvent.phase === "ERROR" /* ERROR */ || modifiedEvent.phase === "ABORT" /* ABORT */)) {
1522
+ errorEvent = modifiedEvent;
1523
+ }
1524
+ }
1525
+ self2.sendMessage(errorEvent);
1526
+ });
1527
+ req.on("timeout", () => {
1528
+ if (responseSent) return;
1529
+ responseSent = true;
1530
+ let errorEvent = {
1531
+ id: requestId,
1532
+ traceId,
1533
+ sessionId: self2.getSessionId(),
1534
+ timestamp: Date.now(),
1535
+ phase: "ERROR" /* ERROR */,
1536
+ networkType: "http" /* HTTP */,
1537
+ errorMessage: "Request timeout"
1538
+ };
1539
+ if (self2.config?.beforeSend) {
1540
+ const modifiedEvent = self2.config.beforeSend(errorEvent);
1541
+ if (modifiedEvent && (modifiedEvent.phase === "ERROR" /* ERROR */ || modifiedEvent.phase === "ABORT" /* ABORT */)) {
1542
+ errorEvent = modifiedEvent;
1543
+ }
1544
+ }
1545
+ self2.sendMessage(errorEvent);
1546
+ });
1547
+ req.on("close", () => {
1548
+ if (responseSent) return;
1549
+ if (!req.destroyed) return;
1550
+ responseSent = true;
1551
+ let errorEvent = {
1552
+ id: requestId,
1553
+ traceId,
1554
+ sessionId: self2.getSessionId(),
1555
+ timestamp: Date.now(),
1556
+ phase: "ABORT" /* ABORT */,
1557
+ networkType: "http" /* HTTP */,
1558
+ errorMessage: "Request aborted"
1559
+ };
1560
+ if (self2.config?.beforeSend) {
1561
+ const modifiedEvent = self2.config.beforeSend(errorEvent);
1562
+ if (modifiedEvent && (modifiedEvent.phase === "ERROR" /* ERROR */ || modifiedEvent.phase === "ABORT" /* ABORT */)) {
1563
+ errorEvent = modifiedEvent;
1564
+ }
1565
+ }
1566
+ self2.sendMessage(errorEvent);
1567
+ });
1568
+ return req;
1569
+ }
1570
+ cleanup() {
1571
+ if (!this.isSetup) {
1572
+ if (this.config?.enableInternalLogging) {
1573
+ console.warn("[Limelight] HTTP interceptor not set up");
1574
+ }
1575
+ return;
1576
+ }
1577
+ this.isSetup = false;
1578
+ if (this.httpModule && this.originalHttpRequest) {
1579
+ this.httpModule.request = this.originalHttpRequest;
1580
+ }
1581
+ if (this.httpModule && this.originalHttpGet) {
1582
+ this.httpModule.get = this.originalHttpGet;
1583
+ }
1584
+ if (this.httpsModule && this.originalHttpsRequest) {
1585
+ this.httpsModule.request = this.originalHttpsRequest;
1586
+ }
1587
+ if (this.httpsModule && this.originalHttpsGet) {
1588
+ this.httpsModule.get = this.originalHttpsGet;
1589
+ }
1590
+ }
1591
+ };
1592
+
1208
1593
  // src/limelight/interceptors/RenderInterceptor.ts
1209
1594
  var RenderInterceptor = class {
1210
1595
  sendMessage;
@@ -2574,6 +2959,7 @@ var LimelightClient = class {
2574
2959
  maxQueueSize = 100;
2575
2960
  networkInterceptor;
2576
2961
  xhrInterceptor;
2962
+ httpInterceptor;
2577
2963
  consoleInterceptor;
2578
2964
  renderInterceptor;
2579
2965
  stateInterceptor;
@@ -2589,6 +2975,10 @@ var LimelightClient = class {
2589
2975
  this.sendMessage.bind(this),
2590
2976
  () => this.sessionId
2591
2977
  );
2978
+ this.httpInterceptor = new HttpInterceptor(
2979
+ this.sendMessage.bind(this),
2980
+ () => this.sessionId
2981
+ );
2592
2982
  this.consoleInterceptor = new ConsoleInterceptor(
2593
2983
  this.sendMessage.bind(this),
2594
2984
  () => this.sessionId
@@ -2649,6 +3039,9 @@ var LimelightClient = class {
2649
3039
  if (typeof XMLHttpRequest !== "undefined") {
2650
3040
  this.xhrInterceptor.setup(this.config);
2651
3041
  }
3042
+ if (!hasDOM()) {
3043
+ this.httpInterceptor.setup(this.config);
3044
+ }
2652
3045
  }
2653
3046
  if (this.config.enableConsole) {
2654
3047
  this.consoleInterceptor.setup(this.config);
@@ -2874,6 +3267,7 @@ var LimelightClient = class {
2874
3267
  }
2875
3268
  this.networkInterceptor.cleanup();
2876
3269
  this.xhrInterceptor.cleanup();
3270
+ this.httpInterceptor.cleanup();
2877
3271
  this.consoleInterceptor.cleanup();
2878
3272
  this.errorInterceptor.cleanup();
2879
3273
  this.renderInterceptor.cleanup();