Skip to content

♻️ [js-core] Schema-driven configuration validation across browser-core, browser-logs, and browser-rum-core#4798

Open
thomas-lebeau wants to merge 9 commits into
mainfrom
worktree-js-core-configuration
Open

♻️ [js-core] Schema-driven configuration validation across browser-core, browser-logs, and browser-rum-core#4798
thomas-lebeau wants to merge 9 commits into
mainfrom
worktree-js-core-configuration

Conversation

@thomas-lebeau

Copy link
Copy Markdown
Collaborator

Motivation

Configuration validation in browser-core, browser-logs, and browser-rum-core was previously done imperatively — each package had its own ad-hoc validation logic with repetitive checks, inconsistent error handling, and no shared abstraction.

This PR introduces a schema-driven configuration system in @datadog/js-core that declaratively describes fields, their types, defaults, and validation rules. Browser packages then derive their Configuration types and validation functions from these schemas.

Changes

  • @datadog/js-core: Add configuration entry point with validateAndBuildConfiguration, InferredConfig, and field definition types (StringField, BooleanField, PercentageField, SiteField, MatchOptionField, EnumField, CustomField). Includes an INVALID sentinel value that custom validators can return to fail the whole configuration.
  • browser-core: Replace imperative validateAndBuildConfiguration and manual Configuration interface with BROWSER_CORE_SCHEMA + InferredConfig<typeof BROWSER_CORE_SCHEMA>. Cookie-option fields (useSecureSessionCookie, etc.) are moved into the schema. buildCookieOptions now takes a typed CookieConfiguration rather than raw init config.
  • browser-logs: Replace LogsConfiguration interface and imperative validation with LOGS_SCHEMA that spreads BROWSER_CORE_SCHEMA and adds forwardErrorsToLogs, forwardConsoleLogs, forwardReports, and requestErrorResponseLengthLimit.
  • browser-rum-core: Same pattern — RUM_SCHEMA spreads BROWSER_CORE_SCHEMA and adds all RUM-specific fields.

Test instructions

yarn test:unit
yarn typecheck
yarn lint

Checklist

  • Tested locally
  • Tested on staging
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.
  • Updated documentation and/or relevant AGENTS.md file

@datadog-prod-us1-3

datadog-prod-us1-3 Bot commented Jun 17, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 61.74%
Overall Coverage: 77.03% (-0.15%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 0690d15 | Docs | Datadog PR Page | Give us feedback!

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Jun 17, 2026

Copy link
Copy Markdown

Bundles Sizes Evolution

📦 Bundle Name Base Size Local Size 𝚫 𝚫% Status
Rum 172.35 KiB 174.10 KiB +1.75 KiB +1.02%
Rum Profiler 8.22 KiB 8.22 KiB -1 B -0.01%
Rum Recorder 21.14 KiB 21.14 KiB -1 B -0.00%
Logs 54.64 KiB 56.24 KiB +1.59 KiB +2.92%
Rum Slim 130.18 KiB 131.97 KiB +1.79 KiB +1.38%
Worker 22.96 KiB 22.96 KiB 0 B 0.00%

@thomas-lebeau thomas-lebeau force-pushed the worktree-js-core-configuration branch 7 times, most recently from 2d8531b to 0e608e6 Compare June 23, 2026 16:31
@thomas-lebeau thomas-lebeau force-pushed the worktree-js-core-configuration branch 4 times, most recently from 9c41061 to 629c7b1 Compare July 3, 2026 06:19
@thomas-lebeau

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 629c7b13dc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/js-core/package.json
Comment on lines +313 to +318
sessionPersistence: {
type: 'enum',
values: ['cookie', 'local-storage', 'memory'] as const,
multiple: true,
strict: false,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't default invalid sessionPersistence to cookies

With strict: false on this public option, an explicit unrecognized sessionPersistence value from plain JavaScript (for example a typo) is dropped by schema validation and becomes undefined, so selectSessionStoreStrategyType() falls back to the default cookie/memory strategy. Before this change the raw invalid value reached the strategy selector and no session store was selected, so this can start tracking with cookies even though the caller explicitly configured an invalid persistence mode; make this field strict or otherwise preserve the invalid value so it does not silently default.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Technically a breaking change, but I don't think anyone willingly use invalid session persistence to prevent the SDK from starting. I think it's fine

export const DEFAULT_REQUEST_ERROR_RESPONSE_LENGTH_LIMIT = 32 * ONE_KIBI_BYTE
export const LOGS_SCHEMA = {
...BROWSER_CORE_SCHEMA,
forwardErrorsToLogs: { type: 'boolean', default: true, strict: false },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve forwardErrorsToLogs !== false semantics

For plain JavaScript users who pass a falsy non-boolean value such as 0 or '', this strict: false boolean coercion turns forwardErrorsToLogs off. The previous implementation, and the test that was removed, treated every value except the literal false as enabled via initConfiguration.forwardErrorsToLogs !== false, so these configurations now silently stop forwarding uncaught/runtime/network errors. This option needs the old !== false behavior rather than generic !!value coercion.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Also technically a small breaking change but this makes the behaviour more predictable. For example forwardErrorsToLogs: 0 is probably not expected to actually forward errors to logs

Comment on lines +431 to +432
strict: false,
default: DEFAULT_PROPAGATOR_TYPES,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't default invalid propagatorTypes to active headers

When an allowedTracingUrls object has invalid propagatorTypes (for example a typo array like ['traceContext'] or a non-array value), this nested strict: false field falls back to DEFAULT_PROPAGATOR_TYPES, so the SDK injects Datadog/tracecontext headers for that URL. Previously invalid propagators produced no tracing headers or caused the option to be ignored, which avoids unexpected CORS preflights and unintended trace propagation; keep invalid propagatorTypes ignored instead of defaulting them to active headers.

Useful? React with 👍 / 👎.

@thomas-lebeau thomas-lebeau force-pushed the worktree-js-core-configuration branch from 629c7b1 to ec72176 Compare July 3, 2026 08:54
Move buildCookieOptions and CookieConfiguration out of configuration.ts
into cookie.ts where they logically belong.

- CookieConfiguration now lives in cookie.ts with optional boolean fields
- buildCookieOptions accepts CookieConfiguration instead of InitConfiguration
- configuration/index.ts re-exports buildCookieOptions from cookie.ts
- cookie.spec.ts covers all four buildCookieOptions scenarios
Introduces a declarative, type-safe configuration engine in a new
@datadog/js-core/configuration sub-path entry point.

Field types: StringField, PercentageField, BooleanField, SiteField,
MatchOptionField, EnumField, UnionField, SchemaField, FunctionField.

Key features:
- InferredConfig<S> derives the output type from the schema definition,
  making it impossible for the interface to drift from the schema
- strict: false mode for backward-compatible validation fallback
- FunctionField with signature phantom field for precise type inference
- ConfigurationSchema as an interface for better type ergonomics
- Per-field auto-generated error messages via display.error

Also registers the package in tsconfig path aliases and eslint
side-effect allowlist.
Replaces the hand-written Configuration interface and per-field validators
with a declarative BROWSER_CORE_SCHEMA. Configuration is now inferred via
InferredConfig<typeof BROWSER_CORE_SCHEMA> — impossible to drift.

Key changes:
- validateAndBuildConfiguration is now a thin wrapper: passes display.error
  to the schema engine so all field errorMessages surface as display.error calls
- trackingConsent uses the object-form enum (INVALID on explicit invalid value)
- source uses the array-form enum (defaults to 'browser' on invalid/missing)
- sessionPersistence uses enum + multiple: true, normalising 'cookie' → ['cookie']
- allowedTrackingOrigins uses match-option + multiple: true
- The three cookie flags (useSecureSessionCookie, usePartitionedCrossSiteSessionCookie,
  trackSessionAcrossSubdomains) are now first-class schema fields; cookieOptions
  is removed from Configuration — sessionInCookie.ts calls buildCookieOptions()
  directly
- BROWSER_CORE_SCHEMA exported so browser-logs and browser-rum-core can extend it
- normalizePersistenceList simplified — sessionPersistence is always
  SessionPersistence[] | undefined after schema validation
- isAllowedTrackingOrigins moved to the init layer (preStartLogs/preStartRum)
Replaces hand-written LogsConfiguration validation with a declarative
LOGS_SCHEMA that extends BROWSER_CORE_SCHEMA.

- forwardErrorsToLogs: boolean field with default true
- forwardConsoleLogs / forwardReports: enum fields with allowAll: true
- Removes validateAndBuildForwardOption helper (schema handles it)
- isAllowedTrackingOrigins check moved to preStartLogs init layer
Replaces hand-written RumConfiguration validation with a declarative
RUM_SCHEMA that extends BROWSER_CORE_SCHEMA.

Key changes:
- allowedTracingUrls / excludedActivityUrls: union + multiple fields,
  single string/regex now normalises to array instead of erroring
- propagatorTypes: invalid values fall back to defaults
- trackFeatureFlagsForEvents: invalid items fall back to []
- RumConfiguration type inferred from schema with manual overrides for
  complex fields (beforeSend, plugins, allowedTracingUrls)
- isAllowedTrackingOrigins check moved to preStartRum init layer
- Cast DEFAULT_CONFIG to Configuration in allowedTrackingOrigins.spec.ts
- Refactor sessionContext.spec.ts: replace beforeEach with setup() factory to
  avoid shared mutable state across tests
- Fix recordingScope.specHelper.ts: spread configuration instead of casting
- Fix trackInput/trackMutation specs: recreate scope instead of mutating
  configuration.defaultPrivacyLevel in place
- Export DEFAULT_REQUEST_ERROR_RESPONSE_LENGTH_LIMIT from networkErrorCollection
  and update e2e import path accordingly
Register src/entries/configuration.ts as a typedoc entry point and add
the generated API Extractor report for the js-core configuration API.
- Document Optionality, Multiple, Strict, and all FieldDef variants
  (StringField, PercentageField, BooleanField, SiteField,
  MatchOptionField, EnumField, UnionField, SchemaField, FunctionField)
- Document ConfigurationSchema, InferredConfig, and
  validateAndBuildConfiguration
- Regenerate configuration.api.md to reflect the newly documented
  exports (removes "(undocumented)" tags)
@thomas-lebeau thomas-lebeau force-pushed the worktree-js-core-configuration branch from ec72176 to 34b7bf5 Compare July 3, 2026 09:38
@thomas-lebeau thomas-lebeau marked this pull request as ready for review July 3, 2026 09:47
@thomas-lebeau thomas-lebeau requested review from a team as code owners July 3, 2026 09:47
- Split InferredConfig into required and optional key sets so fields
  without `required: true` or a `default` become optional properties
  instead of always-present `| undefined` properties
- Lets consumers building configuration object literals by hand (e.g.
  test fixtures) omit fields instead of writing `field: undefined`
- Update API report and add a compile-time test verifying required
  fields stay required while optional fields can be omitted
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