@stacknext/next 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,88 @@
1
+ ---
2
+ title: Configuration
3
+ description: Environment variables and verbose tracing behavior for @stacknext/next.
4
+ ---
5
+
6
+ # Configuration
7
+
8
+ `@stacknext/next` reads environment variables supplied by `stacknext dev`. The
9
+ application does not import `stacknext.config.json` directly; the CLI resolves
10
+ the config and exports the relevant values to the child process.
11
+
12
+ ## Environment variables
13
+
14
+ | Variable | Default | Behavior |
15
+ | --- | --- | --- |
16
+ | `STACKNEXT_COLLECTOR_URL` | none | Required for tracing. Must be loopback. |
17
+ | `STACKNEXT_TOKEN` | none | Required for tracing. At least 16 characters. |
18
+ | `STACKNEXT_PROJECT_NAME` | project name | Reported to the collector. |
19
+ | `STACKNEXT_SERVICE_NAME` | project or `next-app` | OTel service name. |
20
+ | `STACKNEXT_NEXT_VERSION` | none | Used for environment checks. |
21
+ | `STACKNEXT_CAPTURE_FETCH` | `1` | `0` drops `AppRender.fetch` spans. |
22
+ | `STACKNEXT_CAPTURE_ERRORS` | `1` | `0` makes `onRequestError` a no-op. |
23
+ | `STACKNEXT_DEBUG` | unset | `1` enables debug logs. |
24
+ | `NEXT_OTEL_VERBOSE` | unset | `1` enables the documented Next.js verbose span set. |
25
+
26
+ `stacknext dev` sets these from `stacknext.config.json`:
27
+ `instrumentation.captureFetch` → `STACKNEXT_CAPTURE_FETCH`,
28
+ `instrumentation.captureErrors` → `STACKNEXT_CAPTURE_ERRORS`,
29
+ `instrumentation.verbose` → `NEXT_OTEL_VERBOSE`.
30
+
31
+ <!-- coderabbit-ai-generated:v1 -->
32
+
33
+ <!-- coderabbit-ai-generated-section:v1:e042398001c539a0b51d0ae05cbcd223e5aa7ce932217b716003cea788939d36 -->
34
+
35
+ An explicit `NEXT_OTEL_VERBOSE` environment value wins. For example,
36
+ `NEXT_OTEL_VERBOSE=0` disables verbose tracing even when the config says
37
+ `"verbose": true`. `stacknext dev` overwrites `STACKNEXT_CAPTURE_FETCH`,
38
+ `STACKNEXT_CAPTURE_ERRORS` and `STACKNEXT_DEBUG` from configuration (with the
39
+ CLI debug flag also affecting `STACKNEXT_DEBUG`); inherited values for these
40
+ variables do not take precedence.
41
+
42
+ <!-- /coderabbit-ai-generated:v1 -->
43
+
44
+ ## Register options vs environment
45
+
46
+ <!-- coderabbit-ai-generated:v1 -->
47
+
48
+ <!-- coderabbit-ai-generated-section:v1:8045c991239c9f407c0469ae1416579f2a27d6f781161eb4253fee1480f382cf -->
49
+
50
+ `enabled`, `captureFetch`, `serviceName` and `nextVersion` control registration
51
+ and instrumentation for that call. When `transport` is omitted,
52
+ `resolveTransport()` uses the environment directly: `projectName` does not
53
+ override the project reported by that transport, and `collectorUrl` only changes
54
+ the self-instrumentation filter. Provide an explicit `transport` override to
55
+ control the collector or project used for telemetry. With that override,
56
+ `serviceName`, `projectName` and `nextVersion` also override its corresponding
57
+ transport values. The transport requires a valid token and loopback URL.
58
+
59
+ <!-- /coderabbit-ai-generated:v1 -->
60
+
61
+ ## Verbose tracing
62
+
63
+ `NEXT_OTEL_VERBOSE=1` adds documented Next.js span types. It:
64
+
65
+ - increases stored span volume and dev-server work;
66
+ - can shorten the effective retention of older events when capacity is reached;
67
+ - does **not** enable body, header, cookie, query-value or SQL-parameter
68
+ capture.
69
+
70
+ Use `stacknext coverage` or `get_project_summary` to see whether verbose
71
+ evidence is present. Unknown span types are retained as evidence instead of
72
+ being mapped to a guessed feature.
73
+
74
+ ## What cannot be enabled
75
+
76
+ The config schema rejects:
77
+
78
+ - `privacy.captureHeaders`;
79
+ - `privacy.captureRequestBodies`;
80
+ - `privacy.captureSqlParameters`;
81
+ - `privacy.redactSensitiveData: false`.
82
+
83
+ There are no environment variables that bypass these rules.
84
+
85
+ ## Related
86
+
87
+ - [@stacknext/core configuration](../../core/docs/configuration.md)
88
+ - the repository `docs/benchmark.md`
@@ -0,0 +1,105 @@
1
+ ---
2
+ title: Custom spans
3
+ description: Add application and Server Action spans with withStackNextSpan, withStackNextSpanSync and withStackNextAction.
4
+ ---
5
+
6
+ # Custom spans
7
+
8
+ StackNext exports three optional helpers from `@stacknext/next`. They use the
9
+ existing OpenTelemetry context/provider and do **not** create a second SDK.
10
+
11
+ ## Async work
12
+
13
+ ```ts
14
+ import { withStackNextSpan } from '@stacknext/next'
15
+
16
+ const project = await withStackNextSpan(
17
+ 'load project',
18
+ { attributes: { 'project.id': id } },
19
+ async (span) => {
20
+ const project = await loadProject(id)
21
+ span.setAttribute('project.found', project !== null)
22
+ return project
23
+ },
24
+ )
25
+ ```
26
+
27
+ Supported signatures:
28
+
29
+ ```ts
30
+ withStackNextSpan(name, fn, options?)
31
+ withStackNextSpan(name, options, fn)
32
+ ```
33
+
34
+ The callback receives the active OTel `Span`. Return values and thrown errors
35
+ are preserved. By default a thrown exception is recorded unless it is a Next.js
36
+ control-flow error (`NEXT_NOT_FOUND`, `NEXT_REDIRECT*` or
37
+ `NEXT_HTTP_ERROR_FALLBACK*`). Set `recordException: false` to disable recording.
38
+
39
+ ## Synchronous work
40
+
41
+ ```ts
42
+ import { withStackNextSpanSync } from '@stacknext/next'
43
+
44
+ const rows = withStackNextSpanSync(
45
+ 'sqlite batch',
46
+ { attributes: { 'batch.size': 25 } },
47
+ () => runBatch(),
48
+ )
49
+ ```
50
+
51
+ Same argument forms and error behavior as the async helper.
52
+
53
+ ## Server Actions
54
+
55
+ Successful Server Actions do not reach `onRequestError`, so StackNext cannot see
56
+ them automatically. Wrap the action explicitly:
57
+
58
+ ```ts
59
+ 'use server'
60
+
61
+ import { withStackNextAction } from '@stacknext/next'
62
+
63
+ export async function updateProject(formData: FormData) {
64
+ return withStackNextAction(
65
+ 'action updateProject',
66
+ { attributes: { 'project.id': String(formData.get('id') ?? '') } },
67
+ async () => {
68
+ // Action body.
69
+ },
70
+ )
71
+ }
72
+ ```
73
+
74
+ `withStackNextAction` sets `stacknext.span.kind = "action"`. It records only the
75
+ span name and attributes you pass; action arguments, `FormData` values and return
76
+ values are never captured automatically.
77
+
78
+ ## Options
79
+
80
+ `StackNextManualSpanOptions`:
81
+
82
+ | Option | Type | Default | Meaning |
83
+ | --- | --- | --- | --- |
84
+ | `attributes` | `Record<string, unknown>` | none | Sanitized before enqueueing. |
85
+ | `kind` | OTel `SpanKind` | `INTERNAL` | Span kind. |
86
+ | `recordException` | boolean | `true` | Record non-control-flow errors. |
87
+
88
+ The helpers add `stacknext.manual = true` and `stacknext.span.kind` after caller
89
+ attributes so coverage cannot be spoofed.
90
+
91
+ ## Attribute safety
92
+
93
+ Attributes pass through `sanitizeAttributes`: sensitive keys, headers and URL
94
+ query values are redacted. The collector applies a second pass. Do not put large
95
+ payloads or secrets in attribute values.
96
+
97
+ ## What the helpers do not do
98
+
99
+ - They do not automatically trace every Server Component or Server Action.
100
+ - They do not measure work you did not wrap.
101
+ - They do not create a new provider or exporter.
102
+ - They do not capture arguments, return values or bodies.
103
+
104
+ For broader guidance see the repository's `docs/custom-instrumentation.md`
105
+ and `docs/server-actions.md`.
package/docs/index.md ADDED
@@ -0,0 +1,92 @@
1
+ ---
2
+ title: "@stacknext/next"
3
+ description: Next.js instrumentation, OpenTelemetry export, request errors and manual spans for StackNext.
4
+ ---
5
+
6
+ # @stacknext/next
7
+
8
+ `@stacknext/next` connects a Next.js App Router application to a local
9
+ StackNext collector. It registers an OpenTelemetry `NodeTracerProvider`, converts
10
+ spans to the StackNext wire format, installs a W3C propagator, forwards
11
+ `onRequestError` hooks and exports optional manual span helpers.
12
+
13
+ ## Who should read this
14
+
15
+ Application developers installing StackNext. This is a **public integration
16
+ package** and the only instrumentation package a normal project needs.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pnpm add -D @stacknext/cli @stacknext/next
22
+ ```
23
+
24
+ `@stacknext/next` declares `next >=15.0.0 <17` as a peer dependency. It requires
25
+ the Node.js runtime; the `edge` export exists only to keep Edge bundling safe and
26
+ returns an inert module.
27
+
28
+ ## Entry points
29
+
30
+ | Import | Contents |
31
+ | --- | --- |
32
+ | `@stacknext/next` | `register`, `registerStackNext`, `shutdownStackNext`, `getStackNextRegistration`, `onRequestError`, manual span helpers and exporter utilities. |
33
+ | `@stacknext/next` with the `edge` condition | `./dist/edge.js`, an inert module for Edge bundles. |
34
+
35
+ ## Quick start
36
+
37
+ `stacknext init` creates `instrumentation.ts` (or `.js`) that guards on
38
+ `NEXT_RUNTIME === 'nodejs'` and imports StackNext dynamically:
39
+
40
+ ```ts
41
+ export async function register(): Promise<void> {
42
+ if (process.env.NEXT_RUNTIME !== 'nodejs') return
43
+ const stacknext = await import('@stacknext/next')
44
+ await stacknext.register()
45
+ }
46
+
47
+ export async function onRequestError(
48
+ error: unknown,
49
+ request: unknown,
50
+ context: unknown,
51
+ ): Promise<void> {
52
+ if (process.env.NEXT_RUNTIME !== 'nodejs') return
53
+ const stacknext = await import('@stacknext/next')
54
+ stacknext.onRequestError(
55
+ error,
56
+ request as Parameters<typeof stacknext.onRequestError>[1],
57
+ context as Parameters<typeof stacknext.onRequestError>[2],
58
+ )
59
+ }
60
+ ```
61
+
62
+ Do not replace an existing `instrumentation.ts`. Import `registerStackNext` and
63
+ `onRequestError` into the existing hook instead. See
64
+ [Installation](installation.md).
65
+
66
+ ## Behavior
67
+
68
+ - `register()` is inert when `STACKNEXT_COLLECTOR_URL` and `STACKNEXT_TOKEN` are
69
+ absent. A production build can ship safely.
70
+ - If another OpenTelemetry tracer provider is already registered, StackNext
71
+ yields to it and does not replace it.
72
+ - Spans are redacted and normalized before enqueueing.
73
+ - The exporter never performs synchronous network I/O.
74
+ - The transport shares one bounded queue with the Drizzle and Prisma adapters.
75
+ - `shutdownStackNext()` flushes buffered spans and is safe to call more than
76
+ once.
77
+
78
+ ## Documentation map
79
+
80
+ - [Installation](installation.md) — peer requirements and safe setup.
81
+ - [Instrumentation](instrumentation.md) — `register`, options and lifecycle.
82
+ - [Configuration](configuration.md) — environment variables and verbose tracing.
83
+ - [Custom spans](custom-spans.md) — `withStackNextSpan*` and Server Actions.
84
+ - [Troubleshooting](troubleshooting.md) — no telemetry, provider conflicts and
85
+ Edge warnings.
86
+
87
+ ## Related packages
88
+
89
+ - `@stacknext/core` supplies the wire types, redaction and transport.
90
+ - `@stacknext/drizzle` and `@stacknext/prisma` add database query events to the
91
+ same queue.
92
+ - `@stacknext/cli` runs the collector that receives the data.
@@ -0,0 +1,97 @@
1
+ ---
2
+ title: Installation
3
+ description: Install @stacknext/next safely without replacing existing instrumentation or monitoring.
4
+ ---
5
+
6
+ # Installation
7
+
8
+ ## Requirements
9
+
10
+ - Node.js `>=20.9.0`.
11
+ - Next.js 15 or 16 with the App Router.
12
+ - The Node.js runtime. Edge instrumentation is not supported.
13
+ - A local StackNext collector started by `stacknext dev`.
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ npm install --save-dev @stacknext/cli @stacknext/next
19
+ ```
20
+
21
+ or:
22
+
23
+ ```bash
24
+ pnpm add -D @stacknext/cli @stacknext/next
25
+ ```
26
+
27
+ Install inside the Next.js application package, not at a monorepo root.
28
+
29
+ ## Create the hook
30
+
31
+ ```bash
32
+ npx stacknext init
33
+ ```
34
+
35
+ If the project has no `instrumentation.ts`/`.js`, `init` writes one that:
36
+
37
+ 1. runs only when `NEXT_RUNTIME === 'nodejs'`;
38
+ 2. dynamically imports `@stacknext/next` so Edge bundling does not load Node-only
39
+ modules;
40
+ 3. calls `register()` and `onRequestError`.
41
+
42
+ The generated file is idempotent and recognized by `stacknext uninstall`.
43
+
44
+ ## Preserve existing instrumentation
45
+
46
+ Never overwrite an existing hook that another monitoring tool owns. Add
47
+ StackNext inside it:
48
+
49
+ ```ts
50
+ import {
51
+ registerStackNext,
52
+ onRequestError as stackNextOnRequestError,
53
+ } from '@stacknext/next'
54
+
55
+ export async function register() {
56
+ await startExistingMonitoring()
57
+ await registerStackNext()
58
+ }
59
+
60
+ // Only if the file does not already export an error hook.
61
+ export const onRequestError = stackNextOnRequestError
62
+ ```
63
+
64
+ If `onRequestError` already exists, call
65
+ `stackNextOnRequestError(error, request, context)` inside it.
66
+
67
+ StackNext checks for an already-registered OpenTelemetry provider and leaves it
68
+ untouched. It does not create a second SDK when another APM is active.
69
+
70
+ ## Environment
71
+
72
+ `stacknext dev` supplies:
73
+
74
+ | Variable | Purpose |
75
+ | --- | --- |
76
+ | `STACKNEXT_COLLECTOR_URL` | Loopback collector origin. |
77
+ | `STACKNEXT_TOKEN` | Bearer token for ingest. |
78
+ | `STACKNEXT_PROJECT_NAME` | Project name reported with telemetry. |
79
+ | `STACKNEXT_NEXT_VERSION` | Next.js version for environment checks. |
80
+ | `STACKNEXT_CAPTURE_FETCH` | `0` drops Next.js fetch spans. |
81
+ | `STACKNEXT_CAPTURE_ERRORS` | `0` disables the error hook. |
82
+ | `STACKNEXT_DEBUG` | `1` enables debug logs. |
83
+
84
+ Do not commit these values. The token lives in `.stacknext/run.json` with mode
85
+ `0600` and is generated per run.
86
+
87
+ ## Verify
88
+
89
+ With `stacknext dev` running:
90
+
91
+ ```bash
92
+ npx stacknext doctor
93
+ npx stacknext status
94
+ ```
95
+
96
+ Then make one request and confirm `requests` and `spans` increase. If the
97
+ dashboard is empty, see [Troubleshooting](troubleshooting.md).
@@ -0,0 +1,98 @@
1
+ ---
2
+ title: Instrumentation
3
+ description: register, registerStackNext and the OpenTelemetry lifecycle used by StackNext.
4
+ ---
5
+
6
+ # Instrumentation
7
+
8
+ ## `register(options?)`
9
+
10
+ ```ts
11
+ import { register } from '@stacknext/next'
12
+
13
+ await register()
14
+ ```
15
+
16
+ Alias for `registerStackNext()`. Call it from the app's `instrumentation.ts`
17
+ `register()` hook. It returns `null` when tracing is disabled or another
18
+ provider is active.
19
+
20
+ ## `registerStackNext(options?)`
21
+
22
+ ```ts
23
+ import { registerStackNext } from '@stacknext/next'
24
+
25
+ const registration = await registerStackNext()
26
+ ```
27
+
28
+ `StackNextRegisterOptions`:
29
+
30
+ | Option | Type | Meaning |
31
+ | --- | --- | --- |
32
+ | `transport` | `StackNextTransportOptions` | Overrides environment transport configuration. |
33
+ | `collectorUrl` | string | Collector URL, also used to filter self-instrumentation requests. |
34
+ | `serviceName` | string | OTel service name. Defaults to the transport value or `next-app`. |
35
+ | `projectName` | string | Project name reported to the collector. |
36
+ | `nextVersion` | string | Next.js version for the environment snapshot. |
37
+ | `captureFetch` | boolean | Set `false` to drop `AppRender.fetch` spans. |
38
+ | `enabled` | boolean | Set `false` to keep StackNext loaded but inactive. |
39
+
40
+ It returns a `StackNextRegistration` with `provider`, `transport`, `exporter`,
41
+ `serviceName` and `registeredAt`, or `null`.
42
+
43
+ ### Registration order
44
+
45
+ 1. Return the existing registration if this process already registered.
46
+ 2. Return `null` when `enabled: false` or the runtime is not Node.js.
47
+ 3. Return `null` when another OTel provider is already registered.
48
+ 4. Resolve the shared transport from options or environment.
49
+ 5. Return `null` when collector URL/token are absent.
50
+ 6. Build a `NodeTracerProvider` with a `BatchSpanProcessor`:
51
+ - scheduled delay 200 ms;
52
+ - queue size 2,048;
53
+ - export batch 256;
54
+ - export timeout 2,000 ms.
55
+ 7. Register the provider and install a composite W3C trace-context and baggage
56
+ propagator.
57
+ 8. Store the registration globally and hook `beforeExit` to flush.
58
+
59
+ The propagator is required so an incoming `traceparent` from a local Playwright
60
+ capture becomes the parent of the Next.js request trace.
61
+
62
+ ## `getStackNextRegistration()`
63
+
64
+ Returns the active registration without creating one. Useful in tests and
65
+ shutdown code.
66
+
67
+ ## `shutdownStackNext()`
68
+
69
+ ```ts
70
+ import { shutdownStackNext } from '@stacknext/next'
71
+
72
+ await shutdownStackNext()
73
+ ```
74
+
75
+ Flushes buffered spans and shuts down the provider and transport. Safe to call
76
+ more than once. Next.js owns process signals; StackNext only hooks
77
+ `beforeExit`.
78
+
79
+ ## Manual exporter utilities
80
+
81
+ `StackNextSpanExporter`, `readableSpanToInput`, `spanAttributes` and
82
+ `StackNextSpanExporterOptions` are exported for tests and custom integrations.
83
+ `readableSpanToInput` returns `null` for invalid ids, internal instrumentation
84
+ spans and requests to the StackNext collector itself. It redacts names,
85
+ attributes, resource attributes and status messages.
86
+
87
+ ## Self-instrumentation filter
88
+
89
+ Requests to `/__stacknext/` and the collector origin are excluded so the
90
+ dashboard and MCP traffic do not appear as application requests.
91
+
92
+ ## What is not automatic
93
+
94
+ - Server Components are not traced individually.
95
+ - Server Actions are not named automatically. See [Custom spans](custom-spans.md).
96
+ - Application functions and arbitrary database drivers are not inferred.
97
+ - Browser/client tracing is out of scope.
98
+ - Edge runtime is not supported.
@@ -0,0 +1,78 @@
1
+ ---
2
+ title: Troubleshooting
3
+ description: Diagnose missing Next.js telemetry, provider conflicts, Edge warnings and startup failures.
4
+ ---
5
+
6
+ # Troubleshooting
7
+
8
+ ## The dashboard is empty
9
+
10
+ 1. Confirm the app is started through `stacknext dev`, not `next dev`. The CLI
11
+ supplies the collector URL and token.
12
+ 2. Run `stacknext doctor`. It checks Node.js, Next.js, the App Router, config,
13
+ instrumentation, the dashboard build and collector health.
14
+ 3. Run `stacknext status --json` and inspect `runtime` and `connections`.
15
+ 4. Make a request after the app has fully started.
16
+ 5. Check `stacknext coverage`: `active` with no requests means the app is
17
+ connected but the feature has not been exercised yet.
18
+
19
+ ## `register()` returns `null`
20
+
21
+ Possible causes:
22
+
23
+ - `STACKNEXT_COLLECTOR_URL` or `STACKNEXT_TOKEN` is missing. Start the app with
24
+ `stacknext dev`.
25
+ - Another OpenTelemetry provider is already registered. Run with
26
+ `STACKNEXT_DEBUG=1` and look for the "leaving it untouched" message. StackNext
27
+ intentionally yields instead of replacing another APM.
28
+ - The runtime is not Node.js. Edge is unsupported.
29
+ - `enabled: false` was passed explicitly.
30
+
31
+ ## No error records
32
+
33
+ - Check `instrumentation.captureErrors` and `STACKNEXT_CAPTURE_ERRORS`.
34
+ - Confirm `instrumentation.ts` exports `onRequestError`.
35
+ - An existing `onRequestError` must call `stackNextOnRequestError(...)`.
36
+ - Control-flow errors from not-found/redirect responses are intentionally
37
+ excluded from diagnostics.
38
+ - Errors without an active span context are correlated by route/method and a
39
+ 30-second window. They may show as fallback-correlated or uncorrelated.
40
+
41
+ ## Missing fetch spans
42
+
43
+ Set `instrumentation.captureFetch` to `true` (the default) and ensure
44
+ `STACKNEXT_CAPTURE_FETCH` is not `0`. Only Next.js-emitted fetch spans can be
45
+ captured.
46
+
47
+ ## Edge build warnings or failures
48
+
49
+ Keep every StackNext import behind:
50
+
51
+ ```ts
52
+ if (process.env.NEXT_RUNTIME !== 'nodejs') return
53
+ ```
54
+
55
+ Use a dynamic import inside the hook. Do not import `@stacknext/next` at the top
56
+ level of a module that Edge also bundles.
57
+
58
+ ## Existing monitoring stopped working
59
+
60
+ StackNext must never replace a provider. If another tool stops receiving data,
61
+ check whether it registered before or after `registerStackNext()` and whether
62
+ the generated hook was merged into the existing `instrumentation.ts` rather than
63
+ replacing it. `stacknext init` prints a manual patch when a file exists.
64
+
65
+ ## Telemetry is dropped
66
+
67
+ The in-memory store is bounded by `collector.maxSpans` and
68
+ `collector.retentionMs`. `/api/health`, `stacknext status` and the dashboard
69
+ settings page report drop counters. `NEXT_OTEL_VERBOSE=1` increases span volume
70
+ and can shorten the effective retention window.
71
+
72
+ ## Verify
73
+
74
+ ```bash
75
+ stacknext doctor --json
76
+ stacknext status --json
77
+ stacknext coverage --json
78
+ ```
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@stacknext/next",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Next.js instrumentation and OpenTelemetry exporter for StackNext",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "files": [
8
- "dist"
8
+ "dist",
9
+ "docs"
9
10
  ],
10
11
  "main": "./dist/index.js",
11
12
  "types": "./dist/index.d.ts",
@@ -23,7 +24,7 @@
23
24
  "./package.json": "./package.json"
24
25
  },
25
26
  "dependencies": {
26
- "@stacknext/core": "0.9.0",
27
+ "@stacknext/core": "0.11.0",
27
28
  "@opentelemetry/api": "1.9.0",
28
29
  "@opentelemetry/context-async-hooks": "2.12.0",
29
30
  "@opentelemetry/core": "2.12.0",