@geekmidas/telescope 10.0.0-alpha.99 → 10.0.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/CHANGELOG.md +79 -0
- package/README.md +18 -28
- package/dist/InMemoryMetricsStorage-BbKCL3YL.d.mts +47 -0
- package/dist/InMemoryMetricsStorage-BbKCL3YL.d.mts.map +1 -0
- package/dist/InMemoryMetricsStorage-C4drxT7G.mjs +247 -0
- package/dist/InMemoryMetricsStorage-C4drxT7G.mjs.map +1 -0
- package/dist/InMemoryMetricsStorage-D0njWUSi.cjs +252 -0
- package/dist/InMemoryMetricsStorage-D0njWUSi.cjs.map +1 -0
- package/dist/InMemoryMetricsStorage-TvPdZjL0.d.cts +47 -0
- package/dist/InMemoryMetricsStorage-TvPdZjL0.d.cts.map +1 -0
- package/dist/{MetricsAggregator-BJdIvfEv.d.mts → MetricsAggregator-4SqelGcG.d.cts} +6 -3
- package/dist/MetricsAggregator-4SqelGcG.d.cts.map +1 -0
- package/dist/MetricsAggregator-B7lUICdH.cjs +363 -0
- package/dist/MetricsAggregator-B7lUICdH.cjs.map +1 -0
- package/dist/{MetricsAggregator-CnC3oT5q.d.cts → MetricsAggregator-DZrW8ls6.d.mts} +6 -3
- package/dist/MetricsAggregator-DZrW8ls6.d.mts.map +1 -0
- package/dist/MetricsAggregator-S3DQWNas.mjs +357 -0
- package/dist/MetricsAggregator-S3DQWNas.mjs.map +1 -0
- package/dist/MetricsStorage-B86e4131.d.cts +60 -0
- package/dist/MetricsStorage-B86e4131.d.cts.map +1 -0
- package/dist/MetricsStorage-BWyP2_12.d.mts +60 -0
- package/dist/MetricsStorage-BWyP2_12.d.mts.map +1 -0
- package/dist/MetricsStorage-BypQXWiv.mjs +0 -0
- package/dist/MetricsStorage-Or8pVCe4.cjs +0 -0
- package/dist/Telescope-Cs3fv8jt.cjs +395 -0
- package/dist/Telescope-Cs3fv8jt.cjs.map +1 -0
- package/dist/{Telescope-BVfDvVvY.d.mts → Telescope-D4nmwDRA.d.cts} +7 -4
- package/dist/Telescope-D4nmwDRA.d.cts.map +1 -0
- package/dist/Telescope-Dh5av3FC.mjs +389 -0
- package/dist/Telescope-Dh5av3FC.mjs.map +1 -0
- package/dist/{Telescope-DeqSHfuB.d.cts → Telescope-Dl6VSfxd.d.mts} +7 -4
- package/dist/Telescope-Dl6VSfxd.d.mts.map +1 -0
- package/dist/Telescope.cjs +4 -385
- package/dist/Telescope.d.cts +3 -1
- package/dist/Telescope.d.mts +3 -1
- package/dist/Telescope.mjs +4 -384
- package/dist/adapters/index.d.cts +2 -2
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +0 -1
- package/dist/adapters/lambda.cjs +10 -9
- package/dist/adapters/lambda.cjs.map +1 -1
- package/dist/adapters/lambda.d.cts +13 -9
- package/dist/adapters/lambda.d.cts.map +1 -1
- package/dist/adapters/lambda.d.mts +13 -9
- package/dist/adapters/lambda.d.mts.map +1 -1
- package/dist/adapters/lambda.mjs +4 -3
- package/dist/adapters/lambda.mjs.map +1 -1
- package/dist/adapters/middy.cjs +4 -236
- package/dist/adapters/middy.d.cts +5 -60
- package/dist/adapters/middy.d.mts +5 -60
- package/dist/adapters/middy.mjs +3 -234
- package/dist/adapters/types.d.cts +2 -162
- package/dist/adapters/types.d.mts +2 -162
- package/dist/adapters/types.mjs +0 -1
- package/dist/{rolldown-runtime-VH7oDXx4.cjs → chunk-CUT6urMc.cjs} +10 -8
- package/dist/core--quSp5Qr.d.mts +78 -0
- package/dist/core--quSp5Qr.d.mts.map +1 -0
- package/dist/core-B4Jpia5H.d.cts +78 -0
- package/dist/core-B4Jpia5H.d.cts.map +1 -0
- package/dist/core-CtVHRJGv.cjs +199 -0
- package/dist/core-CtVHRJGv.cjs.map +1 -0
- package/dist/core-D6hJ6exL.mjs +139 -0
- package/dist/core-D6hJ6exL.mjs.map +1 -0
- package/dist/core.cjs +22 -22
- package/dist/core.d.cts +4 -4
- package/dist/core.d.mts +4 -4
- package/dist/core.mjs +4 -3
- package/dist/hono--uKQ7Jgi.d.mts +71 -0
- package/dist/hono--uKQ7Jgi.d.mts.map +1 -0
- package/dist/hono-C4EgpbKQ.cjs +160 -0
- package/dist/hono-C4EgpbKQ.cjs.map +1 -0
- package/dist/hono-CemCKU87.d.cts +71 -0
- package/dist/hono-CemCKU87.d.cts.map +1 -0
- package/dist/hono-DxhvnVbF.mjs +136 -0
- package/dist/hono-DxhvnVbF.mjs.map +1 -0
- package/dist/http-BiNtg85L.d.mts +107 -0
- package/dist/http-BiNtg85L.d.mts.map +1 -0
- package/dist/http-DQzgLczm.mjs +159 -0
- package/dist/http-DQzgLczm.mjs.map +1 -0
- package/dist/http-D_Z8sYXZ.cjs +219 -0
- package/dist/http-D_Z8sYXZ.cjs.map +1 -0
- package/dist/http-Dvca6fC3.d.cts +107 -0
- package/dist/http-Dvca6fC3.d.cts.map +1 -0
- package/dist/index-BL32-cvv.d.cts +1 -0
- package/dist/index-CsuikFeJ.d.mts +1 -0
- package/dist/index.cjs +9 -8
- package/dist/index.d.cts +6 -5
- package/dist/index.d.mts +6 -5
- package/dist/index.mjs +7 -5
- package/dist/instrumentation/core.cjs +11 -147
- package/dist/instrumentation/core.d.cts +3 -74
- package/dist/instrumentation/core.d.mts +3 -74
- package/dist/instrumentation/core.mjs +2 -137
- package/dist/instrumentation/hono.cjs +6 -174
- package/dist/instrumentation/hono.d.cts +2 -86
- package/dist/instrumentation/hono.d.mts +2 -86
- package/dist/instrumentation/hono.mjs +3 -170
- package/dist/instrumentation/http.cjs +11 -189
- package/dist/instrumentation/http.d.cts +2 -119
- package/dist/instrumentation/http.d.mts +2 -119
- package/dist/instrumentation/http.mjs +2 -178
- package/dist/instrumentation/index.cjs +47 -56
- package/dist/instrumentation/index.d.cts +9 -11
- package/dist/instrumentation/index.d.mts +9 -11
- package/dist/instrumentation/index.mjs +9 -10
- package/dist/instrumentation/middleware.cjs +6 -164
- package/dist/instrumentation/middleware.d.cts +2 -83
- package/dist/instrumentation/middleware.d.mts +2 -83
- package/dist/instrumentation/middleware.mjs +3 -160
- package/dist/instrumentation/otel.cjs +3 -137
- package/dist/instrumentation/otel.d.cts +2 -97
- package/dist/instrumentation/otel.d.mts +2 -97
- package/dist/instrumentation/otel.mjs +3 -136
- package/dist/instrumentation/setup.cjs +4 -142
- package/dist/instrumentation/setup.d.cts +3 -139
- package/dist/instrumentation/setup.d.mts +3 -139
- package/dist/instrumentation/setup.mjs +3 -139
- package/dist/instrumentation/tracing.cjs +10 -114
- package/dist/instrumentation/tracing.d.cts +2 -49
- package/dist/instrumentation/tracing.d.mts +2 -49
- package/dist/instrumentation/tracing.mjs +2 -105
- package/dist/logger/console.cjs +12 -18
- package/dist/logger/console.cjs.map +1 -1
- package/dist/logger/console.d.cts +10 -7
- package/dist/logger/console.d.cts.map +1 -1
- package/dist/logger/console.d.mts +10 -7
- package/dist/logger/console.d.mts.map +1 -1
- package/dist/logger/console.mjs +11 -17
- package/dist/logger/console.mjs.map +1 -1
- package/dist/logger/pino.cjs +5 -6
- package/dist/logger/pino.cjs.map +1 -1
- package/dist/logger/pino.d.cts +10 -6
- package/dist/logger/pino.d.cts.map +1 -1
- package/dist/logger/pino.d.mts +10 -6
- package/dist/logger/pino.d.mts.map +1 -1
- package/dist/logger/pino.mjs +3 -2
- package/dist/logger/pino.mjs.map +1 -1
- package/dist/memory--BK4iWiv.d.cts +40 -0
- package/dist/memory--BK4iWiv.d.cts.map +1 -0
- package/dist/memory-6S9H-IF5.mjs +123 -0
- package/dist/memory-6S9H-IF5.mjs.map +1 -0
- package/dist/memory-B0d_n1g5.cjs +129 -0
- package/dist/memory-B0d_n1g5.cjs.map +1 -0
- package/dist/memory-DCirEVFW.d.mts +40 -0
- package/dist/memory-DCirEVFW.d.mts.map +1 -0
- package/dist/metrics/MetricsAggregator.cjs +2 -354
- package/dist/metrics/MetricsAggregator.d.cts +2 -1
- package/dist/metrics/MetricsAggregator.d.mts +2 -1
- package/dist/metrics/MetricsAggregator.mjs +2 -353
- package/dist/metrics/index.cjs +4 -3
- package/dist/metrics/index.d.cts +4 -2
- package/dist/metrics/index.d.mts +4 -2
- package/dist/metrics/index.mjs +4 -2
- package/dist/metrics/storage/InMemoryMetricsStorage.cjs +3 -240
- package/dist/metrics/storage/InMemoryMetricsStorage.d.cts +4 -43
- package/dist/metrics/storage/InMemoryMetricsStorage.d.mts +4 -43
- package/dist/metrics/storage/InMemoryMetricsStorage.mjs +3 -239
- package/dist/metrics/storage/MetricsStorage.cjs +1 -0
- package/dist/metrics/storage/MetricsStorage.d.cts +3 -56
- package/dist/metrics/storage/MetricsStorage.d.mts +3 -56
- package/dist/metrics/storage/MetricsStorage.mjs +1 -1
- package/dist/metrics/storage/index.cjs +6 -6
- package/dist/metrics/storage/index.d.cts +3 -3
- package/dist/metrics/storage/index.d.mts +3 -3
- package/dist/metrics/storage/index.mjs +5 -4
- package/dist/metrics/storage/types.cjs +2 -34
- package/dist/metrics/storage/types.d.cts +2 -207
- package/dist/metrics/storage/types.d.mts +2 -207
- package/dist/metrics/storage/types.mjs +2 -33
- package/dist/metrics-D5YT-Rnq.mjs +0 -0
- package/dist/metrics-fhD3l3C3.cjs +0 -0
- package/dist/middleware-B2jFUukM.cjs +184 -0
- package/dist/middleware-B2jFUukM.cjs.map +1 -0
- package/dist/middleware-BTDncHwm.mjs +160 -0
- package/dist/middleware-BTDncHwm.mjs.map +1 -0
- package/dist/middleware-CA84nsNN.d.cts +74 -0
- package/dist/middleware-CA84nsNN.d.cts.map +1 -0
- package/dist/middleware-DAceVpfw.d.mts +74 -0
- package/dist/middleware-DAceVpfw.d.mts.map +1 -0
- package/dist/middy-B6Btl8XE.d.mts +64 -0
- package/dist/middy-B6Btl8XE.d.mts.map +1 -0
- package/dist/middy-BTR3cyvk.mjs +236 -0
- package/dist/middy-BTR3cyvk.mjs.map +1 -0
- package/dist/middy-Bq0defVg.d.cts +64 -0
- package/dist/middy-Bq0defVg.d.cts.map +1 -0
- package/dist/middy-y5Zp27eG.cjs +247 -0
- package/dist/middy-y5Zp27eG.cjs.map +1 -0
- package/dist/otel-1bJPb2Z7.d.mts +101 -0
- package/dist/otel-1bJPb2Z7.d.mts.map +1 -0
- package/dist/otel-C1HqHA2O.cjs +136 -0
- package/dist/otel-C1HqHA2O.cjs.map +1 -0
- package/dist/otel-SBVoVEHr.d.cts +101 -0
- package/dist/otel-SBVoVEHr.d.cts.map +1 -0
- package/dist/otel-wulj5B-X.mjs +130 -0
- package/dist/otel-wulj5B-X.mjs.map +1 -0
- package/dist/otlp/hono.cjs +15 -9
- package/dist/otlp/hono.cjs.map +1 -1
- package/dist/otlp/hono.d.cts +13 -3
- package/dist/otlp/hono.d.cts.map +1 -1
- package/dist/otlp/hono.d.mts +13 -3
- package/dist/otlp/hono.d.mts.map +1 -1
- package/dist/otlp/hono.mjs +11 -5
- package/dist/otlp/hono.mjs.map +1 -1
- package/dist/otlp/index.cjs +11 -11
- package/dist/otlp/index.d.cts +7 -4
- package/dist/otlp/index.d.mts +7 -4
- package/dist/otlp/index.mjs +5 -4
- package/dist/otlp/receiver.cjs +4 -88
- package/dist/otlp/receiver.d.cts +7 -59
- package/dist/otlp/receiver.d.mts +7 -59
- package/dist/otlp/receiver.mjs +4 -87
- package/dist/otlp/transformer.cjs +5 -214
- package/dist/otlp/transformer.d.cts +3 -1
- package/dist/otlp/transformer.d.mts +3 -1
- package/dist/otlp/transformer.mjs +3 -211
- package/dist/otlp/types.cjs +5 -57
- package/dist/otlp/types.d.cts +1 -1
- package/dist/otlp/types.d.mts +1 -1
- package/dist/otlp/types.mjs +2 -53
- package/dist/receiver-Cj1lbAOO.cjs +94 -0
- package/dist/receiver-Cj1lbAOO.cjs.map +1 -0
- package/dist/receiver-CxVd_9CB.mjs +89 -0
- package/dist/receiver-CxVd_9CB.mjs.map +1 -0
- package/dist/receiver-DLICx5uU.d.cts +63 -0
- package/dist/receiver-DLICx5uU.d.cts.map +1 -0
- package/dist/receiver-UeZT-H8u.d.mts +63 -0
- package/dist/receiver-UeZT-H8u.d.mts.map +1 -0
- package/dist/redact-BzkITCNW.mjs +83 -0
- package/dist/redact-BzkITCNW.mjs.map +1 -0
- package/dist/redact-DVaSSPZT.cjs +95 -0
- package/dist/redact-DVaSSPZT.cjs.map +1 -0
- package/dist/redact.cjs +3 -84
- package/dist/redact.d.cts +8 -4
- package/dist/redact.d.cts.map +1 -1
- package/dist/redact.d.mts +8 -4
- package/dist/redact.d.mts.map +1 -1
- package/dist/redact.mjs +2 -80
- package/dist/server/hono.cjs +54 -33
- package/dist/server/hono.cjs.map +1 -1
- package/dist/server/hono.d.cts +14 -19
- package/dist/server/hono.d.cts.map +1 -1
- package/dist/server/hono.d.mts +14 -19
- package/dist/server/hono.d.mts.map +1 -1
- package/dist/server/hono.mjs +52 -31
- package/dist/server/hono.mjs.map +1 -1
- package/dist/setup-B9jM77Qk.mjs +98 -0
- package/dist/setup-B9jM77Qk.mjs.map +1 -0
- package/dist/setup-Bkxm4g6b.d.mts +87 -0
- package/dist/setup-Bkxm4g6b.d.mts.map +1 -0
- package/dist/setup-CYpff5B9.cjs +110 -0
- package/dist/setup-CYpff5B9.cjs.map +1 -0
- package/dist/setup-D58N1f9O.d.cts +87 -0
- package/dist/setup-D58N1f9O.d.cts.map +1 -0
- package/dist/storage/kysely.cjs +70 -82
- package/dist/storage/kysely.cjs.map +1 -1
- package/dist/storage/kysely.d.cts +20 -36
- package/dist/storage/kysely.d.cts.map +1 -1
- package/dist/storage/kysely.d.mts +20 -36
- package/dist/storage/kysely.d.mts.map +1 -1
- package/dist/storage/kysely.mjs +69 -81
- package/dist/storage/kysely.mjs.map +1 -1
- package/dist/storage/memory.cjs +2 -122
- package/dist/storage/memory.d.cts +3 -36
- package/dist/storage/memory.d.mts +3 -36
- package/dist/storage/memory.mjs +2 -121
- package/dist/tracing-BX8uY2nR.d.cts +53 -0
- package/dist/tracing-BX8uY2nR.d.cts.map +1 -0
- package/dist/tracing-Bt1zWRlb.cjs +167 -0
- package/dist/tracing-Bt1zWRlb.cjs.map +1 -0
- package/dist/tracing-Cijm_5NI.mjs +113 -0
- package/dist/tracing-Cijm_5NI.mjs.map +1 -0
- package/dist/tracing-PnECEbEu.d.mts +53 -0
- package/dist/tracing-PnECEbEu.d.mts.map +1 -0
- package/dist/transformer-BXQPhzql.mjs +215 -0
- package/dist/transformer-BXQPhzql.mjs.map +1 -0
- package/dist/transformer-CLGZ0EQc.cjs +232 -0
- package/dist/transformer-CLGZ0EQc.cjs.map +1 -0
- package/dist/{transformer-BtqjAs0b.d.cts → transformer-CTGsaVfV.d.mts} +8 -4
- package/dist/transformer-CTGsaVfV.d.mts.map +1 -0
- package/dist/{transformer-DI6t8-YA.d.mts → transformer-ICEbxpFf.d.cts} +8 -4
- package/dist/transformer-ICEbxpFf.d.cts.map +1 -0
- package/dist/{types-BVujq4zd.d.mts → types-B1EIa_cQ.d.mts} +4 -3
- package/dist/types-B1EIa_cQ.d.mts.map +1 -0
- package/dist/types-BRzW1NM8.d.cts +166 -0
- package/dist/types-BRzW1NM8.d.cts.map +1 -0
- package/dist/types-BS3Rx8Sk.d.cts +209 -0
- package/dist/types-BS3Rx8Sk.d.cts.map +1 -0
- package/dist/types-Bwm_jNU7.mjs +54 -0
- package/dist/types-Bwm_jNU7.mjs.map +1 -0
- package/dist/types-BzQ78Efw.d.mts +166 -0
- package/dist/types-BzQ78Efw.d.mts.map +1 -0
- package/dist/types-CbNGXnJE.d.mts +209 -0
- package/dist/types-CbNGXnJE.d.mts.map +1 -0
- package/dist/{types-DVETVdpa.d.cts → types-CmOB7CLO.d.cts} +7 -6
- package/dist/types-CmOB7CLO.d.cts.map +1 -0
- package/dist/{types-DVETVdpa.d.mts → types-DBc0q5KD.d.mts} +7 -6
- package/dist/types-DBc0q5KD.d.mts.map +1 -0
- package/dist/types-Dsh-DIO_.cjs +78 -0
- package/dist/types-Dsh-DIO_.cjs.map +1 -0
- package/dist/types-ZW-nfWf6.cjs +40 -0
- package/dist/types-ZW-nfWf6.cjs.map +1 -0
- package/dist/{types-BVujq4zd.d.cts → types-l7Rlb5Mg.d.cts} +4 -3
- package/dist/types-l7Rlb5Mg.d.cts.map +1 -0
- package/dist/types-ojhnLdwz.mjs +34 -0
- package/dist/types-ojhnLdwz.mjs.map +1 -0
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +0 -1
- package/dist/ui-assets-BEXqOQLe.cjs +48 -0
- package/dist/ui-assets-BEXqOQLe.cjs.map +1 -0
- package/dist/ui-assets-BhTDUsrM.mjs +30 -0
- package/dist/ui-assets-BhTDUsrM.mjs.map +1 -0
- package/dist/ui-assets.cjs +5 -0
- package/dist/ui-assets.d.cts +13 -0
- package/dist/ui-assets.d.cts.map +1 -0
- package/dist/ui-assets.d.mts +13 -0
- package/dist/ui-assets.d.mts.map +1 -0
- package/dist/ui-assets.mjs +3 -0
- package/package.json +46 -46
- package/src/Telescope.ts +561 -0
- package/src/__tests__/Telescope.spec.ts +438 -0
- package/src/__tests__/pino-transport.spec.ts +115 -0
- package/src/__tests__/redact.spec.ts +336 -0
- package/src/adapters/__tests__/lambda.spec.ts +318 -0
- package/src/adapters/__tests__/middy.spec.ts +741 -0
- package/src/adapters/index.ts +22 -0
- package/src/adapters/lambda.ts +432 -0
- package/src/adapters/middy.ts +402 -0
- package/src/adapters/types.ts +181 -0
- package/src/core.ts +51 -0
- package/src/index.ts +34 -0
- package/src/instrumentation/__tests__/core.spec.ts +248 -0
- package/src/instrumentation/__tests__/hono.spec.ts +348 -0
- package/src/instrumentation/__tests__/middleware.spec.ts +528 -0
- package/src/instrumentation/__tests__/otel.spec.ts +291 -0
- package/src/instrumentation/__tests__/tracing.spec.ts +208 -0
- package/src/instrumentation/core.ts +228 -0
- package/src/instrumentation/hono.ts +270 -0
- package/src/instrumentation/http.ts +306 -0
- package/src/instrumentation/index.ts +90 -0
- package/src/instrumentation/middleware.ts +297 -0
- package/src/instrumentation/otel.ts +271 -0
- package/src/instrumentation/setup.ts +246 -0
- package/src/instrumentation/tracing.ts +145 -0
- package/src/logger/__tests__/console.spec.ts +366 -0
- package/src/logger/__tests__/pino.spec.ts +217 -0
- package/src/logger/console.ts +230 -0
- package/src/logger/pino.ts +201 -0
- package/src/metrics/MetricsAggregator.ts +555 -0
- package/src/metrics/__tests__/MetricsAggregator.spec.ts +298 -0
- package/src/metrics/index.ts +2 -0
- package/src/metrics/storage/InMemoryMetricsStorage.ts +380 -0
- package/src/metrics/storage/MetricsStorage.ts +74 -0
- package/src/metrics/storage/index.ts +3 -0
- package/src/metrics/storage/types.ts +243 -0
- package/src/otlp/__tests__/receiver.spec.ts +367 -0
- package/src/otlp/__tests__/transformer.spec.ts +455 -0
- package/src/otlp/hono.ts +120 -0
- package/src/otlp/index.ts +22 -0
- package/src/otlp/receiver.ts +162 -0
- package/src/otlp/transformer.ts +367 -0
- package/src/otlp/types.ts +364 -0
- package/src/redact.ts +116 -0
- package/src/server/__tests__/hono.spec.ts +814 -0
- package/src/server/hono.ts +442 -0
- package/src/storage/__tests__/kysely.spec.ts +715 -0
- package/src/storage/__tests__/memory.spec.ts +694 -0
- package/src/storage/kysely.ts +599 -0
- package/src/storage/memory.ts +204 -0
- package/src/types.ts +447 -0
- package/src/ui-assets.ts +40 -0
- package/tsconfig.json +9 -0
- package/ui/CHANGELOG.md +7 -0
- package/ui/index.html +12 -0
- package/ui/node_modules/.bin/tsc +21 -0
- package/ui/node_modules/.bin/tsserver +21 -0
- package/ui/node_modules/.bin/vite +21 -0
- package/ui/package.json +24 -0
- package/ui/src/App.tsx +595 -0
- package/ui/src/api.ts +88 -0
- package/ui/src/components/ExceptionDetail.tsx +100 -0
- package/ui/src/components/FilterBar.tsx +162 -0
- package/ui/src/components/LogDetail.tsx +91 -0
- package/ui/src/components/RequestDetail.tsx +143 -0
- package/ui/src/main.tsx +10 -0
- package/ui/src/styles.css +11 -0
- package/ui/src/types.ts +63 -0
- package/ui/src/vite-env.d.ts +1 -0
- package/ui/src/vite-plugin-gkm-config.ts +54 -0
- package/ui/tsconfig.json +20 -0
- package/ui/tsconfig.tsbuildinfo +1 -0
- package/ui/vite.config.ts +13 -0
- package/dist/MetricsAggregator-BJdIvfEv.d.mts.map +0 -1
- package/dist/MetricsAggregator-CnC3oT5q.d.cts.map +0 -1
- package/dist/Telescope-BVfDvVvY.d.mts.map +0 -1
- package/dist/Telescope-DeqSHfuB.d.cts.map +0 -1
- package/dist/Telescope.cjs.map +0 -1
- package/dist/Telescope.mjs.map +0 -1
- package/dist/adapters/middy.cjs.map +0 -1
- package/dist/adapters/middy.d.cts.map +0 -1
- package/dist/adapters/middy.d.mts.map +0 -1
- package/dist/adapters/middy.mjs.map +0 -1
- package/dist/adapters/types.d.cts.map +0 -1
- package/dist/adapters/types.d.mts.map +0 -1
- package/dist/instrumentation/core.cjs.map +0 -1
- package/dist/instrumentation/core.d.cts.map +0 -1
- package/dist/instrumentation/core.d.mts.map +0 -1
- package/dist/instrumentation/core.mjs.map +0 -1
- package/dist/instrumentation/hono.cjs.map +0 -1
- package/dist/instrumentation/hono.d.cts.map +0 -1
- package/dist/instrumentation/hono.d.mts.map +0 -1
- package/dist/instrumentation/hono.mjs.map +0 -1
- package/dist/instrumentation/http.cjs.map +0 -1
- package/dist/instrumentation/http.d.cts.map +0 -1
- package/dist/instrumentation/http.d.mts.map +0 -1
- package/dist/instrumentation/http.mjs.map +0 -1
- package/dist/instrumentation/middleware.cjs.map +0 -1
- package/dist/instrumentation/middleware.d.cts.map +0 -1
- package/dist/instrumentation/middleware.d.mts.map +0 -1
- package/dist/instrumentation/middleware.mjs.map +0 -1
- package/dist/instrumentation/otel.cjs.map +0 -1
- package/dist/instrumentation/otel.d.cts.map +0 -1
- package/dist/instrumentation/otel.d.mts.map +0 -1
- package/dist/instrumentation/otel.mjs.map +0 -1
- package/dist/instrumentation/sampler.cjs +0 -54
- package/dist/instrumentation/sampler.cjs.map +0 -1
- package/dist/instrumentation/sampler.d.cts +0 -38
- package/dist/instrumentation/sampler.d.cts.map +0 -1
- package/dist/instrumentation/sampler.d.mts +0 -38
- package/dist/instrumentation/sampler.d.mts.map +0 -1
- package/dist/instrumentation/sampler.mjs +0 -52
- package/dist/instrumentation/sampler.mjs.map +0 -1
- package/dist/instrumentation/setup.cjs.map +0 -1
- package/dist/instrumentation/setup.d.cts.map +0 -1
- package/dist/instrumentation/setup.d.mts.map +0 -1
- package/dist/instrumentation/setup.mjs.map +0 -1
- package/dist/instrumentation/tracing.cjs.map +0 -1
- package/dist/instrumentation/tracing.d.cts.map +0 -1
- package/dist/instrumentation/tracing.d.mts.map +0 -1
- package/dist/instrumentation/tracing.mjs.map +0 -1
- package/dist/instrumentation/trust.cjs +0 -107
- package/dist/instrumentation/trust.cjs.map +0 -1
- package/dist/instrumentation/trust.d.cts +0 -57
- package/dist/instrumentation/trust.d.cts.map +0 -1
- package/dist/instrumentation/trust.d.mts +0 -57
- package/dist/instrumentation/trust.d.mts.map +0 -1
- package/dist/instrumentation/trust.mjs +0 -104
- package/dist/instrumentation/trust.mjs.map +0 -1
- package/dist/metrics/MetricsAggregator.cjs.map +0 -1
- package/dist/metrics/MetricsAggregator.mjs.map +0 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.cjs.map +0 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.d.cts.map +0 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.d.mts.map +0 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.mjs.map +0 -1
- package/dist/metrics/storage/MetricsStorage.d.cts.map +0 -1
- package/dist/metrics/storage/MetricsStorage.d.mts.map +0 -1
- package/dist/metrics/storage/types.cjs.map +0 -1
- package/dist/metrics/storage/types.d.cts.map +0 -1
- package/dist/metrics/storage/types.d.mts.map +0 -1
- package/dist/metrics/storage/types.mjs.map +0 -1
- package/dist/otlp/receiver.cjs.map +0 -1
- package/dist/otlp/receiver.d.cts.map +0 -1
- package/dist/otlp/receiver.d.mts.map +0 -1
- package/dist/otlp/receiver.mjs.map +0 -1
- package/dist/otlp/transformer.cjs.map +0 -1
- package/dist/otlp/transformer.mjs.map +0 -1
- package/dist/otlp/types.cjs.map +0 -1
- package/dist/otlp/types.mjs.map +0 -1
- package/dist/redact.cjs.map +0 -1
- package/dist/redact.mjs.map +0 -1
- package/dist/storage/memory.cjs.map +0 -1
- package/dist/storage/memory.d.cts.map +0 -1
- package/dist/storage/memory.d.mts.map +0 -1
- package/dist/storage/memory.mjs.map +0 -1
- package/dist/transformer-BtqjAs0b.d.cts.map +0 -1
- package/dist/transformer-DI6t8-YA.d.mts.map +0 -1
- package/dist/types-BVujq4zd.d.cts.map +0 -1
- package/dist/types-BVujq4zd.d.mts.map +0 -1
- package/dist/types-DVETVdpa.d.cts.map +0 -1
- package/dist/types-DVETVdpa.d.mts.map +0 -1
package/dist/storage/kysely.mjs
CHANGED
|
@@ -22,20 +22,15 @@
|
|
|
22
22
|
*/
|
|
23
23
|
var KyselyStorage = class {
|
|
24
24
|
db;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* These were `telescope_requests`, `telescope_exceptions` and
|
|
29
|
-
* `telescope_logs` — a prefix, which is what you reach for when the tables
|
|
30
|
-
* have to share a schema with an application's own. They do not: a telescope
|
|
31
|
-
* derived from a database is a schema tenant, so the names are just the
|
|
32
|
-
* names, and `DROP SCHEMA telescope CASCADE` is the whole cleanup.
|
|
33
|
-
*/
|
|
34
|
-
requestsTable = "requests";
|
|
35
|
-
exceptionsTable = "exceptions";
|
|
36
|
-
logsTable = "logs";
|
|
25
|
+
requestsTable;
|
|
26
|
+
exceptionsTable;
|
|
27
|
+
logsTable;
|
|
37
28
|
constructor(config) {
|
|
38
|
-
this.db = config.
|
|
29
|
+
this.db = config.db;
|
|
30
|
+
const prefix = config.tablePrefix ?? "telescope";
|
|
31
|
+
this.requestsTable = `${prefix}_requests`;
|
|
32
|
+
this.exceptionsTable = `${prefix}_exceptions`;
|
|
33
|
+
this.logsTable = `${prefix}_logs`;
|
|
39
34
|
}
|
|
40
35
|
async saveRequest(entry) {
|
|
41
36
|
const row = this.requestToRow(entry);
|
|
@@ -54,14 +49,16 @@ var KyselyStorage = class {
|
|
|
54
49
|
if (statusFilter.endsWith("xx")) {
|
|
55
50
|
const firstChar = statusFilter[0];
|
|
56
51
|
if (firstChar) {
|
|
57
|
-
const
|
|
52
|
+
const category = parseInt(firstChar, 10);
|
|
53
|
+
const minStatus = category * 100;
|
|
58
54
|
const maxStatus = minStatus + 99;
|
|
59
55
|
query = query.where("status", ">=", minStatus).where("status", "<=", maxStatus);
|
|
60
56
|
}
|
|
61
57
|
} else query = query.where("status", "=", parseInt(statusFilter, 10));
|
|
62
58
|
}
|
|
63
|
-
query = this.applyQueryOptions(query, options
|
|
64
|
-
|
|
59
|
+
query = this.applyQueryOptions(query, options);
|
|
60
|
+
const rows = await query.execute();
|
|
61
|
+
return rows.map((row) => this.rowToRequest(row));
|
|
65
62
|
}
|
|
66
63
|
async getRequest(id) {
|
|
67
64
|
const row = await this.db.selectFrom(this.requestsTable).selectAll().where("id", "=", id).executeTakeFirst();
|
|
@@ -78,8 +75,9 @@ var KyselyStorage = class {
|
|
|
78
75
|
}
|
|
79
76
|
async getExceptions(options) {
|
|
80
77
|
let query = this.db.selectFrom(this.exceptionsTable).selectAll().orderBy("timestamp", "desc");
|
|
81
|
-
query = this.applyQueryOptions(query, options
|
|
82
|
-
|
|
78
|
+
query = this.applyQueryOptions(query, options);
|
|
79
|
+
const rows = await query.execute();
|
|
80
|
+
return rows.map((row) => this.rowToException(row));
|
|
83
81
|
}
|
|
84
82
|
async getException(id) {
|
|
85
83
|
const row = await this.db.selectFrom(this.exceptionsTable).selectAll().where("id", "=", id).executeTakeFirst();
|
|
@@ -97,15 +95,17 @@ var KyselyStorage = class {
|
|
|
97
95
|
async getLogs(options) {
|
|
98
96
|
let query = this.db.selectFrom(this.logsTable).selectAll().orderBy("timestamp", "desc");
|
|
99
97
|
if (options?.level) query = query.where("level", "=", options.level);
|
|
100
|
-
query = this.applyQueryOptions(query, options
|
|
101
|
-
|
|
98
|
+
query = this.applyQueryOptions(query, options);
|
|
99
|
+
const rows = await query.execute();
|
|
100
|
+
return rows.map((row) => this.rowToLog(row));
|
|
102
101
|
}
|
|
103
102
|
async prune(olderThan) {
|
|
104
|
-
|
|
103
|
+
const results = await Promise.all([
|
|
105
104
|
this.db.deleteFrom(this.requestsTable).where("timestamp", "<", olderThan).executeTakeFirst(),
|
|
106
105
|
this.db.deleteFrom(this.exceptionsTable).where("timestamp", "<", olderThan).executeTakeFirst(),
|
|
107
106
|
this.db.deleteFrom(this.logsTable).where("timestamp", "<", olderThan).executeTakeFirst()
|
|
108
|
-
])
|
|
107
|
+
]);
|
|
108
|
+
return results.reduce((sum, result) => sum + Number(result.numDeletedRows ?? 0), 0);
|
|
109
109
|
}
|
|
110
110
|
async getStats() {
|
|
111
111
|
const [requestsResult, exceptionsResult, logsResult] = await Promise.all([
|
|
@@ -142,11 +142,15 @@ var KyselyStorage = class {
|
|
|
142
142
|
newestEntry: newestDate ? new Date(newestDate) : void 0
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
|
-
applyQueryOptions(query, options
|
|
145
|
+
applyQueryOptions(query, options) {
|
|
146
146
|
if (!options) return query.limit(50);
|
|
147
147
|
if (options.after) query = query.where("timestamp", ">=", options.after);
|
|
148
148
|
if (options.before) query = query.where("timestamp", "<=", options.before);
|
|
149
|
-
if (options.search) query = query.where((eb) => eb.or(
|
|
149
|
+
if (options.search) query = query.where((eb) => eb.or([
|
|
150
|
+
eb("message", "ilike", `%${options.search}%`),
|
|
151
|
+
eb("path", "ilike", `%${options.search}%`),
|
|
152
|
+
eb("url", "ilike", `%${options.search}%`)
|
|
153
|
+
]));
|
|
150
154
|
const limit = options.limit ?? 50;
|
|
151
155
|
const offset = options.offset ?? 0;
|
|
152
156
|
return query.limit(limit).offset(offset);
|
|
@@ -157,17 +161,17 @@ var KyselyStorage = class {
|
|
|
157
161
|
method: entry.method,
|
|
158
162
|
path: entry.path,
|
|
159
163
|
url: entry.url,
|
|
160
|
-
headers:
|
|
161
|
-
body:
|
|
162
|
-
query:
|
|
164
|
+
headers: entry.headers,
|
|
165
|
+
body: entry.body ?? null,
|
|
166
|
+
query: entry.query ?? null,
|
|
163
167
|
status: entry.status,
|
|
164
|
-
response_headers:
|
|
165
|
-
response_body:
|
|
168
|
+
response_headers: entry.responseHeaders,
|
|
169
|
+
response_body: entry.responseBody ?? null,
|
|
166
170
|
duration: entry.duration,
|
|
167
171
|
timestamp: entry.timestamp,
|
|
168
172
|
ip: entry.ip ?? null,
|
|
169
173
|
user_id: entry.userId ?? null,
|
|
170
|
-
tags:
|
|
174
|
+
tags: entry.tags ?? null
|
|
171
175
|
};
|
|
172
176
|
}
|
|
173
177
|
rowToRequest(row) {
|
|
@@ -194,12 +198,12 @@ var KyselyStorage = class {
|
|
|
194
198
|
id: entry.id,
|
|
195
199
|
name: entry.name,
|
|
196
200
|
message: entry.message,
|
|
197
|
-
stack:
|
|
198
|
-
source:
|
|
201
|
+
stack: entry.stack,
|
|
202
|
+
source: entry.source ?? null,
|
|
199
203
|
request_id: entry.requestId ?? null,
|
|
200
204
|
timestamp: entry.timestamp,
|
|
201
205
|
handled: entry.handled,
|
|
202
|
-
tags:
|
|
206
|
+
tags: entry.tags ?? null
|
|
203
207
|
};
|
|
204
208
|
}
|
|
205
209
|
rowToException(row) {
|
|
@@ -220,7 +224,7 @@ var KyselyStorage = class {
|
|
|
220
224
|
id: entry.id,
|
|
221
225
|
level: entry.level,
|
|
222
226
|
message: entry.message,
|
|
223
|
-
context:
|
|
227
|
+
context: entry.context ?? null,
|
|
224
228
|
request_id: entry.requestId ?? null,
|
|
225
229
|
timestamp: entry.timestamp
|
|
226
230
|
};
|
|
@@ -249,22 +253,8 @@ var KyselyStorage = class {
|
|
|
249
253
|
}
|
|
250
254
|
};
|
|
251
255
|
/**
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
* Handed an object, node-postgres writes JSON; handed an array it writes a
|
|
255
|
-
* Postgres array literal (`{1,2}`), which a `jsonb` column rejects — so every
|
|
256
|
-
* exception (its stack is an array) failed to save. Serialising here makes
|
|
257
|
-
* the column's type the only thing that decides.
|
|
258
|
-
*/
|
|
259
|
-
function toJson(value) {
|
|
260
|
-
return value === void 0 || value === null ? null : JSON.stringify(value);
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* SQL migration to create telescope's tables.
|
|
264
|
-
*
|
|
265
|
-
* Pass a schema to have them created in one, and to have `down` drop the whole
|
|
266
|
-
* schema rather than three tables. Pass nothing where the connection's
|
|
267
|
-
* `search_path` already places them.
|
|
256
|
+
* SQL migration to create telescope tables.
|
|
257
|
+
* Use this to set up the required tables in your database.
|
|
268
258
|
*
|
|
269
259
|
* @example
|
|
270
260
|
* ```typescript
|
|
@@ -282,13 +272,11 @@ function toJson(value) {
|
|
|
282
272
|
* }
|
|
283
273
|
* ```
|
|
284
274
|
*/
|
|
285
|
-
function getTelescopeMigration(
|
|
286
|
-
const q = (name) => schema ? `${schema}.${name}` : name;
|
|
287
|
-
const idx = (name) => schema ? `${schema}_${name}` : name;
|
|
275
|
+
function getTelescopeMigration(tablePrefix = "telescope") {
|
|
288
276
|
return {
|
|
289
|
-
up:
|
|
290
|
-
-- Telescope requests
|
|
291
|
-
CREATE TABLE IF NOT EXISTS ${
|
|
277
|
+
up: `
|
|
278
|
+
-- Telescope requests table
|
|
279
|
+
CREATE TABLE IF NOT EXISTS ${tablePrefix}_requests (
|
|
292
280
|
id VARCHAR(21) PRIMARY KEY,
|
|
293
281
|
method VARCHAR(10) NOT NULL,
|
|
294
282
|
path TEXT NOT NULL,
|
|
@@ -306,15 +294,15 @@ CREATE TABLE IF NOT EXISTS ${q("requests")} (
|
|
|
306
294
|
tags JSONB
|
|
307
295
|
);
|
|
308
296
|
|
|
309
|
-
CREATE INDEX IF NOT EXISTS idx_${
|
|
310
|
-
ON ${
|
|
311
|
-
CREATE INDEX IF NOT EXISTS idx_${
|
|
312
|
-
ON ${
|
|
313
|
-
CREATE INDEX IF NOT EXISTS idx_${
|
|
314
|
-
ON ${
|
|
297
|
+
CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_requests_timestamp
|
|
298
|
+
ON ${tablePrefix}_requests (timestamp DESC);
|
|
299
|
+
CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_requests_path
|
|
300
|
+
ON ${tablePrefix}_requests (path);
|
|
301
|
+
CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_requests_status
|
|
302
|
+
ON ${tablePrefix}_requests (status);
|
|
315
303
|
|
|
316
|
-
-- Telescope exceptions
|
|
317
|
-
CREATE TABLE IF NOT EXISTS ${
|
|
304
|
+
-- Telescope exceptions table
|
|
305
|
+
CREATE TABLE IF NOT EXISTS ${tablePrefix}_exceptions (
|
|
318
306
|
id VARCHAR(21) PRIMARY KEY,
|
|
319
307
|
name VARCHAR(255) NOT NULL,
|
|
320
308
|
message TEXT NOT NULL,
|
|
@@ -326,13 +314,13 @@ CREATE TABLE IF NOT EXISTS ${q("exceptions")} (
|
|
|
326
314
|
tags JSONB
|
|
327
315
|
);
|
|
328
316
|
|
|
329
|
-
CREATE INDEX IF NOT EXISTS idx_${
|
|
330
|
-
ON ${
|
|
331
|
-
CREATE INDEX IF NOT EXISTS idx_${
|
|
332
|
-
ON ${
|
|
317
|
+
CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_exceptions_timestamp
|
|
318
|
+
ON ${tablePrefix}_exceptions (timestamp DESC);
|
|
319
|
+
CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_exceptions_request_id
|
|
320
|
+
ON ${tablePrefix}_exceptions (request_id);
|
|
333
321
|
|
|
334
|
-
-- Telescope logs
|
|
335
|
-
CREATE TABLE IF NOT EXISTS ${
|
|
322
|
+
-- Telescope logs table
|
|
323
|
+
CREATE TABLE IF NOT EXISTS ${tablePrefix}_logs (
|
|
336
324
|
id VARCHAR(21) PRIMARY KEY,
|
|
337
325
|
level VARCHAR(10) NOT NULL,
|
|
338
326
|
message TEXT NOT NULL,
|
|
@@ -341,21 +329,21 @@ CREATE TABLE IF NOT EXISTS ${q("logs")} (
|
|
|
341
329
|
timestamp TIMESTAMPTZ NOT NULL
|
|
342
330
|
);
|
|
343
331
|
|
|
344
|
-
CREATE INDEX IF NOT EXISTS idx_${
|
|
345
|
-
ON ${
|
|
346
|
-
CREATE INDEX IF NOT EXISTS idx_${
|
|
347
|
-
ON ${
|
|
348
|
-
CREATE INDEX IF NOT EXISTS idx_${
|
|
349
|
-
ON ${
|
|
332
|
+
CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_logs_timestamp
|
|
333
|
+
ON ${tablePrefix}_logs (timestamp DESC);
|
|
334
|
+
CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_logs_level
|
|
335
|
+
ON ${tablePrefix}_logs (level);
|
|
336
|
+
CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_logs_request_id
|
|
337
|
+
ON ${tablePrefix}_logs (request_id);
|
|
350
338
|
`,
|
|
351
|
-
down:
|
|
352
|
-
DROP TABLE IF EXISTS
|
|
353
|
-
DROP TABLE IF EXISTS
|
|
354
|
-
DROP TABLE IF EXISTS
|
|
339
|
+
down: `
|
|
340
|
+
DROP TABLE IF EXISTS ${tablePrefix}_logs;
|
|
341
|
+
DROP TABLE IF EXISTS ${tablePrefix}_exceptions;
|
|
342
|
+
DROP TABLE IF EXISTS ${tablePrefix}_requests;
|
|
355
343
|
`
|
|
356
344
|
};
|
|
357
345
|
}
|
|
346
|
+
|
|
358
347
|
//#endregion
|
|
359
348
|
export { KyselyStorage, getTelescopeMigration };
|
|
360
|
-
|
|
361
349
|
//# sourceMappingURL=kysely.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kysely.mjs","names":[],"sources":["../../src/storage/kysely.ts"],"sourcesContent":["import type { Kysely } from 'kysely';\nimport type {\n\tExceptionEntry,\n\tLogEntry,\n\tQueryOptions,\n\tRequestEntry,\n\tTelescopeStats,\n\tTelescopeStorage,\n} from '../types';\n\n/**\n * Database table interface for telescope requests.\n * Use this to define your telescope_requests table in your Kysely database schema.\n */\nexport interface TelescopeRequestTable {\n\tid: string;\n\tmethod: string;\n\tpath: string;\n\turl: string;\n\theaders: unknown;\n\tbody: unknown | null;\n\tquery: unknown | null;\n\tstatus: number;\n\tresponse_headers: unknown;\n\tresponse_body: unknown | null;\n\tduration: number;\n\ttimestamp: Date;\n\tip: string | null;\n\tuser_id: string | null;\n\ttags: unknown | null;\n}\n\n/**\n * Database table interface for telescope exceptions.\n */\nexport interface TelescopeExceptionTable {\n\tid: string;\n\tname: string;\n\tmessage: string;\n\tstack: unknown;\n\tsource: unknown | null;\n\trequest_id: string | null;\n\ttimestamp: Date;\n\thandled: boolean;\n\ttags: unknown | null;\n}\n\n/**\n * Database table interface for telescope logs.\n */\nexport interface TelescopeLogTable {\n\tid: string;\n\tlevel: string;\n\tmessage: string;\n\tcontext: unknown | null;\n\trequest_id: string | null;\n\ttimestamp: Date;\n}\n\n/**\n * Combined database interface for all telescope tables.\n * Use this to extend your database schema.\n *\n * @example\n * ```typescript\n * import type { TelescopeTables } from '@geekmidas/telescope/storage/kysely';\n *\n * interface Database extends TelescopeTables {\n * users: UserTable;\n * // ... other tables\n * }\n * ```\n */\nexport interface TelescopeTables {\n\trequests: TelescopeRequestTable;\n\texceptions: TelescopeExceptionTable;\n\tlogs: TelescopeLogTable;\n}\n\n/**\n * Configuration for KyselyStorage.\n */\nexport interface KyselyStorageConfig<DB> {\n\t/** Kysely database instance */\n\tdb: Kysely<DB>;\n\t/**\n\t * The schema holding `requests`, `exceptions` and `logs`.\n\t *\n\t * Normally omitted. A telescope derived from a database gets a schema of its\n\t * own and a role whose `search_path` is pinned to it, so an unqualified name\n\t * already resolves there — which is the same rule every other tenant here\n\t * follows, and the reason a connection string never has to remember where\n\t * its tables live.\n\t *\n\t * Name one only when the connection is *not* pinned: a shared pool, a\n\t * migration run as an owner whose `search_path` finds `public` first.\n\t */\n\tschema?: string;\n}\n\n/**\n * Kysely-based storage implementation for Telescope.\n * Stores telescope data in PostgreSQL, MySQL, or SQLite using Kysely.\n *\n * @template DB - Your Kysely database schema (must include TelescopeTables)\n *\n * @example\n * ```typescript\n * import { Kysely, PostgresDialect } from 'kysely';\n * import { KyselyStorage, type TelescopeTables } from '@geekmidas/telescope/storage/kysely';\n *\n * interface Database extends TelescopeTables {\n * users: UserTable;\n * }\n *\n * const db = new Kysely<Database>({ dialect: new PostgresDialect({ pool }) });\n * const storage = new KyselyStorage({ db });\n *\n * const telescope = new Telescope({ storage });\n * ```\n */\nexport class KyselyStorage<DB> implements TelescopeStorage {\n\tprivate readonly db: Kysely<DB>;\n\n\t/**\n\t * Unqualified, and deliberately.\n\t *\n\t * These were `telescope_requests`, `telescope_exceptions` and\n\t * `telescope_logs` — a prefix, which is what you reach for when the tables\n\t * have to share a schema with an application's own. They do not: a telescope\n\t * derived from a database is a schema tenant, so the names are just the\n\t * names, and `DROP SCHEMA telescope CASCADE` is the whole cleanup.\n\t */\n\tprivate readonly requestsTable = 'requests';\n\tprivate readonly exceptionsTable = 'exceptions';\n\tprivate readonly logsTable = 'logs';\n\n\tconstructor(config: KyselyStorageConfig<DB>) {\n\t\t// `withSchema` only where the connection is not already pinned to one.\n\t\tthis.db = config.schema\n\t\t\t? (config.db.withSchema(config.schema) as Kysely<DB>)\n\t\t\t: config.db;\n\t}\n\n\t// ============================================\n\t// Requests\n\t// ============================================\n\n\tasync saveRequest(entry: RequestEntry): Promise<void> {\n\t\tconst row = this.requestToRow(entry);\n\t\tawait (this.db as any).insertInto(this.requestsTable).values(row).execute();\n\t}\n\n\tasync saveRequests(entries: RequestEntry[]): Promise<void> {\n\t\tif (entries.length === 0) return;\n\n\t\tconst rows = entries.map((e) => this.requestToRow(e));\n\t\tawait (this.db as any)\n\t\t\t.insertInto(this.requestsTable)\n\t\t\t.values(rows)\n\t\t\t.execute();\n\t}\n\n\tasync getRequests(options?: QueryOptions): Promise<RequestEntry[]> {\n\t\tlet query = (this.db as any)\n\t\t\t.selectFrom(this.requestsTable)\n\t\t\t.selectAll()\n\t\t\t.orderBy('timestamp', 'desc');\n\n\t\t// Apply request-specific filters\n\t\tif (options?.method) {\n\t\t\tquery = query.where('method', '=', options.method);\n\t\t}\n\n\t\tif (options?.status) {\n\t\t\tconst statusFilter = options.status;\n\t\t\tif (statusFilter.endsWith('xx')) {\n\t\t\t\t// Handle status ranges like \"2xx\", \"4xx\", \"5xx\"\n\t\t\t\tconst firstChar = statusFilter[0];\n\t\t\t\tif (firstChar) {\n\t\t\t\t\tconst category = parseInt(firstChar, 10);\n\t\t\t\t\tconst minStatus = category * 100;\n\t\t\t\t\tconst maxStatus = minStatus + 99;\n\t\t\t\t\tquery = query\n\t\t\t\t\t\t.where('status', '>=', minStatus)\n\t\t\t\t\t\t.where('status', '<=', maxStatus);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Handle exact status codes\n\t\t\t\tquery = query.where('status', '=', parseInt(statusFilter, 10));\n\t\t\t}\n\t\t}\n\n\t\tquery = this.applyQueryOptions(query, options, ['path', 'url']);\n\n\t\tconst rows = await query.execute();\n\t\treturn rows.map((row: TelescopeRequestTable) => this.rowToRequest(row));\n\t}\n\n\tasync getRequest(id: string): Promise<RequestEntry | null> {\n\t\tconst row = await (this.db as any)\n\t\t\t.selectFrom(this.requestsTable)\n\t\t\t.selectAll()\n\t\t\t.where('id', '=', id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToRequest(row) : null;\n\t}\n\n\t// ============================================\n\t// Exceptions\n\t// ============================================\n\n\tasync saveException(entry: ExceptionEntry): Promise<void> {\n\t\tconst row = this.exceptionToRow(entry);\n\t\tawait (this.db as any)\n\t\t\t.insertInto(this.exceptionsTable)\n\t\t\t.values(row)\n\t\t\t.execute();\n\t}\n\n\tasync saveExceptions(entries: ExceptionEntry[]): Promise<void> {\n\t\tif (entries.length === 0) return;\n\n\t\tconst rows = entries.map((e) => this.exceptionToRow(e));\n\t\tawait (this.db as any)\n\t\t\t.insertInto(this.exceptionsTable)\n\t\t\t.values(rows)\n\t\t\t.execute();\n\t}\n\n\tasync getExceptions(options?: QueryOptions): Promise<ExceptionEntry[]> {\n\t\tlet query = (this.db as any)\n\t\t\t.selectFrom(this.exceptionsTable)\n\t\t\t.selectAll()\n\t\t\t.orderBy('timestamp', 'desc');\n\n\t\tquery = this.applyQueryOptions(query, options, ['name', 'message']);\n\n\t\tconst rows = await query.execute();\n\t\treturn rows.map((row: TelescopeExceptionTable) => this.rowToException(row));\n\t}\n\n\tasync getException(id: string): Promise<ExceptionEntry | null> {\n\t\tconst row = await (this.db as any)\n\t\t\t.selectFrom(this.exceptionsTable)\n\t\t\t.selectAll()\n\t\t\t.where('id', '=', id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToException(row) : null;\n\t}\n\n\t// ============================================\n\t// Logs\n\t// ============================================\n\n\tasync saveLog(entry: LogEntry): Promise<void> {\n\t\tconst row = this.logToRow(entry);\n\t\tawait (this.db as any).insertInto(this.logsTable).values(row).execute();\n\t}\n\n\tasync saveLogs(entries: LogEntry[]): Promise<void> {\n\t\tif (entries.length === 0) return;\n\n\t\tconst rows = entries.map((e) => this.logToRow(e));\n\t\tawait (this.db as any).insertInto(this.logsTable).values(rows).execute();\n\t}\n\n\tasync getLogs(options?: QueryOptions): Promise<LogEntry[]> {\n\t\tlet query = (this.db as any)\n\t\t\t.selectFrom(this.logsTable)\n\t\t\t.selectAll()\n\t\t\t.orderBy('timestamp', 'desc');\n\n\t\t// Apply log-specific filters\n\t\tif (options?.level) {\n\t\t\tquery = query.where('level', '=', options.level);\n\t\t}\n\n\t\tquery = this.applyQueryOptions(query, options, ['message']);\n\n\t\tconst rows = await query.execute();\n\t\treturn rows.map((row: TelescopeLogTable) => this.rowToLog(row));\n\t}\n\n\t// ============================================\n\t// Cleanup\n\t// ============================================\n\n\tasync prune(olderThan: Date): Promise<number> {\n\t\tconst results = await Promise.all([\n\t\t\t(this.db as any)\n\t\t\t\t.deleteFrom(this.requestsTable)\n\t\t\t\t.where('timestamp', '<', olderThan)\n\t\t\t\t.executeTakeFirst(),\n\t\t\t(this.db as any)\n\t\t\t\t.deleteFrom(this.exceptionsTable)\n\t\t\t\t.where('timestamp', '<', olderThan)\n\t\t\t\t.executeTakeFirst(),\n\t\t\t(this.db as any)\n\t\t\t\t.deleteFrom(this.logsTable)\n\t\t\t\t.where('timestamp', '<', olderThan)\n\t\t\t\t.executeTakeFirst(),\n\t\t]);\n\n\t\treturn results.reduce(\n\t\t\t(sum, result) => sum + Number(result.numDeletedRows ?? 0),\n\t\t\t0,\n\t\t);\n\t}\n\n\t// ============================================\n\t// Stats\n\t// ============================================\n\n\tasync getStats(): Promise<TelescopeStats> {\n\t\tconst [requestsResult, exceptionsResult, logsResult] = await Promise.all([\n\t\t\t(this.db as any)\n\t\t\t\t.selectFrom(this.requestsTable)\n\t\t\t\t.select((eb: any) => [\n\t\t\t\t\teb.fn.count('id').as('count'),\n\t\t\t\t\teb.fn.min('timestamp').as('oldest'),\n\t\t\t\t\teb.fn.max('timestamp').as('newest'),\n\t\t\t\t])\n\t\t\t\t.executeTakeFirst(),\n\t\t\t(this.db as any)\n\t\t\t\t.selectFrom(this.exceptionsTable)\n\t\t\t\t.select((eb: any) => [\n\t\t\t\t\teb.fn.count('id').as('count'),\n\t\t\t\t\teb.fn.min('timestamp').as('oldest'),\n\t\t\t\t\teb.fn.max('timestamp').as('newest'),\n\t\t\t\t])\n\t\t\t\t.executeTakeFirst(),\n\t\t\t(this.db as any)\n\t\t\t\t.selectFrom(this.logsTable)\n\t\t\t\t.select((eb: any) => [\n\t\t\t\t\teb.fn.count('id').as('count'),\n\t\t\t\t\teb.fn.min('timestamp').as('oldest'),\n\t\t\t\t\teb.fn.max('timestamp').as('newest'),\n\t\t\t\t])\n\t\t\t\t.executeTakeFirst(),\n\t\t]);\n\n\t\tconst allDates = [\n\t\t\trequestsResult?.oldest,\n\t\t\trequestsResult?.newest,\n\t\t\texceptionsResult?.oldest,\n\t\t\texceptionsResult?.newest,\n\t\t\tlogsResult?.oldest,\n\t\t\tlogsResult?.newest,\n\t\t]\n\t\t\t.filter((d): d is Date => d != null)\n\t\t\t.sort((a, b) => new Date(a).getTime() - new Date(b).getTime());\n\n\t\tconst newestDate = allDates[allDates.length - 1];\n\t\treturn {\n\t\t\trequests: Number(requestsResult?.count ?? 0),\n\t\t\texceptions: Number(exceptionsResult?.count ?? 0),\n\t\t\tlogs: Number(logsResult?.count ?? 0),\n\t\t\toldestEntry: allDates[0] ? new Date(allDates[0]) : undefined,\n\t\t\tnewestEntry: newestDate ? new Date(newestDate) : undefined,\n\t\t};\n\t}\n\n\t// ============================================\n\t// Private Helpers\n\t// ============================================\n\n\tprivate applyQueryOptions(\n\t\tquery: any,\n\t\toptions: QueryOptions | undefined,\n\t\tsearchColumns: readonly string[],\n\t): any {\n\t\tif (!options) {\n\t\t\treturn query.limit(50);\n\t\t}\n\n\t\tif (options.after) {\n\t\t\tquery = query.where('timestamp', '>=', options.after);\n\t\t}\n\n\t\tif (options.before) {\n\t\t\tquery = query.where('timestamp', '<=', options.before);\n\t\t}\n\n\t\tif (options.search) {\n\t\t\t// Search in relevant text fields - using ILIKE for case-insensitive\n\t\t\t// This is a simple implementation; for production you'd want full-text search\n\t\t\t// Only the columns this table has: a column another table has and\n\t\t\t// this one lacks is a query error, not a miss.\n\t\t\tquery = query.where((eb: any) =>\n\t\t\t\teb.or(\n\t\t\t\t\tsearchColumns.map((column) =>\n\t\t\t\t\t\teb(column, 'ilike', `%${options.search}%`),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// Tags filter would require array contains operation\n\t\t// which is database-specific (PostgreSQL: @>, etc.)\n\n\t\tconst limit = options.limit ?? 50;\n\t\tconst offset = options.offset ?? 0;\n\n\t\treturn query.limit(limit).offset(offset);\n\t}\n\n\tprivate requestToRow(entry: RequestEntry): TelescopeRequestTable {\n\t\treturn {\n\t\t\tid: entry.id,\n\t\t\tmethod: entry.method,\n\t\t\tpath: entry.path,\n\t\t\turl: entry.url,\n\t\t\theaders: toJson(entry.headers),\n\t\t\tbody: toJson(entry.body),\n\t\t\tquery: toJson(entry.query),\n\t\t\tstatus: entry.status,\n\t\t\tresponse_headers: toJson(entry.responseHeaders),\n\t\t\tresponse_body: toJson(entry.responseBody),\n\t\t\tduration: entry.duration,\n\t\t\ttimestamp: entry.timestamp,\n\t\t\tip: entry.ip ?? null,\n\t\t\tuser_id: entry.userId ?? null,\n\t\t\ttags: toJson(entry.tags),\n\t\t};\n\t}\n\n\tprivate rowToRequest(row: TelescopeRequestTable): RequestEntry {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tmethod: row.method,\n\t\t\tpath: row.path,\n\t\t\turl: row.url,\n\t\t\theaders: this.parseJson(row.headers) as Record<string, string>,\n\t\t\tbody: row.body ? this.parseJson(row.body) : undefined,\n\t\t\tquery: row.query\n\t\t\t\t? (this.parseJson(row.query) as Record<string, string>)\n\t\t\t\t: undefined,\n\t\t\tstatus: row.status,\n\t\t\tresponseHeaders: this.parseJson(row.response_headers) as Record<\n\t\t\t\tstring,\n\t\t\t\tstring\n\t\t\t>,\n\t\t\tresponseBody: row.response_body\n\t\t\t\t? this.parseJson(row.response_body)\n\t\t\t\t: undefined,\n\t\t\tduration: row.duration,\n\t\t\ttimestamp: new Date(row.timestamp),\n\t\t\tip: row.ip ?? undefined,\n\t\t\tuserId: row.user_id ?? undefined,\n\t\t\ttags: row.tags ? (this.parseJson(row.tags) as string[]) : undefined,\n\t\t};\n\t}\n\n\tprivate exceptionToRow(entry: ExceptionEntry): TelescopeExceptionTable {\n\t\treturn {\n\t\t\tid: entry.id,\n\t\t\tname: entry.name,\n\t\t\tmessage: entry.message,\n\t\t\tstack: toJson(entry.stack),\n\t\t\tsource: toJson(entry.source),\n\t\t\trequest_id: entry.requestId ?? null,\n\t\t\ttimestamp: entry.timestamp,\n\t\t\thandled: entry.handled,\n\t\t\ttags: toJson(entry.tags),\n\t\t};\n\t}\n\n\tprivate rowToException(row: TelescopeExceptionTable): ExceptionEntry {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tname: row.name,\n\t\t\tmessage: row.message,\n\t\t\tstack: this.parseJson(row.stack) as ExceptionEntry['stack'],\n\t\t\tsource: row.source\n\t\t\t\t? (this.parseJson(row.source) as ExceptionEntry['source'])\n\t\t\t\t: undefined,\n\t\t\trequestId: row.request_id ?? undefined,\n\t\t\ttimestamp: new Date(row.timestamp),\n\t\t\thandled: row.handled,\n\t\t\ttags: row.tags ? (this.parseJson(row.tags) as string[]) : undefined,\n\t\t};\n\t}\n\n\tprivate logToRow(entry: LogEntry): TelescopeLogTable {\n\t\treturn {\n\t\t\tid: entry.id,\n\t\t\tlevel: entry.level,\n\t\t\tmessage: entry.message,\n\t\t\tcontext: toJson(entry.context),\n\t\t\trequest_id: entry.requestId ?? null,\n\t\t\ttimestamp: entry.timestamp,\n\t\t};\n\t}\n\n\tprivate rowToLog(row: TelescopeLogTable): LogEntry {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tlevel: row.level as LogEntry['level'],\n\t\t\tmessage: row.message,\n\t\t\tcontext: row.context\n\t\t\t\t? (this.parseJson(row.context) as Record<string, unknown>)\n\t\t\t\t: undefined,\n\t\t\trequestId: row.request_id ?? undefined,\n\t\t\ttimestamp: new Date(row.timestamp),\n\t\t};\n\t}\n\n\t/**\n\t * Parse a JSON value that may already be parsed (e.g., from jsonb columns).\n\t */\n\tprivate parseJson(value: unknown): unknown {\n\t\tif (typeof value === 'object' && value !== null) {\n\t\t\treturn value;\n\t\t}\n\t\tif (typeof value === 'string') {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(value);\n\t\t\t} catch {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t}\n}\n\n/**\n * A value for a JSON column, as JSON text.\n *\n * Handed an object, node-postgres writes JSON; handed an array it writes a\n * Postgres array literal (`{1,2}`), which a `jsonb` column rejects — so every\n * exception (its stack is an array) failed to save. Serialising here makes\n * the column's type the only thing that decides.\n */\nfunction toJson(value: unknown): string | null {\n\treturn value === undefined || value === null ? null : JSON.stringify(value);\n}\n\n/**\n * SQL migration to create telescope's tables.\n *\n * Pass a schema to have them created in one, and to have `down` drop the whole\n * schema rather than three tables. Pass nothing where the connection's\n * `search_path` already places them.\n *\n * @example\n * ```typescript\n * import { getTelescopeMigration } from '@geekmidas/telescope/storage/kysely';\n *\n * // In your migration file\n * export async function up(db: Kysely<any>): Promise<void> {\n * const migration = getTelescopeMigration();\n * await db.schema.executeRaw(migration.up).execute();\n * }\n *\n * export async function down(db: Kysely<any>): Promise<void> {\n * const migration = getTelescopeMigration();\n * await db.schema.executeRaw(migration.down).execute();\n * }\n * ```\n */\nexport function getTelescopeMigration(schema?: string): {\n\tup: string;\n\tdown: string;\n} {\n\t// Qualified only when a schema is named. Unqualified otherwise, so the\n\t// connection's `search_path` places them — the same rule the tables\n\t// themselves follow at query time.\n\tconst q = (name: string) => (schema ? `${schema}.${name}` : name);\n\tconst idx = (name: string) => (schema ? `${schema}_${name}` : name);\n\n\treturn {\n\t\tup: `${schema ? `CREATE SCHEMA IF NOT EXISTS ${schema};\\n` : ''}\n-- Telescope requests\nCREATE TABLE IF NOT EXISTS ${q('requests')} (\n id VARCHAR(21) PRIMARY KEY,\n method VARCHAR(10) NOT NULL,\n path TEXT NOT NULL,\n url TEXT NOT NULL,\n headers JSONB NOT NULL,\n body JSONB,\n query JSONB,\n status INTEGER NOT NULL,\n response_headers JSONB NOT NULL,\n response_body JSONB,\n duration DOUBLE PRECISION NOT NULL,\n timestamp TIMESTAMPTZ NOT NULL,\n ip VARCHAR(45),\n user_id VARCHAR(255),\n tags JSONB\n);\n\nCREATE INDEX IF NOT EXISTS idx_${idx('requests')}_timestamp\n ON ${q('requests')} (timestamp DESC);\nCREATE INDEX IF NOT EXISTS idx_${idx('requests')}_path\n ON ${q('requests')} (path);\nCREATE INDEX IF NOT EXISTS idx_${idx('requests')}_status\n ON ${q('requests')} (status);\n\n-- Telescope exceptions\nCREATE TABLE IF NOT EXISTS ${q('exceptions')} (\n id VARCHAR(21) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n message TEXT NOT NULL,\n stack JSONB NOT NULL,\n source JSONB,\n request_id VARCHAR(21),\n timestamp TIMESTAMPTZ NOT NULL,\n handled BOOLEAN NOT NULL DEFAULT FALSE,\n tags JSONB\n);\n\nCREATE INDEX IF NOT EXISTS idx_${idx('exceptions')}_timestamp\n ON ${q('exceptions')} (timestamp DESC);\nCREATE INDEX IF NOT EXISTS idx_${idx('exceptions')}_request_id\n ON ${q('exceptions')} (request_id);\n\n-- Telescope logs\nCREATE TABLE IF NOT EXISTS ${q('logs')} (\n id VARCHAR(21) PRIMARY KEY,\n level VARCHAR(10) NOT NULL,\n message TEXT NOT NULL,\n context JSONB,\n request_id VARCHAR(21),\n timestamp TIMESTAMPTZ NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_${idx('logs')}_timestamp\n ON ${q('logs')} (timestamp DESC);\nCREATE INDEX IF NOT EXISTS idx_${idx('logs')}_level\n ON ${q('logs')} (level);\nCREATE INDEX IF NOT EXISTS idx_${idx('logs')}_request_id\n ON ${q('logs')} (request_id);\n`,\n\t\t// A schema tenant drops whole; only the unqualified case drops tables.\n\t\tdown: schema\n\t\t\t? `DROP SCHEMA IF EXISTS ${schema} CASCADE;\\n`\n\t\t\t: `\nDROP TABLE IF EXISTS logs;\nDROP TABLE IF EXISTS exceptions;\nDROP TABLE IF EXISTS requests;\n`,\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kysely.mjs","names":["config: KyselyStorageConfig<DB>","entry: RequestEntry","entries: RequestEntry[]","options?: QueryOptions","row: TelescopeRequestTable","id: string","entry: ExceptionEntry","entries: ExceptionEntry[]","row: TelescopeExceptionTable","entry: LogEntry","entries: LogEntry[]","row: TelescopeLogTable","olderThan: Date","eb: any","query: any","value: unknown"],"sources":["../../src/storage/kysely.ts"],"sourcesContent":["import type { Kysely } from 'kysely';\nimport type {\n\tExceptionEntry,\n\tLogEntry,\n\tQueryOptions,\n\tRequestEntry,\n\tTelescopeStats,\n\tTelescopeStorage,\n} from '../types';\n\n/**\n * Database table interface for telescope requests.\n * Use this to define your telescope_requests table in your Kysely database schema.\n */\nexport interface TelescopeRequestTable {\n\tid: string;\n\tmethod: string;\n\tpath: string;\n\turl: string;\n\theaders: unknown;\n\tbody: unknown | null;\n\tquery: unknown | null;\n\tstatus: number;\n\tresponse_headers: unknown;\n\tresponse_body: unknown | null;\n\tduration: number;\n\ttimestamp: Date;\n\tip: string | null;\n\tuser_id: string | null;\n\ttags: unknown | null;\n}\n\n/**\n * Database table interface for telescope exceptions.\n */\nexport interface TelescopeExceptionTable {\n\tid: string;\n\tname: string;\n\tmessage: string;\n\tstack: unknown;\n\tsource: unknown | null;\n\trequest_id: string | null;\n\ttimestamp: Date;\n\thandled: boolean;\n\ttags: unknown | null;\n}\n\n/**\n * Database table interface for telescope logs.\n */\nexport interface TelescopeLogTable {\n\tid: string;\n\tlevel: string;\n\tmessage: string;\n\tcontext: unknown | null;\n\trequest_id: string | null;\n\ttimestamp: Date;\n}\n\n/**\n * Combined database interface for all telescope tables.\n * Use this to extend your database schema.\n *\n * @example\n * ```typescript\n * import type { TelescopeTables } from '@geekmidas/telescope/storage/kysely';\n *\n * interface Database extends TelescopeTables {\n * users: UserTable;\n * // ... other tables\n * }\n * ```\n */\nexport interface TelescopeTables {\n\ttelescope_requests: TelescopeRequestTable;\n\ttelescope_exceptions: TelescopeExceptionTable;\n\ttelescope_logs: TelescopeLogTable;\n}\n\n/**\n * Configuration for KyselyStorage.\n */\nexport interface KyselyStorageConfig<DB> {\n\t/** Kysely database instance */\n\tdb: Kysely<DB>;\n\t/**\n\t * Table name prefix (default: 'telescope').\n\t * Tables will be named: {prefix}_requests, {prefix}_exceptions, {prefix}_logs\n\t */\n\ttablePrefix?: string;\n}\n\n/**\n * Kysely-based storage implementation for Telescope.\n * Stores telescope data in PostgreSQL, MySQL, or SQLite using Kysely.\n *\n * @template DB - Your Kysely database schema (must include TelescopeTables)\n *\n * @example\n * ```typescript\n * import { Kysely, PostgresDialect } from 'kysely';\n * import { KyselyStorage, type TelescopeTables } from '@geekmidas/telescope/storage/kysely';\n *\n * interface Database extends TelescopeTables {\n * users: UserTable;\n * }\n *\n * const db = new Kysely<Database>({ dialect: new PostgresDialect({ pool }) });\n * const storage = new KyselyStorage({ db });\n *\n * const telescope = new Telescope({ storage });\n * ```\n */\nexport class KyselyStorage<DB> implements TelescopeStorage {\n\tprivate readonly db: Kysely<DB>;\n\tprivate readonly requestsTable: string;\n\tprivate readonly exceptionsTable: string;\n\tprivate readonly logsTable: string;\n\n\tconstructor(config: KyselyStorageConfig<DB>) {\n\t\tthis.db = config.db;\n\t\tconst prefix = config.tablePrefix ?? 'telescope';\n\t\tthis.requestsTable = `${prefix}_requests`;\n\t\tthis.exceptionsTable = `${prefix}_exceptions`;\n\t\tthis.logsTable = `${prefix}_logs`;\n\t}\n\n\t// ============================================\n\t// Requests\n\t// ============================================\n\n\tasync saveRequest(entry: RequestEntry): Promise<void> {\n\t\tconst row = this.requestToRow(entry);\n\t\tawait (this.db as any).insertInto(this.requestsTable).values(row).execute();\n\t}\n\n\tasync saveRequests(entries: RequestEntry[]): Promise<void> {\n\t\tif (entries.length === 0) return;\n\n\t\tconst rows = entries.map((e) => this.requestToRow(e));\n\t\tawait (this.db as any)\n\t\t\t.insertInto(this.requestsTable)\n\t\t\t.values(rows)\n\t\t\t.execute();\n\t}\n\n\tasync getRequests(options?: QueryOptions): Promise<RequestEntry[]> {\n\t\tlet query = (this.db as any)\n\t\t\t.selectFrom(this.requestsTable)\n\t\t\t.selectAll()\n\t\t\t.orderBy('timestamp', 'desc');\n\n\t\t// Apply request-specific filters\n\t\tif (options?.method) {\n\t\t\tquery = query.where('method', '=', options.method);\n\t\t}\n\n\t\tif (options?.status) {\n\t\t\tconst statusFilter = options.status;\n\t\t\tif (statusFilter.endsWith('xx')) {\n\t\t\t\t// Handle status ranges like \"2xx\", \"4xx\", \"5xx\"\n\t\t\t\tconst firstChar = statusFilter[0];\n\t\t\t\tif (firstChar) {\n\t\t\t\t\tconst category = parseInt(firstChar, 10);\n\t\t\t\t\tconst minStatus = category * 100;\n\t\t\t\t\tconst maxStatus = minStatus + 99;\n\t\t\t\t\tquery = query\n\t\t\t\t\t\t.where('status', '>=', minStatus)\n\t\t\t\t\t\t.where('status', '<=', maxStatus);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Handle exact status codes\n\t\t\t\tquery = query.where('status', '=', parseInt(statusFilter, 10));\n\t\t\t}\n\t\t}\n\n\t\tquery = this.applyQueryOptions(query, options);\n\n\t\tconst rows = await query.execute();\n\t\treturn rows.map((row: TelescopeRequestTable) => this.rowToRequest(row));\n\t}\n\n\tasync getRequest(id: string): Promise<RequestEntry | null> {\n\t\tconst row = await (this.db as any)\n\t\t\t.selectFrom(this.requestsTable)\n\t\t\t.selectAll()\n\t\t\t.where('id', '=', id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToRequest(row) : null;\n\t}\n\n\t// ============================================\n\t// Exceptions\n\t// ============================================\n\n\tasync saveException(entry: ExceptionEntry): Promise<void> {\n\t\tconst row = this.exceptionToRow(entry);\n\t\tawait (this.db as any)\n\t\t\t.insertInto(this.exceptionsTable)\n\t\t\t.values(row)\n\t\t\t.execute();\n\t}\n\n\tasync saveExceptions(entries: ExceptionEntry[]): Promise<void> {\n\t\tif (entries.length === 0) return;\n\n\t\tconst rows = entries.map((e) => this.exceptionToRow(e));\n\t\tawait (this.db as any)\n\t\t\t.insertInto(this.exceptionsTable)\n\t\t\t.values(rows)\n\t\t\t.execute();\n\t}\n\n\tasync getExceptions(options?: QueryOptions): Promise<ExceptionEntry[]> {\n\t\tlet query = (this.db as any)\n\t\t\t.selectFrom(this.exceptionsTable)\n\t\t\t.selectAll()\n\t\t\t.orderBy('timestamp', 'desc');\n\n\t\tquery = this.applyQueryOptions(query, options);\n\n\t\tconst rows = await query.execute();\n\t\treturn rows.map((row: TelescopeExceptionTable) => this.rowToException(row));\n\t}\n\n\tasync getException(id: string): Promise<ExceptionEntry | null> {\n\t\tconst row = await (this.db as any)\n\t\t\t.selectFrom(this.exceptionsTable)\n\t\t\t.selectAll()\n\t\t\t.where('id', '=', id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToException(row) : null;\n\t}\n\n\t// ============================================\n\t// Logs\n\t// ============================================\n\n\tasync saveLog(entry: LogEntry): Promise<void> {\n\t\tconst row = this.logToRow(entry);\n\t\tawait (this.db as any).insertInto(this.logsTable).values(row).execute();\n\t}\n\n\tasync saveLogs(entries: LogEntry[]): Promise<void> {\n\t\tif (entries.length === 0) return;\n\n\t\tconst rows = entries.map((e) => this.logToRow(e));\n\t\tawait (this.db as any).insertInto(this.logsTable).values(rows).execute();\n\t}\n\n\tasync getLogs(options?: QueryOptions): Promise<LogEntry[]> {\n\t\tlet query = (this.db as any)\n\t\t\t.selectFrom(this.logsTable)\n\t\t\t.selectAll()\n\t\t\t.orderBy('timestamp', 'desc');\n\n\t\t// Apply log-specific filters\n\t\tif (options?.level) {\n\t\t\tquery = query.where('level', '=', options.level);\n\t\t}\n\n\t\tquery = this.applyQueryOptions(query, options);\n\n\t\tconst rows = await query.execute();\n\t\treturn rows.map((row: TelescopeLogTable) => this.rowToLog(row));\n\t}\n\n\t// ============================================\n\t// Cleanup\n\t// ============================================\n\n\tasync prune(olderThan: Date): Promise<number> {\n\t\tconst results = await Promise.all([\n\t\t\t(this.db as any)\n\t\t\t\t.deleteFrom(this.requestsTable)\n\t\t\t\t.where('timestamp', '<', olderThan)\n\t\t\t\t.executeTakeFirst(),\n\t\t\t(this.db as any)\n\t\t\t\t.deleteFrom(this.exceptionsTable)\n\t\t\t\t.where('timestamp', '<', olderThan)\n\t\t\t\t.executeTakeFirst(),\n\t\t\t(this.db as any)\n\t\t\t\t.deleteFrom(this.logsTable)\n\t\t\t\t.where('timestamp', '<', olderThan)\n\t\t\t\t.executeTakeFirst(),\n\t\t]);\n\n\t\treturn results.reduce(\n\t\t\t(sum, result) => sum + Number(result.numDeletedRows ?? 0),\n\t\t\t0,\n\t\t);\n\t}\n\n\t// ============================================\n\t// Stats\n\t// ============================================\n\n\tasync getStats(): Promise<TelescopeStats> {\n\t\tconst [requestsResult, exceptionsResult, logsResult] = await Promise.all([\n\t\t\t(this.db as any)\n\t\t\t\t.selectFrom(this.requestsTable)\n\t\t\t\t.select((eb: any) => [\n\t\t\t\t\teb.fn.count('id').as('count'),\n\t\t\t\t\teb.fn.min('timestamp').as('oldest'),\n\t\t\t\t\teb.fn.max('timestamp').as('newest'),\n\t\t\t\t])\n\t\t\t\t.executeTakeFirst(),\n\t\t\t(this.db as any)\n\t\t\t\t.selectFrom(this.exceptionsTable)\n\t\t\t\t.select((eb: any) => [\n\t\t\t\t\teb.fn.count('id').as('count'),\n\t\t\t\t\teb.fn.min('timestamp').as('oldest'),\n\t\t\t\t\teb.fn.max('timestamp').as('newest'),\n\t\t\t\t])\n\t\t\t\t.executeTakeFirst(),\n\t\t\t(this.db as any)\n\t\t\t\t.selectFrom(this.logsTable)\n\t\t\t\t.select((eb: any) => [\n\t\t\t\t\teb.fn.count('id').as('count'),\n\t\t\t\t\teb.fn.min('timestamp').as('oldest'),\n\t\t\t\t\teb.fn.max('timestamp').as('newest'),\n\t\t\t\t])\n\t\t\t\t.executeTakeFirst(),\n\t\t]);\n\n\t\tconst allDates = [\n\t\t\trequestsResult?.oldest,\n\t\t\trequestsResult?.newest,\n\t\t\texceptionsResult?.oldest,\n\t\t\texceptionsResult?.newest,\n\t\t\tlogsResult?.oldest,\n\t\t\tlogsResult?.newest,\n\t\t]\n\t\t\t.filter((d): d is Date => d != null)\n\t\t\t.sort((a, b) => new Date(a).getTime() - new Date(b).getTime());\n\n\t\tconst newestDate = allDates[allDates.length - 1];\n\t\treturn {\n\t\t\trequests: Number(requestsResult?.count ?? 0),\n\t\t\texceptions: Number(exceptionsResult?.count ?? 0),\n\t\t\tlogs: Number(logsResult?.count ?? 0),\n\t\t\toldestEntry: allDates[0] ? new Date(allDates[0]) : undefined,\n\t\t\tnewestEntry: newestDate ? new Date(newestDate) : undefined,\n\t\t};\n\t}\n\n\t// ============================================\n\t// Private Helpers\n\t// ============================================\n\n\tprivate applyQueryOptions(query: any, options?: QueryOptions): any {\n\t\tif (!options) {\n\t\t\treturn query.limit(50);\n\t\t}\n\n\t\tif (options.after) {\n\t\t\tquery = query.where('timestamp', '>=', options.after);\n\t\t}\n\n\t\tif (options.before) {\n\t\t\tquery = query.where('timestamp', '<=', options.before);\n\t\t}\n\n\t\tif (options.search) {\n\t\t\t// Search in relevant text fields - using ILIKE for case-insensitive\n\t\t\t// This is a simple implementation; for production you'd want full-text search\n\t\t\tquery = query.where((eb: any) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb('message', 'ilike', `%${options.search}%`),\n\t\t\t\t\teb('path', 'ilike', `%${options.search}%`),\n\t\t\t\t\teb('url', 'ilike', `%${options.search}%`),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\t// Tags filter would require array contains operation\n\t\t// which is database-specific (PostgreSQL: @>, etc.)\n\n\t\tconst limit = options.limit ?? 50;\n\t\tconst offset = options.offset ?? 0;\n\n\t\treturn query.limit(limit).offset(offset);\n\t}\n\n\tprivate requestToRow(entry: RequestEntry): TelescopeRequestTable {\n\t\treturn {\n\t\t\tid: entry.id,\n\t\t\tmethod: entry.method,\n\t\t\tpath: entry.path,\n\t\t\turl: entry.url,\n\t\t\theaders: entry.headers,\n\t\t\tbody: entry.body ?? null,\n\t\t\tquery: entry.query ?? null,\n\t\t\tstatus: entry.status,\n\t\t\tresponse_headers: entry.responseHeaders,\n\t\t\tresponse_body: entry.responseBody ?? null,\n\t\t\tduration: entry.duration,\n\t\t\ttimestamp: entry.timestamp,\n\t\t\tip: entry.ip ?? null,\n\t\t\tuser_id: entry.userId ?? null,\n\t\t\ttags: entry.tags ?? null,\n\t\t};\n\t}\n\n\tprivate rowToRequest(row: TelescopeRequestTable): RequestEntry {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tmethod: row.method,\n\t\t\tpath: row.path,\n\t\t\turl: row.url,\n\t\t\theaders: this.parseJson(row.headers) as Record<string, string>,\n\t\t\tbody: row.body ? this.parseJson(row.body) : undefined,\n\t\t\tquery: row.query\n\t\t\t\t? (this.parseJson(row.query) as Record<string, string>)\n\t\t\t\t: undefined,\n\t\t\tstatus: row.status,\n\t\t\tresponseHeaders: this.parseJson(row.response_headers) as Record<\n\t\t\t\tstring,\n\t\t\t\tstring\n\t\t\t>,\n\t\t\tresponseBody: row.response_body\n\t\t\t\t? this.parseJson(row.response_body)\n\t\t\t\t: undefined,\n\t\t\tduration: row.duration,\n\t\t\ttimestamp: new Date(row.timestamp),\n\t\t\tip: row.ip ?? undefined,\n\t\t\tuserId: row.user_id ?? undefined,\n\t\t\ttags: row.tags ? (this.parseJson(row.tags) as string[]) : undefined,\n\t\t};\n\t}\n\n\tprivate exceptionToRow(entry: ExceptionEntry): TelescopeExceptionTable {\n\t\treturn {\n\t\t\tid: entry.id,\n\t\t\tname: entry.name,\n\t\t\tmessage: entry.message,\n\t\t\tstack: entry.stack,\n\t\t\tsource: entry.source ?? null,\n\t\t\trequest_id: entry.requestId ?? null,\n\t\t\ttimestamp: entry.timestamp,\n\t\t\thandled: entry.handled,\n\t\t\ttags: entry.tags ?? null,\n\t\t};\n\t}\n\n\tprivate rowToException(row: TelescopeExceptionTable): ExceptionEntry {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tname: row.name,\n\t\t\tmessage: row.message,\n\t\t\tstack: this.parseJson(row.stack) as ExceptionEntry['stack'],\n\t\t\tsource: row.source\n\t\t\t\t? (this.parseJson(row.source) as ExceptionEntry['source'])\n\t\t\t\t: undefined,\n\t\t\trequestId: row.request_id ?? undefined,\n\t\t\ttimestamp: new Date(row.timestamp),\n\t\t\thandled: row.handled,\n\t\t\ttags: row.tags ? (this.parseJson(row.tags) as string[]) : undefined,\n\t\t};\n\t}\n\n\tprivate logToRow(entry: LogEntry): TelescopeLogTable {\n\t\treturn {\n\t\t\tid: entry.id,\n\t\t\tlevel: entry.level,\n\t\t\tmessage: entry.message,\n\t\t\tcontext: entry.context ?? null,\n\t\t\trequest_id: entry.requestId ?? null,\n\t\t\ttimestamp: entry.timestamp,\n\t\t};\n\t}\n\n\tprivate rowToLog(row: TelescopeLogTable): LogEntry {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tlevel: row.level as LogEntry['level'],\n\t\t\tmessage: row.message,\n\t\t\tcontext: row.context\n\t\t\t\t? (this.parseJson(row.context) as Record<string, unknown>)\n\t\t\t\t: undefined,\n\t\t\trequestId: row.request_id ?? undefined,\n\t\t\ttimestamp: new Date(row.timestamp),\n\t\t};\n\t}\n\n\t/**\n\t * Parse a JSON value that may already be parsed (e.g., from jsonb columns).\n\t */\n\tprivate parseJson(value: unknown): unknown {\n\t\tif (typeof value === 'object' && value !== null) {\n\t\t\treturn value;\n\t\t}\n\t\tif (typeof value === 'string') {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(value);\n\t\t\t} catch {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t}\n}\n\n/**\n * SQL migration to create telescope tables.\n * Use this to set up the required tables in your database.\n *\n * @example\n * ```typescript\n * import { getTelescopeMigration } from '@geekmidas/telescope/storage/kysely';\n *\n * // In your migration file\n * export async function up(db: Kysely<any>): Promise<void> {\n * const migration = getTelescopeMigration();\n * await db.schema.executeRaw(migration.up).execute();\n * }\n *\n * export async function down(db: Kysely<any>): Promise<void> {\n * const migration = getTelescopeMigration();\n * await db.schema.executeRaw(migration.down).execute();\n * }\n * ```\n */\nexport function getTelescopeMigration(tablePrefix = 'telescope'): {\n\tup: string;\n\tdown: string;\n} {\n\treturn {\n\t\tup: `\n-- Telescope requests table\nCREATE TABLE IF NOT EXISTS ${tablePrefix}_requests (\n id VARCHAR(21) PRIMARY KEY,\n method VARCHAR(10) NOT NULL,\n path TEXT NOT NULL,\n url TEXT NOT NULL,\n headers JSONB NOT NULL,\n body JSONB,\n query JSONB,\n status INTEGER NOT NULL,\n response_headers JSONB NOT NULL,\n response_body JSONB,\n duration DOUBLE PRECISION NOT NULL,\n timestamp TIMESTAMPTZ NOT NULL,\n ip VARCHAR(45),\n user_id VARCHAR(255),\n tags JSONB\n);\n\nCREATE INDEX IF NOT EXISTS idx_${tablePrefix}_requests_timestamp\n ON ${tablePrefix}_requests (timestamp DESC);\nCREATE INDEX IF NOT EXISTS idx_${tablePrefix}_requests_path\n ON ${tablePrefix}_requests (path);\nCREATE INDEX IF NOT EXISTS idx_${tablePrefix}_requests_status\n ON ${tablePrefix}_requests (status);\n\n-- Telescope exceptions table\nCREATE TABLE IF NOT EXISTS ${tablePrefix}_exceptions (\n id VARCHAR(21) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n message TEXT NOT NULL,\n stack JSONB NOT NULL,\n source JSONB,\n request_id VARCHAR(21),\n timestamp TIMESTAMPTZ NOT NULL,\n handled BOOLEAN NOT NULL DEFAULT FALSE,\n tags JSONB\n);\n\nCREATE INDEX IF NOT EXISTS idx_${tablePrefix}_exceptions_timestamp\n ON ${tablePrefix}_exceptions (timestamp DESC);\nCREATE INDEX IF NOT EXISTS idx_${tablePrefix}_exceptions_request_id\n ON ${tablePrefix}_exceptions (request_id);\n\n-- Telescope logs table\nCREATE TABLE IF NOT EXISTS ${tablePrefix}_logs (\n id VARCHAR(21) PRIMARY KEY,\n level VARCHAR(10) NOT NULL,\n message TEXT NOT NULL,\n context JSONB,\n request_id VARCHAR(21),\n timestamp TIMESTAMPTZ NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_${tablePrefix}_logs_timestamp\n ON ${tablePrefix}_logs (timestamp DESC);\nCREATE INDEX IF NOT EXISTS idx_${tablePrefix}_logs_level\n ON ${tablePrefix}_logs (level);\nCREATE INDEX IF NOT EXISTS idx_${tablePrefix}_logs_request_id\n ON ${tablePrefix}_logs (request_id);\n`,\n\t\tdown: `\nDROP TABLE IF EXISTS ${tablePrefix}_logs;\nDROP TABLE IF EXISTS ${tablePrefix}_exceptions;\nDROP TABLE IF EXISTS ${tablePrefix}_requests;\n`,\n\t};\n}\n"],"mappings":"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"}
|
package/dist/storage/memory.cjs
CHANGED
|
@@ -1,123 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
//#region src/storage/memory.ts
|
|
3
|
-
/**
|
|
4
|
-
* In-memory storage for Telescope data.
|
|
5
|
-
* Ideal for development and testing.
|
|
6
|
-
* Data is lost when the process restarts.
|
|
7
|
-
*/
|
|
8
|
-
var InMemoryStorage = class {
|
|
9
|
-
requests = [];
|
|
10
|
-
exceptions = [];
|
|
11
|
-
logs = [];
|
|
12
|
-
maxEntries;
|
|
13
|
-
constructor(options) {
|
|
14
|
-
this.maxEntries = options?.maxEntries ?? 1e3;
|
|
15
|
-
}
|
|
16
|
-
async saveRequest(entry) {
|
|
17
|
-
this.requests.unshift(entry);
|
|
18
|
-
this.enforceLimit("requests");
|
|
19
|
-
}
|
|
20
|
-
async saveRequests(entries) {
|
|
21
|
-
this.requests.unshift(...entries);
|
|
22
|
-
this.enforceLimit("requests");
|
|
23
|
-
}
|
|
24
|
-
async getRequests(options) {
|
|
25
|
-
let result = this.requests;
|
|
26
|
-
if (options?.method) result = result.filter((r) => r.method === options.method);
|
|
27
|
-
if (options?.status) {
|
|
28
|
-
const statusFilter = options.status;
|
|
29
|
-
result = result.filter((r) => {
|
|
30
|
-
if (statusFilter.endsWith("xx")) {
|
|
31
|
-
const firstChar = statusFilter[0];
|
|
32
|
-
if (!firstChar) return false;
|
|
33
|
-
const category = parseInt(firstChar, 10);
|
|
34
|
-
return Math.floor(r.status / 100) === category;
|
|
35
|
-
}
|
|
36
|
-
return r.status === parseInt(statusFilter, 10);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
return this.filterEntries(result, options);
|
|
40
|
-
}
|
|
41
|
-
async getRequest(id) {
|
|
42
|
-
return this.requests.find((r) => r.id === id) ?? null;
|
|
43
|
-
}
|
|
44
|
-
async saveException(entry) {
|
|
45
|
-
this.exceptions.unshift(entry);
|
|
46
|
-
this.enforceLimit("exceptions");
|
|
47
|
-
}
|
|
48
|
-
async saveExceptions(entries) {
|
|
49
|
-
this.exceptions.unshift(...entries);
|
|
50
|
-
this.enforceLimit("exceptions");
|
|
51
|
-
}
|
|
52
|
-
async getExceptions(options) {
|
|
53
|
-
return this.filterEntries(this.exceptions, options);
|
|
54
|
-
}
|
|
55
|
-
async getException(id) {
|
|
56
|
-
return this.exceptions.find((e) => e.id === id) ?? null;
|
|
57
|
-
}
|
|
58
|
-
async saveLog(entry) {
|
|
59
|
-
this.logs.unshift(entry);
|
|
60
|
-
this.enforceLimit("logs");
|
|
61
|
-
}
|
|
62
|
-
async saveLogs(entries) {
|
|
63
|
-
this.logs.unshift(...entries);
|
|
64
|
-
this.enforceLimit("logs");
|
|
65
|
-
}
|
|
66
|
-
async getLogs(options) {
|
|
67
|
-
let result = this.logs;
|
|
68
|
-
if (options?.level) result = result.filter((l) => l.level === options.level);
|
|
69
|
-
return this.filterEntries(result, options);
|
|
70
|
-
}
|
|
71
|
-
async prune(olderThan) {
|
|
72
|
-
const beforeCount = this.requests.length + this.exceptions.length + this.logs.length;
|
|
73
|
-
this.requests = this.requests.filter((r) => r.timestamp >= olderThan);
|
|
74
|
-
this.exceptions = this.exceptions.filter((e) => e.timestamp >= olderThan);
|
|
75
|
-
this.logs = this.logs.filter((l) => l.timestamp >= olderThan);
|
|
76
|
-
return beforeCount - (this.requests.length + this.exceptions.length + this.logs.length);
|
|
77
|
-
}
|
|
78
|
-
async getStats() {
|
|
79
|
-
const allTimestamps = [
|
|
80
|
-
...this.requests.map((r) => r.timestamp),
|
|
81
|
-
...this.exceptions.map((e) => e.timestamp),
|
|
82
|
-
...this.logs.map((l) => l.timestamp)
|
|
83
|
-
].sort((a, b) => a.getTime() - b.getTime());
|
|
84
|
-
return {
|
|
85
|
-
requests: this.requests.length,
|
|
86
|
-
exceptions: this.exceptions.length,
|
|
87
|
-
logs: this.logs.length,
|
|
88
|
-
oldestEntry: allTimestamps[0],
|
|
89
|
-
newestEntry: allTimestamps[allTimestamps.length - 1]
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
clear() {
|
|
93
|
-
this.requests = [];
|
|
94
|
-
this.exceptions = [];
|
|
95
|
-
this.logs = [];
|
|
96
|
-
}
|
|
97
|
-
enforceLimit(type) {
|
|
98
|
-
if (this[type].length > this.maxEntries) {
|
|
99
|
-
if (type === "requests") this.requests = this.requests.slice(0, this.maxEntries);
|
|
100
|
-
else if (type === "exceptions") this.exceptions = this.exceptions.slice(0, this.maxEntries);
|
|
101
|
-
else this.logs = this.logs.slice(0, this.maxEntries);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
filterEntries(entries, options) {
|
|
105
|
-
let result = entries;
|
|
106
|
-
if (options?.after) result = result.filter((e) => e.timestamp >= options.after);
|
|
107
|
-
if (options?.before) result = result.filter((e) => e.timestamp <= options.before);
|
|
108
|
-
if (options?.tags && options.tags.length > 0) result = result.filter((e) => e.tags && options.tags?.some((t) => e.tags?.includes(t)));
|
|
109
|
-
if (options?.search) {
|
|
110
|
-
const searchLower = options.search.toLowerCase();
|
|
111
|
-
result = result.filter((e) => {
|
|
112
|
-
return JSON.stringify(e).toLowerCase().includes(searchLower);
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
const offset = options?.offset ?? 0;
|
|
116
|
-
const limit = options?.limit ?? 50;
|
|
117
|
-
return result.slice(offset, offset + limit);
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
//#endregion
|
|
121
|
-
exports.InMemoryStorage = InMemoryStorage;
|
|
1
|
+
const require_memory = require('../memory-B0d_n1g5.cjs');
|
|
122
2
|
|
|
123
|
-
|
|
3
|
+
exports.InMemoryStorage = require_memory.InMemoryStorage;
|
|
@@ -1,36 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
/** Maximum number of entries to keep per type (default: 1000) */
|
|
5
|
-
maxEntries?: number;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* In-memory storage for Telescope data.
|
|
9
|
-
* Ideal for development and testing.
|
|
10
|
-
* Data is lost when the process restarts.
|
|
11
|
-
*/
|
|
12
|
-
export declare class InMemoryStorage implements TelescopeStorage {
|
|
13
|
-
private requests;
|
|
14
|
-
private exceptions;
|
|
15
|
-
private logs;
|
|
16
|
-
private maxEntries;
|
|
17
|
-
constructor(options?: InMemoryStorageOptions);
|
|
18
|
-
saveRequest(entry: RequestEntry): Promise<void>;
|
|
19
|
-
saveRequests(entries: RequestEntry[]): Promise<void>;
|
|
20
|
-
getRequests(options?: QueryOptions): Promise<RequestEntry[]>;
|
|
21
|
-
getRequest(id: string): Promise<RequestEntry | null>;
|
|
22
|
-
saveException(entry: ExceptionEntry): Promise<void>;
|
|
23
|
-
saveExceptions(entries: ExceptionEntry[]): Promise<void>;
|
|
24
|
-
getExceptions(options?: QueryOptions): Promise<ExceptionEntry[]>;
|
|
25
|
-
getException(id: string): Promise<ExceptionEntry | null>;
|
|
26
|
-
saveLog(entry: LogEntry): Promise<void>;
|
|
27
|
-
saveLogs(entries: LogEntry[]): Promise<void>;
|
|
28
|
-
getLogs(options?: QueryOptions): Promise<LogEntry[]>;
|
|
29
|
-
prune(olderThan: Date): Promise<number>;
|
|
30
|
-
getStats(): Promise<TelescopeStats>;
|
|
31
|
-
clear(): void;
|
|
32
|
-
private enforceLimit;
|
|
33
|
-
private filterEntries;
|
|
34
|
-
}
|
|
35
|
-
//#endregion
|
|
36
|
-
//# sourceMappingURL=memory.d.cts.map
|
|
1
|
+
import "../types-l7Rlb5Mg.cjs";
|
|
2
|
+
import { InMemoryStorage, InMemoryStorageOptions } from "../memory--BK4iWiv.cjs";
|
|
3
|
+
export { InMemoryStorage, InMemoryStorageOptions };
|
|
@@ -1,36 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
/** Maximum number of entries to keep per type (default: 1000) */
|
|
5
|
-
maxEntries?: number;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* In-memory storage for Telescope data.
|
|
9
|
-
* Ideal for development and testing.
|
|
10
|
-
* Data is lost when the process restarts.
|
|
11
|
-
*/
|
|
12
|
-
export declare class InMemoryStorage implements TelescopeStorage {
|
|
13
|
-
private requests;
|
|
14
|
-
private exceptions;
|
|
15
|
-
private logs;
|
|
16
|
-
private maxEntries;
|
|
17
|
-
constructor(options?: InMemoryStorageOptions);
|
|
18
|
-
saveRequest(entry: RequestEntry): Promise<void>;
|
|
19
|
-
saveRequests(entries: RequestEntry[]): Promise<void>;
|
|
20
|
-
getRequests(options?: QueryOptions): Promise<RequestEntry[]>;
|
|
21
|
-
getRequest(id: string): Promise<RequestEntry | null>;
|
|
22
|
-
saveException(entry: ExceptionEntry): Promise<void>;
|
|
23
|
-
saveExceptions(entries: ExceptionEntry[]): Promise<void>;
|
|
24
|
-
getExceptions(options?: QueryOptions): Promise<ExceptionEntry[]>;
|
|
25
|
-
getException(id: string): Promise<ExceptionEntry | null>;
|
|
26
|
-
saveLog(entry: LogEntry): Promise<void>;
|
|
27
|
-
saveLogs(entries: LogEntry[]): Promise<void>;
|
|
28
|
-
getLogs(options?: QueryOptions): Promise<LogEntry[]>;
|
|
29
|
-
prune(olderThan: Date): Promise<number>;
|
|
30
|
-
getStats(): Promise<TelescopeStats>;
|
|
31
|
-
clear(): void;
|
|
32
|
-
private enforceLimit;
|
|
33
|
-
private filterEntries;
|
|
34
|
-
}
|
|
35
|
-
//#endregion
|
|
36
|
-
//# sourceMappingURL=memory.d.mts.map
|
|
1
|
+
import "../types-B1EIa_cQ.mjs";
|
|
2
|
+
import { InMemoryStorage, InMemoryStorageOptions } from "../memory-DCirEVFW.mjs";
|
|
3
|
+
export { InMemoryStorage, InMemoryStorageOptions };
|