Skip to content

feat: auto-config — consume the platform channel, SSR helpers, loud misconfig failure - #18

Merged
Starefossen merged 3 commits into
mainfrom
feat/auto-config-phase-1
Jul 12, 2026
Merged

feat: auto-config — consume the platform channel, SSR helpers, loud misconfig failure#18
Starefossen merged 3 commits into
mainfrom
feat/auto-config-phase-1

Conversation

@Starefossen

@Starefossen Starefossen commented Jul 12, 2026

Copy link
Copy Markdown
Member

Phases 1–2 of nais/grafana-apm-app#133, per ADR-0001 (#17).

Phase 1 — consume the platform channel (commit 1)

  • fromNaisConfig() — maps the naiserator generatedConfig payload to init options; tolerates today's incomplete payload (pre feat(frontend): complete the generatedConfig payload — namespace, environment, schemaVersion naiserator#687).
  • initFromConfigUrl(url = '/nais.json', options?) — fetch-and-init for pod-served static SPAs. Never throws; falls through to standard resolution on failure. Pre-init buffering: capture calls during the fetch are buffered (capped at 100) and flushed on init, with context/PII sanitization snapshotted at call time (runOrBuffer in internal.ts).
  • NAIS_FRONTEND_TELEMETRY_COLLECTOR_URL joins the telemetryUrl chain.
  • Mode-aware failure (ADR-0001 decision 6): console-echo dev mode only on genuinely local hosts; on a real host, missing collector/namespace → specific console.error, never silent, never a throw.
  • init({ debug: true }) — per-field resolution table.

Phase 2 — SSR helpers + docs (commit 2)

  • getNaisMetaTags() / renderNaisMetaTags() — resolve the five nais meta tags from overrides → generatedConfig payload → pod runtime env; SSR apps author the tags with one call.
  • <NaisMetaTags /> (@nais/apm/react) — the same as a component for Next.js layouts/_document (React 19 hoists metas into document.head).
  • Cross-repo contract test (naisConfigContract.test.ts): naiserator's verbatim golden-file nais.js output — both the pre-#687 shape and the completed schemaVersion: 1 shape — dynamically imported the way an SSR server would, and fed through fromNaisConfig. Template drift on either side fails this test.
  • README: canonical call is now init({ app: 'my-app', namespace: 'my-team' }); retracts the "injected by the nais platform" claim; corrects build-time env guidance (only version via GITHUB_SHA is safe to inline — never NAIS_CLUSTER_NAME); adds Setup per serving architecture (SSR / pod-served SPA / CDN) and documents the loud-failure/dev-mode split.

Tests

187 passing (45 new across both commits). tsc --noEmit clean apart from the pre-existing @grafana/rrweb-types error on main.

Companion

nais/naiserator#687 completes the platform payload (app.namespace, environment, schemaVersion) and adds the nais.json variant that initFromConfigUrl consumes.

