Skip to content

./types re-exports QueueInstrumentationConfig, pulling the optional @opentelemetry peers into every consumer's typecheck #26

Description

@gerardp

Summary

The ./types subpath re-exports one type from the OpenTelemetry module, and
that single line pulls two optional peer dependencies into the typecheck of
every consumer who imports any type from that barrel:

// src/types/index.ts
export type { QueueInstrumentationConfig } from '../otel.js'   // line 35
// build/src/types/index.d.ts
export { QueueInstrumentationConfig } from '../otel.js'
import '@opentelemetry/api'
import 'node:diagnostics_channel'
import '@opentelemetry/instrumentation'

Both packages are declared optional:

"peerDependenciesMeta": {
  "@opentelemetry/api":             { "optional": true },
  "@opentelemetry/instrumentation": { "optional": true }
}

and the package already ships a dedicated ./otel subpath export for consumers
who do want the instrumentation types:

"exports": {
  ".":            "./build/index.js",
  "./otel":       "./build/src/otel.js",
  "./drivers/*":  "./build/src/drivers/*.js",
  "./contracts/*":"./build/src/contracts/*.js",
  "./types":      "./build/src/types/index.js"
}

So the re-export in the general barrel is the only path by which a consumer who
never touches OpenTelemetry ends up needing it installed.

Reproduction

mkdir repro && cd repro
npm init -y && npm pkg set type=module
npm i @boringnode/queue
npm i -D typescript@7.0.2 @types/node@25.9.4 knex@3.1.0

cat > tsconfig.json <<'JSON'
{
  "compilerOptions": {
    "target": "esnext",
    "module": "preserve",
    "moduleResolution": "bundler",
    "types": ["node"],
    "strict": true,
    "skipLibCheck": false,
    "noEmit": true
  }
}
JSON

printf 'import type { JobData } from "@boringnode/queue/types"\nexport type X = JobData\n' > index.ts
npx tsc --noEmit

Result:

node_modules/@boringnode/queue/build/src/otel.d.ts(3,22): error TS2307:
  Cannot find module '@opentelemetry/api' or its corresponding type declarations.
node_modules/@boringnode/queue/build/src/otel.d.ts(5,60): error TS2307:
  Cannot find module '@opentelemetry/instrumentation' or its corresponding type declarations.
node_modules/@boringnode/queue/build/src/types/index.d.ts(4,8): error TS2882:
  Cannot find module or type declarations for side-effect import of '@opentelemetry/api'.
node_modules/@boringnode/queue/build/src/types/index.d.ts(6,8): error TS2882:
  Cannot find module or type declarations for side-effect import of '@opentelemetry/instrumentation'.

(knex and the v25 @types/node pin are only there to isolate this issue from
the two others reported alongside it.)

Proposed fix

Remove the re-export from the general types barrel and let consumers reach it
through the subpath that already exists for exactly this:

  // src/types/index.ts
- export type { QueueInstrumentationConfig } from '../otel.js'
// consumers who want it
import type { QueueInstrumentationConfig } from '@boringnode/queue/otel'

JobDispatchMessage and JobExecuteMessage — exported one line above at
src/types/index.ts:33 — do not have this problem, because
src/types/tracing_channels.ts imports no OpenTelemetry types. Only the
../otel.js re-export does.

This is a breaking change for anyone importing QueueInstrumentationConfig
from @boringnode/queue/types today. Given that the OpenTelemetry support is
documented as experimental and has its own subpath, moving it there seems
reasonable, but you may prefer to schedule it for the next major.

Happy to send a PR

One-line change; I have the reproduction ready.


Related reports opened at the same time: #24 (root barrel re-exporting the Knex-only QueueSchemaService) and #25 (tracingChannel type arguments on @types/node v26). Independent of each other.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions