Skip to content

api-core: configurable ExpressServer CORS allowedHeaders + Datadog RUM by default#118

Merged
SethPaul merged 1 commit into
mainfrom
feat/api-core-configurable-cors-headers
Jun 3, 2026
Merged

api-core: configurable ExpressServer CORS allowedHeaders + Datadog RUM by default#118
SethPaul merged 1 commit into
mainfrom
feat/api-core-configurable-cors-headers

Conversation

@SethPaul
Copy link
Copy Markdown
Contributor

@SethPaul SethPaul commented Jun 3, 2026

What

@saga-ed/soa-api-core's ExpressServer hardcoded allowedHeaders: ['Content-Type', 'Authorization'] with no way to override it. Any service that relies on the built-in CORS (instead of a hand-rolled app.use(cors(...)) before init()) therefore can't clear the browser preflight for Datadog browser-RUM's cross-origin tracing headers (traceparent, tracestate, x-datadog-*). Confirmed inheritors of the default: coach-api, saga-sm (+ the saga-soa examples).

This closes that gap fleet-wide and makes the list configurable.

Changes

  • Default allowedHeaders is now ['Content-Type', 'Authorization', ...DATADOG_RUM_TRACING_HEADERS] — the canonical set from @saga-ed/soa-api-util. Inheriting services get Datadog RUM support automatically, no config needed.
  • New optional allowedHeaders field on ExpressServerConfig. When set, it replaces the default (standard cors semantics). This lets the services that currently hand-roll a cors() override before init() retire that boilerplate and the // TODO: remove when SOA ExpressServer supports configurable allowedHeaders comment (thrive iam-api, etc.).
  • Adds @saga-ed/soa-api-util (workspace:*) as an api-core dependency for the shared constant.
  • Version bump api-core 1.1.4 → 1.2.0 (additive, backward-compatible).

Design note (wants a 👍)

A caller-supplied allowedHeaders replaces the default rather than merging the Datadog headers in. That's the predictable cors semantic and matches the existing per-service override lists (which already spread the constant), but it means an overriding service that forgets to spread DATADOG_RUM_TRACING_HEADERS loses RUM support. If we'd prefer Datadog headers always-on (merge), it's a one-line change — flagging for a decision.

Verification

  • turbo run build --filter=@saga-ed/soa-api-core green (tsup DTS type-check passes).
  • pnpm --filter @saga-ed/soa-api-core test33/33, including 2 new integration tests in express-server.int.test.ts:
    • default preflight Access-Control-Allow-Headers admits the baseline + every Datadog header;
    • an explicit allowedHeaders config replaces the default (Datadog not auto-merged).

Rollout

Backward-compatible — the default only adds allowed request headers (strictly more permissive, no security change). Consumers pick it up when they bump @saga-ed/soa-api-core. No required follow-up; services that hand-roll CORS overrides can now drop them.

Context: this came out of adding Datadog RUM header allows across the APIs (rtsm was the trigger — rtsm itself hand-rolls CORS and doesn't use ExpressServer, so it's handled separately). See hipponot/iac#358.

…og-aware by default

ExpressServer hardcoded `allowedHeaders: ['Content-Type', 'Authorization']`, so
any service relying on its built-in CORS (rather than a hand-rolled cors()
override before init()) silently failed the browser preflight for Datadog RUM's
cross-origin tracing headers (traceparent, tracestate, x-datadog-*). coach-api
and saga-sm inherit this default.

- Default allowedHeaders is now ['Content-Type', 'Authorization',
  ...DATADOG_RUM_TRACING_HEADERS] (the canonical set from @saga-ed/soa-api-util),
  so RUM-instrumented frontends work fleet-wide with no per-service config.
- Add an optional `allowedHeaders` field to ExpressServerConfig; when set it
  replaces the default (services overriding should spread
  DATADOG_RUM_TRACING_HEADERS to keep RUM working). This lets services that
  hand-roll a cors() override before init() retire that boilerplate and the
  "TODO: remove when ExpressServer supports configurable allowedHeaders" comment.
- Add @saga-ed/soa-api-util as a dependency for the shared constant.
- Integration tests: default preflight admits the baseline + every Datadog
  header; an explicit allowedHeaders list replaces the default.

Backward-compatible — the default only ADDS allowed request headers. Bump
api-core 1.1.4 -> 1.2.0.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

✅ Test Results

Status Suites Tests
✅ Passed 117 301
❌ Failed 0 0
⏭️ Skipped 0 0
Total 117 301

Package Results

Package Tests Passed Failed
✅ @saga-ed/soa-core 23 23 0
✅ @saga-ed/soa-node 261 261 0
✅ @saga-ed/soa-web 17 17 0

Commits

  • Branch: 0d253cb (feat/api-core-configurable-cors-headers)
  • Merge: 3f6be10

Links


Updated: 2026-06-03T18:52:24.985Z

@SethPaul SethPaul merged commit 3f4c7d3 into main Jun 3, 2026
30 checks passed
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