Out of scope (later phases of #133)

Interim hostname fallback (tenant profile), release-inject build plugin.

@Starefossen Starefossen changed the title feat(config): consume the nais platform config channel + loud misconfig failure feat: auto-config — consume the platform channel, SSR helpers, loud misconfig failure Jul 12, 2026
@Starefossen
Starefossen force-pushed the feat/auto-config-phase-1 branch from 5aa245c to e4a06f7 Compare July 12, 2026 15:38
@Starefossen
Starefossen marked this pull request as ready for review July 12, 2026 16:39
Copilot AI review requested due to automatic review settings July 12, 2026 16:39
@Starefossen
Starefossen enabled auto-merge July 12, 2026 16:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a runtime config “auto-config” channel for @nais/apm (including naiserator-generated payload consumption), introduces SSR-friendly meta-tag helpers (plus a React component wrapper), and makes misconfiguration behavior explicitly loud on non-local hosts while preserving local dev-mode behavior.

Changes:

  • Introduces fromNaisConfig() and initFromConfigUrl() to consume naiserator generatedConfig via module payload or fetched nais.json, including pre-init signal buffering.
  • Adds SSR meta-tag helpers (getNaisMetaTags() / renderNaisMetaTags()) and <NaisMetaTags /> in @nais/apm/react.
  • Expands config resolution logic (debug resolution table, tenant fallback behavior, local-host detection) and updates docs + test coverage accordingly.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/react/NaisMetaTags.tsx New SSR React component that renders the resolved nais meta tags.
src/react/NaisMetaTags.test.tsx Tests meta rendering behavior for env, overrides, and generatedConfig payload.
src/react/index.ts Exports the new <NaisMetaTags /> component + props type.
src/naisConfigContract.test.ts Adds a cross-repo contract test for naiserator’s generatedConfig payload shapes.
src/metaTags.ts Adds server-side helpers to resolve/render the five nais meta tags.
src/metaTags.test.ts Tests meta resolution precedence and HTML escaping behavior.
src/internal.ts Adds pre-init buffering state and a runOrBuffer helper for capture calls.
src/initFromConfigUrl.test.ts Integration test covering fetch-and-init + buffering during fetch.
src/initFromConfigUrl.failure.test.ts Failure-path test ensuring fetch failure never blocks init and warns.
src/index.ts Adds initFromConfigUrl() and exports new config/meta helpers.
src/config.ts Extends config resolution (generatedConfig mapping, tenant profile, loud failure, debug table).
src/config.test.ts Expands unit tests for new resolution sources, debug output, and helper functions.
src/config.prodhost.test.ts Adds jsdom “real host” tests to pin loud-misconfig behavior.
src/config.navhost.test.ts Adds jsdom nav-host tests for interim hostname-based collector derivation.
src/api.ts Routes public API calls through buffering (runOrBuffer) during async init.
src/api.test.ts Adds tests for buffered call ordering and context snapshot semantics.
README.md Updates recommended init usage and documents per-architecture setup + loud failure behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/api.ts
Comment on lines +218 to +222
runOrBuffer((faro) => {
faro.api.pushMeasurement({
type,
values,
...(options.context ? { context: options.context } : {}),
Comment thread src/api.ts
Comment on lines 235 to +240
export function pushEvent(
name: string,
attributes?: Record<string, string>,
domain?: string
): void {
const faro = getFaroInstance();
if (!faro) {
return;
}
faro.api.pushEvent(name, attributes, domain);
runOrBuffer((faro) => faro.api.pushEvent(name, attributes, domain));
Comment thread src/index.ts
Comment on lines +195 to +201
} catch {
// eslint-disable-next-line no-console
console.warn(
`[@nais/apm] Fetching nais config from '${url}' failed (network error); ` +
'continuing with standard config resolution.'
);
}
@Starefossen
Starefossen disabled auto-merge July 12, 2026 17:51
@Starefossen
Starefossen enabled auto-merge July 12, 2026 18:25
…ig failure

Phase 1 of nais/grafana-apm-app#133 (ADR-0001):

- fromNaisConfig() maps the naiserator generatedConfig payload
  (telemetryCollectorURL, app.{name,namespace,version}, environment,
  schemaVersion) to init options
- initFromConfigUrl() fetches a served nais.json and initializes from it;
  signals raised while the fetch is in flight are buffered and flushed on
  init (never lost, capped at 100)
- NAIS_FRONTEND_TELEMETRY_COLLECTOR_URL joins the telemetryUrl resolution
  chain (pod runtime, SSR)
- Mode-aware failure: console-echo dev mode only on genuinely local hosts;
  on any other host a missing collector is a loud, specific console.error
  (never a silent no-op, never a throw)
- init({ debug: true }) prints the per-field resolution table (which source
  won for each field)
Phase 2 of nais/grafana-apm-app#133:

- getNaisMetaTags()/renderNaisMetaTags(): resolve the five nais meta tags
  from overrides -> generatedConfig payload -> pod runtime env; SSR servers
  author the tags with one call instead of by hand
- <NaisMetaTags /> (@nais/apm/react): the same as a component for Next.js
  layouts/_document (React 19 hoists the metas into document.head)
- Cross-repo contract test: naiserator's verbatim nais.js golden-file
  output (both the pre-#687 and schemaVersion 1 shapes) dynamically
  imported and fed through fromNaisConfig
- README: canonical init({ app, namespace }); retract the 'platform
  injects meta tags' claim; correct the build-time env guidance (only
  version is safe to inline); document the loud-failure/dev-mode split,
  debug mode, and setup per serving architecture (SSR / pod-served SPA /
  CDN)
…file interface

Phase 3 of nais/grafana-apm-app#133 (ADR-0001 decision 7):

- TenantProfile: all domain-shaped knowledge (nav's collector URLs, cluster
  and hostname mappings) moves behind one swappable interface — tenants are
  physically isolated installations, so nothing tenant-specific may live in
  shared resolution code
- navTenant (built-in, default): derives the collector from the cluster name
  (as before) or, on non-local hosts, from the page hostname (*.nav.no ->
  prod collector, *.dev.nav.no -> dev collector; dev checked first). Only
  the collector URL is derived, never environment - a hostname cannot tell
  prod-gcp from prod-fss and a fabricated cluster name is worse than none
- tenant: false disables derivation; a custom profile serves other tenants
- Explicitly interim: demoted once the platform-served well-known config
  URL ships (nais/grafana-apm-app#134 phase 3, #86)

This is what makes bare init({ app, namespace }) in a CI-built static
bundle send telemetry on nav domains with zero runtime wiring.
@Starefossen
Starefossen force-pushed the feat/auto-config-phase-1 branch from e4a06f7 to 98b6ac6 Compare July 12, 2026 18:31
@Starefossen
Starefossen added this pull request to the merge queue Jul 12, 2026
Merged via the queue into main with commit 82b1a03 Jul 12, 2026
6 checks passed
@Starefossen
Starefossen deleted the feat/auto-config-phase-1 branch July 12, 2026 18:33
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.

2 participants