diff --git a/Dockerfile b/Dockerfile index d5fe35d..b514213 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,4 +17,4 @@ ENV PORT=3000 EXPOSE ${PORT} -CMD [ "node", "--import", "./dist/src/tracing.js", "./dist/src/index.js" ] +CMD ["node", "./dist/src/index.js"] diff --git a/env.d.ts b/env.d.ts index 9ab3a6f..68a4818 100644 --- a/env.d.ts +++ b/env.d.ts @@ -11,6 +11,7 @@ declare global { DEV_PROXY_URL: string; PORT: string; IGNORE_PRIVATE_REPOSITORY?: string + SENTRY_DSN?: string; } } } diff --git a/package.json b/package.json index c281008..2d5543c 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/index.js", "type": "module", "scripts": { - "dev:start": "node --experimental-loader @esbuild-kit/esm-loader --env-file .env -r src/tracing.ts src/index.ts", + "dev:start": "node --experimental-loader @esbuild-kit/esm-loader --env-file .env src/index.ts", "dev": "nodemon -e ts --watch src --exec \"npm run dev:start\"", "build": "tsc && tsc-alias", "test:unit": "vitest run", @@ -49,15 +49,7 @@ "dependencies": { "@hono/node-server": "^1.8.0", "@octokit/webhooks-types": "^7.3.2", - "@opentelemetry/api": "^1.7.0", - "@opentelemetry/context-async-hooks": "^1.21.0", - "@opentelemetry/exporter-trace-otlp-grpc": "^0.48.0", - "@opentelemetry/instrumentation-http": "^0.48.0", - "@opentelemetry/sdk-metrics": "^1.21.0", - "@opentelemetry/sdk-node": "^0.48.0", - "@opentelemetry/sdk-trace-node": "^1.21.0", "@sentry/node": "^7.101.1", - "@sentry/opentelemetry": "^7.101.1", "cheerio": "1.0.0-rc.12", "colorette": "^2.0.20", "eventsource": "^2.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d905893..3be0f2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,33 +11,9 @@ dependencies: '@octokit/webhooks-types': specifier: ^7.3.2 version: 7.3.2 - '@opentelemetry/api': - specifier: ^1.7.0 - version: 1.7.0 - '@opentelemetry/context-async-hooks': - specifier: ^1.21.0 - version: 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/exporter-trace-otlp-grpc': - specifier: ^0.48.0 - version: 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/instrumentation-http': - specifier: ^0.48.0 - version: 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-metrics': - specifier: ^1.21.0 - version: 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-node': - specifier: ^0.48.0 - version: 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-node': - specifier: ^1.21.0 - version: 1.21.0(@opentelemetry/api@1.7.0) '@sentry/node': specifier: ^7.101.1 version: 7.101.1 - '@sentry/opentelemetry': - specifier: ^7.101.1 - version: 7.101.1(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.21.0)(@opentelemetry/sdk-trace-base@1.21.0)(@opentelemetry/semantic-conventions@1.21.0) cheerio: specifier: 1.0.0-rc.12 version: 1.0.0-rc.12 @@ -850,25 +826,6 @@ packages: resolution: {integrity: sha512-KZlJcOdgD8N6SMIHWfwmb11L5/L2+rptWBxCexbzNCry/wfLXFFGFniyUrySnvFo+cWMxgy5GuImwY3mhUrP8g==} dev: false - /@grpc/grpc-js@1.10.1: - resolution: {integrity: sha512-55ONqFytZExfOIjF1RjXPcVmT/jJqFzbbDqxK9jmRV4nxiYWtL9hENSW1Jfx0SdZfrvoqd44YJ/GJTqfRrawSQ==} - engines: {node: ^8.13.0 || >=10.10.0} - dependencies: - '@grpc/proto-loader': 0.7.10 - '@types/node': 20.11.19 - dev: false - - /@grpc/proto-loader@0.7.10: - resolution: {integrity: sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==} - engines: {node: '>=6'} - hasBin: true - dependencies: - lodash.camelcase: 4.3.0 - long: 5.2.3 - protobufjs: 7.2.6 - yargs: 17.7.2 - dev: false - /@hono/node-server@1.8.0: resolution: {integrity: sha512-vlebYBWAE9PVbRXps8O918Cj34F1FLCJW+ZlepcIpLKp0SRXgDZ2tpYbSoJeT/QOkKVP6TQcjfTl5rs3z88rVw==} engines: {node: '>=18.14.1'} @@ -965,330 +922,6 @@ packages: resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} dev: true - /@opentelemetry/api-logs@0.48.0: - resolution: {integrity: sha512-1/aMiU4Eqo3Zzpfwu51uXssp5pzvHFObk8S9pKAiXb1ne8pvg1qxBQitYL1XUiAMEXFzgjaidYG2V6624DRhhw==} - engines: {node: '>=14'} - dependencies: - '@opentelemetry/api': 1.7.0 - dev: false - - /@opentelemetry/api@1.7.0: - resolution: {integrity: sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==} - engines: {node: '>=8.0.0'} - dev: false - - /@opentelemetry/context-async-hooks@1.21.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-t0iulGPiMjG/NrSjinPQoIf8ST/o9V0dGOJthfrFporJlNdlKIQPfC7lkrV+5s2dyBThfmSbJlp/4hO1eOcDXA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - dev: false - - /@opentelemetry/core@1.21.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-KP+OIweb3wYoP7qTYL/j5IpOlu52uxBv5M4+QhSmmUfLyTgu1OIS71msK3chFo1D6Y61BIH3wMiMYRCxJCQctA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/semantic-conventions': 1.21.0 - dev: false - - /@opentelemetry/exporter-trace-otlp-grpc@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-+qRQXUbdRW6aNRT5yWOG3G6My1VxxKeqgUyLkkdIjkT20lvymjiN2RpBfGMtAf/oqnuRknf9snFl9VSIO2gniw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.0.0 - dependencies: - '@grpc/grpc-js': 1.10.1 - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-grpc-exporter-base': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-transformer': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.21.0(@opentelemetry/api@1.7.0) - dev: false - - /@opentelemetry/exporter-trace-otlp-http@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-QEZKbfWqXrbKVpr2PHd4KyKI0XVOhUYC+p2RPV8s+2K5QzZBE3+F9WlxxrXDfkrvGmpQAZytBoHQQYA3AGOtpw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.0.0 - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-exporter-base': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-transformer': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.21.0(@opentelemetry/api@1.7.0) - dev: false - - /@opentelemetry/exporter-trace-otlp-proto@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-hVXr/8DYlAKAzQYMsCf3ZsGweS6NTK3IHIEqmLokJZYcvJQBEEazeAdISfrL/utWnapg1Qnpw8u+W6SpxNzmTw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.0.0 - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-exporter-base': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-proto-exporter-base': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-transformer': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.21.0(@opentelemetry/api@1.7.0) - dev: false - - /@opentelemetry/exporter-zipkin@1.21.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-J0ejrOx52s1PqvjNalIHvY/4v9ZxR2r7XS7WZbwK3qpVYZlGVq5V1+iCNweqsKnb/miUt/4TFvJBc9f5Q/kGcA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.0.0 - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/semantic-conventions': 1.21.0 - dev: false - - /@opentelemetry/instrumentation-http@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-uXqOsLhW9WC3ZlGm6+PSX0xjSDTCfy4CMjfYj6TPWusOO8dtdx040trOriF24y+sZmS3M+5UQc6/3/ZxBJh4Mw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/instrumentation': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/semantic-conventions': 1.21.0 - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - dev: false - - /@opentelemetry/instrumentation@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-sjtZQB5PStIdCw5ovVTDGwnmQC+GGYArJNgIcydrDSqUTdYBnMrN9P4pwQZgS3vTGIp+TU1L8vMXGe51NVmIKQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - dependencies: - '@opentelemetry/api': 1.7.0 - '@types/shimmer': 1.0.5 - import-in-the-middle: 1.7.1 - require-in-the-middle: 7.2.0 - semver: 7.5.4 - shimmer: 1.2.1 - transitivePeerDependencies: - - supports-color - dev: false - - /@opentelemetry/otlp-exporter-base@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-T4LJND+Ugl87GUONoyoQzuV9qCn4BFIPOnCH1biYqdGhc2JahjuLqVD9aefwLzGBW638iLAo88Lh68h2F1FLiA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.0.0 - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - dev: false - - /@opentelemetry/otlp-grpc-exporter-base@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-Vdp56RK9OU+Oeoy3YQC/UMOWglKQ9qvgGr49FgF4r8vk5DlcTUgVS0m3KG8pykmRPA+5ZKaDuqwPw5aTvWmHFw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.0.0 - dependencies: - '@grpc/grpc-js': 1.10.1 - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-exporter-base': 0.48.0(@opentelemetry/api@1.7.0) - protobufjs: 7.2.6 - dev: false - - /@opentelemetry/otlp-proto-exporter-base@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-14GSTvPZPfrWsB54fYMGb8v+Uge5xGXyz0r2rf4SzcRnO2hXCPHEuL3yyL50emaKPAY+fj29Dm0bweawe8UA6A==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.0.0 - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/otlp-exporter-base': 0.48.0(@opentelemetry/api@1.7.0) - protobufjs: 7.2.6 - dev: false - - /@opentelemetry/otlp-transformer@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-yuoS4cUumaTK/hhxW3JUy3wl2U4keMo01cFDrUOmjloAdSSXvv1zyQ920IIH4lymp5Xd21Dj2/jq2LOro56TJg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/api-logs': 0.48.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-logs': 0.48.0(@opentelemetry/api-logs@0.48.0)(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-metrics': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.21.0(@opentelemetry/api@1.7.0) - dev: false - - /@opentelemetry/propagator-b3@1.21.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-3ZTobj2VDIOzLsIvvYCdpw6tunxUVElPxDvog9lS49YX4hohHeD84A8u9Ns/6UYUcaN5GSoEf891lzhcBFiOLA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - dev: false - - /@opentelemetry/propagator-jaeger@1.21.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-8TQSwXjBmaDx7JkxRD7hdmBmRK2RGRgzHX1ArJfJhIc5trzlVweyorzqQrXOvqVEdEg+zxUMHkL5qbGH/HDTPA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - dev: false - - /@opentelemetry/resources@1.21.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-1Z86FUxPKL6zWVy2LdhueEGl9AHDJcx+bvHStxomruz6Whd02mE3lNUMjVJ+FGRoktx/xYQcxccYb03DiUP6Yw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/semantic-conventions': 1.21.0 - dev: false - - /@opentelemetry/sdk-logs@0.48.0(@opentelemetry/api-logs@0.48.0)(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-lRcA5/qkSJuSh4ItWCddhdn/nNbVvnzM+cm9Fg1xpZUeTeozjJDBcHnmeKoOaWRnrGYBdz6UTY6bynZR9aBeAA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.4.0 <1.8.0' - '@opentelemetry/api-logs': '>=0.39.1' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/api-logs': 0.48.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.21.0(@opentelemetry/api@1.7.0) - dev: false - - /@opentelemetry/sdk-metrics@1.21.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-on1jTzIHc5DyWhRP+xpf+zrgrREXcHBH4EDAfaB5mIG7TWpKxNXooQ1JCylaPsswZUv4wGnVTinr4HrBdGARAQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.21.0(@opentelemetry/api@1.7.0) - lodash.merge: 4.6.2 - dev: false - - /@opentelemetry/sdk-node@0.48.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-3o3GS6t+VLGVFCV5bqfGOcWIgOdkR/UE6Qz7hHksP5PXrVBeYsPqts7cPma5YXweaI3r3h26mydg9PqQIcqksg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/api-logs': 0.48.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/exporter-trace-otlp-grpc': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/exporter-trace-otlp-http': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/exporter-trace-otlp-proto': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/exporter-zipkin': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/instrumentation': 0.48.0(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-logs': 0.48.0(@opentelemetry/api-logs@0.48.0)(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-metrics': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-node': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/semantic-conventions': 1.21.0 - transitivePeerDependencies: - - supports-color - dev: false - - /@opentelemetry/sdk-trace-base@1.21.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-yrElGX5Fv0umzp8Nxpta/XqU71+jCAyaLk34GmBzNcrW43nqbrqvdPs4gj4MVy/HcTjr6hifCDCYA3rMkajxxA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/resources': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/semantic-conventions': 1.21.0 - dev: false - - /@opentelemetry/sdk-trace-node@1.21.0(@opentelemetry/api@1.7.0): - resolution: {integrity: sha512-1pdm8jnqs+LuJ0Bvx6sNL28EhC8Rv7NYV8rnoXq3GIQo7uOHBDAFSj7makAfbakrla7ecO1FRfI8emnR4WvhYA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.8.0' - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/context-async-hooks': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/propagator-b3': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/propagator-jaeger': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.21.0(@opentelemetry/api@1.7.0) - semver: 7.5.4 - dev: false - - /@opentelemetry/semantic-conventions@1.21.0: - resolution: {integrity: sha512-lkC8kZYntxVKr7b8xmjCVUgE0a8xgDakPyDo9uSWavXPyYqLgYYGdEd2j8NxihRyb6UwpX3G/hFUF4/9q2V+/g==} - engines: {node: '>=14'} - dev: false - - /@protobufjs/aspromise@1.1.2: - resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} - dev: false - - /@protobufjs/base64@1.1.2: - resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} - dev: false - - /@protobufjs/codegen@2.0.4: - resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} - dev: false - - /@protobufjs/eventemitter@1.1.0: - resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} - dev: false - - /@protobufjs/fetch@1.1.0: - resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/inquire': 1.1.0 - dev: false - - /@protobufjs/float@1.0.2: - resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} - dev: false - - /@protobufjs/inquire@1.1.0: - resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} - dev: false - - /@protobufjs/path@1.1.2: - resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} - dev: false - - /@protobufjs/pool@1.1.0: - resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} - dev: false - - /@protobufjs/utf8@1.1.0: - resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - dev: false - /@rollup/rollup-android-arm-eabi@4.9.5: resolution: {integrity: sha512-idWaG8xeSRCfRq9KpRysDHJ/rEHBEXcHuJ82XY0yYFIWnLMjZv9vF/7DOq8djQ2n3Lk6+3qfSH8AqlmHlmi1MA==} cpu: [arm] @@ -1420,24 +1053,6 @@ packages: '@sentry/utils': 7.101.1 dev: false - /@sentry/opentelemetry@7.101.1(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.21.0)(@opentelemetry/sdk-trace-base@1.21.0)(@opentelemetry/semantic-conventions@1.21.0): - resolution: {integrity: sha512-v+5/WGm9M4ihiVCLPTflgXQ1p5iciRASg5EasE+onlaflaorwKln+BvGTzMHmu3DClMei0CHkoPPj7qqsIKDYA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.0.0 - '@opentelemetry/core': ^1.0.0 - '@opentelemetry/sdk-trace-base': ^1.0.0 - '@opentelemetry/semantic-conventions': ^1.0.0 - dependencies: - '@opentelemetry/api': 1.7.0 - '@opentelemetry/core': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/sdk-trace-base': 1.21.0(@opentelemetry/api@1.7.0) - '@opentelemetry/semantic-conventions': 1.21.0 - '@sentry/core': 7.101.1 - '@sentry/types': 7.101.1 - '@sentry/utils': 7.101.1 - dev: false - /@sentry/types@7.101.1: resolution: {integrity: sha512-bwtkQvrCZ6JGc7vqX7TEAKBgkbQFORt84FFS3JQQb8G3efTt9fZd2ReY4buteKQdlALl8h1QWVngTLmI+kyUuw==} engines: {node: '>=8'} @@ -1536,6 +1151,7 @@ packages: resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==} dependencies: undici-types: 5.26.5 + dev: true /@types/sanitize-html@2.11.0: resolution: {integrity: sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==} @@ -1547,10 +1163,6 @@ packages: resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} dev: true - /@types/shimmer@1.0.5: - resolution: {integrity: sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==} - dev: false - /@types/unist@2.0.6: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} dev: false @@ -1765,14 +1377,6 @@ packages: event-target-shim: 5.0.1 dev: false - /acorn-import-assertions@1.9.0(acorn@8.11.3): - resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} - peerDependencies: - acorn: ^8 - dependencies: - acorn: 8.11.3 - dev: false - /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1796,6 +1400,7 @@ packages: resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} engines: {node: '>=0.4.0'} hasBin: true + dev: true /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -1809,12 +1414,14 @@ packages: /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 + dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} @@ -2052,27 +1659,16 @@ packages: fsevents: 2.3.3 dev: true - /cjs-module-lexer@1.2.3: - resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} - dev: false - - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: false - /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 + dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true /colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -2260,10 +1856,6 @@ packages: semver: 7.5.4 dev: true - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: false - /entities@4.4.0: resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} engines: {node: '>=0.12'} @@ -2440,11 +2032,6 @@ packages: '@esbuild/win32-x64': 0.20.0 dev: true - /escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} - engines: {node: '>=6'} - dev: false - /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -2813,6 +2400,7 @@ packages: /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true /function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} @@ -2828,11 +2416,6 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: false - /get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} dev: true @@ -2995,6 +2578,7 @@ packages: engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 + dev: true /hast-util-from-parse5@8.0.1: resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==} @@ -3135,15 +2719,6 @@ packages: resolve-from: 4.0.0 dev: true - /import-in-the-middle@1.7.1: - resolution: {integrity: sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==} - dependencies: - acorn: 8.11.3 - acorn-import-assertions: 1.9.0(acorn@8.11.3) - cjs-module-lexer: 1.2.3 - module-details-from-path: 1.0.3 - dev: false - /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -3207,6 +2782,7 @@ packages: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: hasown: 2.0.0 + dev: true /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} @@ -3220,11 +2796,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: false - /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -3409,21 +2980,14 @@ packages: p-locate: 5.0.0 dev: true - /lodash.camelcase@4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - dev: false - /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true - /long@5.2.3: - resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} - dev: false - /longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} dev: false @@ -3439,6 +3003,7 @@ packages: engines: {node: '>=10'} dependencies: yallist: 4.0.0 + dev: true /magic-string@0.30.5: resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} @@ -3910,10 +3475,6 @@ packages: ufo: 1.3.2 dev: true - /module-details-from-path@1.0.3: - resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==} - dev: false - /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -4138,6 +3699,7 @@ packages: /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} @@ -4211,25 +3773,6 @@ packages: resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==} dev: false - /protobufjs@7.2.6: - resolution: {integrity: sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==} - engines: {node: '>=12.0.0'} - requiresBuild: true - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/base64': 1.1.2 - '@protobufjs/codegen': 2.0.4 - '@protobufjs/eventemitter': 1.1.0 - '@protobufjs/fetch': 1.1.0 - '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.0 - '@protobufjs/path': 1.1.2 - '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.0 - '@types/node': 20.11.19 - long: 5.2.3 - dev: false - /pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} dev: true @@ -4310,22 +3853,6 @@ packages: unified: 11.0.4 dev: false - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: false - - /require-in-the-middle@7.2.0: - resolution: {integrity: sha512-3TLx5TGyAY6AOqLBoXmHkNql0HIf2RGbuMgCDT2WO/uGVAPJs6h7Kl+bN6TIZGd9bWhWPwnDnTHGtW8Iu77sdw==} - engines: {node: '>=8.6.0'} - dependencies: - debug: 4.3.4(supports-color@5.5.0) - module-details-from-path: 1.0.3 - resolve: 1.22.4 - transitivePeerDependencies: - - supports-color - dev: false - /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -4342,6 +3869,7 @@ packages: is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + dev: true /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -4430,6 +3958,7 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 + dev: true /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -4443,10 +3972,6 @@ packages: engines: {node: '>=8'} dev: true - /shimmer@1.2.1: - resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} - dev: false - /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: @@ -4504,15 +4029,6 @@ packages: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} dev: true - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: false - /string.prototype.trim@1.2.7: resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} engines: {node: '>= 0.4'} @@ -4550,6 +4066,7 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 + dev: true /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -4588,6 +4105,7 @@ packages: /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + dev: true /templite@1.2.0: resolution: {integrity: sha512-O9BpPXF44a9Pg84Be6mjzlrqOtbP2I/B5PNLWu5hb1n9UQ1GTLsjdMg1z5ROCkF6NFXsO5LQfRXEpgTGrZ7Q0Q==} @@ -4776,6 +4294,7 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true /unified@11.0.4: resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==} @@ -5051,26 +4570,13 @@ packages: stackback: 0.0.2 dev: true - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: false - /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: false - /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true /yaml-eslint-parser@1.2.2: resolution: {integrity: sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg==} @@ -5086,24 +4592,6 @@ packages: engines: {node: '>= 14'} dev: true - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: false - - /yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - dependencies: - cliui: 8.0.1 - escalade: 3.1.2 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - dev: false - /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} diff --git a/src/application/adapters/GithubAdapter.ts b/src/application/adapters/GithubAdapter.ts index c78e398..e499fa5 100644 --- a/src/application/adapters/GithubAdapter.ts +++ b/src/application/adapters/GithubAdapter.ts @@ -1,5 +1,5 @@ import type { WebhookEvent } from "@octokit/webhooks-types"; -import { trace } from "@opentelemetry/api"; +import * as Sentry from "@sentry/node"; import type { Comment, CommentChanges, @@ -14,8 +14,6 @@ import type { WebhookEventName } from "~/application/webhook/types"; -const tracer = trace.getTracer("application.adaptersGithubAdapter"); - export class GithubAdapter { private readonly _repository?: Repository; private readonly _issue?: Issue; @@ -137,9 +135,13 @@ export class GithubAdapter { } get(eventName: WebhookEventName) { - return tracer.startActiveSpan("get", (span) => { - span.setAttribute("event_name", eventName); - + return Sentry.startSpan({ + name: "get", + op: "application.adaptersGithubAdapter", + attributes: { + "event_name": eventName + } + }, () => { // issue related events if (eventName.startsWith("issue")) { const payload = { diff --git a/src/application/webhook/GithubWebhook.ts b/src/application/webhook/GithubWebhook.ts index 3f78916..3c4db96 100644 --- a/src/application/webhook/GithubWebhook.ts +++ b/src/application/webhook/GithubWebhook.ts @@ -1,13 +1,11 @@ import { createHmac, timingSafeEqual } from "node:crypto"; import type { WebhookEvent } from "@octokit/webhooks-types"; -import { trace } from "@opentelemetry/api"; +import * as Sentry from "@sentry/node"; import { GithubAdapter } from "../adapters/GithubAdapter"; import type { ILogger } from "../interfaces/ILogger"; import type { HandlerFunction, IWebhook, WebhookEventName } from "./types"; import { IGNORE_PRIVATE_REPOSITORY } from "~/env"; -const tracer = trace.getTracer("application.webhook.GithubWebhook"); - export class GithubWebhook implements IWebhook { public readonly secretToken: string; private readonly _handlers: Partial[]>> = {}; @@ -20,7 +18,10 @@ export class GithubWebhook implements IWebhook { } public verify(payload: string, signature: string) { - return tracer.startActiveSpan("verify", async () => { + return Sentry.startSpan({ + name: "verify", + op: "application.webhook.GithubWebhook" + }, async () => { if (payload.length === 0 || signature.length === 0) throw Error("payload or signature wasn't provided."); const signatureBuffer = Buffer.from(signature); @@ -35,15 +36,23 @@ export class GithubWebhook implements IWebhook { } public sign(payload: string): Promise { - return tracer.startActiveSpan("sign", () => { + return Sentry.startSpan({ + name: "sign", + op: "application.webhook.GithubWebhook" + }, () => { if (payload.length === 0) throw Error("payload wasn't provided."); return Promise.resolve(`sha256=${createHmac("sha256", this.secretToken).update(payload).digest("hex")}`); }); } public on(event: E, handler: HandlerFunction): void { - return tracer.startActiveSpan("on", (span) => { - span.setAttribute("event", event); + return Sentry.startSpan({ + name: "on", + op: "application.webhook.GithubWebhook", + attributes: { + event: event + } + }, () => { if (this._handlers[event] === undefined) { this._handlers[event] = []; } @@ -52,8 +61,13 @@ export class GithubWebhook implements IWebhook { } public handle(eventName: WebhookEventName, payload: WebhookEvent, targetsId: bigint[]): Promise { - return tracer.startActiveSpan("handle", async (span) => { - span.setAttribute("event_name", eventName); + return Sentry.startSpan({ + name: "handle", + op: "application.webhook.GithubWebhook", + attributes: { + "event_name": eventName + } + }, async () => { const handlers = this._handlers[eventName] as HandlerFunction[]; // no handler available diff --git a/src/index.ts b/src/index.ts index 63fb5fa..c7750b8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,8 @@ import path from "path"; import { Bot } from "grammy"; import { parse as parseGura } from "gura"; import { Hono } from "hono"; -import { otelTracer } from "./utils/honoOtelTracer"; +import * as Sentry from "@sentry/node"; +import { sentryMiddleware } from "./utils/honoSentryTracer"; import { appConfigSchema } from "~/schema"; import { BOT_TOKEN, GITHUB_WEBHOOK_SECRET, PORT, HOME_GROUP } from "~/env"; import { InMemoryGroupMapping } from "~/infrastructure/InMemoryGroupMapping"; @@ -22,6 +23,15 @@ import { GithubRoute } from "~/presentation/routes/GithubRoute"; import { GithubWebhook } from "~/application/webhook/GithubWebhook"; import { TelegramPresenter } from "~/presentation/TelegramPresenter"; +Sentry.init({ + dsn: process.env.SENTRY_DSN ?? "", + sampleRate: 1.0, + tracesSampleRate: 0.3, + integrations: [ + Sentry.httpIntegration({ tracing: true }) + ] +}); + // configurations const configFile = await readFile(path.resolve("config", "config.ura"), { encoding: "utf-8" }); const config = appConfigSchema.parse(parseGura(configFile)); @@ -56,7 +66,11 @@ const eventHandlers: EventHandlerMapping = { // webhook server and handlers const serverInstance = new Hono(); serverInstance.get("/", (c) => c.text("OK")); -serverInstance.use("*", otelTracer("gitgram")); +serverInstance.use(sentryMiddleware()); +serverInstance.onError((_, c) => { + c.status(500); + return c.json({ message: "Internal server error" }); +}); const githubRoute = new GithubRoute(serverInstance, { path: "/github", webhook: new GithubWebhook(GITHUB_WEBHOOK_SECRET, logger), diff --git a/src/presentation/event-handlers/Deployment.ts b/src/presentation/event-handlers/Deployment.ts index 58d692d..ca33326 100644 --- a/src/presentation/event-handlers/Deployment.ts +++ b/src/presentation/event-handlers/Deployment.ts @@ -1,12 +1,10 @@ -import { trace } from "@opentelemetry/api"; +import * as Sentry from "@sentry/node"; import { z } from "zod"; import type { IDeploymentEvent } from "~/application/interfaces/events/IDeploymentEvent"; import type { IPresenter } from "~/application/interfaces/IPresenter"; import type { HandlerFunction } from "~/application/webhook/types"; import { interpolate } from "~/utils/interpolate"; -const tracer = trace.getTracer("presentation.event-handlers.Deployment"); - export const deploymentTemplateSchema = z.object({ status: z.object({ base: z.string(), @@ -22,7 +20,10 @@ export class DeploymentEventHandler implements IDeploymentEvent { status(): HandlerFunction<"deployment_status"> { return (event) => { - return tracer.startActiveSpan("status", () => { + return Sentry.startSpan({ + name: "status", + op: "presentation.event-handlers.Deployment" + }, () => { const description = event.payload.deploymentStatus.description; const response = interpolate( this._templates.status.statuses[event.payload.deploymentStatus.state.toLowerCase()] + diff --git a/src/presentation/event-handlers/Discussion.ts b/src/presentation/event-handlers/Discussion.ts index 35d0869..437dbea 100644 --- a/src/presentation/event-handlers/Discussion.ts +++ b/src/presentation/event-handlers/Discussion.ts @@ -1,12 +1,10 @@ -import { trace } from "@opentelemetry/api"; +import * as Sentry from "@sentry/node"; import { z } from "zod"; import type { IPresenter } from "~/application/interfaces/IPresenter"; import type { IDiscussionEvent } from "~/application/interfaces/events/IDiscussionEvent"; import type { HandlerFunction } from "~/application/webhook/types"; import { interpolate } from "~/utils/interpolate"; -const tracer = trace.getTracer("presentation.event-handlers.Discussion"); - export const discussionTemplateSchema = z.object({ created: z.string().trim(), closed: z.string().trim(), @@ -27,7 +25,10 @@ export class DiscussionEventHandler implements IDiscussionEvent { created(): HandlerFunction<"discussion.created"> { return (event) => { - return tracer.startActiveSpan("created", () => { + return Sentry.startSpan({ + name: "created", + op: "presentation.event-handlers.Discussion" + }, () => { const message = this._templates.created; const payload = interpolate(message, { url: event.payload.discussion.url, @@ -49,7 +50,10 @@ export class DiscussionEventHandler implements IDiscussionEvent { closed(): HandlerFunction<"discussion.closed"> { return (event) => { - return tracer.startActiveSpan("closed", () => { + return Sentry.startSpan({ + name: "closed", + op: "presentation.event-handlers.Discussion" + }, () => { const message = this._templates.closed; const payload = interpolate(message, { url: event.payload.discussion.url, @@ -71,7 +75,10 @@ export class DiscussionEventHandler implements IDiscussionEvent { reopened(): HandlerFunction<"discussion.reopened"> { return (event) => { - return tracer.startActiveSpan("reopened", () => { + return Sentry.startSpan({ + name: "reopened", + op: "presentation.event-handlers.Discussion" + }, () => { const message = this._templates.reopened; const payload = interpolate(message, { url: event.payload.discussion.url, @@ -93,7 +100,10 @@ export class DiscussionEventHandler implements IDiscussionEvent { edited(): HandlerFunction<"discussion.edited"> { return (event) => { - return tracer.startActiveSpan("edited", () => { + return Sentry.startSpan({ + name: "edited", + op: "presentation.event-handlers.Discussion" + }, () => { const message = this._templates.edited; const payload = interpolate(message, { url: event.payload.discussion.url, @@ -115,7 +125,10 @@ export class DiscussionEventHandler implements IDiscussionEvent { deleted(): HandlerFunction<"discussion.deleted"> { return (event) => { - return tracer.startActiveSpan("deleted", () => { + return Sentry.startSpan({ + name: "deleted", + op: "presentation.event-handlers.Discussion" + }, () => { const message = this._templates.deleted; const payload = interpolate(message, { url: event.payload.discussion.url, @@ -137,7 +150,10 @@ export class DiscussionEventHandler implements IDiscussionEvent { pinned(): HandlerFunction<"discussion.pinned"> { return (event) => { - return tracer.startActiveSpan("pinned", () => { + return Sentry.startSpan({ + name: "pinned", + op: "presentation.event-handlers.Discussion" + }, () => { const message = this._templates.pinned; const payload = interpolate(message, { url: event.payload.discussion.url, diff --git a/src/presentation/event-handlers/PullRequest.ts b/src/presentation/event-handlers/PullRequest.ts index 465d640..907adc8 100644 --- a/src/presentation/event-handlers/PullRequest.ts +++ b/src/presentation/event-handlers/PullRequest.ts @@ -1,3 +1,4 @@ +import * as Sentry from "@sentry/node"; import { z } from "zod"; import type { IPullRequestEvent } from "~/application/interfaces/events"; import { markdownToHTML } from "~/utils/markdown"; @@ -26,31 +27,36 @@ export class PullRequestEventHandler implements IPullRequestEvent { closed(): HandlerFunction<"pull_request.closed"> { return (event) => { - let template = this._templates.closed.base; - - if (event.payload.pullRequest.isMerged) { - template = this._templates.closed.type.merged + "\n" + this._templates.closed.base; - } else { - template = this._templates.closed.type.closed + "\n" + this._templates.closed.base; - } - - const body = markdownToHTML(event.payload.pullRequest?.body ?? ""); - const response = - interpolate(template, { - url: event.payload.pullRequest.url, - no: event.payload.pullRequest.number, - title: event.payload.pullRequest.title, - body: body || "No description provided.", - assignee: event.payload.pullRequest.assignee?.name || "No Assignee", - author: event.payload.pullRequest.user.name, - repoName: event.payload.repository.fullName, - actor: event.payload.sender.name - }) + "\n" + transformLabels(event.payload.pullRequest.labels); - - this._hub.send({ - event: "pull_request.closed", - targetsId: event.targetsId, - payload: response + return Sentry.startSpan({ + name: "closed", + op: "presentation.event-handlers.PullRequest" + }, () => { + let template = this._templates.closed.base; + + if (event.payload.pullRequest.isMerged) { + template = this._templates.closed.type.merged + "\n" + this._templates.closed.base; + } else { + template = this._templates.closed.type.closed + "\n" + this._templates.closed.base; + } + + const body = markdownToHTML(event.payload.pullRequest?.body ?? ""); + const response = + interpolate(template, { + url: event.payload.pullRequest.url, + no: event.payload.pullRequest.number, + title: event.payload.pullRequest.title, + body: body || "No description provided.", + assignee: event.payload.pullRequest.assignee?.name || "No Assignee", + author: event.payload.pullRequest.user.name, + repoName: event.payload.repository.fullName, + actor: event.payload.sender.name + }) + "\n" + transformLabels(event.payload.pullRequest.labels); + + this._hub.send({ + event: "pull_request.closed", + targetsId: event.targetsId, + payload: response + }); }); }; } @@ -58,45 +64,55 @@ export class PullRequestEventHandler implements IPullRequestEvent { opened(): HandlerFunction<"pull_request.opened"> { const template = this._templates.opened; return (event) => { - const body = markdownToHTML(event.payload.pullRequest?.body ?? ""); - const response = - interpolate(template, { - url: event.payload.pullRequest.url, - repoName: event.payload.repository.fullName, - no: event.payload.pullRequest.number, - title: event.payload.pullRequest.title, - body: body || "No description provided.", - assignee: event.payload.pullRequest.assignee?.name || "No Assignee", - author: event.payload.pullRequest.user.name - }) + "\n" + transformLabels(event.payload.pullRequest.labels); - - this._hub.send({ - event: "pull_request.opened", - targetsId: event.targetsId, - payload: response + return Sentry.startSpan({ + name: "opened", + op: "presentation.event-handlers.PullRequest" + }, () => { + const body = markdownToHTML(event.payload.pullRequest?.body ?? ""); + const response = + interpolate(template, { + url: event.payload.pullRequest.url, + repoName: event.payload.repository.fullName, + no: event.payload.pullRequest.number, + title: event.payload.pullRequest.title, + body: body || "No description provided.", + assignee: event.payload.pullRequest.assignee?.name || "No Assignee", + author: event.payload.pullRequest.user.name + }) + "\n" + transformLabels(event.payload.pullRequest.labels); + + this._hub.send({ + event: "pull_request.opened", + targetsId: event.targetsId, + payload: response + }); }); }; } edited(): HandlerFunction<"pull_request.edited"> { return (event) => { - const body = markdownToHTML(event.payload.pullRequest?.body ?? ""); - const response = - interpolate(this._templates.edited, { - url: event.payload.pullRequest.url, - repoName: event.payload.repository.fullName, - no: event.payload.pullRequest.number, - title: event.payload.pullRequest.title, - body: body || "No description provided.", - assignee: event.payload.pullRequest.assignee?.name || "No Assignee", - author: event.payload.pullRequest.user.name, - actor: event.payload.sender.name - }) + "\n" + transformLabels(event.payload.pullRequest.labels); - - this._hub.send({ - event: "pull_request.edited", - targetsId: event.targetsId, - payload: response + return Sentry.startSpan({ + name: "edited", + op: "presentation.event-handlers.PullRequest" + }, () => { + const body = markdownToHTML(event.payload.pullRequest?.body ?? ""); + const response = + interpolate(this._templates.edited, { + url: event.payload.pullRequest.url, + repoName: event.payload.repository.fullName, + no: event.payload.pullRequest.number, + title: event.payload.pullRequest.title, + body: body || "No description provided.", + assignee: event.payload.pullRequest.assignee?.name || "No Assignee", + author: event.payload.pullRequest.user.name, + actor: event.payload.sender.name + }) + "\n" + transformLabels(event.payload.pullRequest.labels); + + this._hub.send({ + event: "pull_request.edited", + targetsId: event.targetsId, + payload: response + }); }); }; } diff --git a/src/presentation/event-handlers/Release.ts b/src/presentation/event-handlers/Release.ts index 9a8a807..9eff78c 100644 --- a/src/presentation/event-handlers/Release.ts +++ b/src/presentation/event-handlers/Release.ts @@ -1,3 +1,4 @@ +import * as Sentry from "@sentry/node"; import { z } from "zod"; import type { IReleaseEvent } from "~/application/interfaces/events"; import { markdownToHTML } from "~/utils/markdown"; @@ -17,20 +18,25 @@ export class ReleaseEventHandler implements IReleaseEvent { published(): HandlerFunction<"release.published"> { return (event) => { - const body = markdownToHTML(event.payload.release.body); - const response = interpolate(this._templates.published, { - tag_name: event.payload.release.tagName, - repoName: event.payload.repository.fullName, - name: event.payload.release.name, - url: event.payload.release.url, - body: body || "No description provided.", - actor: event.payload.sender.name - }); - - this._hub.send({ - event: "release.published", - targetsId: event.targetsId, - payload: response + return Sentry.startSpan({ + name: "published", + op: "presentation.event-handlers.Release" + }, () => { + const body = markdownToHTML(event.payload.release.body); + const response = interpolate(this._templates.published, { + tag_name: event.payload.release.tagName, + repoName: event.payload.repository.fullName, + name: event.payload.release.name, + url: event.payload.release.url, + body: body || "No description provided.", + actor: event.payload.sender.name + }); + + this._hub.send({ + event: "release.published", + targetsId: event.targetsId, + payload: response + }); }); }; } diff --git a/src/tracing.ts b/src/tracing.ts deleted file mode 100644 index fbb7a7e..0000000 --- a/src/tracing.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Sentry dependencies -import Sentry from "@sentry/node"; -import { getClient, setupGlobalHub, SentryPropagator, SentrySampler, SentrySpanProcessor, setupEventContextTrace, wrapContextManagerClass, setOpenTelemetryContextAsyncContextStrategy } from "@sentry/opentelemetry"; - -// OpenTelemetry dependencies -import opentelemetry from "@opentelemetry/sdk-node"; -import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc"; -import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks"; -import { HttpInstrumentation } from "@opentelemetry/instrumentation-http"; - -function setupSentry() { - setupGlobalHub(); - - // Make sure to call `Sentry.init` BEFORE initializing the OpenTelemetry SDK - Sentry.init({ - dsn: "", - sampleRate: 1.0, - tracesSampleRate: 0.3, - // set the instrumenter to use OpenTelemetry instead of Sentry - instrumenter: "otel" - }); - - const client = getClient()!; - setupEventContextTrace(client); - - // You can wrap whatever local storage context manager you want to use - const SentryContextManager = wrapContextManagerClass( - AsyncLocalStorageContextManager - ); - - const sdk = new opentelemetry.NodeSDK({ - // Existing config - traceExporter: new OTLPTraceExporter(), - instrumentations: [new HttpInstrumentation()], - - // Sentry config - spanProcessor: new SentrySpanProcessor(), - textMapPropagator: new SentryPropagator(), - contextManager: new SentryContextManager(), - sampler: new SentrySampler(client) - }); - - // Ensure OpenTelemetry Context & Sentry Hub/Scope is synced - setOpenTelemetryContextAsyncContextStrategy(); - - sdk.start(); -} - -setupSentry(); \ No newline at end of file diff --git a/src/utils/honoOtelTracer.ts b/src/utils/honoOtelTracer.ts deleted file mode 100644 index 84792f7..0000000 --- a/src/utils/honoOtelTracer.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { trace } from "@opentelemetry/api"; -import type { Span } from "@opentelemetry/api"; -import type { Context, Next } from "hono"; -import { createMiddleware } from "hono/factory"; -import * as Sentry from "@sentry/node"; - -const recordError = (span: Span, error: unknown) => { - if (error instanceof Error) { - span.recordException({ - name: error.name, - message: error.message - }); - span.setStatus({ code: 2, message: error.message }); - } else { - const errorMessage = String(error); - span.recordException({ message: errorMessage }); - span.setStatus({ code: 2, message: errorMessage }); - } -}; - -export const otelTracer = ( - tracerName: string, - customAttributes?: (context: Context) => Record -) => { - const tracer = trace.getTracer(tracerName); - return createMiddleware(async (c: Context, next: Next) => { - const span = tracer.startSpan("http.server", { - attributes: { - "http.request.method": c.req.method, - "http.request.url": c.req.url, - ...customAttributes - } - }); - const startTime = Date.now(); - - try { - await next(); - span.setAttribute("http.response.status_code", c.res.status); - } catch (error) { - recordError(span, error); - if (c.req.header("User-Agent")) { - const userAgent = c.req.header("User-Agent") || "Unknown"; - span.setAttribute("http.user_agent", userAgent); - } - Sentry.captureException(error); - throw error; - } finally { - const duration = Date.now() - startTime; - span.setAttribute("http.request_duration", duration); - span.end(); - } - }); -}; \ No newline at end of file diff --git a/src/utils/honoSentryTracer.ts b/src/utils/honoSentryTracer.ts new file mode 100644 index 0000000..3422b10 --- /dev/null +++ b/src/utils/honoSentryTracer.ts @@ -0,0 +1,82 @@ +import type { Context, Next } from "hono"; +import { createMiddleware } from "hono/factory"; +import * as Sentry from "@sentry/node"; + +const getUserIP = (c: Context): string | undefined => { + let ipAddress: string | undefined; + const possibleHeaders = ["Forwarded", "Forwarded-For", "Client-IP", "X-Forwarded", "X-Forwarded-For", "X-Client-IP", "X-Real-IP", "True-Client-IP"]; + for (const possibleHeader of possibleHeaders) { + const value = c.req.header(possibleHeader); + if (value !== undefined && value !== "") { + ipAddress = value; + } + } + + return ipAddress; +}; + +const convertOpenTelemetryHeaders = (headers: Iterable<[key: string, value: string | string[]]>, precedence: "request" | "response"): Record => { + const openTelemetryHeadersCollection: Record = {}; + for (const [key, value] of headers) { + if (Array.isArray(value)) { + openTelemetryHeadersCollection[`http.${precedence}.header.${key.toLowerCase()}`] = value; + continue; + } + + openTelemetryHeadersCollection[`http.${precedence}.header.${key.toLowerCase()}`] = [value]; + } + + return openTelemetryHeadersCollection; +}; + +export const sentryMiddleware = () => { + return createMiddleware(async (c: Context, next: Next) => { + const scope = Sentry.getCurrentScope(); + const requestHeaders: Record = c.req.header(); + const userIPAddress = getUserIP(c); + if (userIPAddress) { + scope.setUser({ ip_address: userIPAddress }); + } + scope.setExtra("Headers", requestHeaders); + return Sentry.continueTrace( + { + sentryTrace: c.req.header("sentry-trace"), + baggage: c.req.header("baggage") + }, + () => { + return Sentry.startSpan({ + name: c.req.method + " " + c.req.path, + op: "http.server", + onlyIfParent: false, + attributes: { + source: "url", + "http.request.method": c.req.method, + "http.method": c.req.method, + "http.url": c.req.url, + "http.user_agent": c.req.header("User-Agent") || "unknown", + "http.host": c.req.header("Host"), + "http.client_ip": userIPAddress, + ...convertOpenTelemetryHeaders(Object.entries(requestHeaders), "request") + } + }, + async (span) => { + try { + await next(); + if (c.error !== undefined && c.error !== null) { + if (c.res.status >= 500) { + scope.captureException(c.error); + } + } + } catch (error) { + scope.captureException(error); + throw error; + } finally { + span?.setAttribute("http.response.status_code", c.res.status); + span?.setAttribute("http.status_code", c.res.status); + span?.setAttributes(convertOpenTelemetryHeaders(c.res.headers.entries(), "response")); + span?.end(); + } + }); + }); + }); +}; \ No newline at end of file