@ngn-net/nestjs-telescope 0.2.15 → 0.3.0
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 +168 -20
- package/dist/index.js +0 -2
- package/dist/storage/entities/telescope-entry.entity.d.ts +12 -1
- package/dist/storage/entities/telescope-entry.entity.js +11 -42
- package/dist/storage/telescope-repository.service.d.ts +5 -5
- package/dist/storage/telescope-repository.service.js +36 -43
- package/dist/telescope.module.js +10 -30
- package/dist/telescope.service.js +1 -1
- package/dist/ui/manifest.json +2 -2
- package/dist/watchers/command.watcher.d.ts +1 -5
- package/dist/watchers/command.watcher.js +19 -18
- package/dist/watchers/gate.watcher.d.ts +4 -9
- package/dist/watchers/gate.watcher.js +39 -22
- package/dist/watchers/http-client.watcher.d.ts +1 -0
- package/dist/watchers/http-client.watcher.js +58 -16
- package/dist/watchers/model.subscriber.d.ts +0 -4
- package/dist/watchers/model.subscriber.js +1 -8
- package/dist/watchers/model.watcher.d.ts +1 -4
- package/dist/watchers/model.watcher.js +45 -17
- package/dist/watchers/notification.watcher.d.ts +1 -5
- package/dist/watchers/notification.watcher.js +35 -18
- package/dist/watchers/schedule.watcher.d.ts +3 -4
- package/dist/watchers/schedule.watcher.js +79 -60
- package/package.json +4 -2
package/dist/telescope.module.js
CHANGED
|
@@ -16,9 +16,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
16
16
|
exports.TelescopeModule = void 0;
|
|
17
17
|
const common_1 = require("@nestjs/common");
|
|
18
18
|
const serve_static_1 = require("@nestjs/serve-static");
|
|
19
|
+
const mongoose_1 = require("@nestjs/mongoose");
|
|
19
20
|
const path_1 = require("path");
|
|
20
21
|
const core_1 = require("@nestjs/core");
|
|
21
|
-
const typeorm_1 = require("@nestjs/typeorm");
|
|
22
22
|
const jwt_1 = require("@nestjs/jwt");
|
|
23
23
|
const telescope_service_1 = require("./telescope.service");
|
|
24
24
|
const telescope_controller_1 = require("./controllers/telescope.controller");
|
|
@@ -54,7 +54,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
54
54
|
Reflect.defineMetadata('path', path, telescope_controller_1.TelescopeController);
|
|
55
55
|
}
|
|
56
56
|
onModuleInit() {
|
|
57
|
-
// Dynamic peer dependency validation at bootstrap
|
|
58
57
|
const warnedTypes = new Set();
|
|
59
58
|
const hasDependency = (type, packageName) => {
|
|
60
59
|
try {
|
|
@@ -77,7 +76,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
77
76
|
hasDependency(entry_type_enum_1.EntryType.EVENT, '@nestjs/event-emitter');
|
|
78
77
|
hasDependency(entry_type_enum_1.EntryType.SCHEDULED_TASK, '@nestjs/schedule');
|
|
79
78
|
hasDependency(entry_type_enum_1.EntryType.MAIL, 'nodemailer');
|
|
80
|
-
// Dynamic EventEmitter2 configuration
|
|
81
79
|
try {
|
|
82
80
|
const eventWatcher = this.moduleRef.get(event_watcher_1.EventWatcher, { strict: false });
|
|
83
81
|
const { EventEmitter2 } = require('@nestjs/event-emitter');
|
|
@@ -88,10 +86,7 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
88
|
}
|
|
91
|
-
catch (e) {
|
|
92
|
-
// EventEmitter2 or EventWatcher not registered/available
|
|
93
|
-
}
|
|
94
|
-
// Dynamic SchedulerRegistry configuration
|
|
89
|
+
catch (e) { }
|
|
95
90
|
try {
|
|
96
91
|
const scheduleWatcher = this.moduleRef.get(schedule_watcher_1.ScheduleWatcher, { strict: false });
|
|
97
92
|
const { SchedulerRegistry } = require('@nestjs/schedule');
|
|
@@ -102,19 +97,18 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
102
97
|
}
|
|
103
98
|
}
|
|
104
99
|
}
|
|
105
|
-
catch (e) {
|
|
106
|
-
// SchedulerRegistry or ScheduleWatcher not registered/available
|
|
107
|
-
}
|
|
100
|
+
catch (e) { }
|
|
108
101
|
}
|
|
109
102
|
static forRoot(options = {}) {
|
|
110
103
|
const imports = [
|
|
111
|
-
|
|
104
|
+
mongoose_1.MongooseModule.forFeature([
|
|
105
|
+
{ name: telescope_entry_entity_1.TelescopeEntry.name, schema: telescope_entry_entity_1.TelescopeEntrySchema },
|
|
106
|
+
]),
|
|
112
107
|
jwt_1.JwtModule.register({
|
|
113
108
|
secret: options.jwtSecret || process.env.TELESCOPE_JWT_SECRET || constants_1.DEFAULT_JWT_SECRET,
|
|
114
109
|
signOptions: { expiresIn: '1d' },
|
|
115
110
|
}),
|
|
116
111
|
];
|
|
117
|
-
// Serve static UI assets if dashboard is enabled (default true)
|
|
118
112
|
if (options.enableDashboard !== false) {
|
|
119
113
|
const staticPath = (0, path_1.join)(__dirname, '..', 'ui');
|
|
120
114
|
const routePath = options.path || constants_1.DEFAULT_TELESCOPE_PATH;
|
|
@@ -132,7 +126,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
132
126
|
telescope_repository_service_1.TelescopeRepository,
|
|
133
127
|
telescope_jwt_guard_1.JwtAuthGuard,
|
|
134
128
|
];
|
|
135
|
-
// Register watchers (both core and optional)
|
|
136
129
|
this.registerWatchersAndModules(options, providers, imports);
|
|
137
130
|
return {
|
|
138
131
|
module: TelescopeModule_1,
|
|
@@ -150,7 +143,9 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
150
143
|
telescope_jwt_guard_1.JwtAuthGuard,
|
|
151
144
|
];
|
|
152
145
|
const imports = [
|
|
153
|
-
|
|
146
|
+
mongoose_1.MongooseModule.forFeature([
|
|
147
|
+
{ name: telescope_entry_entity_1.TelescopeEntry.name, schema: telescope_entry_entity_1.TelescopeEntrySchema },
|
|
148
|
+
]),
|
|
154
149
|
jwt_1.JwtModule.registerAsync({
|
|
155
150
|
imports: options.imports || [],
|
|
156
151
|
inject: [constants_1.TELESCOPE_OPTIONS],
|
|
@@ -160,7 +155,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
160
155
|
}),
|
|
161
156
|
}),
|
|
162
157
|
];
|
|
163
|
-
// Serve static UI assets if dashboard is enabled (default true)
|
|
164
158
|
imports.push(serve_static_1.ServeStaticModule.forRootAsync({
|
|
165
159
|
imports: options.imports || [],
|
|
166
160
|
inject: [constants_1.TELESCOPE_OPTIONS],
|
|
@@ -178,7 +172,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
178
172
|
];
|
|
179
173
|
},
|
|
180
174
|
}));
|
|
181
|
-
// Register all available/supported watchers & modules dynamically
|
|
182
175
|
this.registerWatchersAndModulesAsync(providers, imports);
|
|
183
176
|
return {
|
|
184
177
|
module: TelescopeModule_1,
|
|
@@ -215,14 +208,13 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
215
208
|
return [];
|
|
216
209
|
}
|
|
217
210
|
static registerWatchersAndModules(options, providers, imports) {
|
|
218
|
-
// 1. Core watchers (always registered if enabled or not specified)
|
|
219
211
|
const coreWatchers = [
|
|
220
212
|
{ type: entry_type_enum_1.EntryType.REQUEST, watcher: http_request_watcher_1.HttpRequestWatcher, isInterceptor: true },
|
|
221
213
|
{ type: entry_type_enum_1.EntryType.QUERY, watcher: query_watcher_1.QueryWatcher },
|
|
222
214
|
{ type: entry_type_enum_1.EntryType.LOG, watcher: log_watcher_1.LogWatcher },
|
|
223
215
|
{ type: entry_type_enum_1.EntryType.EXCEPTION, watcher: exception_watcher_1.ExceptionWatcher, isInterceptor: true },
|
|
216
|
+
{ type: entry_type_enum_1.EntryType.GATE, watcher: gate_watcher_1.GateWatcher, isInterceptor: true },
|
|
224
217
|
{ type: entry_type_enum_1.EntryType.REDIS, watcher: redis_watcher_1.RedisWatcher },
|
|
225
|
-
// New watchers for parity with Laravel Telescope
|
|
226
218
|
{ type: entry_type_enum_1.EntryType.COMMAND, watcher: command_watcher_1.CommandWatcher },
|
|
227
219
|
{ type: entry_type_enum_1.EntryType.MODEL, watcher: model_watcher_1.ModelWatcher },
|
|
228
220
|
{ type: entry_type_enum_1.EntryType.NOTIFICATION, watcher: notification_watcher_1.NotificationWatcher },
|
|
@@ -237,7 +229,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
237
229
|
}
|
|
238
230
|
}
|
|
239
231
|
}
|
|
240
|
-
// Additional optional watchers (non-interceptors)
|
|
241
232
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.HTTP_CLIENT)) {
|
|
242
233
|
providers.push(http_service_watcher_1.HttpServiceWatcher);
|
|
243
234
|
providers.push(http_client_watcher_1.HttpClientWatcher);
|
|
@@ -252,10 +243,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
252
243
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.NOTIFICATION)) {
|
|
253
244
|
providers.push(notification_watcher_1.NotificationWatcher);
|
|
254
245
|
}
|
|
255
|
-
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.GATE)) {
|
|
256
|
-
providers.push(gate_watcher_1.GateWatcher);
|
|
257
|
-
}
|
|
258
|
-
// 2. CacheWatcher
|
|
259
246
|
try {
|
|
260
247
|
require('@nestjs/cache-manager');
|
|
261
248
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.CACHE)) {
|
|
@@ -265,7 +252,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
265
252
|
}
|
|
266
253
|
}
|
|
267
254
|
catch (e) { }
|
|
268
|
-
// 3. QueueWatcher
|
|
269
255
|
try {
|
|
270
256
|
require('@nestjs/bullmq');
|
|
271
257
|
require('bullmq');
|
|
@@ -282,7 +268,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
282
268
|
}
|
|
283
269
|
}
|
|
284
270
|
catch (e) { }
|
|
285
|
-
// 4. EventWatcher
|
|
286
271
|
try {
|
|
287
272
|
require('@nestjs/event-emitter');
|
|
288
273
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.EVENT)) {
|
|
@@ -290,7 +275,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
290
275
|
}
|
|
291
276
|
}
|
|
292
277
|
catch (e) { }
|
|
293
|
-
// 5. ScheduleWatcher
|
|
294
278
|
try {
|
|
295
279
|
require('@nestjs/schedule');
|
|
296
280
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.SCHEDULED_TASK)) {
|
|
@@ -298,7 +282,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
298
282
|
}
|
|
299
283
|
}
|
|
300
284
|
catch (e) { }
|
|
301
|
-
// 6. MailWatcher
|
|
302
285
|
try {
|
|
303
286
|
require('nodemailer');
|
|
304
287
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.MAIL)) {
|
|
@@ -308,7 +291,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
308
291
|
catch (e) { }
|
|
309
292
|
}
|
|
310
293
|
static registerWatchersAndModulesAsync(providers, imports) {
|
|
311
|
-
// Core interceptors and watchers
|
|
312
294
|
providers.push({ provide: core_1.APP_INTERCEPTOR, useClass: http_request_watcher_1.HttpRequestWatcher });
|
|
313
295
|
providers.push({ provide: core_1.APP_INTERCEPTOR, useClass: exception_watcher_1.ExceptionWatcher });
|
|
314
296
|
providers.push(query_watcher_1.QueryWatcher);
|
|
@@ -320,8 +302,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
320
302
|
providers.push(model_watcher_1.ModelWatcher);
|
|
321
303
|
providers.push(model_subscriber_1.ModelSubscriber);
|
|
322
304
|
providers.push(notification_watcher_1.NotificationWatcher);
|
|
323
|
-
providers.push(gate_watcher_1.GateWatcher);
|
|
324
|
-
// Optional modules/watchers if packages are present
|
|
325
305
|
try {
|
|
326
306
|
require('@nestjs/cache-manager');
|
|
327
307
|
const { CacheModule } = require('@nestjs/cache-manager');
|
|
@@ -32,7 +32,7 @@ let TelescopeService = class TelescopeService {
|
|
|
32
32
|
this.adapterHost = adapterHost;
|
|
33
33
|
}
|
|
34
34
|
async onModuleInit() {
|
|
35
|
-
// Module is initialized;
|
|
35
|
+
// Module is initialized; Mongoose will handle schema sync
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
38
|
* Run a function inside a specific request context.
|
package/dist/ui/manifest.json
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { OnModuleInit } from '@nestjs/common';
|
|
2
2
|
import { TelescopeService } from '../telescope.service';
|
|
3
|
-
/**
|
|
4
|
-
* Placeholder watcher for command execution monitoring.
|
|
5
|
-
* In a real implementation you would integrate with a command runner
|
|
6
|
-
* such as `nest-commander` or capture process events.
|
|
7
|
-
*/
|
|
8
3
|
export declare class CommandWatcher implements OnModuleInit {
|
|
9
4
|
private readonly telescope;
|
|
10
5
|
private readonly logger;
|
|
11
6
|
constructor(telescope: TelescopeService);
|
|
12
7
|
onModuleInit(): void;
|
|
8
|
+
private recordStartupCommand;
|
|
13
9
|
}
|
|
@@ -11,15 +11,9 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
var CommandWatcher_1;
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.CommandWatcher = void 0;
|
|
14
|
-
// src/watchers/command.watcher.ts
|
|
15
14
|
const common_1 = require("@nestjs/common");
|
|
16
15
|
const telescope_service_1 = require("../telescope.service");
|
|
17
16
|
const entry_type_enum_1 = require("../enums/entry-type.enum");
|
|
18
|
-
/**
|
|
19
|
-
* Placeholder watcher for command execution monitoring.
|
|
20
|
-
* In a real implementation you would integrate with a command runner
|
|
21
|
-
* such as `nest-commander` or capture process events.
|
|
22
|
-
*/
|
|
23
17
|
let CommandWatcher = CommandWatcher_1 = class CommandWatcher {
|
|
24
18
|
telescope;
|
|
25
19
|
logger = new common_1.Logger(CommandWatcher_1.name);
|
|
@@ -27,18 +21,25 @@ let CommandWatcher = CommandWatcher_1 = class CommandWatcher {
|
|
|
27
21
|
this.telescope = telescope;
|
|
28
22
|
}
|
|
29
23
|
onModuleInit() {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
24
|
+
this.recordStartupCommand();
|
|
25
|
+
}
|
|
26
|
+
recordStartupCommand() {
|
|
27
|
+
const args = process.argv.slice(2);
|
|
28
|
+
if (args.length > 0) {
|
|
29
|
+
const command = args[0];
|
|
30
|
+
const isKnownCommand = ['start', 'build', 'test', 'lint', 'format'].some((c) => command.includes(c));
|
|
31
|
+
if (isKnownCommand) {
|
|
32
|
+
this.telescope.record({
|
|
33
|
+
type: entry_type_enum_1.EntryType.COMMAND,
|
|
34
|
+
content: {
|
|
35
|
+
command,
|
|
36
|
+
args: args.slice(1),
|
|
37
|
+
timestamp: new Date().toISOString(),
|
|
38
|
+
pid: process.pid,
|
|
39
|
+
},
|
|
40
|
+
}).catch(() => { });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
42
43
|
}
|
|
43
44
|
};
|
|
44
45
|
exports.CommandWatcher = CommandWatcher;
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
2
3
|
import { TelescopeService } from '../telescope.service';
|
|
3
|
-
|
|
4
|
-
* Placeholder watcher for authorization gate checks.
|
|
5
|
-
* In a full implementation you would hook into NestJS guards (CanActivate)
|
|
6
|
-
* and record the decision, user, policy, etc.
|
|
7
|
-
*/
|
|
8
|
-
export declare class GateWatcher implements OnModuleInit {
|
|
4
|
+
export declare class GateWatcher implements NestInterceptor {
|
|
9
5
|
private readonly telescope;
|
|
10
|
-
private readonly logger;
|
|
11
6
|
constructor(telescope: TelescopeService);
|
|
12
|
-
|
|
7
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
|
|
13
8
|
}
|
|
@@ -8,41 +8,58 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
-
var GateWatcher_1;
|
|
12
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
12
|
exports.GateWatcher = void 0;
|
|
14
|
-
// src/watchers/gate.watcher.ts
|
|
15
13
|
const common_1 = require("@nestjs/common");
|
|
14
|
+
const rxjs_1 = require("rxjs");
|
|
16
15
|
const telescope_service_1 = require("../telescope.service");
|
|
17
16
|
const entry_type_enum_1 = require("../enums/entry-type.enum");
|
|
18
|
-
|
|
19
|
-
* Placeholder watcher for authorization gate checks.
|
|
20
|
-
* In a full implementation you would hook into NestJS guards (CanActivate)
|
|
21
|
-
* and record the decision, user, policy, etc.
|
|
22
|
-
*/
|
|
23
|
-
let GateWatcher = GateWatcher_1 = class GateWatcher {
|
|
17
|
+
let GateWatcher = class GateWatcher {
|
|
24
18
|
telescope;
|
|
25
|
-
logger = new common_1.Logger(GateWatcher_1.name);
|
|
26
19
|
constructor(telescope) {
|
|
27
20
|
this.telescope = telescope;
|
|
28
21
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
intercept(context, next) {
|
|
23
|
+
if (context.getType() !== 'http') {
|
|
24
|
+
return next.handle();
|
|
25
|
+
}
|
|
26
|
+
const request = context.switchToHttp().getRequest();
|
|
27
|
+
const user = request.user || request.auth || null;
|
|
28
|
+
return next.handle().pipe((0, rxjs_1.tap)({
|
|
29
|
+
next: () => {
|
|
30
|
+
this.telescope.record({
|
|
31
|
+
type: entry_type_enum_1.EntryType.GATE,
|
|
32
|
+
content: {
|
|
33
|
+
gate: 'auth',
|
|
34
|
+
allowed: true,
|
|
35
|
+
user: user ? { id: user.sub || user.id || user.username } : null,
|
|
36
|
+
method: request.method,
|
|
37
|
+
url: request.originalUrl || request.url,
|
|
38
|
+
},
|
|
39
|
+
}).catch(() => { });
|
|
38
40
|
},
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
error: (err) => {
|
|
42
|
+
const isAuthError = err.status === 401 || err.status === 403 ||
|
|
43
|
+
err.name === 'UnauthorizedException' || err.name === 'ForbiddenException';
|
|
44
|
+
if (isAuthError) {
|
|
45
|
+
this.telescope.record({
|
|
46
|
+
type: entry_type_enum_1.EntryType.GATE,
|
|
47
|
+
content: {
|
|
48
|
+
gate: 'auth',
|
|
49
|
+
allowed: false,
|
|
50
|
+
reason: err.message || err.constructor?.name || 'Access denied',
|
|
51
|
+
user: user ? { id: user.sub || user.id || user.username } : null,
|
|
52
|
+
method: request.method,
|
|
53
|
+
url: request.originalUrl || request.url,
|
|
54
|
+
},
|
|
55
|
+
}).catch(() => { });
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
}));
|
|
42
59
|
}
|
|
43
60
|
};
|
|
44
61
|
exports.GateWatcher = GateWatcher;
|
|
45
|
-
exports.GateWatcher = GateWatcher =
|
|
62
|
+
exports.GateWatcher = GateWatcher = __decorate([
|
|
46
63
|
(0, common_1.Injectable)(),
|
|
47
64
|
__metadata("design:paramtypes", [telescope_service_1.TelescopeService])
|
|
48
65
|
], GateWatcher);
|
|
@@ -46,7 +46,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
48
|
exports.HttpClientWatcher = void 0;
|
|
49
|
-
// src/watchers/http-client.watcher.ts
|
|
50
49
|
const common_1 = require("@nestjs/common");
|
|
51
50
|
const http = __importStar(require("http"));
|
|
52
51
|
const https = __importStar(require("https"));
|
|
@@ -67,7 +66,6 @@ let HttpClientWatcher = class HttpClientWatcher {
|
|
|
67
66
|
this.patched = true;
|
|
68
67
|
this.patch(http);
|
|
69
68
|
this.patch(https);
|
|
70
|
-
// Also patch follow-redirects if used by HTTP clients like Axios
|
|
71
69
|
try {
|
|
72
70
|
const followRedirects = require('follow-redirects');
|
|
73
71
|
if (followRedirects) {
|
|
@@ -77,9 +75,62 @@ let HttpClientWatcher = class HttpClientWatcher {
|
|
|
77
75
|
this.patch(followRedirects.https);
|
|
78
76
|
}
|
|
79
77
|
}
|
|
80
|
-
catch (e) {
|
|
81
|
-
|
|
78
|
+
catch (e) { }
|
|
79
|
+
this.patchAxios();
|
|
80
|
+
}
|
|
81
|
+
patchAxios() {
|
|
82
|
+
try {
|
|
83
|
+
const axios = require('axios');
|
|
84
|
+
if (!axios || !axios.Axios)
|
|
85
|
+
return;
|
|
86
|
+
const originalRequest = axios.Axios.prototype.request;
|
|
87
|
+
const self = this;
|
|
88
|
+
axios.Axios.prototype.request = async function (...args) {
|
|
89
|
+
const config = args[0] || {};
|
|
90
|
+
const startTime = Date.now();
|
|
91
|
+
const url = typeof config === 'string' ? config : (config.url || '');
|
|
92
|
+
const method = (config.method || 'GET').toUpperCase();
|
|
93
|
+
if (self.telescope.shouldIgnorePath(url)) {
|
|
94
|
+
return originalRequest.apply(this, args);
|
|
95
|
+
}
|
|
96
|
+
if (!self.telescope.isEnabled(entry_type_enum_1.EntryType.HTTP_CLIENT)) {
|
|
97
|
+
return originalRequest.apply(this, args);
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const response = await originalRequest.apply(this, args);
|
|
101
|
+
const duration = Date.now() - startTime;
|
|
102
|
+
self.telescope.record({
|
|
103
|
+
type: entry_type_enum_1.EntryType.HTTP_CLIENT,
|
|
104
|
+
content: {
|
|
105
|
+
method,
|
|
106
|
+
url,
|
|
107
|
+
requestBody: config.data || null,
|
|
108
|
+
responseStatus: response?.status,
|
|
109
|
+
responseData: response?.data,
|
|
110
|
+
duration,
|
|
111
|
+
},
|
|
112
|
+
}).catch(() => { });
|
|
113
|
+
return response;
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
const duration = Date.now() - startTime;
|
|
117
|
+
self.telescope.record({
|
|
118
|
+
type: entry_type_enum_1.EntryType.HTTP_CLIENT,
|
|
119
|
+
content: {
|
|
120
|
+
method,
|
|
121
|
+
url,
|
|
122
|
+
requestBody: config.data || null,
|
|
123
|
+
responseStatus: err?.response?.status || 0,
|
|
124
|
+
responseData: err?.response?.data || null,
|
|
125
|
+
error: err.message,
|
|
126
|
+
duration,
|
|
127
|
+
},
|
|
128
|
+
}).catch(() => { });
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
82
132
|
}
|
|
133
|
+
catch (e) { }
|
|
83
134
|
}
|
|
84
135
|
patch(module) {
|
|
85
136
|
try {
|
|
@@ -91,7 +142,6 @@ let HttpClientWatcher = class HttpClientWatcher {
|
|
|
91
142
|
const customRequest = function (...args) {
|
|
92
143
|
const req = originalRequestBound(...args);
|
|
93
144
|
const startTime = Date.now();
|
|
94
|
-
// Resolve URL and method
|
|
95
145
|
let urlStr = '';
|
|
96
146
|
let method = 'GET';
|
|
97
147
|
try {
|
|
@@ -114,15 +164,12 @@ let HttpClientWatcher = class HttpClientWatcher {
|
|
|
114
164
|
catch {
|
|
115
165
|
urlStr = '';
|
|
116
166
|
}
|
|
117
|
-
// Ignore telescope's own internal paths and configured ignore list
|
|
118
167
|
if (self.telescope.shouldIgnorePath(urlStr)) {
|
|
119
168
|
return req;
|
|
120
169
|
}
|
|
121
|
-
// Skip if this type is disabled
|
|
122
170
|
if (!self.telescope.isEnabled(entry_type_enum_1.EntryType.HTTP_CLIENT)) {
|
|
123
171
|
return req;
|
|
124
172
|
}
|
|
125
|
-
// Capture request body chunks written
|
|
126
173
|
const reqChunks = [];
|
|
127
174
|
const originalWrite = req.write.bind(req);
|
|
128
175
|
const originalEnd = req.end.bind(req);
|
|
@@ -150,12 +197,11 @@ let HttpClientWatcher = class HttpClientWatcher {
|
|
|
150
197
|
try {
|
|
151
198
|
requestBody = JSON.parse(requestBodyRaw);
|
|
152
199
|
}
|
|
153
|
-
catch {
|
|
200
|
+
catch { }
|
|
154
201
|
try {
|
|
155
202
|
responseBody = JSON.parse(responseBodyRaw);
|
|
156
203
|
}
|
|
157
|
-
catch {
|
|
158
|
-
// Sanitize headers — remove Authorization tokens from logs
|
|
204
|
+
catch { }
|
|
159
205
|
const reqHeaders = { ...req.getHeaders?.() };
|
|
160
206
|
if (reqHeaders['authorization']) {
|
|
161
207
|
reqHeaders['authorization'] = '[REDACTED]';
|
|
@@ -197,7 +243,6 @@ let HttpClientWatcher = class HttpClientWatcher {
|
|
|
197
243
|
try {
|
|
198
244
|
const desc = Object.getOwnPropertyDescriptor(module, 'request');
|
|
199
245
|
if (desc && desc.configurable === false) {
|
|
200
|
-
// Can't redefine using defineProperty, try simple assignment
|
|
201
246
|
module.request = customRequest;
|
|
202
247
|
}
|
|
203
248
|
else {
|
|
@@ -222,7 +267,6 @@ let HttpClientWatcher = class HttpClientWatcher {
|
|
|
222
267
|
try {
|
|
223
268
|
const desc = Object.getOwnPropertyDescriptor(module, 'get');
|
|
224
269
|
if (desc && desc.configurable === false) {
|
|
225
|
-
// Can't redefine using defineProperty, try simple assignment
|
|
226
270
|
module.get = customGet;
|
|
227
271
|
}
|
|
228
272
|
else {
|
|
@@ -240,9 +284,7 @@ let HttpClientWatcher = class HttpClientWatcher {
|
|
|
240
284
|
catch { }
|
|
241
285
|
}
|
|
242
286
|
}
|
|
243
|
-
catch (e) {
|
|
244
|
-
// Prevent any crash
|
|
245
|
-
}
|
|
287
|
+
catch (e) { }
|
|
246
288
|
}
|
|
247
289
|
};
|
|
248
290
|
exports.HttpClientWatcher = HttpClientWatcher;
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent, DataSource } from 'typeorm';
|
|
2
2
|
import { OnModuleInit } from '@nestjs/common';
|
|
3
3
|
import { TelescopeService } from '../telescope.service';
|
|
4
|
-
/**
|
|
5
|
-
* Subscribes to TypeORM entity lifecycle events and records them.
|
|
6
|
-
* This watcher is automatically registered when TypeORM is present.
|
|
7
|
-
*/
|
|
8
4
|
export declare class ModelSubscriber implements EntitySubscriberInterface, OnModuleInit {
|
|
9
5
|
private readonly telescope;
|
|
10
6
|
private readonly dataSource?;
|
|
@@ -18,10 +18,6 @@ const typeorm_1 = require("typeorm");
|
|
|
18
18
|
const common_1 = require("@nestjs/common");
|
|
19
19
|
const telescope_service_1 = require("../telescope.service");
|
|
20
20
|
const entry_type_enum_1 = require("../enums/entry-type.enum");
|
|
21
|
-
/**
|
|
22
|
-
* Subscribes to TypeORM entity lifecycle events and records them.
|
|
23
|
-
* This watcher is automatically registered when TypeORM is present.
|
|
24
|
-
*/
|
|
25
21
|
let ModelSubscriber = ModelSubscriber_1 = class ModelSubscriber {
|
|
26
22
|
telescope;
|
|
27
23
|
dataSource;
|
|
@@ -37,13 +33,10 @@ let ModelSubscriber = ModelSubscriber_1 = class ModelSubscriber {
|
|
|
37
33
|
this.dataSource.subscribers.push(this);
|
|
38
34
|
}
|
|
39
35
|
}
|
|
40
|
-
catch {
|
|
41
|
-
// Ignore registration errors
|
|
42
|
-
}
|
|
36
|
+
catch { }
|
|
43
37
|
}
|
|
44
38
|
}
|
|
45
39
|
listenTo() {
|
|
46
|
-
// Listen to all entities
|
|
47
40
|
return Object;
|
|
48
41
|
}
|
|
49
42
|
isTelescopeEntity(event) {
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { OnModuleInit } from '@nestjs/common';
|
|
2
2
|
import { TelescopeService } from '../telescope.service';
|
|
3
|
-
/**
|
|
4
|
-
* Placeholder watcher for ORM model events (e.g., TypeORM, Mongoose, Sequelize).
|
|
5
|
-
* Real implementation would subscribe to lifecycle hooks and record create/update/delete.
|
|
6
|
-
*/
|
|
7
3
|
export declare class ModelWatcher implements OnModuleInit {
|
|
8
4
|
private readonly telescope;
|
|
9
5
|
private readonly logger;
|
|
10
6
|
constructor(telescope: TelescopeService);
|
|
11
7
|
onModuleInit(): void;
|
|
8
|
+
private tryHookMongoose;
|
|
12
9
|
}
|
|
@@ -11,14 +11,9 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
var ModelWatcher_1;
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.ModelWatcher = void 0;
|
|
14
|
-
// src/watchers/model.watcher.ts
|
|
15
14
|
const common_1 = require("@nestjs/common");
|
|
16
15
|
const telescope_service_1 = require("../telescope.service");
|
|
17
16
|
const entry_type_enum_1 = require("../enums/entry-type.enum");
|
|
18
|
-
/**
|
|
19
|
-
* Placeholder watcher for ORM model events (e.g., TypeORM, Mongoose, Sequelize).
|
|
20
|
-
* Real implementation would subscribe to lifecycle hooks and record create/update/delete.
|
|
21
|
-
*/
|
|
22
17
|
let ModelWatcher = ModelWatcher_1 = class ModelWatcher {
|
|
23
18
|
telescope;
|
|
24
19
|
logger = new common_1.Logger(ModelWatcher_1.name);
|
|
@@ -26,18 +21,51 @@ let ModelWatcher = ModelWatcher_1 = class ModelWatcher {
|
|
|
26
21
|
this.telescope = telescope;
|
|
27
22
|
}
|
|
28
23
|
onModuleInit() {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
this.tryHookMongoose();
|
|
25
|
+
}
|
|
26
|
+
tryHookMongoose() {
|
|
27
|
+
try {
|
|
28
|
+
const mongoose = require('mongoose');
|
|
29
|
+
if (!mongoose || !mongoose.Schema)
|
|
30
|
+
return;
|
|
31
|
+
const originalSave = mongoose.Document.prototype.save;
|
|
32
|
+
if (!originalSave)
|
|
33
|
+
return;
|
|
34
|
+
const self = this;
|
|
35
|
+
mongoose.Document.prototype.save = async function (...args) {
|
|
36
|
+
const isNew = this.isNew;
|
|
37
|
+
const operation = isNew ? 'insert' : 'update';
|
|
38
|
+
const entity = this.constructor?.modelName || 'Unknown';
|
|
39
|
+
const result = await originalSave.apply(this, args);
|
|
40
|
+
self.telescope.record({
|
|
41
|
+
type: entry_type_enum_1.EntryType.MODEL,
|
|
42
|
+
content: {
|
|
43
|
+
action: operation,
|
|
44
|
+
entity,
|
|
45
|
+
primaryKey: this._id?.toString() || null,
|
|
46
|
+
data: isNew ? this.toObject() : { modified: true },
|
|
47
|
+
},
|
|
48
|
+
}).catch(() => { });
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
const originalRemove = mongoose.Document.prototype.deleteOne;
|
|
52
|
+
if (originalRemove) {
|
|
53
|
+
mongoose.Document.prototype.deleteOne = async function (...args) {
|
|
54
|
+
const entity = this.constructor?.modelName || 'Unknown';
|
|
55
|
+
const result = await originalRemove.apply(this, args);
|
|
56
|
+
self.telescope.record({
|
|
57
|
+
type: entry_type_enum_1.EntryType.MODEL,
|
|
58
|
+
content: {
|
|
59
|
+
action: 'remove',
|
|
60
|
+
entity,
|
|
61
|
+
primaryKey: this._id?.toString() || null,
|
|
62
|
+
},
|
|
63
|
+
}).catch(() => { });
|
|
64
|
+
return result;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch { }
|
|
41
69
|
}
|
|
42
70
|
};
|
|
43
71
|
exports.ModelWatcher = ModelWatcher;
|