@ngn-net/nestjs-telescope 0.2.15 → 0.3.1
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/constants.d.ts +4 -0
- package/dist/constants.js +5 -1
- package/dist/index.js +0 -2
- package/dist/interfaces/telescope-options.interface.d.ts +2 -0
- 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 +37 -43
- package/dist/telescope.module.js +16 -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 = {}) {
|
|
103
|
+
const mongoUri = options.mongoUri || process.env.TELESCOPE_MONGO_URI || constants_1.DEFAULT_MONGO_URI;
|
|
110
104
|
const imports = [
|
|
111
|
-
|
|
105
|
+
mongoose_1.MongooseModule.forRoot(mongoUri, { connectionName: constants_1.TELESCOPE_MONGO_CONNECTION }),
|
|
106
|
+
mongoose_1.MongooseModule.forFeature([{ name: telescope_entry_entity_1.TelescopeEntry.name, schema: telescope_entry_entity_1.TelescopeEntrySchema }], constants_1.TELESCOPE_MONGO_CONNECTION),
|
|
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,15 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
150
143
|
telescope_jwt_guard_1.JwtAuthGuard,
|
|
151
144
|
];
|
|
152
145
|
const imports = [
|
|
153
|
-
|
|
146
|
+
mongoose_1.MongooseModule.forRootAsync({
|
|
147
|
+
connectionName: constants_1.TELESCOPE_MONGO_CONNECTION,
|
|
148
|
+
imports: options.imports || [],
|
|
149
|
+
inject: [constants_1.TELESCOPE_OPTIONS],
|
|
150
|
+
useFactory: async (telescopeOpts) => ({
|
|
151
|
+
uri: telescopeOpts.mongoUri || process.env.TELESCOPE_MONGO_URI || constants_1.DEFAULT_MONGO_URI,
|
|
152
|
+
}),
|
|
153
|
+
}),
|
|
154
|
+
mongoose_1.MongooseModule.forFeature([{ name: telescope_entry_entity_1.TelescopeEntry.name, schema: telescope_entry_entity_1.TelescopeEntrySchema }], constants_1.TELESCOPE_MONGO_CONNECTION),
|
|
154
155
|
jwt_1.JwtModule.registerAsync({
|
|
155
156
|
imports: options.imports || [],
|
|
156
157
|
inject: [constants_1.TELESCOPE_OPTIONS],
|
|
@@ -160,7 +161,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
160
161
|
}),
|
|
161
162
|
}),
|
|
162
163
|
];
|
|
163
|
-
// Serve static UI assets if dashboard is enabled (default true)
|
|
164
164
|
imports.push(serve_static_1.ServeStaticModule.forRootAsync({
|
|
165
165
|
imports: options.imports || [],
|
|
166
166
|
inject: [constants_1.TELESCOPE_OPTIONS],
|
|
@@ -178,7 +178,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
178
178
|
];
|
|
179
179
|
},
|
|
180
180
|
}));
|
|
181
|
-
// Register all available/supported watchers & modules dynamically
|
|
182
181
|
this.registerWatchersAndModulesAsync(providers, imports);
|
|
183
182
|
return {
|
|
184
183
|
module: TelescopeModule_1,
|
|
@@ -215,14 +214,13 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
215
214
|
return [];
|
|
216
215
|
}
|
|
217
216
|
static registerWatchersAndModules(options, providers, imports) {
|
|
218
|
-
// 1. Core watchers (always registered if enabled or not specified)
|
|
219
217
|
const coreWatchers = [
|
|
220
218
|
{ type: entry_type_enum_1.EntryType.REQUEST, watcher: http_request_watcher_1.HttpRequestWatcher, isInterceptor: true },
|
|
221
219
|
{ type: entry_type_enum_1.EntryType.QUERY, watcher: query_watcher_1.QueryWatcher },
|
|
222
220
|
{ type: entry_type_enum_1.EntryType.LOG, watcher: log_watcher_1.LogWatcher },
|
|
223
221
|
{ type: entry_type_enum_1.EntryType.EXCEPTION, watcher: exception_watcher_1.ExceptionWatcher, isInterceptor: true },
|
|
222
|
+
{ type: entry_type_enum_1.EntryType.GATE, watcher: gate_watcher_1.GateWatcher, isInterceptor: true },
|
|
224
223
|
{ type: entry_type_enum_1.EntryType.REDIS, watcher: redis_watcher_1.RedisWatcher },
|
|
225
|
-
// New watchers for parity with Laravel Telescope
|
|
226
224
|
{ type: entry_type_enum_1.EntryType.COMMAND, watcher: command_watcher_1.CommandWatcher },
|
|
227
225
|
{ type: entry_type_enum_1.EntryType.MODEL, watcher: model_watcher_1.ModelWatcher },
|
|
228
226
|
{ type: entry_type_enum_1.EntryType.NOTIFICATION, watcher: notification_watcher_1.NotificationWatcher },
|
|
@@ -237,7 +235,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
237
235
|
}
|
|
238
236
|
}
|
|
239
237
|
}
|
|
240
|
-
// Additional optional watchers (non-interceptors)
|
|
241
238
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.HTTP_CLIENT)) {
|
|
242
239
|
providers.push(http_service_watcher_1.HttpServiceWatcher);
|
|
243
240
|
providers.push(http_client_watcher_1.HttpClientWatcher);
|
|
@@ -252,10 +249,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
252
249
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.NOTIFICATION)) {
|
|
253
250
|
providers.push(notification_watcher_1.NotificationWatcher);
|
|
254
251
|
}
|
|
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
252
|
try {
|
|
260
253
|
require('@nestjs/cache-manager');
|
|
261
254
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.CACHE)) {
|
|
@@ -265,7 +258,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
265
258
|
}
|
|
266
259
|
}
|
|
267
260
|
catch (e) { }
|
|
268
|
-
// 3. QueueWatcher
|
|
269
261
|
try {
|
|
270
262
|
require('@nestjs/bullmq');
|
|
271
263
|
require('bullmq');
|
|
@@ -282,7 +274,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
282
274
|
}
|
|
283
275
|
}
|
|
284
276
|
catch (e) { }
|
|
285
|
-
// 4. EventWatcher
|
|
286
277
|
try {
|
|
287
278
|
require('@nestjs/event-emitter');
|
|
288
279
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.EVENT)) {
|
|
@@ -290,7 +281,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
290
281
|
}
|
|
291
282
|
}
|
|
292
283
|
catch (e) { }
|
|
293
|
-
// 5. ScheduleWatcher
|
|
294
284
|
try {
|
|
295
285
|
require('@nestjs/schedule');
|
|
296
286
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.SCHEDULED_TASK)) {
|
|
@@ -298,7 +288,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
298
288
|
}
|
|
299
289
|
}
|
|
300
290
|
catch (e) { }
|
|
301
|
-
// 6. MailWatcher
|
|
302
291
|
try {
|
|
303
292
|
require('nodemailer');
|
|
304
293
|
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.MAIL)) {
|
|
@@ -308,7 +297,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
308
297
|
catch (e) { }
|
|
309
298
|
}
|
|
310
299
|
static registerWatchersAndModulesAsync(providers, imports) {
|
|
311
|
-
// Core interceptors and watchers
|
|
312
300
|
providers.push({ provide: core_1.APP_INTERCEPTOR, useClass: http_request_watcher_1.HttpRequestWatcher });
|
|
313
301
|
providers.push({ provide: core_1.APP_INTERCEPTOR, useClass: exception_watcher_1.ExceptionWatcher });
|
|
314
302
|
providers.push(query_watcher_1.QueryWatcher);
|
|
@@ -320,8 +308,6 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
320
308
|
providers.push(model_watcher_1.ModelWatcher);
|
|
321
309
|
providers.push(model_subscriber_1.ModelSubscriber);
|
|
322
310
|
providers.push(notification_watcher_1.NotificationWatcher);
|
|
323
|
-
providers.push(gate_watcher_1.GateWatcher);
|
|
324
|
-
// Optional modules/watchers if packages are present
|
|
325
311
|
try {
|
|
326
312
|
require('@nestjs/cache-manager');
|
|
327
313
|
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;
|