@ngn-net/nestjs-telescope 0.2.4 → 0.2.6

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.d.ts CHANGED
@@ -12,3 +12,4 @@ export * from './watchers/command.watcher';
12
12
  export * from './watchers/model.watcher';
13
13
  export * from './watchers/notification.watcher';
14
14
  export * from './watchers/gate.watcher';
15
+ export * from './watchers/http-client.watcher';
package/dist/index.js CHANGED
@@ -30,3 +30,4 @@ __exportStar(require("./watchers/command.watcher"), exports);
30
30
  __exportStar(require("./watchers/model.watcher"), exports);
31
31
  __exportStar(require("./watchers/notification.watcher"), exports);
32
32
  __exportStar(require("./watchers/gate.watcher"), exports);
33
+ __exportStar(require("./watchers/http-client.watcher"), exports);
@@ -25,6 +25,7 @@ const telescope_controller_1 = require("./controllers/telescope.controller");
25
25
  const telescope_repository_service_1 = require("./storage/telescope-repository.service");
26
26
  const telescope_entry_entity_1 = require("./storage/entities/telescope-entry.entity");
27
27
  const http_request_watcher_1 = require("./watchers/http-request.watcher");
28
+ const http_client_watcher_1 = require("./watchers/http-client.watcher");
28
29
  const query_watcher_1 = require("./watchers/query.watcher");
29
30
  const cache_watcher_1 = require("./watchers/cache.watcher");
30
31
  const queue_watcher_1 = require("./watchers/queue.watcher");
@@ -238,6 +239,7 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
238
239
  // Additional optional watchers (non-interceptors)
239
240
  if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.HTTP_CLIENT)) {
240
241
  providers.push(http_service_watcher_1.HttpServiceWatcher);
242
+ providers.push(http_client_watcher_1.HttpClientWatcher);
241
243
  }
