@ngn-net/nestjs-telescope 0.2.4 → 0.2.5

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.5",
4
+ "builtAt": "2026-06-08T12:21:55.387Z"
5
5
  }
@@ -69,126 +69,167 @@ let HttpClientWatcher = class HttpClientWatcher {
69
69
  this.patch(https);
70
70
  }
71
71
  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;
72
+ try {
73
+ const originalRequest = module.request;
74
+ if (typeof originalRequest !== 'function')
75
+ return;
76
+ const originalRequestBound = originalRequest.bind(module);
77
+ const self = this;
78
+ const customRequest = function (...args) {
79
+ const req = originalRequestBound(...args);
80
+ const startTime = Date.now();
81
+ // Resolve URL and method
82
+ let urlStr = '';
83
+ let method = 'GET';
84
+ try {
85
+ const firstArg = args[0];
86
+ if (typeof firstArg === 'string') {
87
+ urlStr = firstArg;
88
+ }
89
+ else if (firstArg instanceof URL) {
90
+ urlStr = firstArg.toString();
91
+ }
92
+ else if (typeof firstArg === 'object' && firstArg !== null) {
93
+ const { protocol, hostname, host, port, path: urlPath } = firstArg;
94
+ const proto = protocol || 'http:';
95
+ const h = hostname || host || 'localhost';
96
+ const p = port ? `:${port}` : '';
97
+ urlStr = `${proto}//${h}${p}${urlPath || '/'}`;
98
+ method = (firstArg.method || 'GET').toUpperCase();
99
+ }
85
100
  }
86
- else if (firstArg instanceof URL) {
87
- urlStr = firstArg.toString();
101
+ catch {
102
+ urlStr = '';
88
103
  }
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();
104
+ // Ignore telescope's own internal paths and configured ignore list
105
+ if (self.telescope.shouldIgnorePath(urlStr)) {
106
+ return req;
96
107
  }
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));
108
+ // Skip if this type is disabled
109
+ if (!self.telescope.isEnabled(entry_type_enum_1.EntryType.HTTP_CLIENT)) {
110
+ return req;
111
+ }
112
+ // Capture request body chunks written
113
+ const reqChunks = [];
114
+ const originalWrite = req.write.bind(req);
115
+ const originalEnd = req.end.bind(req);
116
+ req.write = function (chunk, ...rest) {
117
+ if (chunk)
118
+ reqChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
119
+ return originalWrite(chunk, ...rest);
120
+ };
121
+ req.end = function (chunk, ...rest) {
122
+ if (chunk)
123
+ reqChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
124
+ return originalEnd(chunk, ...rest);
125
+ };
126
+ req.on('response', (res) => {
127
+ const resChunks = [];
128
+ res.on('data', (chunk) => {
129
+ resChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
130
+ });
131
+ res.on('end', () => {
132
+ const duration = Date.now() - startTime;
133
+ const requestBodyRaw = Buffer.concat(reqChunks).toString('utf8');
134
+ const responseBodyRaw = Buffer.concat(resChunks).toString('utf8');
135
+ let requestBody = requestBodyRaw;
136
+ let responseBody = responseBodyRaw;
137
+ try {
138
+ requestBody = JSON.parse(requestBodyRaw);
139
+ }
140
+ catch { /* keep raw */ }
141
+ try {
142
+ responseBody = JSON.parse(responseBodyRaw);
143
+ }
144
+ catch { /* keep raw */ }
145
+ // Sanitize headers — remove Authorization tokens from logs
146
+ const reqHeaders = { ...req.getHeaders?.() };
147
+ if (reqHeaders['authorization']) {
148
+ reqHeaders['authorization'] = '[REDACTED]';
149
+ }
150
+ self.telescope.record({
151
+ type: entry_type_enum_1.EntryType.HTTP_CLIENT,
152
+ content: {
153
+ method: method || (req.method || 'GET').toUpperCase(),
154
+ url: urlStr,
155
+ requestHeaders: reqHeaders,
156
+ requestBody,
157
+ responseStatus: res.statusCode,
158
+ responseHeaders: res.headers,
159
+ responseBody,
160
+ duration,
161
+ },
162
+ }).catch(() => { });
163
+ });
164
+ res.on('error', () => { });
131
165
  });
132
- res.on('end', () => {
166
+ req.on('error', (err) => {
133
167
  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
168
  self.telescope.record({
152
169
  type: entry_type_enum_1.EntryType.HTTP_CLIENT,
153
170
  content: {
154
- method: method || (req.method || 'GET').toUpperCase(),
171
+ method,
155
172
  url: urlStr,
156
- requestHeaders: reqHeaders,
157
- requestBody,
158
- responseStatus: res.statusCode,
159
- responseHeaders: res.headers,
160
- responseBody,
173
+ requestHeaders: {},
174
+ requestBody: null,
175
+ responseStatus: 0,
176
+ responseBody: null,
177
+ error: err.message,
161
178
  duration,
162
179
  },
163
180
  }).catch(() => { });
164
181
  });
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
- };
182
+ return req;
183
+ };
184
+ try {
185
+ const desc = Object.getOwnPropertyDescriptor(module, 'request');
186
+ if (desc && desc.configurable === false) {
187
+ // Can't redefine using defineProperty, try simple assignment
188
+ module.request = customRequest;
189
+ }
190
+ else {
191
+ Object.defineProperty(module, 'request', {
192
+ value: customRequest,
193
+ configurable: true,
194
+ writable: true,
195
+ });
196
+ }
197
+ }
198
+ catch {
199
+ try {
200
+ module.request = customRequest;
201
+ }
202
+ catch { }
203
+ }
204
+ const customGet = function (...args) {
205
+ const req = module.request(...args);
206
+ req.end();
207
+ return req;
208
+ };
209
+ try {
210
+ const desc = Object.getOwnPropertyDescriptor(module, 'get');
211
+ if (desc && desc.configurable === false) {
212
+ // Can't redefine using defineProperty, try simple assignment
213
+ module.get = customGet;
214
+ }
215
+ else {
216
+ Object.defineProperty(module, 'get', {
217
+ value: customGet,
218
+ configurable: true,
219
+ writable: true,
220
+ });
221
+ }
222
+ }
223
+ catch {
224
+ try {
225
+ module.get = customGet;
226
+ }
227
+ catch { }
228
+ }
229
+ }
230
+ catch (e) {
231
+ // Prevent any crash
232
+ }
192
233
  }
193
234
  };
194
235
  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.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },