@ngn-net/nestjs-telescope 0.1.9 → 0.1.11
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/telescope.module.d.ts +2 -0
- package/dist/telescope.module.js +57 -7
- package/dist/telescope.service.d.ts +1 -1
- package/dist/telescope.service.js +36 -34
- package/package.json +24 -23
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,
|
|
@@ -87,17 +98,14 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
87
98
|
];
|
|
88
99
|
// Always registered watchers (no external peer dependencies needed)
|
|
89
100
|
const watchersToRegister = [
|
|
90
|
-
{ type: entry_type_enum_1.EntryType.REQUEST, watcher: http_request_watcher_1.HttpRequestWatcher },
|
|
101
|
+
{ type: entry_type_enum_1.EntryType.REQUEST, watcher: http_request_watcher_1.HttpRequestWatcher, isInterceptor: true },
|
|
91
102
|
{ type: entry_type_enum_1.EntryType.QUERY, watcher: query_watcher_1.QueryWatcher },
|
|
92
103
|
{ type: entry_type_enum_1.EntryType.LOG, watcher: log_watcher_1.LogWatcher },
|
|
93
|
-
{ type: entry_type_enum_1.EntryType.EXCEPTION, watcher: exception_watcher_1.ExceptionWatcher },
|
|
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
|
-
providers.push(item.watcher);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
107
|
+
// Register core watchers
|
|
108
|
+
this.registerWatchers(options, providers);
|
|
101
109
|
// Optional dependencies checking:
|
|
102
110
|
// 1. CacheWatcher (@nestjs/cache-manager)
|
|
103
111
|
let hasCache = false;
|
|
@@ -173,6 +181,10 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
173
181
|
// Dynamic Route Prefix Setup using Reflect metadata on TelescopeController
|
|
174
182
|
const path = options.path || 'telescope';
|
|
175
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
|
+
}
|
|
176
188
|
return {
|
|
177
189
|
module: TelescopeModule_1,
|
|
178
190
|
imports,
|
|
@@ -181,6 +193,44 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
181
193
|
exports: [telescope_service_1.TelescopeService, telescope_repository_service_1.TelescopeRepository],
|
|
182
194
|
};
|
|
183
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
|
+
}
|
|
184
234
|
};
|
|
185
235
|
exports.TelescopeModule = TelescopeModule;
|
|
186
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.11",
|
|
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
|
}
|