242
244
  if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.COMMAND)) {
243
245
  providers.push(command_watcher_1.CommandWatcher);
@@ -310,6 +312,8 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
310
312
  providers.push(query_watcher_1.QueryWatcher);
311
313
  providers.push(log_watcher_1.LogWatcher);
312
314
  providers.push(redis_watcher_1.RedisWatcher);
315
+ providers.push(http_client_watcher_1.HttpClientWatcher);
316
+ providers.push(http_service_watcher_1.HttpServiceWatcher);
313
317
  // Optional modules/watchers if packages are present
314
318
  try {
315
319
  require('@nestjs/cache-manager');
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ngn-net/nestjs-telescope",
3
- "version": "0.2.4",
4
- "builtAt": "2026-06-08T12:15:54.627Z"
3
+ "version": "0.2.6",
4
+ "builtAt": "2026-06-08T12:28:43.444Z"
5
5
  }
@@ -67,128 +67,182 @@ let HttpClientWatcher = class HttpClientWatcher {
67
67
  this.patched = true;
68
68
  this.patch(http);
69
69
  this.patch(https);
70
+ // Also patch follow-redirects if used by HTTP clients like Axios
71
+ try {
72
+ const followRedirects = require('follow-redirects');
73
+ if (followRedirects) {
74
+ if (followRedirects.http)
75
+ this.patch(followRedirects.http);
76
+ if (followRedirects.https)
77
+ this.patch(followRedirects.https);
78
+ }
79
+ }
80
+ catch (e) {
81
+ // follow-redirects not available, skip
82
+ }
70
83
  }
71
84
  patch(module) {
72
- const originalRequest = module.request.bind(module);
73
- const self = this;
74
- // Override module.request
75
- module.request = function (...args) {
76
- const req = originalRequest(...args);
77
- const startTime = Date.now();
78
- // Resolve URL and method
79
- let urlStr = '';
80
- let method = 'GET';
81
- try {
82
- const firstArg = args[0];
83
- if (typeof firstArg === 'string') {
84
- urlStr = firstArg;
85
+ try {
86
+ const originalRequest = module.request;
87
+ if (typeof originalRequest !== 'function')
88
+ return;
89
+ const originalRequestBound = originalRequest.bind(module);
90
+ const self = this;
91
+ const customRequest = function (...args) {
92
+ const req = originalRequestBound(...args);
93
+ const startTime = Date.now();
94
+ // Resolve URL and method
95
+ let urlStr = '';
96
+ let method = 'GET';
97
+ try {
98
+ const firstArg = args[0];
99
+ if (typeof firstArg === 'string') {
100
+ urlStr = firstArg;
101
+ }
102
+ else if (firstArg instanceof URL) {
103
+ urlStr = firstArg.toString();
104
+ }
105
+ else if (typeof firstArg === 'object' && firstArg !== null) {
106
+ const { protocol, hostname, host, port, path: urlPath } = firstArg;
107
+ const proto = protocol || 'http:';
108
+ const h = hostname || host || 'localhost';
109
+ const p = port ? `:${port}` : '';
110
+ urlStr = `${proto}//${h}${p}${urlPath || '/'}`;
111
+ method = (firstArg.method || 'GET').toUpperCase();
112
+ }
85
113
  }
86
- else if (firstArg instanceof URL) {
87
- urlStr = firstArg.toString();
114
+ catch {
115
+ urlStr = '';
88
116
  }
89
- else if (typeof firstArg === 'object' && firstArg !== null) {
90
- const { protocol, hostname, host, port, path: urlPath } = firstArg;
91
- const proto = protocol || 'http:';
92
- const h = hostname || host || 'localhost';
93
- const p = port ? `:${port}` : '';
94
- urlStr = `${proto}//${h}${p}${urlPath || '/'}`;
95
- method = (firstArg.method || 'GET').toUpperCase();
117
+ // Ignore telescope's own internal paths and configured ignore list
118
+ if (self.telescope.shouldIgnorePath(urlStr)) {
119
+ return req;
96
120
  }
97
- }
98
- catch {
99
- urlStr = '';
100
- }
101
- // Ignore telescope's own internal paths and configured ignore list
102
- if (self.telescope.shouldIgnorePath(urlStr)) {
103
- return req;
104
- }
105
- // Skip if this type is disabled
106
- if (!self.telescope.isEnabled(entry_type_enum_1.EntryType.HTTP_CLIENT)) {
107
- return req;
108
- }
109
- // Capture request body chunks written
110
- const reqChunks = [];
111
- const originalWrite = req.write.bind(req);
112
- const originalEnd = req.end.bind(req);
113
- req.write = function (chunk, ...rest) {
114
- if (chunk)
115
- reqChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
116
- return originalWrite(chunk, ...rest);
117
- };
118
- req.end = function (chunk, ...rest) {
119
- if (chunk)
120
- reqChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
121
- return originalEnd(chunk, ...rest);
122
- };
123
- // Capture request headers snapshot after end
124
- req.on('finish', () => {
125
- // headers captured at response time
126
- });
127
- req.on('response', (res) => {
128
- const resChunks = [];
129
- res.on('data', (chunk) => {
130
- resChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
121
+ // Skip if this type is disabled
122
+ if (!self.telescope.isEnabled(entry_type_enum_1.EntryType.HTTP_CLIENT)) {
123
+ return req;
124
+ }
125
+ // Capture request body chunks written
126
+ const reqChunks = [];
127
+ const originalWrite = req.write.bind(req);
128
+ const originalEnd = req.end.bind(req);
129
+ req.write = function (chunk, ...rest) {
130
+ if (chunk)
131
+ reqChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
132
+ return originalWrite(chunk, ...rest);
133
+ };
134
+ req.end = function (chunk, ...rest) {
135
+ if (chunk)
136
+ reqChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
137
+ return originalEnd(chunk, ...rest);
138
+ };
139
+ req.on('response', (res) => {
140
+ const resChunks = [];
141
+ res.on('data', (chunk) => {
142
+ resChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
143
+ });
144
+ res.on('end', () => {
145
+ const duration = Date.now() - startTime;
146
+ const requestBodyRaw = Buffer.concat(reqChunks).toString('utf8');
147
+ const responseBodyRaw = Buffer.concat(resChunks).toString('utf8');
148
+ let requestBody = requestBodyRaw;
149
+ let responseBody = responseBodyRaw;
150
+ try {
151
+ requestBody = JSON.parse(requestBodyRaw);
152
+ }
153
+ catch { /* keep raw */ }
154
+ try {
155
+ responseBody = JSON.parse(responseBodyRaw);
156
+ }
157
+ catch { /* keep raw */ }
158
+ // Sanitize headers — remove Authorization tokens from logs
159
+ const reqHeaders = { ...req.getHeaders?.() };
160
+ if (reqHeaders['authorization']) {
161
+ reqHeaders['authorization'] = '[REDACTED]';
162
+ }
163
+ self.telescope.record({
164
+ type: entry_type_enum_1.EntryType.HTTP_CLIENT,
165
+ content: {
166
+ method: method || (req.method || 'GET').toUpperCase(),
167
+ url: urlStr,
168
+ requestHeaders: reqHeaders,
169
+ requestBody,
170
+ responseStatus: res.statusCode,
171
+ responseHeaders: res.headers,
172
+ responseBody,
173
+ duration,
174
+ },
175
+ }).catch(() => { });
176
+ });
177
+ res.on('error', () => { });
131
178
  });
132
- res.on('end', () => {
179
+ req.on('error', (err) => {
133
180
  const duration = Date.now() - startTime;
134
- const requestBodyRaw = Buffer.concat(reqChunks).toString('utf8');
135
- const responseBodyRaw = Buffer.concat(resChunks).toString('utf8');
136
- let requestBody = requestBodyRaw;
137
- let responseBody = responseBodyRaw;
138
- try {
139
- requestBody = JSON.parse(requestBodyRaw);
140
- }
141
- catch { /* keep raw */ }
142
- try {
143
- responseBody = JSON.parse(responseBodyRaw);
144
- }
145
- catch { /* keep raw */ }
146
- // Sanitize headers — remove Authorization tokens from logs
147
- const reqHeaders = { ...req.getHeaders?.() };
148
- if (reqHeaders['authorization']) {
149
- reqHeaders['authorization'] = '[REDACTED]';
150
- }
151
181
  self.telescope.record({
152
182
  type: entry_type_enum_1.EntryType.HTTP_CLIENT,
153
183
  content: {
154
- method: method || (req.method || 'GET').toUpperCase(),
184
+ method,
155
185
  url: urlStr,
156
- requestHeaders: reqHeaders,
157
- requestBody,
158
- responseStatus: res.statusCode,
159
- responseHeaders: res.headers,
160
- responseBody,
186
+ requestHeaders: {},
187
+ requestBody: null,
188
+ responseStatus: 0,
189
+ responseBody: null,
190
+ error: err.message,
161
191
  duration,
162
192
  },
163
193
  }).catch(() => { });
164
194
  });
165
- res.on('error', () => { });
166
- });
167
- req.on('error', (err) => {
168
- const duration = Date.now() - startTime;
169
- self.telescope.record({
170
- type: entry_type_enum_1.EntryType.HTTP_CLIENT,
171
- content: {
172
- method,
173
- url: urlStr,
174
- requestHeaders: {},
175
- requestBody: null,
176
- responseStatus: 0,
177
- responseBody: null,
178
- error: err.message,
179
- duration,
180
- },
181
- }).catch(() => { });
182
- });
183
- return req;
184
- };
185
- // Also handle module.get (convenience method)
186
- const originalGet = module.get.bind(module);
187
- module.get = function (...args) {
188
- const req = module.request(...args);
189
- req.end();
190
- return req;
191
- };
195
+ return req;
196
+ };
197
+ try {
198
+ const desc = Object.getOwnPropertyDescriptor(module, 'request');
199
+ if (desc && desc.configurable === false) {
200
+ // Can't redefine using defineProperty, try simple assignment
201
+ module.request = customRequest;
202
+ }
203
+ else {
204
+ Object.defineProperty(module, 'request', {
205
+ value: customRequest,
206
+ configurable: true,
207
+ writable: true,
208
+ });
209
+ }
210
+ }
211
+ catch {
212
+ try {
213
+ module.request = customRequest;
214
+ }
215
+ catch { }
216
+ }
217
+ const customGet = function (...args) {
218
+ const req = module.request(...args);
219
+ req.end();
220
+ return req;
221
+ };
222
+ try {
223
+ const desc = Object.getOwnPropertyDescriptor(module, 'get');
224
+ if (desc && desc.configurable === false) {
225
+ // Can't redefine using defineProperty, try simple assignment
226
+ module.get = customGet;
227
+ }
228
+ else {
229
+ Object.defineProperty(module, 'get', {
230
+ value: customGet,
231
+ configurable: true,
232
+ writable: true,
233
+ });
234
+ }
235
+ }
236
+ catch {
237
+ try {
238
+ module.get = customGet;
239
+ }
240
+ catch { }
241
+ }
242
+ }
243
+ catch (e) {
244
+ // Prevent any crash
245
+ }
192
246
  }
193
247
  };
194
248
  exports.HttpClientWatcher = HttpClientWatcher;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ngn-net/nestjs-telescope",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },