@ngn-net/nestjs-telescope 0.1.10 → 0.1.12
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/controllers/telescope.controller.js +1 -1
- package/dist/storage/telescope-repository.service.js +4 -1
- package/dist/telescope.module.d.ts +2 -0
- package/dist/telescope.module.js +55 -13
- package/dist/telescope.service.d.ts +1 -1
- package/dist/telescope.service.js +36 -34
- package/package.json +24 -23
|
@@ -151,7 +151,7 @@ __decorate([
|
|
|
151
151
|
__metadata("design:returntype", void 0)
|
|
152
152
|
], TelescopeController.prototype, "serveDashboard", null);
|
|
153
153
|
__decorate([
|
|
154
|
-
(0, common_1.Get)('*'),
|
|
154
|
+
(0, common_1.Get)('*path'),
|
|
155
155
|
__param(0, (0, common_1.Req)()),
|
|
156
156
|
__param(1, (0, common_1.Res)()),
|
|
157
157
|
__metadata("design:type", Function),
|
|
@@ -78,7 +78,10 @@ let TelescopeRepository = class TelescopeRepository {
|
|
|
78
78
|
return await this.entryRepo.findOne({ where: { uuid } });
|
|
79
79
|
}
|
|
80
80
|
async clearAll() {
|
|
81
|
-
return await this.entryRepo
|
|
81
|
+
return await this.entryRepo
|
|
82
|
+
.createQueryBuilder()
|
|
83
|
+
.delete()
|
|
84
|
+
.execute();
|
|
82
85
|
}
|
|
83
86
|
async countByType() {
|
|
84
87
|
const results = await this.entryRepo
|
package/dist/telescope.module.js
CHANGED
|
@@ -13,6 +13,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
13
13
|
exports.TelescopeModule = void 0;
|
|
14
14
|
// src/telescope.module.ts
|
|
15
15
|
const common_1 = require("@nestjs/common");
|
|
16
|
+
const serve_static_1 = require("@nestjs/serve-static");
|
|
17
|
+
const path_1 = require("path");
|
|
16
18
|
const core_1 = require("@nestjs/core");
|
|
17
19
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
18
20
|
const jwt_1 = require("@nestjs/jwt");
|
|
@@ -76,6 +78,15 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
76
78
|
signOptions: { expiresIn: '1d' },
|
|
77
79
|
}),
|
|
78
80
|
];
|
|
81
|
+
// Serve static UI assets if dashboard is enabled (default true)
|
|
82
|
+
if (options.enableDashboard !== false) {
|
|
83
|
+
const staticPath = (0, path_1.join)(__dirname, '..', 'ui');
|
|
84
|
+
const routePath = options.path || 'telescope';
|
|
85
|
+
imports.push(serve_static_1.ServeStaticModule.forRoot({
|
|
86
|
+
rootPath: staticPath,
|
|
87
|
+
serveRoot: `/${routePath}`,
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
79
90
|
const providers = [
|
|
80
91
|
{
|
|
81
92
|
provide: constants_1.TELESCOPE_OPTIONS,
|
|
@@ -93,19 +104,8 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
93
104
|
{ type: entry_type_enum_1.EntryType.EXCEPTION, watcher: exception_watcher_1.ExceptionWatcher, isInterceptor: true },
|
|
94
105
|
{ type: entry_type_enum_1.EntryType.REDIS, watcher: redis_watcher_1.RedisWatcher },
|
|
95
106
|
];
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (item.isInterceptor) {
|
|
99
|
-
providers.push({
|
|
100
|
-
provide: core_1.APP_INTERCEPTOR,
|
|
101
|
-
useClass: item.watcher,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
providers.push(item.watcher);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
107
|
+
// Register core watchers
|
|
108
|
+
this.registerWatchers(options, providers);
|
|
109
109
|
// Optional dependencies checking:
|
|
110
110
|
// 1. CacheWatcher (@nestjs/cache-manager)
|
|
111
111
|
let hasCache = false;
|
|
@@ -181,6 +181,10 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
181
181
|
// Dynamic Route Prefix Setup using Reflect metadata on TelescopeController
|
|
182
182
|
const path = options.path || 'telescope';
|
|
183
183
|
Reflect.defineMetadata('path', path, telescope_controller_1.TelescopeController);
|
|
184
|
+
// Ensure static assets are served under the same path when dashboard enabled
|
|
185
|
+
if (options.enableDashboard !== false) {
|
|
186
|
+
// ServeStaticModule already handles static files; no extra code needed here.
|
|
187
|
+
}
|
|
184
188
|
return {
|
|
185
189
|
module: TelescopeModule_1,
|
|
186
190
|
imports,
|
|
@@ -189,6 +193,44 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
189
193
|
exports: [telescope_service_1.TelescopeService, telescope_repository_service_1.TelescopeRepository],
|
|
190
194
|
};
|
|
191
195
|
}
|
|
196
|
+
// Helper to register core watchers
|
|
197
|
+
static registerWatchers(options, providers) {
|
|
198
|
+
const watchersToRegister = [
|
|
199
|
+
{ type: entry_type_enum_1.EntryType.REQUEST, watcher: http_request_watcher_1.HttpRequestWatcher, isInterceptor: true },
|
|
200
|
+
{ type: entry_type_enum_1.EntryType.QUERY, watcher: query_watcher_1.QueryWatcher },
|
|
201
|
+
{ type: entry_type_enum_1.EntryType.LOG, watcher: log_watcher_1.LogWatcher },
|
|
202
|
+
{ type: entry_type_enum_1.EntryType.EXCEPTION, watcher: exception_watcher_1.ExceptionWatcher, isInterceptor: true },
|
|
203
|
+
{ type: entry_type_enum_1.EntryType.REDIS, watcher: redis_watcher_1.RedisWatcher },
|
|
204
|
+
];
|
|
205
|
+
for (const item of watchersToRegister) {
|
|
206
|
+
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(item.type)) {
|
|
207
|
+
if (item.isInterceptor) {
|
|
208
|
+
providers.push({ provide: core_1.APP_INTERCEPTOR, useClass: item.watcher });
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
providers.push(item.watcher);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
static forRootAsync(optionsFactory) {
|
|
217
|
+
// Allows async injection of TelescopeOptions (e.g., from ConfigService)
|
|
218
|
+
return {
|
|
219
|
+
module: TelescopeModule_1,
|
|
220
|
+
imports: [
|
|
221
|
+
typeorm_1.TypeOrmModule.forFeature([telescope_entry_entity_1.TelescopeEntry]),
|
|
222
|
+
jwt_1.JwtModule.registerAsync({
|
|
223
|
+
useFactory: async (options) => ({
|
|
224
|
+
secret: options.jwtSecret || process.env.TELESCOPE_JWT_SECRET || constants_1.DEFAULT_JWT_SECRET,
|
|
225
|
+
signOptions: { expiresIn: '1d' },
|
|
226
|
+
}),
|
|
227
|
+
inject: [optionsFactory],
|
|
228
|
+
}),
|
|
229
|
+
],
|
|
230
|
+
providers: [],
|
|
231
|
+
controllers: [telescope_controller_1.TelescopeController],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
192
234
|
};
|
|
193
235
|
exports.TelescopeModule = TelescopeModule;
|
|
194
236
|
exports.TelescopeModule = TelescopeModule = TelescopeModule_1 = __decorate([
|
|
@@ -7,7 +7,7 @@ export declare class TelescopeService implements OnModuleInit {
|
|
|
7
7
|
private readonly repo;
|
|
8
8
|
private readonly options?;
|
|
9
9
|
private lastPruneTime;
|
|
10
|
-
private
|
|
10
|
+
private readonly asyncLocalStorage;
|
|
11
11
|
constructor(repo: TelescopeRepository, options?: TelescopeOptions | undefined);
|
|
12
12
|
onModuleInit(): Promise<void>;
|
|
13
13
|
/**
|
|
@@ -15,13 +15,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.TelescopeService = void 0;
|
|
16
16
|
// src/telescope.service.ts
|
|
17
17
|
const common_1 = require("@nestjs/common");
|
|
18
|
+
const async_hooks_1 = require("async_hooks");
|
|
18
19
|
const telescope_repository_service_1 = require("./storage/telescope-repository.service");
|
|
19
20
|
const constants_1 = require("./constants");
|
|
20
21
|
let TelescopeService = class TelescopeService {
|
|
21
22
|
repo;
|
|
22
23
|
options;
|
|
23
24
|
lastPruneTime = 0;
|
|
24
|
-
|
|
25
|
+
asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
|
|
25
26
|
constructor(repo, options) {
|
|
26
27
|
this.repo = repo;
|
|
27
28
|
this.options = options;
|
|
@@ -42,12 +43,14 @@ let TelescopeService = class TelescopeService {
|
|
|
42
43
|
* Check if a request path should be ignored.
|
|
43
44
|
*/
|
|
44
45
|
shouldIgnorePath(path) {
|
|
45
|
-
if (!path
|
|
46
|
+
if (!path)
|
|
46
47
|
return false;
|
|
47
|
-
const telescopePath = this.options
|
|
48
|
+
const telescopePath = this.options?.path || 'telescope';
|
|
48
49
|
// Always ignore telescope's own routes
|
|
49
50
|
if (path.startsWith(`/${telescopePath}`))
|
|
50
51
|
return true;
|
|
52
|
+
if (!this.options?.ignorePaths)
|
|
53
|
+
return false;
|
|
51
54
|
return this.options.ignorePaths.some((p) => path.startsWith(p));
|
|
52
55
|
}
|
|
53
56
|
/**
|
|
@@ -67,40 +70,39 @@ let TelescopeService = class TelescopeService {
|
|
|
67
70
|
if (!this.isEnabled(entry.type))
|
|
68
71
|
return;
|
|
69
72
|
// Guard against recursive calls (e.g., LogWatcher triggering another record)
|
|
70
|
-
|
|
73
|
+
// using AsyncLocalStorage to avoid blocking concurrent requests
|
|
74
|
+
if (this.asyncLocalStorage.getStore())
|
|
71
75
|
return;
|
|
72
|
-
this.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
76
|
+
await this.asyncLocalStorage.run(true, async () => {
|
|
77
|
+
try {
|
|
78
|
+
const uuidStr = entry.uuid ?? `${Date.now()}-${Math.floor(Math.random() * 1000000)}`;
|
|
79
|
+
const fullEntry = {
|
|
80
|
+
uuid: uuidStr,
|
|
81
|
+
type: entry.type,
|
|
82
|
+
content: entry.content ?? {},
|
|
83
|
+
recordedAt: entry.recordedAt ?? new Date(),
|
|
84
|
+
familyHash: entry.familyHash ?? null,
|
|
85
|
+
batchId: entry.batchId,
|
|
86
|
+
};
|
|
87
|
+
await this.repo.save(fullEntry);
|
|
88
|
+
// Throttled pruning: at most once every PRUNE_THROTTLE_MS
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
if (now - this.lastPruneTime >= constants_1.PRUNE_THROTTLE_MS) {
|
|
91
|
+
this.lastPruneTime = now;
|
|
92
|
+
const maxEntries = this.options?.maxEntries ?? constants_1.DEFAULT_MAX_ENTRIES;
|
|
93
|
+
try {
|
|
94
|
+
await this.repo.prune(maxEntries);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Ignore pruning errors
|
|
98
|
+
}
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
finally {
|
|
102
|
-
this.recording = false;
|
|
103
|
-
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
// Gracefully catch all database/metadata errors to protect host app stability.
|
|
103
|
+
// Avoid using console.log here as it might trigger infinite recursion in LogWatcher.
|
|
104
|
+
}
|
|
105
|
+
});
|
|
104
106
|
}
|
|
105
107
|
};
|
|
106
108
|
exports.TelescopeService = TelescopeService;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngn-net/nestjs-telescope",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -21,25 +21,26 @@
|
|
|
21
21
|
"prepare": "npm run build"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
+
"@nestjs/serve-static": "^5.0.5",
|
|
24
25
|
"class-transformer": "^0.5",
|
|
25
26
|
"class-validator": "^0.14",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
27
|
+
"passport-jwt": "^4",
|
|
28
|
+
"reflect-metadata": "^0.2"
|
|
28
29
|
},
|
|
29
30
|
"peerDependencies": {
|
|
31
|
+
"@nestjs/bullmq": "^11",
|
|
32
|
+
"@nestjs/cache-manager": "^3",
|
|
30
33
|
"@nestjs/common": "^11",
|
|
31
34
|
"@nestjs/core": "^11",
|
|
32
|
-
"@nestjs/
|
|
33
|
-
"typeorm": "^0.3",
|
|
35
|
+
"@nestjs/event-emitter": "^2",
|
|
34
36
|
"@nestjs/jwt": "^11",
|
|
35
37
|
"@nestjs/passport": "^11",
|
|
36
|
-
"@nestjs/
|
|
38
|
+
"@nestjs/schedule": "^4",
|
|
39
|
+
"@nestjs/typeorm": "^11",
|
|
37
40
|
"bullmq": "^5",
|
|
38
|
-
"@nestjs/cache-manager": "^3",
|
|
39
41
|
"cache-manager": "^5",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"nodemailer": "^6"
|
|
42
|
+
"nodemailer": "^6",
|
|
43
|
+
"typeorm": "^0.3"
|
|
43
44
|
},
|
|
44
45
|
"peerDependenciesMeta": {
|
|
45
46
|
"@nestjs/bullmq": {
|
|
@@ -65,26 +66,26 @@
|
|
|
65
66
|
}
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
69
|
+
"@nestjs/bullmq": "^11",
|
|
70
|
+
"@nestjs/cache-manager": "^3",
|
|
68
71
|
"@nestjs/common": "^11",
|
|
69
72
|
"@nestjs/core": "^11",
|
|
70
|
-
"@nestjs/
|
|
71
|
-
"@nestjs/bullmq": "^11",
|
|
73
|
+
"@nestjs/event-emitter": "^2",
|
|
72
74
|
"@nestjs/jwt": "^11",
|
|
73
75
|
"@nestjs/passport": "^11",
|
|
74
|
-
"@nestjs/event-emitter": "^2",
|
|
75
76
|
"@nestjs/schedule": "^4",
|
|
76
|
-
"@nestjs/
|
|
77
|
-
"
|
|
78
|
-
"
|
|
77
|
+
"@nestjs/typeorm": "^11",
|
|
78
|
+
"@types/express": "^4.17.21",
|
|
79
|
+
"@types/jest": "^29",
|
|
80
|
+
"@types/node": "^20",
|
|
81
|
+
"@types/nodemailer": "^6.4.15",
|
|
79
82
|
"jest": "^29",
|
|
80
|
-
"
|
|
81
|
-
"
|
|
83
|
+
"nodemailer": "^6",
|
|
84
|
+
"rimraf": "^5",
|
|
82
85
|
"rxjs": "^7",
|
|
86
|
+
"ts-jest": "^29",
|
|
87
|
+
"ts-node": "^10",
|
|
83
88
|
"typeorm": "^0.3",
|
|
84
|
-
"
|
|
85
|
-
"@types/jest": "^29",
|
|
86
|
-
"@types/node": "^20",
|
|
87
|
-
"@types/express": "^4.17.21",
|
|
88
|
-
"@types/nodemailer": "^6.4.15"
|
|
89
|
+
"typescript": "^5"
|
|
89
90
|
}
|
|
90
91
|
}
|