apitally 0.25.8 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +228 -178
- package/dist/activation.cjs +393 -0
- package/dist/activation.cjs.map +1 -0
- package/dist/activation.d.cts +42 -0
- package/dist/activation.d.ts +42 -0
- package/dist/activation.js +383 -0
- package/dist/activation.js.map +1 -0
- package/dist/adonisjs/configure.cjs +86 -30
- package/dist/adonisjs/configure.cjs.map +1 -1
- package/dist/adonisjs/configure.d.cts +0 -4
- package/dist/adonisjs/configure.d.ts +0 -4
- package/dist/adonisjs/configure.js +83 -29
- package/dist/adonisjs/configure.js.map +1 -1
- package/dist/adonisjs/index.cjs +38 -21
- package/dist/adonisjs/index.cjs.map +1 -1
- package/dist/adonisjs/index.d.cts +5 -14
- package/dist/adonisjs/index.d.ts +5 -14
- package/dist/adonisjs/index.js +39 -18
- package/dist/adonisjs/index.js.map +1 -1
- package/dist/adonisjs/middleware.cjs +43 -109
- package/dist/adonisjs/middleware.cjs.map +1 -1
- package/dist/adonisjs/middleware.d.cts +1 -16
- package/dist/adonisjs/middleware.d.ts +1 -16
- package/dist/adonisjs/middleware.js +43 -110
- package/dist/adonisjs/middleware.js.map +1 -1
- package/dist/adonisjs/provider.cjs +19 -87
- package/dist/adonisjs/provider.cjs.map +1 -1
- package/dist/adonisjs/provider.d.cts +0 -22
- package/dist/adonisjs/provider.d.ts +0 -22
- package/dist/adonisjs/provider.js +19 -88
- package/dist/adonisjs/provider.js.map +1 -1
- package/dist/adonisjs/stubs/config/apitally.stub +11 -15
- package/dist/bodyCapture.cjs +128 -0
- package/dist/bodyCapture.cjs.map +1 -0
- package/dist/bodyCapture.d.cts +31 -0
- package/dist/bodyCapture.d.ts +31 -0
- package/dist/bodyCapture.js +101 -0
- package/dist/bodyCapture.js.map +1 -0
- package/dist/config.cjs +227 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +45 -0
- package/dist/config.d.ts +45 -0
- package/dist/config.js +192 -0
- package/dist/config.js.map +1 -0
- package/dist/consumer.cjs +98 -0
- package/dist/consumer.cjs.map +1 -0
- package/dist/consumer.d.cts +15 -0
- package/dist/consumer.d.ts +15 -0
- package/dist/consumer.js +78 -0
- package/dist/consumer.js.map +1 -0
- package/dist/context.cjs +68 -0
- package/dist/context.cjs.map +1 -0
- package/dist/context.d.cts +33 -0
- package/dist/context.d.ts +33 -0
- package/dist/context.js +40 -0
- package/dist/context.js.map +1 -0
- package/dist/elysia/index.cjs +12 -3
- package/dist/elysia/index.cjs.map +1 -1
- package/dist/elysia/index.d.cts +8 -16
- package/dist/elysia/index.d.ts +8 -16
- package/dist/elysia/index.js +10 -2
- package/dist/elysia/index.js.map +1 -1
- package/dist/elysia/middleware.cjs +261 -0
- package/dist/elysia/middleware.cjs.map +1 -0
- package/dist/elysia/middleware.d.cts +14 -0
- package/dist/elysia/middleware.d.ts +14 -0
- package/dist/elysia/middleware.js +250 -0
- package/dist/elysia/middleware.js.map +1 -0
- package/dist/{otel/index.cjs → elysia/routes.cjs} +16 -7
- package/dist/elysia/routes.cjs.map +1 -0
- package/dist/elysia/routes.d.cts +7 -0
- package/dist/elysia/routes.d.ts +7 -0
- package/dist/elysia/routes.js +14 -0
- package/dist/elysia/routes.js.map +1 -0
- package/dist/exceptions.cjs +81 -0
- package/dist/exceptions.cjs.map +1 -0
- package/dist/exceptions.d.cts +7 -0
- package/dist/exceptions.d.ts +7 -0
- package/dist/exceptions.js +55 -0
- package/dist/exceptions.js.map +1 -0
- package/dist/exportSerialization.cjs +56 -0
- package/dist/exportSerialization.cjs.map +1 -0
- package/dist/exportSerialization.d.cts +7 -0
- package/dist/exportSerialization.d.ts +7 -0
- package/dist/exportSerialization.js +32 -0
- package/dist/exportSerialization.js.map +1 -0
- package/dist/exportWorker.cjs +305 -0
- package/dist/exportWorker.cjs.map +1 -0
- package/dist/exportWorker.d.cts +46 -0
- package/dist/exportWorker.d.ts +46 -0
- package/dist/exportWorker.js +279 -0
- package/dist/exportWorker.js.map +1 -0
- package/dist/express/index.cjs +9 -4
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.d.cts +7 -10
- package/dist/express/index.d.ts +7 -10
- package/dist/express/index.js +8 -2
- package/dist/express/index.js.map +1 -1
- package/dist/express/install.cjs +45 -0
- package/dist/express/install.cjs.map +1 -0
- package/dist/express/install.d.cts +10 -0
- package/dist/express/install.d.ts +10 -0
- package/dist/express/install.js +21 -0
- package/dist/express/install.js.map +1 -0
- package/dist/express/middleware.cjs +87 -331
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.d.cts +3 -21
- package/dist/express/middleware.d.ts +3 -21
- package/dist/express/middleware.js +91 -327
- package/dist/express/middleware.js.map +1 -1
- package/dist/express/register.cjs +20 -0
- package/dist/express/register.cjs.map +1 -0
- package/dist/express/register.d.cts +2 -0
- package/dist/express/register.d.ts +2 -0
- package/dist/express/register.js +19 -0
- package/dist/express/register.js.map +1 -0
- package/dist/express/routes.cjs +429 -0
- package/dist/express/routes.cjs.map +1 -0
- package/dist/express/routes.d.cts +14 -0
- package/dist/express/routes.d.ts +14 -0
- package/dist/express/routes.js +401 -0
- package/dist/express/routes.js.map +1 -0
- package/dist/fastify/index.cjs +10 -5
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.d.cts +7 -11
- package/dist/fastify/index.d.ts +7 -11
- package/dist/fastify/index.js +9 -3
- package/dist/fastify/index.js.map +1 -1
- package/dist/{loggers/index.cjs → fastify/install.cjs} +17 -19
- package/dist/fastify/install.cjs.map +1 -0
- package/dist/fastify/install.d.cts +10 -0
- package/dist/fastify/install.d.ts +10 -0
- package/dist/fastify/install.js +15 -0
- package/dist/fastify/install.js.map +1 -0
- package/dist/fastify/middleware.cjs +135 -0
- package/dist/fastify/middleware.cjs.map +1 -0
- package/dist/fastify/middleware.d.cts +7 -0
- package/dist/fastify/middleware.d.ts +7 -0
- package/dist/fastify/middleware.js +114 -0
- package/dist/fastify/middleware.js.map +1 -0
- package/dist/{common/paramValidation.cjs → fastify/routes.cjs} +15 -17
- package/dist/fastify/routes.cjs.map +1 -0
- package/dist/fastify/routes.d.cts +8 -0
- package/dist/fastify/routes.d.ts +8 -0
- package/dist/fastify/routes.js +14 -0
- package/dist/fastify/routes.js.map +1 -0
- package/dist/h3/index.cjs +28 -4
- package/dist/h3/index.cjs.map +1 -1
- package/dist/h3/index.d.cts +8 -10
- package/dist/h3/index.d.ts +8 -10
- package/dist/h3/index.js +26 -2
- package/dist/h3/index.js.map +1 -1
- package/dist/h3/middleware.cjs +210 -0
- package/dist/h3/middleware.cjs.map +1 -0
- package/dist/h3/middleware.d.cts +5 -0
- package/dist/h3/middleware.d.ts +5 -0
- package/dist/h3/middleware.js +194 -0
- package/dist/h3/middleware.js.map +1 -0
- package/dist/h3/routes.cjs +66 -0
- package/dist/h3/routes.cjs.map +1 -0
- package/dist/h3/routes.d.cts +8 -0
- package/dist/h3/routes.d.ts +8 -0
- package/dist/h3/routes.js +41 -0
- package/dist/h3/routes.js.map +1 -0
- package/dist/hapi/index.cjs +15 -4
- package/dist/hapi/index.cjs.map +1 -1
- package/dist/hapi/index.d.cts +8 -10
- package/dist/hapi/index.d.ts +8 -10
- package/dist/hapi/index.js +13 -2
- package/dist/hapi/index.js.map +1 -1
- package/dist/{loggers/hapi.cjs → hapi/install.cjs} +20 -26
- package/dist/hapi/install.cjs.map +1 -0
- package/dist/hapi/install.d.cts +8 -0
- package/dist/hapi/install.d.ts +8 -0
- package/dist/hapi/install.js +22 -0
- package/dist/hapi/install.js.map +1 -0
- package/dist/hapi/middleware.cjs +158 -0
- package/dist/hapi/middleware.cjs.map +1 -0
- package/dist/hapi/middleware.d.cts +5 -0
- package/dist/hapi/middleware.d.ts +5 -0
- package/dist/hapi/middleware.js +137 -0
- package/dist/hapi/middleware.js.map +1 -0
- package/dist/{common/logging.cjs → hapi/routes.cjs} +14 -17
- package/dist/hapi/routes.cjs.map +1 -0
- package/dist/hapi/routes.d.cts +8 -0
- package/dist/hapi/routes.d.ts +8 -0
- package/dist/hapi/routes.js +12 -0
- package/dist/hapi/routes.js.map +1 -0
- package/dist/hono/index.cjs +13 -3
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.d.cts +7 -10
- package/dist/hono/index.d.ts +7 -10
- package/dist/hono/index.js +13 -2
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.cjs +219 -127
- package/dist/hono/middleware.cjs.map +1 -1
- package/dist/hono/middleware.d.cts +3 -18
- package/dist/hono/middleware.d.ts +3 -18
- package/dist/hono/middleware.js +229 -126
- package/dist/hono/middleware.js.map +1 -1
- package/dist/hono/routes.cjs +74 -0
- package/dist/hono/routes.cjs.map +1 -0
- package/dist/hono/routes.d.cts +8 -0
- package/dist/hono/routes.d.ts +8 -0
- package/dist/hono/routes.js +49 -0
- package/dist/hono/routes.js.map +1 -0
- package/dist/index.cjs +108 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -1
- package/dist/koa/index.cjs +13 -3
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.d.cts +7 -10
- package/dist/koa/index.d.ts +7 -10
- package/dist/koa/index.js +13 -2
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +85 -184
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.d.cts +3 -13
- package/dist/koa/middleware.d.ts +3 -13
- package/dist/koa/middleware.js +88 -183
- package/dist/koa/middleware.js.map +1 -1
- package/dist/koa/routes.cjs +71 -0
- package/dist/koa/routes.cjs.map +1 -0
- package/dist/koa/routes.d.cts +8 -0
- package/dist/koa/routes.d.ts +8 -0
- package/dist/koa/routes.js +46 -0
- package/dist/koa/routes.js.map +1 -0
- package/dist/logCapture.cjs +417 -0
- package/dist/logCapture.cjs.map +1 -0
- package/dist/logCapture.d.cts +18 -0
- package/dist/logCapture.d.ts +18 -0
- package/dist/logCapture.js +390 -0
- package/dist/logCapture.js.map +1 -0
- package/dist/logRecordExporter.cjs +51 -0
- package/dist/logRecordExporter.cjs.map +1 -0
- package/dist/logRecordExporter.d.cts +14 -0
- package/dist/logRecordExporter.d.ts +14 -0
- package/dist/logRecordExporter.js +27 -0
- package/dist/logRecordExporter.js.map +1 -0
- package/dist/logRecordProcessor.cjs +137 -0
- package/dist/logRecordProcessor.cjs.map +1 -0
- package/dist/logRecordProcessor.d.cts +27 -0
- package/dist/logRecordProcessor.d.ts +27 -0
- package/dist/logRecordProcessor.js +113 -0
- package/dist/logRecordProcessor.js.map +1 -0
- package/dist/logger.cjs +62 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +7 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.js +34 -0
- package/dist/logger.js.map +1 -0
- package/dist/metrics.cjs +171 -0
- package/dist/metrics.cjs.map +1 -0
- package/dist/metrics.d.cts +26 -0
- package/dist/metrics.d.ts +26 -0
- package/dist/metrics.js +153 -0
- package/dist/metrics.js.map +1 -0
- package/dist/nestjs/index.cjs +81 -71
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +4 -11
- package/dist/nestjs/index.d.ts +4 -11
- package/dist/nestjs/index.js +81 -61
- package/dist/nestjs/index.js.map +1 -1
- package/dist/packageVersion.cjs +67 -0
- package/dist/packageVersion.cjs.map +1 -0
- package/dist/packageVersion.d.cts +5 -0
- package/dist/packageVersion.d.ts +5 -0
- package/dist/packageVersion.js +39 -0
- package/dist/packageVersion.js.map +1 -0
- package/dist/providers.cjs +149 -0
- package/dist/providers.cjs.map +1 -0
- package/dist/providers.d.cts +15 -0
- package/dist/providers.d.ts +15 -0
- package/dist/providers.js +136 -0
- package/dist/providers.js.map +1 -0
- package/dist/redaction.cjs +116 -0
- package/dist/redaction.cjs.map +1 -0
- package/dist/redaction.d.cts +17 -0
- package/dist/redaction.d.ts +17 -0
- package/dist/redaction.js +98 -0
- package/dist/redaction.js.map +1 -0
- package/dist/{common/packageVersions.cjs → requestAttributes.cjs} +21 -19
- package/dist/requestAttributes.cjs.map +1 -0
- package/dist/requestAttributes.d.cts +10 -0
- package/dist/requestAttributes.d.ts +10 -0
- package/dist/requestAttributes.js +22 -0
- package/dist/requestAttributes.js.map +1 -0
- package/dist/requestObservation.cjs +246 -0
- package/dist/requestObservation.cjs.map +1 -0
- package/dist/requestObservation.d.cts +62 -0
- package/dist/requestObservation.d.ts +62 -0
- package/dist/requestObservation.js +226 -0
- package/dist/requestObservation.js.map +1 -0
- package/dist/requestObservationNode.cjs +193 -0
- package/dist/requestObservationNode.cjs.map +1 -0
- package/dist/requestObservationNode.d.cts +31 -0
- package/dist/requestObservationNode.d.ts +31 -0
- package/dist/requestObservationNode.js +170 -0
- package/dist/requestObservationNode.js.map +1 -0
- package/dist/requestObservationWeb.cjs +202 -0
- package/dist/requestObservationWeb.cjs.map +1 -0
- package/dist/requestObservationWeb.d.cts +34 -0
- package/dist/requestObservationWeb.d.ts +34 -0
- package/dist/requestObservationWeb.js +182 -0
- package/dist/requestObservationWeb.js.map +1 -0
- package/dist/sentry.cjs +103 -0
- package/dist/sentry.cjs.map +1 -0
- package/dist/sentry.d.cts +3 -0
- package/dist/sentry.d.ts +3 -0
- package/dist/sentry.js +79 -0
- package/dist/sentry.js.map +1 -0
- package/dist/serverErrors.cjs +118 -0
- package/dist/serverErrors.cjs.map +1 -0
- package/dist/serverErrors.d.cts +8 -0
- package/dist/serverErrors.d.ts +8 -0
- package/dist/serverErrors.js +91 -0
- package/dist/serverErrors.js.map +1 -0
- package/dist/spanExporter.cjs +217 -0
- package/dist/spanExporter.cjs.map +1 -0
- package/dist/spanExporter.d.cts +34 -0
- package/dist/spanExporter.d.ts +34 -0
- package/dist/spanExporter.js +193 -0
- package/dist/spanExporter.js.map +1 -0
- package/dist/spanProcessor.cjs +535 -0
- package/dist/spanProcessor.cjs.map +1 -0
- package/dist/spanProcessor.d.cts +70 -0
- package/dist/spanProcessor.d.ts +70 -0
- package/dist/spanProcessor.js +513 -0
- package/dist/spanProcessor.js.map +1 -0
- package/dist/spool.cjs +314 -0
- package/dist/spool.cjs.map +1 -0
- package/dist/spool.d.cts +49 -0
- package/dist/spool.d.ts +49 -0
- package/dist/spool.js +297 -0
- package/dist/spool.js.map +1 -0
- package/dist/startup.cjs +98 -0
- package/dist/startup.cjs.map +1 -0
- package/dist/startup.d.cts +15 -0
- package/dist/startup.d.ts +15 -0
- package/dist/startup.js +73 -0
- package/dist/startup.js.map +1 -0
- package/dist/tracing.cjs +116 -0
- package/dist/tracing.cjs.map +1 -0
- package/dist/tracing.d.cts +5 -0
- package/dist/tracing.d.ts +5 -0
- package/dist/tracing.js +96 -0
- package/dist/tracing.js.map +1 -0
- package/dist/validationErrors.cjs +229 -0
- package/dist/validationErrors.cjs.map +1 -0
- package/dist/validationErrors.d.cts +21 -0
- package/dist/validationErrors.d.ts +21 -0
- package/dist/validationErrors.js +195 -0
- package/dist/validationErrors.js.map +1 -0
- package/package.json +113 -154
- package/dist/common/client.cjs +0 -335
- package/dist/common/client.cjs.map +0 -1
- package/dist/common/client.d.cts +0 -50
- package/dist/common/client.d.ts +0 -50
- package/dist/common/client.js +0 -302
- package/dist/common/client.js.map +0 -1
- package/dist/common/consumerRegistry.cjs +0 -86
- package/dist/common/consumerRegistry.cjs.map +0 -1
- package/dist/common/consumerRegistry.d.cts +0 -20
- package/dist/common/consumerRegistry.d.ts +0 -20
- package/dist/common/consumerRegistry.js +0 -62
- package/dist/common/consumerRegistry.js.map +0 -1
- package/dist/common/headers.cjs +0 -55
- package/dist/common/headers.cjs.map +0 -1
- package/dist/common/headers.d.cts +0 -6
- package/dist/common/headers.d.ts +0 -6
- package/dist/common/headers.js +0 -31
- package/dist/common/headers.js.map +0 -1
- package/dist/common/instance.cjs +0 -158
- package/dist/common/instance.cjs.map +0 -1
- package/dist/common/instance.d.cts +0 -4
- package/dist/common/instance.d.ts +0 -4
- package/dist/common/instance.js +0 -134
- package/dist/common/instance.js.map +0 -1
- package/dist/common/logging.cjs.map +0 -1
- package/dist/common/logging.d.cts +0 -11
- package/dist/common/logging.d.ts +0 -11
- package/dist/common/logging.js +0 -17
- package/dist/common/logging.js.map +0 -1
- package/dist/common/packageVersions.cjs.map +0 -1
- package/dist/common/packageVersions.d.cts +0 -3
- package/dist/common/packageVersions.d.ts +0 -3
- package/dist/common/packageVersions.js +0 -21
- package/dist/common/packageVersions.js.map +0 -1
- package/dist/common/paramValidation.cjs.map +0 -1
- package/dist/common/paramValidation.d.cts +0 -4
- package/dist/common/paramValidation.d.ts +0 -4
- package/dist/common/paramValidation.js +0 -17
- package/dist/common/paramValidation.js.map +0 -1
- package/dist/common/requestCounter.cjs +0 -114
- package/dist/common/requestCounter.cjs.map +0 -1
- package/dist/common/requestCounter.d.cts +0 -24
- package/dist/common/requestCounter.d.ts +0 -24
- package/dist/common/requestCounter.js +0 -91
- package/dist/common/requestCounter.js.map +0 -1
- package/dist/common/requestLogger.cjs +0 -543
- package/dist/common/requestLogger.cjs.map +0 -1
- package/dist/common/requestLogger.d.cts +0 -85
- package/dist/common/requestLogger.d.ts +0 -85
- package/dist/common/requestLogger.js +0 -508
- package/dist/common/requestLogger.js.map +0 -1
- package/dist/common/resources.cjs +0 -49
- package/dist/common/resources.cjs.map +0 -1
- package/dist/common/resources.d.cts +0 -6
- package/dist/common/resources.d.ts +0 -6
- package/dist/common/resources.js +0 -26
- package/dist/common/resources.js.map +0 -1
- package/dist/common/response.cjs +0 -104
- package/dist/common/response.cjs.map +0 -1
- package/dist/common/response.d.cts +0 -15
- package/dist/common/response.d.ts +0 -15
- package/dist/common/response.js +0 -80
- package/dist/common/response.js.map +0 -1
- package/dist/common/sentry.cjs +0 -56
- package/dist/common/sentry.cjs.map +0 -1
- package/dist/common/sentry.d.cts +0 -6
- package/dist/common/sentry.d.ts +0 -6
- package/dist/common/sentry.js +0 -23
- package/dist/common/sentry.js.map +0 -1
- package/dist/common/serverErrorCounter.cjs +0 -123
- package/dist/common/serverErrorCounter.cjs.map +0 -1
- package/dist/common/serverErrorCounter.d.cts +0 -23
- package/dist/common/serverErrorCounter.d.ts +0 -23
- package/dist/common/serverErrorCounter.js +0 -98
- package/dist/common/serverErrorCounter.js.map +0 -1
- package/dist/common/spanCollector.cjs +0 -201
- package/dist/common/spanCollector.cjs.map +0 -1
- package/dist/common/spanCollector.d.cts +0 -45
- package/dist/common/spanCollector.d.ts +0 -45
- package/dist/common/spanCollector.js +0 -177
- package/dist/common/spanCollector.js.map +0 -1
- package/dist/common/tempGzipFile.cjs +0 -127
- package/dist/common/tempGzipFile.cjs.map +0 -1
- package/dist/common/tempGzipFile.d.cts +0 -19
- package/dist/common/tempGzipFile.d.ts +0 -19
- package/dist/common/tempGzipFile.js +0 -103
- package/dist/common/tempGzipFile.js.map +0 -1
- package/dist/common/types.cjs +0 -17
- package/dist/common/types.cjs.map +0 -1
- package/dist/common/types.d.cts +0 -95
- package/dist/common/types.d.ts +0 -95
- package/dist/common/types.js +0 -1
- package/dist/common/types.js.map +0 -1
- package/dist/common/validationErrorCounter.cjs +0 -79
- package/dist/common/validationErrorCounter.cjs.map +0 -1
- package/dist/common/validationErrorCounter.d.cts +0 -20
- package/dist/common/validationErrorCounter.d.ts +0 -20
- package/dist/common/validationErrorCounter.js +0 -56
- package/dist/common/validationErrorCounter.js.map +0 -1
- package/dist/elysia/plugin.cjs +0 -242
- package/dist/elysia/plugin.cjs.map +0 -1
- package/dist/elysia/plugin.d.cts +0 -70
- package/dist/elysia/plugin.d.ts +0 -70
- package/dist/elysia/plugin.js +0 -219
- package/dist/elysia/plugin.js.map +0 -1
- package/dist/elysia/utils.cjs +0 -77
- package/dist/elysia/utils.cjs.map +0 -1
- package/dist/elysia/utils.d.cts +0 -14
- package/dist/elysia/utils.d.ts +0 -14
- package/dist/elysia/utils.js +0 -54
- package/dist/elysia/utils.js.map +0 -1
- package/dist/express/utils.cjs +0 -217
- package/dist/express/utils.cjs.map +0 -1
- package/dist/express/utils.d.cts +0 -37
- package/dist/express/utils.d.ts +0 -37
- package/dist/express/utils.js +0 -189
- package/dist/express/utils.js.map +0 -1
- package/dist/fastify/plugin.cjs +0 -319
- package/dist/fastify/plugin.cjs.map +0 -1
- package/dist/fastify/plugin.d.cts +0 -34
- package/dist/fastify/plugin.d.ts +0 -34
- package/dist/fastify/plugin.js +0 -284
- package/dist/fastify/plugin.js.map +0 -1
- package/dist/h3/plugin.cjs +0 -183
- package/dist/h3/plugin.cjs.map +0 -1
- package/dist/h3/plugin.d.cts +0 -27
- package/dist/h3/plugin.d.ts +0 -27
- package/dist/h3/plugin.js +0 -159
- package/dist/h3/plugin.js.map +0 -1
- package/dist/h3/utils.cjs +0 -77
- package/dist/h3/utils.cjs.map +0 -1
- package/dist/h3/utils.d.cts +0 -14
- package/dist/h3/utils.d.ts +0 -14
- package/dist/h3/utils.js +0 -54
- package/dist/h3/utils.js.map +0 -1
- package/dist/hapi/plugin.cjs +0 -212
- package/dist/hapi/plugin.cjs.map +0 -1
- package/dist/hapi/plugin.d.cts +0 -40
- package/dist/hapi/plugin.d.ts +0 -40
- package/dist/hapi/plugin.js +0 -188
- package/dist/hapi/plugin.js.map +0 -1
- package/dist/hapi/utils.cjs +0 -77
- package/dist/hapi/utils.cjs.map +0 -1
- package/dist/hapi/utils.d.cts +0 -16
- package/dist/hapi/utils.d.ts +0 -16
- package/dist/hapi/utils.js +0 -53
- package/dist/hapi/utils.js.map +0 -1
- package/dist/hono/utils.cjs +0 -113
- package/dist/hono/utils.cjs.map +0 -1
- package/dist/hono/utils.d.cts +0 -16
- package/dist/hono/utils.d.ts +0 -16
- package/dist/hono/utils.js +0 -88
- package/dist/hono/utils.js.map +0 -1
- package/dist/loggers/console.cjs +0 -67
- package/dist/loggers/console.cjs.map +0 -1
- package/dist/loggers/console.d.cts +0 -11
- package/dist/loggers/console.d.ts +0 -11
- package/dist/loggers/console.js +0 -44
- package/dist/loggers/console.js.map +0 -1
- package/dist/loggers/hapi.cjs.map +0 -1
- package/dist/loggers/hapi.d.cts +0 -12
- package/dist/loggers/hapi.d.ts +0 -12
- package/dist/loggers/hapi.js +0 -29
- package/dist/loggers/hapi.js.map +0 -1
- package/dist/loggers/index.cjs.map +0 -1
- package/dist/loggers/index.d.cts +0 -13
- package/dist/loggers/index.d.ts +0 -13
- package/dist/loggers/index.js +0 -13
- package/dist/loggers/index.js.map +0 -1
- package/dist/loggers/nestjs.cjs +0 -104
- package/dist/loggers/nestjs.cjs.map +0 -1
- package/dist/loggers/nestjs.d.cts +0 -11
- package/dist/loggers/nestjs.d.ts +0 -11
- package/dist/loggers/nestjs.js +0 -71
- package/dist/loggers/nestjs.js.map +0 -1
- package/dist/loggers/pino.cjs +0 -152
- package/dist/loggers/pino.cjs.map +0 -1
- package/dist/loggers/pino.d.cts +0 -11
- package/dist/loggers/pino.d.ts +0 -11
- package/dist/loggers/pino.js +0 -119
- package/dist/loggers/pino.js.map +0 -1
- package/dist/loggers/utils.cjs +0 -64
- package/dist/loggers/utils.cjs.map +0 -1
- package/dist/loggers/utils.d.cts +0 -6
- package/dist/loggers/utils.d.ts +0 -6
- package/dist/loggers/utils.js +0 -40
- package/dist/loggers/utils.js.map +0 -1
- package/dist/loggers/winston.cjs +0 -101
- package/dist/loggers/winston.cjs.map +0 -1
- package/dist/loggers/winston.d.cts +0 -11
- package/dist/loggers/winston.d.ts +0 -11
- package/dist/loggers/winston.js +0 -68
- package/dist/loggers/winston.js.map +0 -1
- package/dist/otel/index.cjs.map +0 -1
- package/dist/otel/index.d.cts +0 -2
- package/dist/otel/index.d.ts +0 -2
- package/dist/otel/index.js +0 -5
- package/dist/otel/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tracing.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport {\n type Attributes,\n context,\n type Span,\n SpanKind,\n SpanStatusCode,\n trace,\n} from \"@opentelemetry/api\";\nimport { coerceToException } from \"./exceptions.js\";\nimport { logDebug } from \"./logger.js\";\n\nconst STACK_FRAME_PATTERN = /at (?:.*\\()?(.*?):(\\d+):\\d+\\)?$/;\n\nexport function instrument<Fn extends (...args: never[]) => unknown>(fn: Fn): Fn;\nexport function instrument<Fn extends (...args: never[]) => unknown>(name: string, fn: Fn): Fn;\nexport function instrument(\n nameOrFn: string | ((...args: unknown[]) => unknown),\n fnWhenNamed?: (...args: unknown[]) => unknown,\n): (...args: unknown[]) => unknown {\n const fn =\n typeof nameOrFn === \"function\" ? nameOrFn : (fnWhenNamed as (...args: unknown[]) => unknown);\n const spanName = typeof nameOrFn === \"string\" ? nameOrFn : fn.name || \"anonymous\";\n const attributes: Attributes = {};\n if (fn.name) {\n attributes[\"code.function.name\"] = fn.name;\n }\n const wrapSite = resolveWrapSite();\n if (wrapSite) {\n attributes[\"code.file.path\"] = wrapSite.filePath;\n attributes[\"code.line.number\"] = wrapSite.lineNumber;\n }\n return function (this: unknown, ...args: unknown[]): unknown {\n return runInsideSpan(spanName, attributes, () => fn.apply(this, args));\n };\n}\n\nexport function span<Result>(name: string, fn: () => Result): Result {\n return runInsideSpan(name, undefined, fn);\n}\n\n// Function errors propagate unchanged. If span creation fails, the function\n// runs without a span.\nfunction runInsideSpan<Result>(\n name: string,\n attributes: Attributes | undefined,\n fn: () => Result,\n): Result {\n let internalSpan: Span;\n try {\n internalSpan = trace\n .getTracer(\"apitally.otel\")\n .startSpan(name, { kind: SpanKind.INTERNAL, attributes });\n } catch (error) {\n logDebug(`Error starting a manual span: ${String(error)}`);\n return fn();\n }\n let result: Result;\n try {\n result = context.with(trace.setSpan(context.active(), internalSpan), fn);\n } catch (error) {\n endSpanWithError(internalSpan, error);\n throw error;\n }\n if (isPromiseLike(result)) {\n // Side listener on the function's own promise, which passes through\n // unchanged; neither handler rethrows, so this chain never rejects.\n result.then(\n () => endSpan(internalSpan),\n (error: unknown) => endSpanWithError(internalSpan, error),\n );\n return result;\n }\n endSpan(internalSpan);\n return result;\n}\n\n// The wrap-time call site, taken from a stack capture that starts at\n// instrument's caller. An unparseable stack yields no location attributes.\nfunction resolveWrapSite(): { filePath: string; lineNumber: number } | undefined {\n const holder: { stack?: string } = {};\n Error.captureStackTrace(holder, instrument);\n for (const frame of (holder.stack ?? \"\").split(\"\\n\")) {\n const match = STACK_FRAME_PATTERN.exec(frame);\n if (match) {\n return {\n filePath: match[1].startsWith(\"file://\") ? fileURLToPath(match[1]) : match[1],\n lineNumber: Number(match[2]),\n };\n }\n }\n return undefined;\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as PromiseLike<unknown>).then === \"function\"\n );\n}\n\nfunction endSpan(internalSpan: Span): void {\n try {\n internalSpan.end();\n } catch (error) {\n logDebug(`Error ending a manual span: ${String(error)}`);\n }\n}\n\nfunction endSpanWithError(internalSpan: Span, error: unknown): void {\n try {\n const exception = coerceToException(error);\n internalSpan.recordException(exception);\n internalSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: typeof exception === \"string\" ? exception : exception.message,\n });\n internalSpan.end();\n } catch (endError) {\n logDebug(`Error ending a manual span: ${String(endError)}`);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAA8B;AAC9B,iBAOO;AACP,wBAAkC;AAClC,oBAAyB;AAEzB,MAAM,sBAAsB;AAIrB,SAAS,WACd,UACA,aACiC;AACjC,QAAM,KACJ,OAAO,aAAa,aAAa,WAAY;AAC/C,QAAM,WAAW,OAAO,aAAa,WAAW,WAAW,GAAG,QAAQ;AACtE,QAAM,aAAyB,CAAC;AAChC,MAAI,GAAG,MAAM;AACX,eAAW,oBAAoB,IAAI,GAAG;AAAA,EACxC;AACA,QAAM,WAAW,gBAAgB;AACjC,MAAI,UAAU;AACZ,eAAW,gBAAgB,IAAI,SAAS;AACxC,eAAW,kBAAkB,IAAI,SAAS;AAAA,EAC5C;AACA,SAAO,YAA4B,MAA0B;AAC3D,WAAO,cAAc,UAAU,YAAY,MAAM,GAAG,MAAM,MAAM,IAAI,CAAC;AAAA,EACvE;AACF;AAEO,SAAS,KAAa,MAAc,IAA0B;AACnE,SAAO,cAAc,MAAM,QAAW,EAAE;AAC1C;AAIA,SAAS,cACP,MACA,YACA,IACQ;AACR,MAAI;AACJ,MAAI;AACF,mBAAe,iBACZ,UAAU,eAAe,EACzB,UAAU,MAAM,EAAE,MAAM,oBAAS,UAAU,WAAW,CAAC;AAAA,EAC5D,SAAS,OAAO;AACd,gCAAS,iCAAiC,OAAO,KAAK,CAAC,EAAE;AACzD,WAAO,GAAG;AAAA,EACZ;AACA,MAAI;AACJ,MAAI;AACF,aAAS,mBAAQ,KAAK,iBAAM,QAAQ,mBAAQ,OAAO,GAAG,YAAY,GAAG,EAAE;AAAA,EACzE,SAAS,OAAO;AACd,qBAAiB,cAAc,KAAK;AACpC,UAAM;AAAA,EACR;AACA,MAAI,cAAc,MAAM,GAAG;AAGzB,WAAO;AAAA,MACL,MAAM,QAAQ,YAAY;AAAA,MAC1B,CAAC,UAAmB,iBAAiB,cAAc,KAAK;AAAA,IAC1D;AACA,WAAO;AAAA,EACT;AACA,UAAQ,YAAY;AACpB,SAAO;AACT;AAIA,SAAS,kBAAwE;AAC/E,QAAM,SAA6B,CAAC;AACpC,QAAM,kBAAkB,QAAQ,UAAU;AAC1C,aAAW,UAAU,OAAO,SAAS,IAAI,MAAM,IAAI,GAAG;AACpD,UAAM,QAAQ,oBAAoB,KAAK,KAAK;AAC5C,QAAI,OAAO;AACT,aAAO;AAAA,QACL,UAAU,MAAM,CAAC,EAAE,WAAW,SAAS,QAAI,+BAAc,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC;AAAA,QAC5E,YAAY,OAAO,MAAM,CAAC,CAAC;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,OAA+C;AACpE,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA+B,SAAS;AAEpD;AAEA,SAAS,QAAQ,cAA0B;AACzC,MAAI;AACF,iBAAa,IAAI;AAAA,EACnB,SAAS,OAAO;AACd,gCAAS,+BAA+B,OAAO,KAAK,CAAC,EAAE;AAAA,EACzD;AACF;AAEA,SAAS,iBAAiB,cAAoB,OAAsB;AAClE,MAAI;AACF,UAAM,gBAAY,qCAAkB,KAAK;AACzC,iBAAa,gBAAgB,SAAS;AACtC,iBAAa,UAAU;AAAA,MACrB,MAAM,0BAAe;AAAA,MACrB,SAAS,OAAO,cAAc,WAAW,YAAY,UAAU;AAAA,IACjE,CAAC;AACD,iBAAa,IAAI;AAAA,EACnB,SAAS,UAAU;AACjB,gCAAS,+BAA+B,OAAO,QAAQ,CAAC,EAAE;AAAA,EAC5D;AACF;","names":[]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare function instrument<Fn extends (...args: never[]) => unknown>(fn: Fn): Fn;
|
|
2
|
+
declare function instrument<Fn extends (...args: never[]) => unknown>(name: string, fn: Fn): Fn;
|
|
3
|
+
declare function span<Result>(name: string, fn: () => Result): Result;
|
|
4
|
+
|
|
5
|
+
export { instrument, span };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare function instrument<Fn extends (...args: never[]) => unknown>(fn: Fn): Fn;
|
|
2
|
+
declare function instrument<Fn extends (...args: never[]) => unknown>(name: string, fn: Fn): Fn;
|
|
3
|
+
declare function span<Result>(name: string, fn: () => Result): Result;
|
|
4
|
+
|
|
5
|
+
export { instrument, span };
|
package/dist/tracing.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import {
|
|
3
|
+
context,
|
|
4
|
+
SpanKind,
|
|
5
|
+
SpanStatusCode,
|
|
6
|
+
trace
|
|
7
|
+
} from "@opentelemetry/api";
|
|
8
|
+
import { coerceToException } from "./exceptions.js";
|
|
9
|
+
import { logDebug } from "./logger.js";
|
|
10
|
+
const STACK_FRAME_PATTERN = /at (?:.*\()?(.*?):(\d+):\d+\)?$/;
|
|
11
|
+
function instrument(nameOrFn, fnWhenNamed) {
|
|
12
|
+
const fn = typeof nameOrFn === "function" ? nameOrFn : fnWhenNamed;
|
|
13
|
+
const spanName = typeof nameOrFn === "string" ? nameOrFn : fn.name || "anonymous";
|
|
14
|
+
const attributes = {};
|
|
15
|
+
if (fn.name) {
|
|
16
|
+
attributes["code.function.name"] = fn.name;
|
|
17
|
+
}
|
|
18
|
+
const wrapSite = resolveWrapSite();
|
|
19
|
+
if (wrapSite) {
|
|
20
|
+
attributes["code.file.path"] = wrapSite.filePath;
|
|
21
|
+
attributes["code.line.number"] = wrapSite.lineNumber;
|
|
22
|
+
}
|
|
23
|
+
return function(...args) {
|
|
24
|
+
return runInsideSpan(spanName, attributes, () => fn.apply(this, args));
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function span(name, fn) {
|
|
28
|
+
return runInsideSpan(name, void 0, fn);
|
|
29
|
+
}
|
|
30
|
+
function runInsideSpan(name, attributes, fn) {
|
|
31
|
+
let internalSpan;
|
|
32
|
+
try {
|
|
33
|
+
internalSpan = trace.getTracer("apitally.otel").startSpan(name, { kind: SpanKind.INTERNAL, attributes });
|
|
34
|
+
} catch (error) {
|
|
35
|
+
logDebug(`Error starting a manual span: ${String(error)}`);
|
|
36
|
+
return fn();
|
|
37
|
+
}
|
|
38
|
+
let result;
|
|
39
|
+
try {
|
|
40
|
+
result = context.with(trace.setSpan(context.active(), internalSpan), fn);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
endSpanWithError(internalSpan, error);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
if (isPromiseLike(result)) {
|
|
46
|
+
result.then(
|
|
47
|
+
() => endSpan(internalSpan),
|
|
48
|
+
(error) => endSpanWithError(internalSpan, error)
|
|
49
|
+
);
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
endSpan(internalSpan);
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function resolveWrapSite() {
|
|
56
|
+
const holder = {};
|
|
57
|
+
Error.captureStackTrace(holder, instrument);
|
|
58
|
+
for (const frame of (holder.stack ?? "").split("\n")) {
|
|
59
|
+
const match = STACK_FRAME_PATTERN.exec(frame);
|
|
60
|
+
if (match) {
|
|
61
|
+
return {
|
|
62
|
+
filePath: match[1].startsWith("file://") ? fileURLToPath(match[1]) : match[1],
|
|
63
|
+
lineNumber: Number(match[2])
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
function isPromiseLike(value) {
|
|
70
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
71
|
+
}
|
|
72
|
+
function endSpan(internalSpan) {
|
|
73
|
+
try {
|
|
74
|
+
internalSpan.end();
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logDebug(`Error ending a manual span: ${String(error)}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function endSpanWithError(internalSpan, error) {
|
|
80
|
+
try {
|
|
81
|
+
const exception = coerceToException(error);
|
|
82
|
+
internalSpan.recordException(exception);
|
|
83
|
+
internalSpan.setStatus({
|
|
84
|
+
code: SpanStatusCode.ERROR,
|
|
85
|
+
message: typeof exception === "string" ? exception : exception.message
|
|
86
|
+
});
|
|
87
|
+
internalSpan.end();
|
|
88
|
+
} catch (endError) {
|
|
89
|
+
logDebug(`Error ending a manual span: ${String(endError)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export {
|
|
93
|
+
instrument,
|
|
94
|
+
span
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=tracing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tracing.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport {\n type Attributes,\n context,\n type Span,\n SpanKind,\n SpanStatusCode,\n trace,\n} from \"@opentelemetry/api\";\nimport { coerceToException } from \"./exceptions.js\";\nimport { logDebug } from \"./logger.js\";\n\nconst STACK_FRAME_PATTERN = /at (?:.*\\()?(.*?):(\\d+):\\d+\\)?$/;\n\nexport function instrument<Fn extends (...args: never[]) => unknown>(fn: Fn): Fn;\nexport function instrument<Fn extends (...args: never[]) => unknown>(name: string, fn: Fn): Fn;\nexport function instrument(\n nameOrFn: string | ((...args: unknown[]) => unknown),\n fnWhenNamed?: (...args: unknown[]) => unknown,\n): (...args: unknown[]) => unknown {\n const fn =\n typeof nameOrFn === \"function\" ? nameOrFn : (fnWhenNamed as (...args: unknown[]) => unknown);\n const spanName = typeof nameOrFn === \"string\" ? nameOrFn : fn.name || \"anonymous\";\n const attributes: Attributes = {};\n if (fn.name) {\n attributes[\"code.function.name\"] = fn.name;\n }\n const wrapSite = resolveWrapSite();\n if (wrapSite) {\n attributes[\"code.file.path\"] = wrapSite.filePath;\n attributes[\"code.line.number\"] = wrapSite.lineNumber;\n }\n return function (this: unknown, ...args: unknown[]): unknown {\n return runInsideSpan(spanName, attributes, () => fn.apply(this, args));\n };\n}\n\nexport function span<Result>(name: string, fn: () => Result): Result {\n return runInsideSpan(name, undefined, fn);\n}\n\n// Function errors propagate unchanged. If span creation fails, the function\n// runs without a span.\nfunction runInsideSpan<Result>(\n name: string,\n attributes: Attributes | undefined,\n fn: () => Result,\n): Result {\n let internalSpan: Span;\n try {\n internalSpan = trace\n .getTracer(\"apitally.otel\")\n .startSpan(name, { kind: SpanKind.INTERNAL, attributes });\n } catch (error) {\n logDebug(`Error starting a manual span: ${String(error)}`);\n return fn();\n }\n let result: Result;\n try {\n result = context.with(trace.setSpan(context.active(), internalSpan), fn);\n } catch (error) {\n endSpanWithError(internalSpan, error);\n throw error;\n }\n if (isPromiseLike(result)) {\n // Side listener on the function's own promise, which passes through\n // unchanged; neither handler rethrows, so this chain never rejects.\n result.then(\n () => endSpan(internalSpan),\n (error: unknown) => endSpanWithError(internalSpan, error),\n );\n return result;\n }\n endSpan(internalSpan);\n return result;\n}\n\n// The wrap-time call site, taken from a stack capture that starts at\n// instrument's caller. An unparseable stack yields no location attributes.\nfunction resolveWrapSite(): { filePath: string; lineNumber: number } | undefined {\n const holder: { stack?: string } = {};\n Error.captureStackTrace(holder, instrument);\n for (const frame of (holder.stack ?? \"\").split(\"\\n\")) {\n const match = STACK_FRAME_PATTERN.exec(frame);\n if (match) {\n return {\n filePath: match[1].startsWith(\"file://\") ? fileURLToPath(match[1]) : match[1],\n lineNumber: Number(match[2]),\n };\n }\n }\n return undefined;\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as PromiseLike<unknown>).then === \"function\"\n );\n}\n\nfunction endSpan(internalSpan: Span): void {\n try {\n internalSpan.end();\n } catch (error) {\n logDebug(`Error ending a manual span: ${String(error)}`);\n }\n}\n\nfunction endSpanWithError(internalSpan: Span, error: unknown): void {\n try {\n const exception = coerceToException(error);\n internalSpan.recordException(exception);\n internalSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: typeof exception === \"string\" ? exception : exception.message,\n });\n internalSpan.end();\n } catch (endError) {\n logDebug(`Error ending a manual span: ${String(endError)}`);\n }\n}\n"],"mappings":"AAAA,SAAS,qBAAqB;AAC9B;AAAA,EAEE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,yBAAyB;AAClC,SAAS,gBAAgB;AAEzB,MAAM,sBAAsB;AAIrB,SAAS,WACd,UACA,aACiC;AACjC,QAAM,KACJ,OAAO,aAAa,aAAa,WAAY;AAC/C,QAAM,WAAW,OAAO,aAAa,WAAW,WAAW,GAAG,QAAQ;AACtE,QAAM,aAAyB,CAAC;AAChC,MAAI,GAAG,MAAM;AACX,eAAW,oBAAoB,IAAI,GAAG;AAAA,EACxC;AACA,QAAM,WAAW,gBAAgB;AACjC,MAAI,UAAU;AACZ,eAAW,gBAAgB,IAAI,SAAS;AACxC,eAAW,kBAAkB,IAAI,SAAS;AAAA,EAC5C;AACA,SAAO,YAA4B,MAA0B;AAC3D,WAAO,cAAc,UAAU,YAAY,MAAM,GAAG,MAAM,MAAM,IAAI,CAAC;AAAA,EACvE;AACF;AAEO,SAAS,KAAa,MAAc,IAA0B;AACnE,SAAO,cAAc,MAAM,QAAW,EAAE;AAC1C;AAIA,SAAS,cACP,MACA,YACA,IACQ;AACR,MAAI;AACJ,MAAI;AACF,mBAAe,MACZ,UAAU,eAAe,EACzB,UAAU,MAAM,EAAE,MAAM,SAAS,UAAU,WAAW,CAAC;AAAA,EAC5D,SAAS,OAAO;AACd,aAAS,iCAAiC,OAAO,KAAK,CAAC,EAAE;AACzD,WAAO,GAAG;AAAA,EACZ;AACA,MAAI;AACJ,MAAI;AACF,aAAS,QAAQ,KAAK,MAAM,QAAQ,QAAQ,OAAO,GAAG,YAAY,GAAG,EAAE;AAAA,EACzE,SAAS,OAAO;AACd,qBAAiB,cAAc,KAAK;AACpC,UAAM;AAAA,EACR;AACA,MAAI,cAAc,MAAM,GAAG;AAGzB,WAAO;AAAA,MACL,MAAM,QAAQ,YAAY;AAAA,MAC1B,CAAC,UAAmB,iBAAiB,cAAc,KAAK;AAAA,IAC1D;AACA,WAAO;AAAA,EACT;AACA,UAAQ,YAAY;AACpB,SAAO;AACT;AAIA,SAAS,kBAAwE;AAC/E,QAAM,SAA6B,CAAC;AACpC,QAAM,kBAAkB,QAAQ,UAAU;AAC1C,aAAW,UAAU,OAAO,SAAS,IAAI,MAAM,IAAI,GAAG;AACpD,UAAM,QAAQ,oBAAoB,KAAK,KAAK;AAC5C,QAAI,OAAO;AACT,aAAO;AAAA,QACL,UAAU,MAAM,CAAC,EAAE,WAAW,SAAS,IAAI,cAAc,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC;AAAA,QAC5E,YAAY,OAAO,MAAM,CAAC,CAAC;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,OAA+C;AACpE,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA+B,SAAS;AAEpD;AAEA,SAAS,QAAQ,cAA0B;AACzC,MAAI;AACF,iBAAa,IAAI;AAAA,EACnB,SAAS,OAAO;AACd,aAAS,+BAA+B,OAAO,KAAK,CAAC,EAAE;AAAA,EACzD;AACF;AAEA,SAAS,iBAAiB,cAAoB,OAAsB;AAClE,MAAI;AACF,UAAM,YAAY,kBAAkB,KAAK;AACzC,iBAAa,gBAAgB,SAAS;AACtC,iBAAa,UAAU;AAAA,MACrB,MAAM,eAAe;AAAA,MACrB,SAAS,OAAO,cAAc,WAAW,YAAY,UAAU;AAAA,IACjE,CAAC;AACD,iBAAa,IAAI;AAAA,EACnB,SAAS,UAAU;AACjB,aAAS,+BAA+B,OAAO,QAAQ,CAAC,EAAE;AAAA,EAC5D;AACF;","names":[]}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var validationErrors_exports = {};
|
|
20
|
+
__export(validationErrors_exports, {
|
|
21
|
+
VALIDATION_ERROR_EVENT_NAME: () => VALIDATION_ERROR_EVENT_NAME,
|
|
22
|
+
addValidationErrors: () => addValidationErrors,
|
|
23
|
+
drainValidationErrors: () => drainValidationErrors,
|
|
24
|
+
extractExpressValidationErrors: () => extractExpressValidationErrors,
|
|
25
|
+
extractZodValidationErrors: () => extractZodValidationErrors,
|
|
26
|
+
formatIssues: () => formatIssues,
|
|
27
|
+
isRecord: () => isRecord,
|
|
28
|
+
isValidationResponseStatus: () => isValidationResponseStatus,
|
|
29
|
+
normalizeSource: () => normalizeSource,
|
|
30
|
+
parseJsonResponseBody: () => parseJsonResponseBody,
|
|
31
|
+
resetValidationErrors: () => resetValidationErrors
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(validationErrors_exports);
|
|
34
|
+
var import_node_zlib = require("node:zlib");
|
|
35
|
+
var import_bodyCapture = require('./bodyCapture.cjs');
|
|
36
|
+
const VALIDATION_ERROR_EVENT_NAME = "apitally.request.validation_error";
|
|
37
|
+
const MAX_GROUPS = 100;
|
|
38
|
+
const MAX_CONSUMER_LENGTH = 128;
|
|
39
|
+
const MAX_PATH_LENGTH = 2e3;
|
|
40
|
+
const MAX_SOURCE_LENGTH = 32;
|
|
41
|
+
const MAX_FIELD_LENGTH = 2048;
|
|
42
|
+
const MAX_MESSAGE_LENGTH = 2048;
|
|
43
|
+
const MAX_TYPE_LENGTH = 128;
|
|
44
|
+
const MAX_COUNT = 2 ** 32 - 1;
|
|
45
|
+
const SOURCE_ALIASES = {
|
|
46
|
+
body: "body",
|
|
47
|
+
query: "query",
|
|
48
|
+
path: "path",
|
|
49
|
+
header: "header",
|
|
50
|
+
cookie: "cookie",
|
|
51
|
+
querystring: "query",
|
|
52
|
+
params: "path",
|
|
53
|
+
path_params: "path",
|
|
54
|
+
headers: "header",
|
|
55
|
+
cookies: "cookie"
|
|
56
|
+
};
|
|
57
|
+
const VALIDATION_ERROR_GROUPS_KEY = /* @__PURE__ */ Symbol.for("apitally.validationErrorGroups");
|
|
58
|
+
const validationErrorGroupsHolder = globalThis;
|
|
59
|
+
const validationErrorGroups = validationErrorGroupsHolder[VALIDATION_ERROR_GROUPS_KEY] ?? /* @__PURE__ */ new Map();
|
|
60
|
+
validationErrorGroupsHolder[VALIDATION_ERROR_GROUPS_KEY] = validationErrorGroups;
|
|
61
|
+
function isValidationResponseStatus(statusCode) {
|
|
62
|
+
return statusCode === 400 || statusCode === 422;
|
|
63
|
+
}
|
|
64
|
+
function addValidationErrors(consumer, method, path, details) {
|
|
65
|
+
method = method.toUpperCase();
|
|
66
|
+
if (method === "OPTIONS" || !path) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
for (const detail of details) {
|
|
70
|
+
const group = {
|
|
71
|
+
method,
|
|
72
|
+
path: path.slice(0, MAX_PATH_LENGTH),
|
|
73
|
+
source: detail.source.slice(0, MAX_SOURCE_LENGTH),
|
|
74
|
+
field: detail.field.slice(0, MAX_FIELD_LENGTH),
|
|
75
|
+
message: detail.message.slice(0, MAX_MESSAGE_LENGTH),
|
|
76
|
+
type: detail.type.slice(0, MAX_TYPE_LENGTH),
|
|
77
|
+
count: 1
|
|
78
|
+
};
|
|
79
|
+
if (consumer !== void 0) {
|
|
80
|
+
group.consumer = consumer.slice(0, MAX_CONSUMER_LENGTH);
|
|
81
|
+
}
|
|
82
|
+
const key = [
|
|
83
|
+
group.consumer ?? "",
|
|
84
|
+
group.method,
|
|
85
|
+
group.path,
|
|
86
|
+
group.source,
|
|
87
|
+
group.field,
|
|
88
|
+
group.message,
|
|
89
|
+
group.type
|
|
90
|
+
].join("\0");
|
|
91
|
+
const existing = validationErrorGroups.get(key);
|
|
92
|
+
if (existing) {
|
|
93
|
+
existing.count = Math.min(existing.count + 1, MAX_COUNT);
|
|
94
|
+
} else if (validationErrorGroups.size < MAX_GROUPS) {
|
|
95
|
+
validationErrorGroups.set(key, group);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function drainValidationErrors() {
|
|
100
|
+
const groups = [...validationErrorGroups.values()];
|
|
101
|
+
validationErrorGroups.clear();
|
|
102
|
+
return groups;
|
|
103
|
+
}
|
|
104
|
+
function resetValidationErrors() {
|
|
105
|
+
validationErrorGroups.clear();
|
|
106
|
+
}
|
|
107
|
+
function normalizeSource(source) {
|
|
108
|
+
return typeof source === "string" ? SOURCE_ALIASES[source.toLowerCase()] ?? "" : "";
|
|
109
|
+
}
|
|
110
|
+
function formatIssues(issues, source = "") {
|
|
111
|
+
if (!Array.isArray(issues)) {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
const details = [];
|
|
115
|
+
for (const issue of issues) {
|
|
116
|
+
if (!isRecord(issue) || typeof issue.message !== "string") {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const path = Array.isArray(issue.path) ? issue.path : typeof issue.path === "string" ? issue.path.split("/").filter(Boolean).map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")) : [];
|
|
120
|
+
details.push({
|
|
121
|
+
source,
|
|
122
|
+
field: path.map((segment) => isRecord(segment) ? segment.key : segment).filter((segment) => typeof segment === "string" || typeof segment === "number").join("."),
|
|
123
|
+
message: issue.message,
|
|
124
|
+
type: typeof issue.code === "string" ? issue.code : ""
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return details;
|
|
128
|
+
}
|
|
129
|
+
function extractZodValidationErrors(body) {
|
|
130
|
+
if (!isRecord(body)) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
const error = isRecord(body.error) ? body.error : void 0;
|
|
134
|
+
let issues = body.issues ?? error?.issues;
|
|
135
|
+
if (issues === void 0 && error?.name === "ZodError" && typeof error.message === "string") {
|
|
136
|
+
try {
|
|
137
|
+
issues = JSON.parse(error.message);
|
|
138
|
+
} catch {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return formatIssues(issues);
|
|
143
|
+
}
|
|
144
|
+
function extractExpressValidationErrors(body) {
|
|
145
|
+
if (!isRecord(body)) {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
const zodDetails = extractZodValidationErrors(body);
|
|
149
|
+
if (zodDetails.length > 0) {
|
|
150
|
+
return zodDetails;
|
|
151
|
+
}
|
|
152
|
+
if (Array.isArray(body.errors)) {
|
|
153
|
+
return extractExpressValidatorErrors(body.errors);
|
|
154
|
+
}
|
|
155
|
+
if (isRecord(body.validation)) {
|
|
156
|
+
return extractCelebrateErrors(body.validation);
|
|
157
|
+
}
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
function extractExpressValidatorErrors(errors) {
|
|
161
|
+
const details = [];
|
|
162
|
+
for (const error of errors) {
|
|
163
|
+
if (!isRecord(error) || error.type !== "field" || typeof error.path !== "string" || typeof error.msg !== "string") {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const source = normalizeSource(error.location);
|
|
167
|
+
if (source) {
|
|
168
|
+
details.push({ source, field: error.path, message: error.msg, type: "" });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return details;
|
|
172
|
+
}
|
|
173
|
+
function extractCelebrateErrors(validation) {
|
|
174
|
+
const details = [];
|
|
175
|
+
for (const error of Object.values(validation)) {
|
|
176
|
+
if (!isRecord(error) || !Array.isArray(error.keys) || typeof error.message !== "string") {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const sentences = error.message.split(". ");
|
|
180
|
+
for (const key of error.keys) {
|
|
181
|
+
if (typeof key === "string") {
|
|
182
|
+
details.push({
|
|
183
|
+
source: normalizeSource(error.source),
|
|
184
|
+
field: key,
|
|
185
|
+
message: sentences.find((sentence) => sentence.includes(`"${key}"`)) ?? error.message,
|
|
186
|
+
type: ""
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return details;
|
|
192
|
+
}
|
|
193
|
+
function parseJsonResponseBody(body, contentEncoding) {
|
|
194
|
+
if (!body) {
|
|
195
|
+
return void 0;
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
const encoding = typeof contentEncoding === "string" ? contentEncoding.trim().toLowerCase() : "";
|
|
199
|
+
let decoded = body;
|
|
200
|
+
if (encoding === "br") {
|
|
201
|
+
decoded = (0, import_node_zlib.brotliDecompressSync)(body, { maxOutputLength: import_bodyCapture.MAX_BODY_SIZE });
|
|
202
|
+
} else if (encoding === "gzip" || encoding === "deflate") {
|
|
203
|
+
decoded = (0, import_node_zlib.unzipSync)(body, { maxOutputLength: import_bodyCapture.MAX_BODY_SIZE });
|
|
204
|
+
} else if (encoding !== "" && encoding !== "identity") {
|
|
205
|
+
return void 0;
|
|
206
|
+
}
|
|
207
|
+
return JSON.parse(decoded.toString());
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
function isRecord(value) {
|
|
213
|
+
return typeof value === "object" && value !== null;
|
|
214
|
+
}
|
|
215
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
216
|
+
0 && (module.exports = {
|
|
217
|
+
VALIDATION_ERROR_EVENT_NAME,
|
|
218
|
+
addValidationErrors,
|
|
219
|
+
drainValidationErrors,
|
|
220
|
+
extractExpressValidationErrors,
|
|
221
|
+
extractZodValidationErrors,
|
|
222
|
+
formatIssues,
|
|
223
|
+
isRecord,
|
|
224
|
+
isValidationResponseStatus,
|
|
225
|
+
normalizeSource,
|
|
226
|
+
parseJsonResponseBody,
|
|
227
|
+
resetValidationErrors
|
|
228
|
+
});
|
|
229
|
+
//# sourceMappingURL=validationErrors.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/validationErrors.ts"],"sourcesContent":["import { brotliDecompressSync, unzipSync } from \"node:zlib\";\nimport type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { MAX_BODY_SIZE } from \"./bodyCapture.js\";\n\nexport const VALIDATION_ERROR_EVENT_NAME = \"apitally.request.validation_error\";\n\nconst MAX_GROUPS = 100;\nconst MAX_CONSUMER_LENGTH = 128;\nconst MAX_PATH_LENGTH = 2_000;\nconst MAX_SOURCE_LENGTH = 32;\nconst MAX_FIELD_LENGTH = 2_048;\nconst MAX_MESSAGE_LENGTH = 2_048;\nconst MAX_TYPE_LENGTH = 128;\nconst MAX_COUNT = 2 ** 32 - 1;\n\nconst SOURCE_ALIASES: Record<string, string> = {\n body: \"body\",\n query: \"query\",\n path: \"path\",\n header: \"header\",\n cookie: \"cookie\",\n querystring: \"query\",\n params: \"path\",\n path_params: \"path\",\n headers: \"header\",\n cookies: \"cookie\",\n};\n\nexport type ValidationErrorDetail = {\n source: string;\n field: string;\n message: string;\n type: string;\n};\n\ntype ValidationErrorGroup = ValidationErrorDetail & {\n consumer?: string;\n method: string;\n path: string;\n count: number;\n};\n\nconst VALIDATION_ERROR_GROUPS_KEY = Symbol.for(\"apitally.validationErrorGroups\");\nconst validationErrorGroupsHolder = globalThis as Record<\n symbol,\n Map<string, ValidationErrorGroup> | undefined\n>;\nconst validationErrorGroups =\n validationErrorGroupsHolder[VALIDATION_ERROR_GROUPS_KEY] ??\n new Map<string, ValidationErrorGroup>();\nvalidationErrorGroupsHolder[VALIDATION_ERROR_GROUPS_KEY] = validationErrorGroups;\n\nexport function isValidationResponseStatus(statusCode: number): boolean {\n return statusCode === 400 || statusCode === 422;\n}\n\nexport function addValidationErrors(\n consumer: string | undefined,\n method: string,\n path: string,\n details: ValidationErrorDetail[],\n): void {\n method = method.toUpperCase();\n if (method === \"OPTIONS\" || !path) {\n return;\n }\n for (const detail of details) {\n const group: ValidationErrorGroup = {\n method,\n path: path.slice(0, MAX_PATH_LENGTH),\n source: detail.source.slice(0, MAX_SOURCE_LENGTH),\n field: detail.field.slice(0, MAX_FIELD_LENGTH),\n message: detail.message.slice(0, MAX_MESSAGE_LENGTH),\n type: detail.type.slice(0, MAX_TYPE_LENGTH),\n count: 1,\n };\n if (consumer !== undefined) {\n group.consumer = consumer.slice(0, MAX_CONSUMER_LENGTH);\n }\n const key = [\n group.consumer ?? \"\",\n group.method,\n group.path,\n group.source,\n group.field,\n group.message,\n group.type,\n ].join(\"\\0\");\n const existing = validationErrorGroups.get(key);\n if (existing) {\n existing.count = Math.min(existing.count + 1, MAX_COUNT);\n } else if (validationErrorGroups.size < MAX_GROUPS) {\n validationErrorGroups.set(key, group);\n }\n }\n}\n\nexport function drainValidationErrors(): AnyValueMap[] {\n const groups = [...validationErrorGroups.values()];\n validationErrorGroups.clear();\n return groups;\n}\n\nexport function resetValidationErrors(): void {\n validationErrorGroups.clear();\n}\n\nexport function normalizeSource(source: unknown): string {\n return typeof source === \"string\" ? (SOURCE_ALIASES[source.toLowerCase()] ?? \"\") : \"\";\n}\n\n// Zod, Standard Schema, and TypeBox issues share this shape. A Standard Schema\n// path segment may be an object carrying the key; a TypeBox path is a JSON pointer.\nexport function formatIssues(issues: unknown, source = \"\"): ValidationErrorDetail[] {\n if (!Array.isArray(issues)) {\n return [];\n }\n const details: ValidationErrorDetail[] = [];\n for (const issue of issues) {\n if (!isRecord(issue) || typeof issue.message !== \"string\") {\n continue;\n }\n const path = Array.isArray(issue.path)\n ? issue.path\n : typeof issue.path === \"string\"\n ? issue.path\n .split(\"/\")\n .filter(Boolean)\n .map((segment) => segment.replace(/~1/g, \"/\").replace(/~0/g, \"~\"))\n : [];\n details.push({\n source,\n field: path\n .map((segment: unknown) => (isRecord(segment) ? segment.key : segment))\n .filter((segment) => typeof segment === \"string\" || typeof segment === \"number\")\n .join(\".\"),\n message: issue.message,\n type: typeof issue.code === \"string\" ? issue.code : \"\",\n });\n }\n return details;\n}\n\n// zod 3 serializes issues as `error.issues`; zod 4 hides them as a JSON string\n// in `error.message`.\nexport function extractZodValidationErrors(body: unknown): ValidationErrorDetail[] {\n if (!isRecord(body)) {\n return [];\n }\n const error = isRecord(body.error) ? body.error : undefined;\n let issues = body.issues ?? error?.issues;\n if (issues === undefined && error?.name === \"ZodError\" && typeof error.message === \"string\") {\n try {\n issues = JSON.parse(error.message);\n } catch {\n return [];\n }\n }\n return formatIssues(issues);\n}\n\n// Recognized response shapes: zod issues, express-validator, and celebrate.\nexport function extractExpressValidationErrors(body: unknown): ValidationErrorDetail[] {\n if (!isRecord(body)) {\n return [];\n }\n const zodDetails = extractZodValidationErrors(body);\n if (zodDetails.length > 0) {\n return zodDetails;\n }\n if (Array.isArray(body.errors)) {\n return extractExpressValidatorErrors(body.errors);\n }\n if (isRecord(body.validation)) {\n return extractCelebrateErrors(body.validation);\n }\n return [];\n}\n\nfunction extractExpressValidatorErrors(errors: unknown[]): ValidationErrorDetail[] {\n const details: ValidationErrorDetail[] = [];\n for (const error of errors) {\n if (\n !isRecord(error) ||\n error.type !== \"field\" ||\n typeof error.path !== \"string\" ||\n typeof error.msg !== \"string\"\n ) {\n continue;\n }\n const source = normalizeSource(error.location);\n if (source) {\n details.push({ source, field: error.path, message: error.msg, type: \"\" });\n }\n }\n return details;\n}\n\n// Celebrate joins the messages of all failed keys into one sentence list, so\n// each key takes the sentence naming it.\nfunction extractCelebrateErrors(validation: Record<string, unknown>): ValidationErrorDetail[] {\n const details: ValidationErrorDetail[] = [];\n for (const error of Object.values(validation)) {\n if (!isRecord(error) || !Array.isArray(error.keys) || typeof error.message !== \"string\") {\n continue;\n }\n const sentences = error.message.split(\". \");\n for (const key of error.keys) {\n if (typeof key === \"string\") {\n details.push({\n source: normalizeSource(error.source),\n field: key,\n message: sentences.find((sentence) => sentence.includes(`\"${key}\"`)) ?? error.message,\n type: \"\",\n });\n }\n }\n }\n return details;\n}\n\nexport function parseJsonResponseBody(body: Buffer | undefined, contentEncoding: unknown): unknown {\n if (!body) {\n return undefined;\n }\n try {\n const encoding =\n typeof contentEncoding === \"string\" ? contentEncoding.trim().toLowerCase() : \"\";\n let decoded = body;\n if (encoding === \"br\") {\n decoded = brotliDecompressSync(body, { maxOutputLength: MAX_BODY_SIZE });\n } else if (encoding === \"gzip\" || encoding === \"deflate\") {\n decoded = unzipSync(body, { maxOutputLength: MAX_BODY_SIZE });\n } else if (encoding !== \"\" && encoding !== \"identity\") {\n return undefined;\n }\n return JSON.parse(decoded.toString());\n } catch {\n // A body that cannot be decoded as JSON carries no recognizable validation details.\n }\n return undefined;\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AnyValueMap } from '@opentelemetry/api-logs';
|
|
2
|
+
|
|
3
|
+
declare const VALIDATION_ERROR_EVENT_NAME = "apitally.request.validation_error";
|
|
4
|
+
type ValidationErrorDetail = {
|
|
5
|
+
source: string;
|
|
6
|
+
field: string;
|
|
7
|
+
message: string;
|
|
8
|
+
type: string;
|
|
9
|
+
};
|
|
10
|
+
declare function isValidationResponseStatus(statusCode: number): boolean;
|
|
11
|
+
declare function addValidationErrors(consumer: string | undefined, method: string, path: string, details: ValidationErrorDetail[]): void;
|
|
12
|
+
declare function drainValidationErrors(): AnyValueMap[];
|
|
13
|
+
declare function resetValidationErrors(): void;
|
|
14
|
+
declare function normalizeSource(source: unknown): string;
|
|
15
|
+
declare function formatIssues(issues: unknown, source?: string): ValidationErrorDetail[];
|
|
16
|
+
declare function extractZodValidationErrors(body: unknown): ValidationErrorDetail[];
|
|
17
|
+
declare function extractExpressValidationErrors(body: unknown): ValidationErrorDetail[];
|
|
18
|
+
declare function parseJsonResponseBody(body: Buffer | undefined, contentEncoding: unknown): unknown;
|
|
19
|
+
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
20
|
+
|
|
21
|
+
export { VALIDATION_ERROR_EVENT_NAME, type ValidationErrorDetail, addValidationErrors, drainValidationErrors, extractExpressValidationErrors, extractZodValidationErrors, formatIssues, isRecord, isValidationResponseStatus, normalizeSource, parseJsonResponseBody, resetValidationErrors };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AnyValueMap } from '@opentelemetry/api-logs';
|
|
2
|
+
|
|
3
|
+
declare const VALIDATION_ERROR_EVENT_NAME = "apitally.request.validation_error";
|
|
4
|
+
type ValidationErrorDetail = {
|
|
5
|
+
source: string;
|
|
6
|
+
field: string;
|
|
7
|
+
message: string;
|
|
8
|
+
type: string;
|
|
9
|
+
};
|
|
10
|
+
declare function isValidationResponseStatus(statusCode: number): boolean;
|
|
11
|
+
declare function addValidationErrors(consumer: string | undefined, method: string, path: string, details: ValidationErrorDetail[]): void;
|
|
12
|
+
declare function drainValidationErrors(): AnyValueMap[];
|
|
13
|
+
declare function resetValidationErrors(): void;
|
|
14
|
+
declare function normalizeSource(source: unknown): string;
|
|
15
|
+
declare function formatIssues(issues: unknown, source?: string): ValidationErrorDetail[];
|
|
16
|
+
declare function extractZodValidationErrors(body: unknown): ValidationErrorDetail[];
|
|
17
|
+
declare function extractExpressValidationErrors(body: unknown): ValidationErrorDetail[];
|
|
18
|
+
declare function parseJsonResponseBody(body: Buffer | undefined, contentEncoding: unknown): unknown;
|
|
19
|
+
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
20
|
+
|
|
21
|
+
export { VALIDATION_ERROR_EVENT_NAME, type ValidationErrorDetail, addValidationErrors, drainValidationErrors, extractExpressValidationErrors, extractZodValidationErrors, formatIssues, isRecord, isValidationResponseStatus, normalizeSource, parseJsonResponseBody, resetValidationErrors };
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { brotliDecompressSync, unzipSync } from "node:zlib";
|
|
2
|
+
import { MAX_BODY_SIZE } from "./bodyCapture.js";
|
|
3
|
+
const VALIDATION_ERROR_EVENT_NAME = "apitally.request.validation_error";
|
|
4
|
+
const MAX_GROUPS = 100;
|
|
5
|
+
const MAX_CONSUMER_LENGTH = 128;
|
|
6
|
+
const MAX_PATH_LENGTH = 2e3;
|
|
7
|
+
const MAX_SOURCE_LENGTH = 32;
|
|
8
|
+
const MAX_FIELD_LENGTH = 2048;
|
|
9
|
+
const MAX_MESSAGE_LENGTH = 2048;
|
|
10
|
+
const MAX_TYPE_LENGTH = 128;
|
|
11
|
+
const MAX_COUNT = 2 ** 32 - 1;
|
|
12
|
+
const SOURCE_ALIASES = {
|
|
13
|
+
body: "body",
|
|
14
|
+
query: "query",
|
|
15
|
+
path: "path",
|
|
16
|
+
header: "header",
|
|
17
|
+
cookie: "cookie",
|
|
18
|
+
querystring: "query",
|
|
19
|
+
params: "path",
|
|
20
|
+
path_params: "path",
|
|
21
|
+
headers: "header",
|
|
22
|
+
cookies: "cookie"
|
|
23
|
+
};
|
|
24
|
+
const VALIDATION_ERROR_GROUPS_KEY = /* @__PURE__ */ Symbol.for("apitally.validationErrorGroups");
|
|
25
|
+
const validationErrorGroupsHolder = globalThis;
|
|
26
|
+
const validationErrorGroups = validationErrorGroupsHolder[VALIDATION_ERROR_GROUPS_KEY] ?? /* @__PURE__ */ new Map();
|
|
27
|
+
validationErrorGroupsHolder[VALIDATION_ERROR_GROUPS_KEY] = validationErrorGroups;
|
|
28
|
+
function isValidationResponseStatus(statusCode) {
|
|
29
|
+
return statusCode === 400 || statusCode === 422;
|
|
30
|
+
}
|
|
31
|
+
function addValidationErrors(consumer, method, path, details) {
|
|
32
|
+
method = method.toUpperCase();
|
|
33
|
+
if (method === "OPTIONS" || !path) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
for (const detail of details) {
|
|
37
|
+
const group = {
|
|
38
|
+
method,
|
|
39
|
+
path: path.slice(0, MAX_PATH_LENGTH),
|
|
40
|
+
source: detail.source.slice(0, MAX_SOURCE_LENGTH),
|
|
41
|
+
field: detail.field.slice(0, MAX_FIELD_LENGTH),
|
|
42
|
+
message: detail.message.slice(0, MAX_MESSAGE_LENGTH),
|
|
43
|
+
type: detail.type.slice(0, MAX_TYPE_LENGTH),
|
|
44
|
+
count: 1
|
|
45
|
+
};
|
|
46
|
+
if (consumer !== void 0) {
|
|
47
|
+
group.consumer = consumer.slice(0, MAX_CONSUMER_LENGTH);
|
|
48
|
+
}
|
|
49
|
+
const key = [
|
|
50
|
+
group.consumer ?? "",
|
|
51
|
+
group.method,
|
|
52
|
+
group.path,
|
|
53
|
+
group.source,
|
|
54
|
+
group.field,
|
|
55
|
+
group.message,
|
|
56
|
+
group.type
|
|
57
|
+
].join("\0");
|
|
58
|
+
const existing = validationErrorGroups.get(key);
|
|
59
|
+
if (existing) {
|
|
60
|
+
existing.count = Math.min(existing.count + 1, MAX_COUNT);
|
|
61
|
+
} else if (validationErrorGroups.size < MAX_GROUPS) {
|
|
62
|
+
validationErrorGroups.set(key, group);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function drainValidationErrors() {
|
|
67
|
+
const groups = [...validationErrorGroups.values()];
|
|
68
|
+
validationErrorGroups.clear();
|
|
69
|
+
return groups;
|
|
70
|
+
}
|
|
71
|
+
function resetValidationErrors() {
|
|
72
|
+
validationErrorGroups.clear();
|
|
73
|
+
}
|
|
74
|
+
function normalizeSource(source) {
|
|
75
|
+
return typeof source === "string" ? SOURCE_ALIASES[source.toLowerCase()] ?? "" : "";
|
|
76
|
+
}
|
|
77
|
+
function formatIssues(issues, source = "") {
|
|
78
|
+
if (!Array.isArray(issues)) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
const details = [];
|
|
82
|
+
for (const issue of issues) {
|
|
83
|
+
if (!isRecord(issue) || typeof issue.message !== "string") {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const path = Array.isArray(issue.path) ? issue.path : typeof issue.path === "string" ? issue.path.split("/").filter(Boolean).map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")) : [];
|
|
87
|
+
details.push({
|
|
88
|
+
source,
|
|
89
|
+
field: path.map((segment) => isRecord(segment) ? segment.key : segment).filter((segment) => typeof segment === "string" || typeof segment === "number").join("."),
|
|
90
|
+
message: issue.message,
|
|
91
|
+
type: typeof issue.code === "string" ? issue.code : ""
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return details;
|
|
95
|
+
}
|
|
96
|
+
function extractZodValidationErrors(body) {
|
|
97
|
+
if (!isRecord(body)) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const error = isRecord(body.error) ? body.error : void 0;
|
|
101
|
+
let issues = body.issues ?? error?.issues;
|
|
102
|
+
if (issues === void 0 && error?.name === "ZodError" && typeof error.message === "string") {
|
|
103
|
+
try {
|
|
104
|
+
issues = JSON.parse(error.message);
|
|
105
|
+
} catch {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return formatIssues(issues);
|
|
110
|
+
}
|
|
111
|
+
function extractExpressValidationErrors(body) {
|
|
112
|
+
if (!isRecord(body)) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
const zodDetails = extractZodValidationErrors(body);
|
|
116
|
+
if (zodDetails.length > 0) {
|
|
117
|
+
return zodDetails;
|
|
118
|
+
}
|
|
119
|
+
if (Array.isArray(body.errors)) {
|
|
120
|
+
return extractExpressValidatorErrors(body.errors);
|
|
121
|
+
}
|
|
122
|
+
if (isRecord(body.validation)) {
|
|
123
|
+
return extractCelebrateErrors(body.validation);
|
|
124
|
+
}
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
function extractExpressValidatorErrors(errors) {
|
|
128
|
+
const details = [];
|
|
129
|
+
for (const error of errors) {
|
|
130
|
+
if (!isRecord(error) || error.type !== "field" || typeof error.path !== "string" || typeof error.msg !== "string") {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const source = normalizeSource(error.location);
|
|
134
|
+
if (source) {
|
|
135
|
+
details.push({ source, field: error.path, message: error.msg, type: "" });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return details;
|
|
139
|
+
}
|
|
140
|
+
function extractCelebrateErrors(validation) {
|
|
141
|
+
const details = [];
|
|
142
|
+
for (const error of Object.values(validation)) {
|
|
143
|
+
if (!isRecord(error) || !Array.isArray(error.keys) || typeof error.message !== "string") {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const sentences = error.message.split(". ");
|
|
147
|
+
for (const key of error.keys) {
|
|
148
|
+
if (typeof key === "string") {
|
|
149
|
+
details.push({
|
|
150
|
+
source: normalizeSource(error.source),
|
|
151
|
+
field: key,
|
|
152
|
+
message: sentences.find((sentence) => sentence.includes(`"${key}"`)) ?? error.message,
|
|
153
|
+
type: ""
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return details;
|
|
159
|
+
}
|
|
160
|
+
function parseJsonResponseBody(body, contentEncoding) {
|
|
161
|
+
if (!body) {
|
|
162
|
+
return void 0;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const encoding = typeof contentEncoding === "string" ? contentEncoding.trim().toLowerCase() : "";
|
|
166
|
+
let decoded = body;
|
|
167
|
+
if (encoding === "br") {
|
|
168
|
+
decoded = brotliDecompressSync(body, { maxOutputLength: MAX_BODY_SIZE });
|
|
169
|
+
} else if (encoding === "gzip" || encoding === "deflate") {
|
|
170
|
+
decoded = unzipSync(body, { maxOutputLength: MAX_BODY_SIZE });
|
|
171
|
+
} else if (encoding !== "" && encoding !== "identity") {
|
|
172
|
+
return void 0;
|
|
173
|
+
}
|
|
174
|
+
return JSON.parse(decoded.toString());
|
|
175
|
+
} catch {
|
|
176
|
+
}
|
|
177
|
+
return void 0;
|
|
178
|
+
}
|
|
179
|
+
function isRecord(value) {
|
|
180
|
+
return typeof value === "object" && value !== null;
|
|
181
|
+
}
|
|
182
|
+
export {
|
|
183
|
+
VALIDATION_ERROR_EVENT_NAME,
|
|
184
|
+
addValidationErrors,
|
|
185
|
+
drainValidationErrors,
|
|
186
|
+
extractExpressValidationErrors,
|
|
187
|
+
extractZodValidationErrors,
|
|
188
|
+
formatIssues,
|
|
189
|
+
isRecord,
|
|
190
|
+
isValidationResponseStatus,
|
|
191
|
+
normalizeSource,
|
|
192
|
+
parseJsonResponseBody,
|
|
193
|
+
resetValidationErrors
|
|
194
|
+
};
|
|
195
|
+
//# sourceMappingURL=validationErrors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/validationErrors.ts"],"sourcesContent":["import { brotliDecompressSync, unzipSync } from \"node:zlib\";\nimport type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { MAX_BODY_SIZE } from \"./bodyCapture.js\";\n\nexport const VALIDATION_ERROR_EVENT_NAME = \"apitally.request.validation_error\";\n\nconst MAX_GROUPS = 100;\nconst MAX_CONSUMER_LENGTH = 128;\nconst MAX_PATH_LENGTH = 2_000;\nconst MAX_SOURCE_LENGTH = 32;\nconst MAX_FIELD_LENGTH = 2_048;\nconst MAX_MESSAGE_LENGTH = 2_048;\nconst MAX_TYPE_LENGTH = 128;\nconst MAX_COUNT = 2 ** 32 - 1;\n\nconst SOURCE_ALIASES: Record<string, string> = {\n body: \"body\",\n query: \"query\",\n path: \"path\",\n header: \"header\",\n cookie: \"cookie\",\n querystring: \"query\",\n params: \"path\",\n path_params: \"path\",\n headers: \"header\",\n cookies: \"cookie\",\n};\n\nexport type ValidationErrorDetail = {\n source: string;\n field: string;\n message: string;\n type: string;\n};\n\ntype ValidationErrorGroup = ValidationErrorDetail & {\n consumer?: string;\n method: string;\n path: string;\n count: number;\n};\n\nconst VALIDATION_ERROR_GROUPS_KEY = Symbol.for(\"apitally.validationErrorGroups\");\nconst validationErrorGroupsHolder = globalThis as Record<\n symbol,\n Map<string, ValidationErrorGroup> | undefined\n>;\nconst validationErrorGroups =\n validationErrorGroupsHolder[VALIDATION_ERROR_GROUPS_KEY] ??\n new Map<string, ValidationErrorGroup>();\nvalidationErrorGroupsHolder[VALIDATION_ERROR_GROUPS_KEY] = validationErrorGroups;\n\nexport function isValidationResponseStatus(statusCode: number): boolean {\n return statusCode === 400 || statusCode === 422;\n}\n\nexport function addValidationErrors(\n consumer: string | undefined,\n method: string,\n path: string,\n details: ValidationErrorDetail[],\n): void {\n method = method.toUpperCase();\n if (method === \"OPTIONS\" || !path) {\n return;\n }\n for (const detail of details) {\n const group: ValidationErrorGroup = {\n method,\n path: path.slice(0, MAX_PATH_LENGTH),\n source: detail.source.slice(0, MAX_SOURCE_LENGTH),\n field: detail.field.slice(0, MAX_FIELD_LENGTH),\n message: detail.message.slice(0, MAX_MESSAGE_LENGTH),\n type: detail.type.slice(0, MAX_TYPE_LENGTH),\n count: 1,\n };\n if (consumer !== undefined) {\n group.consumer = consumer.slice(0, MAX_CONSUMER_LENGTH);\n }\n const key = [\n group.consumer ?? \"\",\n group.method,\n group.path,\n group.source,\n group.field,\n group.message,\n group.type,\n ].join(\"\\0\");\n const existing = validationErrorGroups.get(key);\n if (existing) {\n existing.count = Math.min(existing.count + 1, MAX_COUNT);\n } else if (validationErrorGroups.size < MAX_GROUPS) {\n validationErrorGroups.set(key, group);\n }\n }\n}\n\nexport function drainValidationErrors(): AnyValueMap[] {\n const groups = [...validationErrorGroups.values()];\n validationErrorGroups.clear();\n return groups;\n}\n\nexport function resetValidationErrors(): void {\n validationErrorGroups.clear();\n}\n\nexport function normalizeSource(source: unknown): string {\n return typeof source === \"string\" ? (SOURCE_ALIASES[source.toLowerCase()] ?? \"\") : \"\";\n}\n\n// Zod, Standard Schema, and TypeBox issues share this shape. A Standard Schema\n// path segment may be an object carrying the key; a TypeBox path is a JSON pointer.\nexport function formatIssues(issues: unknown, source = \"\"): ValidationErrorDetail[] {\n if (!Array.isArray(issues)) {\n return [];\n }\n const details: ValidationErrorDetail[] = [];\n for (const issue of issues) {\n if (!isRecord(issue) || typeof issue.message !== \"string\") {\n continue;\n }\n const path = Array.isArray(issue.path)\n ? issue.path\n : typeof issue.path === \"string\"\n ? issue.path\n .split(\"/\")\n .filter(Boolean)\n .map((segment) => segment.replace(/~1/g, \"/\").replace(/~0/g, \"~\"))\n : [];\n details.push({\n source,\n field: path\n .map((segment: unknown) => (isRecord(segment) ? segment.key : segment))\n .filter((segment) => typeof segment === \"string\" || typeof segment === \"number\")\n .join(\".\"),\n message: issue.message,\n type: typeof issue.code === \"string\" ? issue.code : \"\",\n });\n }\n return details;\n}\n\n// zod 3 serializes issues as `error.issues`; zod 4 hides them as a JSON string\n// in `error.message`.\nexport function extractZodValidationErrors(body: unknown): ValidationErrorDetail[] {\n if (!isRecord(body)) {\n return [];\n }\n const error = isRecord(body.error) ? body.error : undefined;\n let issues = body.issues ?? error?.issues;\n if (issues === undefined && error?.name === \"ZodError\" && typeof error.message === \"string\") {\n try {\n issues = JSON.parse(error.message);\n } catch {\n return [];\n }\n }\n return formatIssues(issues);\n}\n\n// Recognized response shapes: zod issues, express-validator, and celebrate.\nexport function extractExpressValidationErrors(body: unknown): ValidationErrorDetail[] {\n if (!isRecord(body)) {\n return [];\n }\n const zodDetails = extractZodValidationErrors(body);\n if (zodDetails.length > 0) {\n return zodDetails;\n }\n if (Array.isArray(body.errors)) {\n return extractExpressValidatorErrors(body.errors);\n }\n if (isRecord(body.validation)) {\n return extractCelebrateErrors(body.validation);\n }\n return [];\n}\n\nfunction extractExpressValidatorErrors(errors: unknown[]): ValidationErrorDetail[] {\n const details: ValidationErrorDetail[] = [];\n for (const error of errors) {\n if (\n !isRecord(error) ||\n error.type !== \"field\" ||\n typeof error.path !== \"string\" ||\n typeof error.msg !== \"string\"\n ) {\n continue;\n }\n const source = normalizeSource(error.location);\n if (source) {\n details.push({ source, field: error.path, message: error.msg, type: \"\" });\n }\n }\n return details;\n}\n\n// Celebrate joins the messages of all failed keys into one sentence list, so\n// each key takes the sentence naming it.\nfunction extractCelebrateErrors(validation: Record<string, unknown>): ValidationErrorDetail[] {\n const details: ValidationErrorDetail[] = [];\n for (const error of Object.values(validation)) {\n if (!isRecord(error) || !Array.isArray(error.keys) || typeof error.message !== \"string\") {\n continue;\n }\n const sentences = error.message.split(\". \");\n for (const key of error.keys) {\n if (typeof key === \"string\") {\n details.push({\n source: normalizeSource(error.source),\n field: key,\n message: sentences.find((sentence) => sentence.includes(`\"${key}\"`)) ?? error.message,\n type: \"\",\n });\n }\n }\n }\n return details;\n}\n\nexport function parseJsonResponseBody(body: Buffer | undefined, contentEncoding: unknown): unknown {\n if (!body) {\n return undefined;\n }\n try {\n const encoding =\n typeof contentEncoding === \"string\" ? contentEncoding.trim().toLowerCase() : \"\";\n let decoded = body;\n if (encoding === \"br\") {\n decoded = brotliDecompressSync(body, { maxOutputLength: MAX_BODY_SIZE });\n } else if (encoding === \"gzip\" || encoding === \"deflate\") {\n decoded = unzipSync(body, { maxOutputLength: MAX_BODY_SIZE });\n } else if (encoding !== \"\" && encoding !== \"identity\") {\n return undefined;\n }\n return JSON.parse(decoded.toString());\n } catch {\n // A body that cannot be decoded as JSON carries no recognizable validation details.\n }\n return undefined;\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n"],"mappings":"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","names":[]}
|