Skip to content

SMOODEV-1067: Node SDK capture handlers + Hono middleware - #3

Merged
brentrager merged 1 commit into
mainfrom
smoodev-1067-node-handlers
May 18, 2026
Merged

SMOODEV-1067: Node SDK capture handlers + Hono middleware#3
brentrager merged 1 commit into
mainfrom
smoodev-1067-node-handlers

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Summary

Wires the node-side TODO stubs into real implementations so @smooai/observability works end-to-end on Lambda / long-running Node services. Closes the th-bafeb7 follow-up under the SMOODEV-1067 Phase 1 epic and unblocks the logger ↔ observability integration tracked separately.

What lands

  • registerNodeGlobalHandlers({ flush, exitOnUncaught }) — attaches uncaughtException + unhandledRejection listeners forwarding to Client.captureException, plus SIGTERM / SIGINT / beforeExit flushing so a Lambda container shutdown drains the queue. Idempotent.
  • makeNodeTransport(options) — node-flavored Transport (fetch + keepalive; no Beacon).
  • observabilityMiddleware({ resolveUser, requestHeaderAllowlist }) — Hono-shaped middleware. Hydrates the request Scope with the authenticated user (default reader matches @smooai/auth's c.get('auth')), records request context, wraps the chain in withScope, captures thrown errors before re-throwing so Hono's onError still renders the response.
  • Client.init on node auto-wires transport + handlers (autoInstrumentation: false to opt out).

Latent bug fix

withScope used to pop the cloned scope inside finally, which ran BEFORE awaits inside an async callback resolved — request-scoped user/tags were gone by the time async handlers ran. Now: if the callback returns a thenable, the pop is deferred until that thenable settles. Sync callers are unchanged (the pop still runs in finally if no thenable was returned).

Test plan

  • pnpm --filter @smooai/observability exec vitest run — 24/24 green (was 13).
  • pnpm --filter @smooai/observability typecheck clean.
  • pnpm --filter @smooai/observability build clean.

🤖 Generated with Claude Code

Wire the node-side TODO stubs into real implementations:

- `registerNodeGlobalHandlers({ flush, exitOnUncaught })` attaches
  `uncaughtException` + `unhandledRejection` listeners that forward to
  `Client.captureException`, plus SIGTERM / SIGINT / `beforeExit` flushing
  so a Lambda container shutdown drains the in-memory queue. Idempotent.
- `makeNodeTransport(options)` returns a node-flavored `Transport` (fetch
  with keepalive, no Beacon). Caller keeps the instance so the global
  handlers can hook its `flush()` into the process lifecycle.
- `observabilityMiddleware({ resolveUser, requestHeaderAllowlist })` —
  Hono-shaped middleware. Per request: hydrates the active `Scope` from
  `c.get('auth')` (matches `@smooai/auth`), adds a `request` context
  with method/path/allow-listed-headers, wraps the handler chain in
  `withScope` so any `captureException` from a downstream handler picks
  up that request's identity, and captures thrown errors before re-
  throwing so Hono's `onError` still renders the response.
- `Client.init` on node now auto-wires the transport + global handlers
  (override with `autoInstrumentation: false`).

Also fixed a latent bug in `withScope`: previously the cloned scope was
popped before any `await` inside the callback resolved, so request-scoped
state was gone by the time async handlers ran. `withScope` now defers the
pop until a returned thenable settles, while keeping the synchronous fast
path unchanged.

24 tests (was 13). Build + typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented May 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5422d89

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@smooai/observability Minor
@smooai/observability-next Minor
@smooai/observability-react Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@brentrager
brentrager merged commit bd64532 into main May 18, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant