@geekmidas/telescope 10.0.0-alpha.2 → 10.0.0-alpha.21
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/{MetricsAggregator-4SqelGcG.d.cts → MetricsAggregator-BxBLQUPj.d.cts} +3 -6
- package/dist/MetricsAggregator-BxBLQUPj.d.cts.map +1 -0
- package/dist/{MetricsAggregator-DZrW8ls6.d.mts → MetricsAggregator-j9wmZ0K_.d.mts} +3 -6
- package/dist/MetricsAggregator-j9wmZ0K_.d.mts.map +1 -0
- package/dist/{Telescope-D4nmwDRA.d.cts → Telescope-BcrWTaar.d.mts} +4 -7
- package/dist/Telescope-BcrWTaar.d.mts.map +1 -0
- package/dist/{Telescope-Dl6VSfxd.d.mts → Telescope-DnCMZT7V.d.cts} +4 -7
- package/dist/Telescope-DnCMZT7V.d.cts.map +1 -0
- package/dist/Telescope.cjs +385 -4
- package/dist/Telescope.cjs.map +1 -0
- package/dist/Telescope.d.cts +1 -3
- package/dist/Telescope.d.mts +1 -3
- package/dist/Telescope.mjs +384 -4
- package/dist/Telescope.mjs.map +1 -0
- package/dist/adapters/index.d.cts +2 -2
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -0
- package/dist/adapters/lambda.cjs +9 -10
- package/dist/adapters/lambda.cjs.map +1 -1
- package/dist/adapters/lambda.d.cts +9 -13
- package/dist/adapters/lambda.d.cts.map +1 -1
- package/dist/adapters/lambda.d.mts +9 -13
- package/dist/adapters/lambda.d.mts.map +1 -1
- package/dist/adapters/lambda.mjs +3 -4
- package/dist/adapters/lambda.mjs.map +1 -1
- package/dist/adapters/middy.cjs +236 -4
- package/dist/adapters/middy.cjs.map +1 -0
- package/dist/adapters/middy.d.cts +60 -5
- package/dist/adapters/middy.d.cts.map +1 -0
- package/dist/adapters/middy.d.mts +60 -5
- package/dist/adapters/middy.d.mts.map +1 -0
- package/dist/adapters/middy.mjs +234 -3
- package/dist/adapters/middy.mjs.map +1 -0
- package/dist/adapters/types.d.cts +162 -2
- package/dist/adapters/types.d.cts.map +1 -0
- package/dist/adapters/types.d.mts +162 -2
- package/dist/adapters/types.d.mts.map +1 -0
- package/dist/adapters/types.mjs +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 +3 -4
- package/dist/index.cjs +8 -9
- package/dist/index.d.cts +5 -6
- package/dist/index.d.mts +5 -6
- package/dist/index.mjs +5 -7
- package/dist/instrumentation/core.cjs +147 -11
- package/dist/instrumentation/core.cjs.map +1 -0
- package/dist/instrumentation/core.d.cts +74 -3
- package/dist/instrumentation/core.d.cts.map +1 -0
- package/dist/instrumentation/core.d.mts +74 -3
- package/dist/instrumentation/core.d.mts.map +1 -0
- package/dist/instrumentation/core.mjs +137 -2
- package/dist/instrumentation/core.mjs.map +1 -0
- package/dist/instrumentation/hono.cjs +134 -6
- package/dist/instrumentation/hono.cjs.map +1 -0
- package/dist/instrumentation/hono.d.cts +67 -2
- package/dist/instrumentation/hono.d.cts.map +1 -0
- package/dist/instrumentation/hono.d.mts +67 -2
- package/dist/instrumentation/hono.d.mts.map +1 -0
- package/dist/instrumentation/hono.mjs +130 -3
- package/dist/instrumentation/hono.mjs.map +1 -0
- package/dist/instrumentation/http.cjs +164 -11
- package/dist/instrumentation/http.cjs.map +1 -0
- package/dist/instrumentation/http.d.cts +103 -2
- package/dist/instrumentation/http.d.cts.map +1 -0
- package/dist/instrumentation/http.d.mts +103 -2
- package/dist/instrumentation/http.d.mts.map +1 -0
- package/dist/instrumentation/http.mjs +154 -2
- package/dist/instrumentation/http.mjs.map +1 -0
- package/dist/instrumentation/index.cjs +47 -47
- package/dist/instrumentation/index.d.cts +9 -9
- package/dist/instrumentation/index.d.mts +9 -9
- package/dist/instrumentation/index.mjs +8 -9
- package/dist/instrumentation/middleware.cjs +162 -6
- package/dist/instrumentation/middleware.cjs.map +1 -0
- package/dist/instrumentation/middleware.d.cts +70 -2
- package/dist/instrumentation/middleware.d.cts.map +1 -0
- package/dist/instrumentation/middleware.d.mts +70 -2
- package/dist/instrumentation/middleware.d.mts.map +1 -0
- package/dist/instrumentation/middleware.mjs +158 -3
- package/dist/instrumentation/middleware.mjs.map +1 -0
- package/dist/instrumentation/otel.cjs +137 -3
- package/dist/instrumentation/otel.cjs.map +1 -0
- package/dist/instrumentation/otel.d.cts +97 -2
- package/dist/instrumentation/otel.d.cts.map +1 -0
- package/dist/instrumentation/otel.d.mts +97 -2
- package/dist/instrumentation/otel.d.mts.map +1 -0
- package/dist/instrumentation/otel.mjs +136 -3
- package/dist/instrumentation/otel.mjs.map +1 -0
- package/dist/instrumentation/setup.cjs +100 -4
- package/dist/instrumentation/setup.cjs.map +1 -0
- package/dist/instrumentation/setup.d.cts +83 -3
- package/dist/instrumentation/setup.d.cts.map +1 -0
- package/dist/instrumentation/setup.d.mts +83 -3
- package/dist/instrumentation/setup.d.mts.map +1 -0
- package/dist/instrumentation/setup.mjs +98 -3
- package/dist/instrumentation/setup.mjs.map +1 -0
- package/dist/instrumentation/tracing.cjs +114 -10
- package/dist/instrumentation/tracing.cjs.map +1 -0
- package/dist/instrumentation/tracing.d.cts +49 -2
- package/dist/instrumentation/tracing.d.cts.map +1 -0
- package/dist/instrumentation/tracing.d.mts +49 -2
- package/dist/instrumentation/tracing.d.mts.map +1 -0
- package/dist/instrumentation/tracing.mjs +105 -2
- package/dist/instrumentation/tracing.mjs.map +1 -0
- package/dist/logger/console.cjs +18 -12
- package/dist/logger/console.cjs.map +1 -1
- package/dist/logger/console.d.cts +7 -10
- package/dist/logger/console.d.cts.map +1 -1
- package/dist/logger/console.d.mts +7 -10
- package/dist/logger/console.d.mts.map +1 -1
- package/dist/logger/console.mjs +17 -11
- package/dist/logger/console.mjs.map +1 -1
- package/dist/logger/pino.cjs +6 -5
- package/dist/logger/pino.cjs.map +1 -1
- package/dist/logger/pino.d.cts +6 -10
- package/dist/logger/pino.d.cts.map +1 -1
- package/dist/logger/pino.d.mts +6 -10
- package/dist/logger/pino.d.mts.map +1 -1
- package/dist/logger/pino.mjs +2 -3
- package/dist/logger/pino.mjs.map +1 -1
- package/dist/metrics/MetricsAggregator.cjs +354 -2
- package/dist/metrics/MetricsAggregator.cjs.map +1 -0
- package/dist/metrics/MetricsAggregator.d.cts +1 -2
- package/dist/metrics/MetricsAggregator.d.mts +1 -2
- package/dist/metrics/MetricsAggregator.mjs +353 -2
- package/dist/metrics/MetricsAggregator.mjs.map +1 -0
- package/dist/metrics/index.cjs +3 -4
- package/dist/metrics/index.d.cts +2 -4
- package/dist/metrics/index.d.mts +2 -4
- package/dist/metrics/index.mjs +2 -4
- package/dist/metrics/storage/InMemoryMetricsStorage.cjs +240 -3
- package/dist/metrics/storage/InMemoryMetricsStorage.cjs.map +1 -0
- package/dist/metrics/storage/InMemoryMetricsStorage.d.cts +43 -4
- package/dist/metrics/storage/InMemoryMetricsStorage.d.cts.map +1 -0
- package/dist/metrics/storage/InMemoryMetricsStorage.d.mts +43 -4
- package/dist/metrics/storage/InMemoryMetricsStorage.d.mts.map +1 -0
- package/dist/metrics/storage/InMemoryMetricsStorage.mjs +239 -3
- package/dist/metrics/storage/InMemoryMetricsStorage.mjs.map +1 -0
- package/dist/metrics/storage/MetricsStorage.cjs +0 -1
- package/dist/metrics/storage/MetricsStorage.d.cts +56 -3
- package/dist/metrics/storage/MetricsStorage.d.cts.map +1 -0
- package/dist/metrics/storage/MetricsStorage.d.mts +56 -3
- package/dist/metrics/storage/MetricsStorage.d.mts.map +1 -0
- 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 +4 -5
- package/dist/metrics/storage/types.cjs +34 -2
- package/dist/metrics/storage/types.cjs.map +1 -0
- package/dist/metrics/storage/types.d.cts +207 -2
- package/dist/metrics/storage/types.d.cts.map +1 -0
- package/dist/metrics/storage/types.d.mts +207 -2
- package/dist/metrics/storage/types.d.mts.map +1 -0
- package/dist/metrics/storage/types.mjs +33 -2
- package/dist/metrics/storage/types.mjs.map +1 -0
- package/dist/otlp/hono.cjs +9 -15
- package/dist/otlp/hono.cjs.map +1 -1
- package/dist/otlp/hono.d.cts +3 -13
- package/dist/otlp/hono.d.cts.map +1 -1
- package/dist/otlp/hono.d.mts +3 -13
- package/dist/otlp/hono.d.mts.map +1 -1
- package/dist/otlp/hono.mjs +5 -11
- package/dist/otlp/hono.mjs.map +1 -1
- package/dist/otlp/index.cjs +11 -11
- package/dist/otlp/index.d.cts +4 -7
- package/dist/otlp/index.d.mts +4 -7
- package/dist/otlp/index.mjs +4 -5
- package/dist/otlp/receiver.cjs +88 -4
- package/dist/otlp/receiver.cjs.map +1 -0
- package/dist/otlp/receiver.d.cts +59 -7
- package/dist/otlp/receiver.d.cts.map +1 -0
- package/dist/otlp/receiver.d.mts +59 -7
- package/dist/otlp/receiver.d.mts.map +1 -0
- package/dist/otlp/receiver.mjs +87 -4
- package/dist/otlp/receiver.mjs.map +1 -0
- package/dist/otlp/transformer.cjs +214 -5
- package/dist/otlp/transformer.cjs.map +1 -0
- package/dist/otlp/transformer.d.cts +1 -3
- package/dist/otlp/transformer.d.mts +1 -3
- package/dist/otlp/transformer.mjs +211 -3
- package/dist/otlp/transformer.mjs.map +1 -0
- package/dist/otlp/types.cjs +57 -5
- package/dist/otlp/types.cjs.map +1 -0
- package/dist/otlp/types.d.cts +1 -1
- package/dist/otlp/types.d.mts +1 -1
- package/dist/otlp/types.mjs +53 -2
- package/dist/otlp/types.mjs.map +1 -0
- package/dist/redact.cjs +84 -3
- package/dist/redact.cjs.map +1 -0
- package/dist/redact.d.cts +4 -8
- package/dist/redact.d.cts.map +1 -1
- package/dist/redact.d.mts +4 -8
- package/dist/redact.d.mts.map +1 -1
- package/dist/redact.mjs +80 -2
- package/dist/redact.mjs.map +1 -0
- package/dist/{chunk-CUT6urMc.cjs → rolldown-runtime-VH7oDXx4.cjs} +8 -10
- package/dist/server/hono.cjs +24 -33
- package/dist/server/hono.cjs.map +1 -1
- package/dist/server/hono.d.cts +10 -13
- package/dist/server/hono.d.cts.map +1 -1
- package/dist/server/hono.d.mts +10 -13
- package/dist/server/hono.d.mts.map +1 -1
- package/dist/server/hono.mjs +22 -31
- package/dist/server/hono.mjs.map +1 -1
- package/dist/storage/kysely.cjs +34 -32
- package/dist/storage/kysely.cjs.map +1 -1
- package/dist/storage/kysely.d.cts +8 -12
- package/dist/storage/kysely.d.cts.map +1 -1
- package/dist/storage/kysely.d.mts +8 -12
- package/dist/storage/kysely.d.mts.map +1 -1
- package/dist/storage/kysely.mjs +33 -31
- package/dist/storage/kysely.mjs.map +1 -1
- package/dist/storage/memory.cjs +122 -2
- package/dist/storage/memory.cjs.map +1 -0
- package/dist/storage/memory.d.cts +36 -3
- package/dist/storage/memory.d.cts.map +1 -0
- package/dist/storage/memory.d.mts +36 -3
- package/dist/storage/memory.d.mts.map +1 -0
- package/dist/storage/memory.mjs +121 -2
- package/dist/storage/memory.mjs.map +1 -0
- package/dist/{transformer-CTGsaVfV.d.mts → transformer-BBBXCjHP.d.mts} +4 -8
- package/dist/transformer-BBBXCjHP.d.mts.map +1 -0
- package/dist/{transformer-ICEbxpFf.d.cts → transformer-DlESim6Q.d.cts} +4 -8
- package/dist/transformer-DlESim6Q.d.cts.map +1 -0
- package/dist/{types-CmOB7CLO.d.cts → types-DVETVdpa.d.cts} +6 -7
- package/dist/types-DVETVdpa.d.cts.map +1 -0
- package/dist/{types-DBc0q5KD.d.mts → types-DVETVdpa.d.mts} +6 -7
- package/dist/types-DVETVdpa.d.mts.map +1 -0
- package/dist/{types-B1EIa_cQ.d.mts → types-a9Vistj1.d.cts} +2 -3
- package/dist/types-a9Vistj1.d.cts.map +1 -0
- package/dist/{types-l7Rlb5Mg.d.cts → types-a9Vistj1.d.mts} +2 -3
- package/dist/types-a9Vistj1.d.mts.map +1 -0
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +1 -0
- package/dist/ui-assets.cjs +31 -4
- package/dist/ui-assets.cjs.map +1 -0
- package/dist/ui-assets.d.cts +4 -6
- package/dist/ui-assets.d.cts.map +1 -1
- package/dist/ui-assets.d.mts +4 -6
- package/dist/ui-assets.d.mts.map +1 -1
- package/dist/ui-assets.mjs +28 -2
- package/dist/ui-assets.mjs.map +1 -0
- package/package.json +39 -37
- package/dist/InMemoryMetricsStorage-BbKCL3YL.d.mts +0 -47
- package/dist/InMemoryMetricsStorage-BbKCL3YL.d.mts.map +0 -1
- package/dist/InMemoryMetricsStorage-C4drxT7G.mjs +0 -247
- package/dist/InMemoryMetricsStorage-C4drxT7G.mjs.map +0 -1
- package/dist/InMemoryMetricsStorage-D0njWUSi.cjs +0 -252
- package/dist/InMemoryMetricsStorage-D0njWUSi.cjs.map +0 -1
- package/dist/InMemoryMetricsStorage-TvPdZjL0.d.cts +0 -47
- package/dist/InMemoryMetricsStorage-TvPdZjL0.d.cts.map +0 -1
- package/dist/MetricsAggregator-4SqelGcG.d.cts.map +0 -1
- package/dist/MetricsAggregator-B7lUICdH.cjs +0 -363
- package/dist/MetricsAggregator-B7lUICdH.cjs.map +0 -1
- package/dist/MetricsAggregator-DZrW8ls6.d.mts.map +0 -1
- package/dist/MetricsAggregator-S3DQWNas.mjs +0 -357
- package/dist/MetricsAggregator-S3DQWNas.mjs.map +0 -1
- package/dist/MetricsStorage-B86e4131.d.cts +0 -60
- package/dist/MetricsStorage-B86e4131.d.cts.map +0 -1
- package/dist/MetricsStorage-BWyP2_12.d.mts +0 -60
- package/dist/MetricsStorage-BWyP2_12.d.mts.map +0 -1
- package/dist/MetricsStorage-BypQXWiv.mjs +0 -0
- package/dist/MetricsStorage-Or8pVCe4.cjs +0 -0
- package/dist/Telescope-Cs3fv8jt.cjs +0 -395
- package/dist/Telescope-Cs3fv8jt.cjs.map +0 -1
- package/dist/Telescope-D4nmwDRA.d.cts.map +0 -1
- package/dist/Telescope-Dh5av3FC.mjs +0 -389
- package/dist/Telescope-Dh5av3FC.mjs.map +0 -1
- package/dist/Telescope-Dl6VSfxd.d.mts.map +0 -1
- package/dist/core--quSp5Qr.d.mts +0 -78
- package/dist/core--quSp5Qr.d.mts.map +0 -1
- package/dist/core-B4Jpia5H.d.cts +0 -78
- package/dist/core-B4Jpia5H.d.cts.map +0 -1
- package/dist/core-CtVHRJGv.cjs +0 -199
- package/dist/core-CtVHRJGv.cjs.map +0 -1
- package/dist/core-D6hJ6exL.mjs +0 -139
- package/dist/core-D6hJ6exL.mjs.map +0 -1
- package/dist/hono--uKQ7Jgi.d.mts +0 -71
- package/dist/hono--uKQ7Jgi.d.mts.map +0 -1
- package/dist/hono-Bw-ey6CT.mjs +0 -136
- package/dist/hono-Bw-ey6CT.mjs.map +0 -1
- package/dist/hono-CPHX7FAm.cjs +0 -160
- package/dist/hono-CPHX7FAm.cjs.map +0 -1
- package/dist/hono-CemCKU87.d.cts +0 -71
- package/dist/hono-CemCKU87.d.cts.map +0 -1
- package/dist/http-BIvr0YdI.mjs +0 -159
- package/dist/http-BIvr0YdI.mjs.map +0 -1
- package/dist/http-BiNtg85L.d.mts +0 -107
- package/dist/http-BiNtg85L.d.mts.map +0 -1
- package/dist/http-BsqmhurZ.cjs +0 -219
- package/dist/http-BsqmhurZ.cjs.map +0 -1
- package/dist/http-D1oTbfap.d.cts +0 -107
- package/dist/http-D1oTbfap.d.cts.map +0 -1
- package/dist/index-BL32-cvv.d.cts +0 -1
- package/dist/index-CsuikFeJ.d.mts +0 -1
- package/dist/memory--BK4iWiv.d.cts +0 -40
- package/dist/memory--BK4iWiv.d.cts.map +0 -1
- package/dist/memory-6S9H-IF5.mjs +0 -123
- package/dist/memory-6S9H-IF5.mjs.map +0 -1
- package/dist/memory-B0d_n1g5.cjs +0 -129
- package/dist/memory-B0d_n1g5.cjs.map +0 -1
- package/dist/memory-DCirEVFW.d.mts +0 -40
- package/dist/memory-DCirEVFW.d.mts.map +0 -1
- package/dist/metrics-D5YT-Rnq.mjs +0 -0
- package/dist/metrics-fhD3l3C3.cjs +0 -0
- package/dist/middleware-Bcq6XXGG.cjs +0 -184
- package/dist/middleware-Bcq6XXGG.cjs.map +0 -1
- package/dist/middleware-D1XEHvyy.mjs +0 -160
- package/dist/middleware-D1XEHvyy.mjs.map +0 -1
- package/dist/middleware-PeyS-9Ny.d.cts +0 -74
- package/dist/middleware-PeyS-9Ny.d.cts.map +0 -1
- package/dist/middleware-oHvo_ZgU.d.mts +0 -74
- package/dist/middleware-oHvo_ZgU.d.mts.map +0 -1
- package/dist/middy-B6Btl8XE.d.mts +0 -64
- package/dist/middy-B6Btl8XE.d.mts.map +0 -1
- package/dist/middy-Bq0defVg.d.cts +0 -64
- package/dist/middy-Bq0defVg.d.cts.map +0 -1
- package/dist/middy-DHWLmUAD.mjs +0 -236
- package/dist/middy-DHWLmUAD.mjs.map +0 -1
- package/dist/middy-DlWnZilH.cjs +0 -247
- package/dist/middy-DlWnZilH.cjs.map +0 -1
- package/dist/otel-B9bNoeZ2.mjs +0 -130
- package/dist/otel-B9bNoeZ2.mjs.map +0 -1
- package/dist/otel-Bk89b1lX.d.cts +0 -101
- package/dist/otel-Bk89b1lX.d.cts.map +0 -1
- package/dist/otel-BzjOtVxZ.cjs +0 -136
- package/dist/otel-BzjOtVxZ.cjs.map +0 -1
- package/dist/otel-lPMsM26e.d.mts +0 -101
- package/dist/otel-lPMsM26e.d.mts.map +0 -1
- package/dist/receiver-D46dfkYI.mjs +0 -89
- package/dist/receiver-D46dfkYI.mjs.map +0 -1
- package/dist/receiver-DLICx5uU.d.cts +0 -63
- package/dist/receiver-DLICx5uU.d.cts.map +0 -1
- package/dist/receiver-UeZT-H8u.d.mts +0 -63
- package/dist/receiver-UeZT-H8u.d.mts.map +0 -1
- package/dist/receiver-slCoAFat.cjs +0 -94
- package/dist/receiver-slCoAFat.cjs.map +0 -1
- package/dist/redact-BzkITCNW.mjs +0 -83
- package/dist/redact-BzkITCNW.mjs.map +0 -1
- package/dist/redact-DVaSSPZT.cjs +0 -95
- package/dist/redact-DVaSSPZT.cjs.map +0 -1
- package/dist/setup-Bkxm4g6b.d.mts +0 -87
- package/dist/setup-Bkxm4g6b.d.mts.map +0 -1
- package/dist/setup-D58N1f9O.d.cts +0 -87
- package/dist/setup-D58N1f9O.d.cts.map +0 -1
- package/dist/setup-DC9JMEYZ.mjs +0 -98
- package/dist/setup-DC9JMEYZ.mjs.map +0 -1
- package/dist/setup-DufxQpi9.cjs +0 -110
- package/dist/setup-DufxQpi9.cjs.map +0 -1
- package/dist/tracing-BX8uY2nR.d.cts +0 -53
- package/dist/tracing-BX8uY2nR.d.cts.map +0 -1
- package/dist/tracing-Bt1zWRlb.cjs +0 -167
- package/dist/tracing-Bt1zWRlb.cjs.map +0 -1
- package/dist/tracing-Cijm_5NI.mjs +0 -113
- package/dist/tracing-Cijm_5NI.mjs.map +0 -1
- package/dist/tracing-PnECEbEu.d.mts +0 -53
- package/dist/tracing-PnECEbEu.d.mts.map +0 -1
- package/dist/transformer-CFQ4WFk6.mjs +0 -215
- package/dist/transformer-CFQ4WFk6.mjs.map +0 -1
- package/dist/transformer-CTGsaVfV.d.mts.map +0 -1
- package/dist/transformer-Csl6fbgv.cjs +0 -232
- package/dist/transformer-Csl6fbgv.cjs.map +0 -1
- package/dist/transformer-ICEbxpFf.d.cts.map +0 -1
- package/dist/types-B1EIa_cQ.d.mts.map +0 -1
- package/dist/types-BMiHgsi4.cjs +0 -78
- package/dist/types-BMiHgsi4.cjs.map +0 -1
- package/dist/types-BRzW1NM8.d.cts +0 -166
- package/dist/types-BRzW1NM8.d.cts.map +0 -1
- package/dist/types-BS3Rx8Sk.d.cts +0 -209
- package/dist/types-BS3Rx8Sk.d.cts.map +0 -1
- package/dist/types-BzQ78Efw.d.mts +0 -166
- package/dist/types-BzQ78Efw.d.mts.map +0 -1
- package/dist/types-CbNGXnJE.d.mts +0 -209
- package/dist/types-CbNGXnJE.d.mts.map +0 -1
- package/dist/types-Cj59nqy7.mjs +0 -54
- package/dist/types-Cj59nqy7.mjs.map +0 -1
- package/dist/types-CmOB7CLO.d.cts.map +0 -1
- package/dist/types-DBc0q5KD.d.mts.map +0 -1
- package/dist/types-ZW-nfWf6.cjs +0 -40
- package/dist/types-ZW-nfWf6.cjs.map +0 -1
- package/dist/types-l7Rlb5Mg.d.cts.map +0 -1
- package/dist/types-ojhnLdwz.mjs +0 -34
- package/dist/types-ojhnLdwz.mjs.map +0 -1
- package/dist/ui-assets-BEXqOQLe.cjs +0 -48
- package/dist/ui-assets-BEXqOQLe.cjs.map +0 -1
- package/dist/ui-assets-BhTDUsrM.mjs +0 -30
- package/dist/ui-assets-BhTDUsrM.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kysely.cjs","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","schema?: string","name: string"],"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);\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'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":";;;;;;;;;;;;;;;;;;;;;;;AAyHA,IAAa,gBAAb,MAA2D;CAC1D,AAAiB;;;;;;;;;;CAWjB,AAAiB,gBAAgB;CACjC,AAAiB,kBAAkB;CACnC,AAAiB,YAAY;CAE7B,YAAYA,QAAiC;AAE5C,OAAK,KAAK,OAAO,SACb,OAAO,GAAG,WAAW,OAAO,OAAO,GACpC,OAAO;CACV;CAMD,MAAM,YAAYC,OAAoC;EACrD,MAAM,MAAM,KAAK,aAAa,MAAM;AACpC,QAAM,AAAC,KAAK,GAAW,WAAW,KAAK,cAAc,CAAC,OAAO,IAAI,CAAC,SAAS;CAC3E;CAED,MAAM,aAAaC,SAAwC;AAC1D,MAAI,QAAQ,WAAW,EAAG;EAE1B,MAAM,OAAO,QAAQ,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;AACrD,QAAM,AAAC,KAAK,GACV,WAAW,KAAK,cAAc,CAC9B,OAAO,KAAK,CACZ,SAAS;CACX;CAED,MAAM,YAAYC,SAAiD;EAClE,IAAI,QAAQ,AAAC,KAAK,GAChB,WAAW,KAAK,cAAc,CAC9B,WAAW,CACX,QAAQ,aAAa,OAAO;AAG9B,MAAI,SAAS,OACZ,SAAQ,MAAM,MAAM,UAAU,KAAK,QAAQ,OAAO;AAGnD,MAAI,SAAS,QAAQ;GACpB,MAAM,eAAe,QAAQ;AAC7B,OAAI,aAAa,SAAS,KAAK,EAAE;IAEhC,MAAM,YAAY,aAAa;AAC/B,QAAI,WAAW;KACd,MAAM,WAAW,SAAS,WAAW,GAAG;KACxC,MAAM,YAAY,WAAW;KAC7B,MAAM,YAAY,YAAY;AAC9B,aAAQ,MACN,MAAM,UAAU,MAAM,UAAU,CAChC,MAAM,UAAU,MAAM,UAAU;IAClC;GACD,MAEA,SAAQ,MAAM,MAAM,UAAU,KAAK,SAAS,cAAc,GAAG,CAAC;EAE/D;AAED,UAAQ,KAAK,kBAAkB,OAAO,QAAQ;EAE9C,MAAM,OAAO,MAAM,MAAM,SAAS;AAClC,SAAO,KAAK,IAAI,CAACC,QAA+B,KAAK,aAAa,IAAI,CAAC;CACvE;CAED,MAAM,WAAWC,IAA0C;EAC1D,MAAM,MAAM,MAAM,AAAC,KAAK,GACtB,WAAW,KAAK,cAAc,CAC9B,WAAW,CACX,MAAM,MAAM,KAAK,GAAG,CACpB,kBAAkB;AAEpB,SAAO,MAAM,KAAK,aAAa,IAAI,GAAG;CACtC;CAMD,MAAM,cAAcC,OAAsC;EACzD,MAAM,MAAM,KAAK,eAAe,MAAM;AACtC,QAAM,AAAC,KAAK,GACV,WAAW,KAAK,gBAAgB,CAChC,OAAO,IAAI,CACX,SAAS;CACX;CAED,MAAM,eAAeC,SAA0C;AAC9D,MAAI,QAAQ,WAAW,EAAG;EAE1B,MAAM,OAAO,QAAQ,IAAI,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;AACvD,QAAM,AAAC,KAAK,GACV,WAAW,KAAK,gBAAgB,CAChC,OAAO,KAAK,CACZ,SAAS;CACX;CAED,MAAM,cAAcJ,SAAmD;EACtE,IAAI,QAAQ,AAAC,KAAK,GAChB,WAAW,KAAK,gBAAgB,CAChC,WAAW,CACX,QAAQ,aAAa,OAAO;AAE9B,UAAQ,KAAK,kBAAkB,OAAO,QAAQ;EAE9C,MAAM,OAAO,MAAM,MAAM,SAAS;AAClC,SAAO,KAAK,IAAI,CAACK,QAAiC,KAAK,eAAe,IAAI,CAAC;CAC3E;CAED,MAAM,aAAaH,IAA4C;EAC9D,MAAM,MAAM,MAAM,AAAC,KAAK,GACtB,WAAW,KAAK,gBAAgB,CAChC,WAAW,CACX,MAAM,MAAM,KAAK,GAAG,CACpB,kBAAkB;AAEpB,SAAO,MAAM,KAAK,eAAe,IAAI,GAAG;CACxC;CAMD,MAAM,QAAQI,OAAgC;EAC7C,MAAM,MAAM,KAAK,SAAS,MAAM;AAChC,QAAM,AAAC,KAAK,GAAW,WAAW,KAAK,UAAU,CAAC,OAAO,IAAI,CAAC,SAAS;CACvE;CAED,MAAM,SAASC,SAAoC;AAClD,MAAI,QAAQ,WAAW,EAAG;EAE1B,MAAM,OAAO,QAAQ,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;AACjD,QAAM,AAAC,KAAK,GAAW,WAAW,KAAK,UAAU,CAAC,OAAO,KAAK,CAAC,SAAS;CACxE;CAED,MAAM,QAAQP,SAA6C;EAC1D,IAAI,QAAQ,AAAC,KAAK,GAChB,WAAW,KAAK,UAAU,CAC1B,WAAW,CACX,QAAQ,aAAa,OAAO;AAG9B,MAAI,SAAS,MACZ,SAAQ,MAAM,MAAM,SAAS,KAAK,QAAQ,MAAM;AAGjD,UAAQ,KAAK,kBAAkB,OAAO,QAAQ;EAE9C,MAAM,OAAO,MAAM,MAAM,SAAS;AAClC,SAAO,KAAK,IAAI,CAACQ,QAA2B,KAAK,SAAS,IAAI,CAAC;CAC/D;CAMD,MAAM,MAAMC,WAAkC;EAC7C,MAAM,UAAU,MAAM,QAAQ,IAAI;GACjC,AAAC,KAAK,GACJ,WAAW,KAAK,cAAc,CAC9B,MAAM,aAAa,KAAK,UAAU,CAClC,kBAAkB;GACpB,AAAC,KAAK,GACJ,WAAW,KAAK,gBAAgB,CAChC,MAAM,aAAa,KAAK,UAAU,CAClC,kBAAkB;GACpB,AAAC,KAAK,GACJ,WAAW,KAAK,UAAU,CAC1B,MAAM,aAAa,KAAK,UAAU,CAClC,kBAAkB;EACpB,EAAC;AAEF,SAAO,QAAQ,OACd,CAAC,KAAK,WAAW,MAAM,OAAO,OAAO,kBAAkB,EAAE,EACzD,EACA;CACD;CAMD,MAAM,WAAoC;EACzC,MAAM,CAAC,gBAAgB,kBAAkB,WAAW,GAAG,MAAM,QAAQ,IAAI;GACxE,AAAC,KAAK,GACJ,WAAW,KAAK,cAAc,CAC9B,OAAO,CAACC,OAAY;IACpB,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ;IAC7B,GAAG,GAAG,IAAI,YAAY,CAAC,GAAG,SAAS;IACnC,GAAG,GAAG,IAAI,YAAY,CAAC,GAAG,SAAS;GACnC,EAAC,CACD,kBAAkB;GACpB,AAAC,KAAK,GACJ,WAAW,KAAK,gBAAgB,CAChC,OAAO,CAACA,OAAY;IACpB,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ;IAC7B,GAAG,GAAG,IAAI,YAAY,CAAC,GAAG,SAAS;IACnC,GAAG,GAAG,IAAI,YAAY,CAAC,GAAG,SAAS;GACnC,EAAC,CACD,kBAAkB;GACpB,AAAC,KAAK,GACJ,WAAW,KAAK,UAAU,CAC1B,OAAO,CAACA,OAAY;IACpB,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ;IAC7B,GAAG,GAAG,IAAI,YAAY,CAAC,GAAG,SAAS;IACnC,GAAG,GAAG,IAAI,YAAY,CAAC,GAAG,SAAS;GACnC,EAAC,CACD,kBAAkB;EACpB,EAAC;EAEF,MAAM,WAAW;GAChB,gBAAgB;GAChB,gBAAgB;GAChB,kBAAkB;GAClB,kBAAkB;GAClB,YAAY;GACZ,YAAY;EACZ,EACC,OAAO,CAAC,MAAiB,KAAK,KAAK,CACnC,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,GAAG,SAAS,GAAG,IAAI,KAAK,GAAG,SAAS,CAAC;EAE/D,MAAM,aAAa,SAAS,SAAS,SAAS;AAC9C,SAAO;GACN,UAAU,OAAO,gBAAgB,SAAS,EAAE;GAC5C,YAAY,OAAO,kBAAkB,SAAS,EAAE;GAChD,MAAM,OAAO,YAAY,SAAS,EAAE;GACpC,aAAa,SAAS,KAAK,IAAI,KAAK,SAAS;GAC7C,aAAa,aAAa,IAAI,KAAK;EACnC;CACD;CAMD,AAAQ,kBAAkBC,OAAYX,SAA6B;AAClE,OAAK,QACJ,QAAO,MAAM,MAAM,GAAG;AAGvB,MAAI,QAAQ,MACX,SAAQ,MAAM,MAAM,aAAa,MAAM,QAAQ,MAAM;AAGtD,MAAI,QAAQ,OACX,SAAQ,MAAM,MAAM,aAAa,MAAM,QAAQ,OAAO;AAGvD,MAAI,QAAQ,OAGX,SAAQ,MAAM,MAAM,CAACU,OACpB,GAAG,GAAG;GACL,GAAG,WAAW,UAAU,GAAG,QAAQ,OAAO,GAAG;GAC7C,GAAG,QAAQ,UAAU,GAAG,QAAQ,OAAO,GAAG;GAC1C,GAAG,OAAO,UAAU,GAAG,QAAQ,OAAO,GAAG;EACzC,EAAC,CACF;EAMF,MAAM,QAAQ,QAAQ,SAAS;EAC/B,MAAM,SAAS,QAAQ,UAAU;AAEjC,SAAO,MAAM,MAAM,MAAM,CAAC,OAAO,OAAO;CACxC;CAED,AAAQ,aAAaZ,OAA4C;AAChE,SAAO;GACN,IAAI,MAAM;GACV,QAAQ,MAAM;GACd,MAAM,MAAM;GACZ,KAAK,MAAM;GACX,SAAS,MAAM;GACf,MAAM,MAAM,QAAQ;GACpB,OAAO,MAAM,SAAS;GACtB,QAAQ,MAAM;GACd,kBAAkB,MAAM;GACxB,eAAe,MAAM,gBAAgB;GACrC,UAAU,MAAM;GAChB,WAAW,MAAM;GACjB,IAAI,MAAM,MAAM;GAChB,SAAS,MAAM,UAAU;GACzB,MAAM,MAAM,QAAQ;EACpB;CACD;CAED,AAAQ,aAAaG,KAA0C;AAC9D,SAAO;GACN,IAAI,IAAI;GACR,QAAQ,IAAI;GACZ,MAAM,IAAI;GACV,KAAK,IAAI;GACT,SAAS,KAAK,UAAU,IAAI,QAAQ;GACpC,MAAM,IAAI,OAAO,KAAK,UAAU,IAAI,KAAK;GACzC,OAAO,IAAI,QACP,KAAK,UAAU,IAAI,MAAM;GAE7B,QAAQ,IAAI;GACZ,iBAAiB,KAAK,UAAU,IAAI,iBAAiB;GAIrD,cAAc,IAAI,gBACf,KAAK,UAAU,IAAI,cAAc;GAEpC,UAAU,IAAI;GACd,WAAW,IAAI,KAAK,IAAI;GACxB,IAAI,IAAI;GACR,QAAQ,IAAI;GACZ,MAAM,IAAI,OAAQ,KAAK,UAAU,IAAI,KAAK;EAC1C;CACD;CAED,AAAQ,eAAeE,OAAgD;AACtE,SAAO;GACN,IAAI,MAAM;GACV,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,OAAO,MAAM;GACb,QAAQ,MAAM,UAAU;GACxB,YAAY,MAAM,aAAa;GAC/B,WAAW,MAAM;GACjB,SAAS,MAAM;GACf,MAAM,MAAM,QAAQ;EACpB;CACD;CAED,AAAQ,eAAeE,KAA8C;AACpE,SAAO;GACN,IAAI,IAAI;GACR,MAAM,IAAI;GACV,SAAS,IAAI;GACb,OAAO,KAAK,UAAU,IAAI,MAAM;GAChC,QAAQ,IAAI,SACR,KAAK,UAAU,IAAI,OAAO;GAE9B,WAAW,IAAI;GACf,WAAW,IAAI,KAAK,IAAI;GACxB,SAAS,IAAI;GACb,MAAM,IAAI,OAAQ,KAAK,UAAU,IAAI,KAAK;EAC1C;CACD;CAED,AAAQ,SAASC,OAAoC;AACpD,SAAO;GACN,IAAI,MAAM;GACV,OAAO,MAAM;GACb,SAAS,MAAM;GACf,SAAS,MAAM,WAAW;GAC1B,YAAY,MAAM,aAAa;GAC/B,WAAW,MAAM;EACjB;CACD;CAED,AAAQ,SAASE,KAAkC;AAClD,SAAO;GACN,IAAI,IAAI;GACR,OAAO,IAAI;GACX,SAAS,IAAI;GACb,SAAS,IAAI,UACT,KAAK,UAAU,IAAI,QAAQ;GAE/B,WAAW,IAAI;GACf,WAAW,IAAI,KAAK,IAAI;EACxB;CACD;;;;CAKD,AAAQ,UAAUI,OAAyB;AAC1C,aAAW,UAAU,YAAY,UAAU,KAC1C,QAAO;AAER,aAAW,UAAU,SACpB,KAAI;AACH,UAAO,KAAK,MAAM,MAAM;EACxB,QAAO;AACP,UAAO;EACP;AAEF,SAAO;CACP;AACD;;;;;;;;;;;;;;;;;;;;;;;;AAyBD,SAAgB,sBAAsBC,QAGpC;CAID,MAAM,IAAI,CAACC,SAAkB,UAAU,EAAE,OAAO,GAAG,KAAK,IAAI;CAC5D,MAAM,MAAM,CAACA,SAAkB,UAAU,EAAE,OAAO,GAAG,KAAK,IAAI;AAE9D,QAAO;EACN,KAAK,EAAE,UAAU,8BAA8B,OAAO,OAAO,GAAG;;6BAErC,EAAE,WAAW,CAAC;;;;;;;;;;;;;;;;;;iCAkBV,IAAI,WAAW,CAAC;OAC1C,EAAE,WAAW,CAAC;iCACY,IAAI,WAAW,CAAC;OAC1C,EAAE,WAAW,CAAC;iCACY,IAAI,WAAW,CAAC;OAC1C,EAAE,WAAW,CAAC;;;6BAGQ,EAAE,aAAa,CAAC;;;;;;;;;;;;iCAYZ,IAAI,aAAa,CAAC;OAC5C,EAAE,aAAa,CAAC;iCACU,IAAI,aAAa,CAAC;OAC5C,EAAE,aAAa,CAAC;;;6BAGM,EAAE,OAAO,CAAC;;;;;;;;;iCASN,IAAI,OAAO,CAAC;OACtC,EAAE,OAAO,CAAC;iCACgB,IAAI,OAAO,CAAC;OACtC,EAAE,OAAO,CAAC;iCACgB,IAAI,OAAO,CAAC;OACtC,EAAE,OAAO,CAAC;;EAGf,MAAM,UACF,wBAAwB,OAAO,gBAC/B;;;;;CAKJ;AACD"}
|
|
1
|
+
{"version":3,"file":"kysely.cjs","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,13 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as TelescopeStorage, a as LogEntry, f as RequestEntry, i as ExceptionEntry, u as QueryOptions, x as TelescopeStats } from "../types-a9Vistj1.cjs";
|
|
2
2
|
import { Kysely } from "kysely";
|
|
3
|
-
|
|
4
3
|
//#region src/storage/kysely.d.ts
|
|
5
|
-
|
|
6
4
|
/**
|
|
7
5
|
* Database table interface for telescope requests.
|
|
8
6
|
* Use this to define your telescope_requests table in your Kysely database schema.
|
|
9
7
|
*/
|
|
10
|
-
interface TelescopeRequestTable {
|
|
8
|
+
export interface TelescopeRequestTable {
|
|
11
9
|
id: string;
|
|
12
10
|
method: string;
|
|
13
11
|
path: string;
|
|
@@ -27,7 +25,7 @@ interface TelescopeRequestTable {
|
|
|
27
25
|
/**
|
|
28
26
|
* Database table interface for telescope exceptions.
|
|
29
27
|
*/
|
|
30
|
-
interface TelescopeExceptionTable {
|
|
28
|
+
export interface TelescopeExceptionTable {
|
|
31
29
|
id: string;
|
|
32
30
|
name: string;
|
|
33
31
|
message: string;
|
|
@@ -41,7 +39,7 @@ interface TelescopeExceptionTable {
|
|
|
41
39
|
/**
|
|
42
40
|
* Database table interface for telescope logs.
|
|
43
41
|
*/
|
|
44
|
-
interface TelescopeLogTable {
|
|
42
|
+
export interface TelescopeLogTable {
|
|
45
43
|
id: string;
|
|
46
44
|
level: string;
|
|
47
45
|
message: string;
|
|
@@ -63,7 +61,7 @@ interface TelescopeLogTable {
|
|
|
63
61
|
* }
|
|
64
62
|
* ```
|
|
65
63
|
*/
|
|
66
|
-
interface TelescopeTables {
|
|
64
|
+
export interface TelescopeTables {
|
|
67
65
|
requests: TelescopeRequestTable;
|
|
68
66
|
exceptions: TelescopeExceptionTable;
|
|
69
67
|
logs: TelescopeLogTable;
|
|
@@ -71,7 +69,7 @@ interface TelescopeTables {
|
|
|
71
69
|
/**
|
|
72
70
|
* Configuration for KyselyStorage.
|
|
73
71
|
*/
|
|
74
|
-
interface KyselyStorageConfig<DB> {
|
|
72
|
+
export interface KyselyStorageConfig<DB> {
|
|
75
73
|
/** Kysely database instance */
|
|
76
74
|
db: Kysely<DB>;
|
|
77
75
|
/**
|
|
@@ -109,7 +107,7 @@ interface KyselyStorageConfig<DB> {
|
|
|
109
107
|
* const telescope = new Telescope({ storage });
|
|
110
108
|
* ```
|
|
111
109
|
*/
|
|
112
|
-
declare class KyselyStorage<DB> implements TelescopeStorage {
|
|
110
|
+
export declare class KyselyStorage<DB> implements TelescopeStorage {
|
|
113
111
|
private readonly db;
|
|
114
112
|
/**
|
|
115
113
|
* Unqualified, and deliberately.
|
|
@@ -172,11 +170,9 @@ declare class KyselyStorage<DB> implements TelescopeStorage {
|
|
|
172
170
|
* }
|
|
173
171
|
* ```
|
|
174
172
|
*/
|
|
175
|
-
declare function getTelescopeMigration(schema?: string): {
|
|
173
|
+
export declare function getTelescopeMigration(schema?: string): {
|
|
176
174
|
up: string;
|
|
177
175
|
down: string;
|
|
178
176
|
};
|
|
179
|
-
//# sourceMappingURL=kysely.d.ts.map
|
|
180
177
|
//#endregion
|
|
181
|
-
export { KyselyStorage, KyselyStorageConfig, TelescopeExceptionTable, TelescopeLogTable, TelescopeRequestTable, TelescopeTables, getTelescopeMigration };
|
|
182
178
|
//# sourceMappingURL=kysely.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kysely.d.cts","names":[],"sources":["../../src/storage/kysely.ts"],"
|
|
1
|
+
{"version":3,"file":"kysely.d.cts","names":[],"sources":["../../src/storage/kysely.ts"],"mappings":";;;;;;;iBAciB;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;EACX;EACA;EACA;;;;;iBAMgB;EAChB;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;EACX;EACA;;;;;iBAMgB;EAChB;EACA;EACA;EACA;EACA;EACA,WAAW;;;;;;;;;;;;;;;;iBAiBK;EAChB,UAAU;EACV,YAAY;EACZ,MAAM;;;;;iBAMU,oBAAoB;;EAEpC,IAAI,OAAO;;;;;;;;;;;;;EAaX;;;;;;;;;;;;;;;;;;;;;;;qBAwBY,cAAc,eAAe;mBACxB;;;;;;;;;;mBAWA;mBACA;mBACA;EAEjB,YAAY,QAAQ,oBAAoB;EAWlC,YAAY,OAAO,eAAe;EAKlC,aAAa,SAAS,iBAAiB;EAUvC,YAAY,UAAU,eAAe,QAAQ;EAoC7C,WAAW,aAAa,QAAQ;EAchC,cAAc,OAAO,iBAAiB;EAQtC,eAAe,SAAS,mBAAmB;EAU3C,cAAc,UAAU,eAAe,QAAQ;EAY/C,aAAa,aAAa,QAAQ;EAclC,QAAQ,OAAO,WAAW;EAK1B,SAAS,SAAS,aAAa;EAO/B,QAAQ,UAAU,eAAe,QAAQ;EAqBzC,MAAM,WAAW,OAAO;EA0BxB,YAAY,QAAQ;UAqDlB;UAwCA;UAoBA;UA2BA;UAcA;UAgBA;UAWA;;;;UAgBA;;;;;;;;;;;;;;;;;;;;;;;;;wBAkDO,sBAAsB;EACrC;EACA"}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as TelescopeStorage, a as LogEntry, f as RequestEntry, i as ExceptionEntry, u as QueryOptions, x as TelescopeStats } from "../types-a9Vistj1.mjs";
|
|
2
2
|
import { Kysely } from "kysely";
|
|
3
|
-
|
|
4
3
|
//#region src/storage/kysely.d.ts
|
|
5
|
-
|
|
6
4
|
/**
|
|
7
5
|
* Database table interface for telescope requests.
|
|
8
6
|
* Use this to define your telescope_requests table in your Kysely database schema.
|
|
9
7
|
*/
|
|
10
|
-
interface TelescopeRequestTable {
|
|
8
|
+
export interface TelescopeRequestTable {
|
|
11
9
|
id: string;
|
|
12
10
|
method: string;
|
|
13
11
|
path: string;
|
|
@@ -27,7 +25,7 @@ interface TelescopeRequestTable {
|
|
|
27
25
|
/**
|
|
28
26
|
* Database table interface for telescope exceptions.
|
|
29
27
|
*/
|
|
30
|
-
interface TelescopeExceptionTable {
|
|
28
|
+
export interface TelescopeExceptionTable {
|
|
31
29
|
id: string;
|
|
32
30
|
name: string;
|
|
33
31
|
message: string;
|
|
@@ -41,7 +39,7 @@ interface TelescopeExceptionTable {
|
|
|
41
39
|
/**
|
|
42
40
|
* Database table interface for telescope logs.
|
|
43
41
|
*/
|
|
44
|
-
interface TelescopeLogTable {
|
|
42
|
+
export interface TelescopeLogTable {
|
|
45
43
|
id: string;
|
|
46
44
|
level: string;
|
|
47
45
|
message: string;
|
|
@@ -63,7 +61,7 @@ interface TelescopeLogTable {
|
|
|
63
61
|
* }
|
|
64
62
|
* ```
|
|
65
63
|
*/
|
|
66
|
-
interface TelescopeTables {
|
|
64
|
+
export interface TelescopeTables {
|
|
67
65
|
requests: TelescopeRequestTable;
|
|
68
66
|
exceptions: TelescopeExceptionTable;
|
|
69
67
|
logs: TelescopeLogTable;
|
|
@@ -71,7 +69,7 @@ interface TelescopeTables {
|
|
|
71
69
|
/**
|
|
72
70
|
* Configuration for KyselyStorage.
|
|
73
71
|
*/
|
|
74
|
-
interface KyselyStorageConfig<DB> {
|
|
72
|
+
export interface KyselyStorageConfig<DB> {
|
|
75
73
|
/** Kysely database instance */
|
|
76
74
|
db: Kysely<DB>;
|
|
77
75
|
/**
|
|
@@ -109,7 +107,7 @@ interface KyselyStorageConfig<DB> {
|
|
|
109
107
|
* const telescope = new Telescope({ storage });
|
|
110
108
|
* ```
|
|
111
109
|
*/
|
|
112
|
-
declare class KyselyStorage<DB> implements TelescopeStorage {
|
|
110
|
+
export declare class KyselyStorage<DB> implements TelescopeStorage {
|
|
113
111
|
private readonly db;
|
|
114
112
|
/**
|
|
115
113
|
* Unqualified, and deliberately.
|
|
@@ -172,11 +170,9 @@ declare class KyselyStorage<DB> implements TelescopeStorage {
|
|
|
172
170
|
* }
|
|
173
171
|
* ```
|
|
174
172
|
*/
|
|
175
|
-
declare function getTelescopeMigration(schema?: string): {
|
|
173
|
+
export declare function getTelescopeMigration(schema?: string): {
|
|
176
174
|
up: string;
|
|
177
175
|
down: string;
|
|
178
176
|
};
|
|
179
|
-
//# sourceMappingURL=kysely.d.ts.map
|
|
180
177
|
//#endregion
|
|
181
|
-
export { KyselyStorage, KyselyStorageConfig, TelescopeExceptionTable, TelescopeLogTable, TelescopeRequestTable, TelescopeTables, getTelescopeMigration };
|
|
182
178
|
//# sourceMappingURL=kysely.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kysely.d.mts","names":[],"sources":["../../src/storage/kysely.ts"],"
|
|
1
|
+
{"version":3,"file":"kysely.d.mts","names":[],"sources":["../../src/storage/kysely.ts"],"mappings":";;;;;;;iBAciB;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;EACX;EACA;EACA;;;;;iBAMgB;EAChB;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;EACX;EACA;;;;;iBAMgB;EAChB;EACA;EACA;EACA;EACA;EACA,WAAW;;;;;;;;;;;;;;;;iBAiBK;EAChB,UAAU;EACV,YAAY;EACZ,MAAM;;;;;iBAMU,oBAAoB;;EAEpC,IAAI,OAAO;;;;;;;;;;;;;EAaX;;;;;;;;;;;;;;;;;;;;;;;qBAwBY,cAAc,eAAe;mBACxB;;;;;;;;;;mBAWA;mBACA;mBACA;EAEjB,YAAY,QAAQ,oBAAoB;EAWlC,YAAY,OAAO,eAAe;EAKlC,aAAa,SAAS,iBAAiB;EAUvC,YAAY,UAAU,eAAe,QAAQ;EAoC7C,WAAW,aAAa,QAAQ;EAchC,cAAc,OAAO,iBAAiB;EAQtC,eAAe,SAAS,mBAAmB;EAU3C,cAAc,UAAU,eAAe,QAAQ;EAY/C,aAAa,aAAa,QAAQ;EAclC,QAAQ,OAAO,WAAW;EAK1B,SAAS,SAAS,aAAa;EAO/B,QAAQ,UAAU,eAAe,QAAQ;EAqBzC,MAAM,WAAW,OAAO;EA0BxB,YAAY,QAAQ;UAqDlB;UAwCA;UAoBA;UA2BA;UAcA;UAgBA;UAWA;;;;UAgBA;;;;;;;;;;;;;;;;;;;;;;;;;wBAkDO,sBAAsB;EACrC;EACA"}
|
package/dist/storage/kysely.mjs
CHANGED
|
@@ -54,16 +54,14 @@ var KyselyStorage = class {
|
|
|
54
54
|
if (statusFilter.endsWith("xx")) {
|
|
55
55
|
const firstChar = statusFilter[0];
|
|
56
56
|
if (firstChar) {
|
|
57
|
-
const
|
|
58
|
-
const minStatus = category * 100;
|
|
57
|
+
const minStatus = parseInt(firstChar, 10) * 100;
|
|
59
58
|
const maxStatus = minStatus + 99;
|
|
60
59
|
query = query.where("status", ">=", minStatus).where("status", "<=", maxStatus);
|
|
61
60
|
}
|
|
62
61
|
} else query = query.where("status", "=", parseInt(statusFilter, 10));
|
|
63
62
|
}
|
|
64
|
-
query = this.applyQueryOptions(query, options);
|
|
65
|
-
|
|
66
|
-
return rows.map((row) => this.rowToRequest(row));
|
|
63
|
+
query = this.applyQueryOptions(query, options, ["path", "url"]);
|
|
64
|
+
return (await query.execute()).map((row) => this.rowToRequest(row));
|
|
67
65
|
}
|
|
68
66
|
async getRequest(id) {
|
|
69
67
|
const row = await this.db.selectFrom(this.requestsTable).selectAll().where("id", "=", id).executeTakeFirst();
|
|
@@ -80,9 +78,8 @@ var KyselyStorage = class {
|
|
|
80
78
|
}
|
|
81
79
|
async getExceptions(options) {
|
|
82
80
|
let query = this.db.selectFrom(this.exceptionsTable).selectAll().orderBy("timestamp", "desc");
|
|
83
|
-
query = this.applyQueryOptions(query, options);
|
|
84
|
-
|
|
85
|
-
return rows.map((row) => this.rowToException(row));
|
|
81
|
+
query = this.applyQueryOptions(query, options, ["name", "message"]);
|
|
82
|
+
return (await query.execute()).map((row) => this.rowToException(row));
|
|
86
83
|
}
|
|
87
84
|
async getException(id) {
|
|
88
85
|
const row = await this.db.selectFrom(this.exceptionsTable).selectAll().where("id", "=", id).executeTakeFirst();
|
|
@@ -100,17 +97,15 @@ var KyselyStorage = class {
|
|
|
100
97
|
async getLogs(options) {
|
|
101
98
|
let query = this.db.selectFrom(this.logsTable).selectAll().orderBy("timestamp", "desc");
|
|
102
99
|
if (options?.level) query = query.where("level", "=", options.level);
|
|
103
|
-
query = this.applyQueryOptions(query, options);
|
|
104
|
-
|
|
105
|
-
return rows.map((row) => this.rowToLog(row));
|
|
100
|
+
query = this.applyQueryOptions(query, options, ["message"]);
|
|
101
|
+
return (await query.execute()).map((row) => this.rowToLog(row));
|
|
106
102
|
}
|
|
107
103
|
async prune(olderThan) {
|
|
108
|
-
|
|
104
|
+
return (await Promise.all([
|
|
109
105
|
this.db.deleteFrom(this.requestsTable).where("timestamp", "<", olderThan).executeTakeFirst(),
|
|
110
106
|
this.db.deleteFrom(this.exceptionsTable).where("timestamp", "<", olderThan).executeTakeFirst(),
|
|
111
107
|
this.db.deleteFrom(this.logsTable).where("timestamp", "<", olderThan).executeTakeFirst()
|
|
112
|
-
]);
|
|
113
|
-
return results.reduce((sum, result) => sum + Number(result.numDeletedRows ?? 0), 0);
|
|
108
|
+
])).reduce((sum, result) => sum + Number(result.numDeletedRows ?? 0), 0);
|
|
114
109
|
}
|
|
115
110
|
async getStats() {
|
|
116
111
|
const [requestsResult, exceptionsResult, logsResult] = await Promise.all([
|
|
@@ -147,15 +142,11 @@ var KyselyStorage = class {
|
|
|
147
142
|
newestEntry: newestDate ? new Date(newestDate) : void 0
|
|
148
143
|
};
|
|
149
144
|
}
|
|
150
|
-
applyQueryOptions(query, options) {
|
|
145
|
+
applyQueryOptions(query, options, searchColumns) {
|
|
151
146
|
if (!options) return query.limit(50);
|
|
152
147
|
if (options.after) query = query.where("timestamp", ">=", options.after);
|
|
153
148
|
if (options.before) query = query.where("timestamp", "<=", options.before);
|
|
154
|
-
if (options.search) query = query.where((eb) => eb.or(
|
|
155
|
-
eb("message", "ilike", `%${options.search}%`),
|
|
156
|
-
eb("path", "ilike", `%${options.search}%`),
|
|
157
|
-
eb("url", "ilike", `%${options.search}%`)
|
|
158
|
-
]));
|
|
149
|
+
if (options.search) query = query.where((eb) => eb.or(searchColumns.map((column) => eb(column, "ilike", `%${options.search}%`))));
|
|
159
150
|
const limit = options.limit ?? 50;
|
|
160
151
|
const offset = options.offset ?? 0;
|
|
161
152
|
return query.limit(limit).offset(offset);
|
|
@@ -166,17 +157,17 @@ var KyselyStorage = class {
|
|
|
166
157
|
method: entry.method,
|
|
167
158
|
path: entry.path,
|
|
168
159
|
url: entry.url,
|
|
169
|
-
headers: entry.headers,
|
|
170
|
-
body: entry.body
|
|
171
|
-
query: entry.query
|
|
160
|
+
headers: toJson(entry.headers),
|
|
161
|
+
body: toJson(entry.body),
|
|
162
|
+
query: toJson(entry.query),
|
|
172
163
|
status: entry.status,
|
|
173
|
-
response_headers: entry.responseHeaders,
|
|
174
|
-
response_body: entry.responseBody
|
|
164
|
+
response_headers: toJson(entry.responseHeaders),
|
|
165
|
+
response_body: toJson(entry.responseBody),
|
|
175
166
|
duration: entry.duration,
|
|
176
167
|
timestamp: entry.timestamp,
|
|
177
168
|
ip: entry.ip ?? null,
|
|
178
169
|
user_id: entry.userId ?? null,
|
|
179
|
-
tags: entry.tags
|
|
170
|
+
tags: toJson(entry.tags)
|
|
180
171
|
};
|
|
181
172
|
}
|
|
182
173
|
rowToRequest(row) {
|
|
@@ -203,12 +194,12 @@ var KyselyStorage = class {
|
|
|
203
194
|
id: entry.id,
|
|
204
195
|
name: entry.name,
|
|
205
196
|
message: entry.message,
|
|
206
|
-
stack: entry.stack,
|
|
207
|
-
source: entry.source
|
|
197
|
+
stack: toJson(entry.stack),
|
|
198
|
+
source: toJson(entry.source),
|
|
208
199
|
request_id: entry.requestId ?? null,
|
|
209
200
|
timestamp: entry.timestamp,
|
|
210
201
|
handled: entry.handled,
|
|
211
|
-
tags: entry.tags
|
|
202
|
+
tags: toJson(entry.tags)
|
|
212
203
|
};
|
|
213
204
|
}
|
|
214
205
|
rowToException(row) {
|
|
@@ -229,7 +220,7 @@ var KyselyStorage = class {
|
|
|
229
220
|
id: entry.id,
|
|
230
221
|
level: entry.level,
|
|
231
222
|
message: entry.message,
|
|
232
|
-
context: entry.context
|
|
223
|
+
context: toJson(entry.context),
|
|
233
224
|
request_id: entry.requestId ?? null,
|
|
234
225
|
timestamp: entry.timestamp
|
|
235
226
|
};
|
|
@@ -258,6 +249,17 @@ var KyselyStorage = class {
|
|
|
258
249
|
}
|
|
259
250
|
};
|
|
260
251
|
/**
|
|
252
|
+
* A value for a JSON column, as JSON text.
|
|
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
|
+
/**
|
|
261
263
|
* SQL migration to create telescope's tables.
|
|
262
264
|
*
|
|
263
265
|
* Pass a schema to have them created in one, and to have `down` drop the whole
|
|
@@ -353,7 +355,7 @@ DROP TABLE IF EXISTS requests;
|
|
|
353
355
|
`
|
|
354
356
|
};
|
|
355
357
|
}
|
|
356
|
-
|
|
357
358
|
//#endregion
|
|
358
359
|
export { KyselyStorage, getTelescopeMigration };
|
|
360
|
+
|
|
359
361
|
//# sourceMappingURL=kysely.mjs.map
|
|
@@ -1 +1 @@
|
|
|
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","schema?: string","name: string"],"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);\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'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":[],"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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"}
|