Skip to content

feat(api)!: split schema configuration into a DataSchema builder#870

Merged
johngeorgewright merged 4 commits into
masterfrom
performance
Apr 20, 2026
Merged

feat(api)!: split schema configuration into a DataSchema builder#870
johngeorgewright merged 4 commits into
masterfrom
performance

Conversation

@johngeorgewright

Copy link
Copy Markdown
Collaborator

Introduce DataSchema, a new class for declaring payload parsers,
targeting descriptors, and fall-through targeting. Its chained methods
accumulate parser shapes via intersection and materialise them into a
BuiltDataSchema via .build(), which is then passed to Data.create(schema).

This replaces the previous flow where Data.create() returned a chainable
PromisedData with usePayload/useTargeting/useFallThroughTargeting methods.
Chaining many of those methods accumulated mapped types via utility-types'
Assign and hit TS2589 "Type instantiation is excessively deep" around
60–95 chained calls. DataSchema's intersection-based accumulation keeps
100 payloads + 30 targeting descriptors well within TypeScript's depth
limits and type-checks in under a second.

The utility-types dependency is no longer needed and has been removed.

BREAKING CHANGE: Data.create() now requires a BuiltDataSchema argument.
The schema configuration methods (usePayload, useTargeting,
useFallThroughTargeting) have moved from Data/PromisedData to DataSchema.
The ConfigurableData interface and the DT.Assign* type helpers have been
removed from the public API.

Before:
const data = await Data.create()
.usePayload({ greeting: z.string() })
.useTargeting({ country: targetIncludes(z.string()) })
.addRules('greeting', [...])

After:
const schema = DataSchema.create()
.usePayload({ greeting: z.string() })
.useTargeting({ country: targetIncludes(z.string()) })
.build()

const data = await Data.create(schema).addRules('greeting', [...])

Introduce DataSchema, a new class for declaring payload parsers,
targeting descriptors, and fall-through targeting. Its chained methods
accumulate parser shapes via intersection and materialise them into a
BuiltDataSchema via .build(), which is then passed to Data.create(schema).

This replaces the previous flow where Data.create() returned a chainable
PromisedData with usePayload/useTargeting/useFallThroughTargeting methods.
Chaining many of those methods accumulated mapped types via utility-types'
Assign and hit TS2589 "Type instantiation is excessively deep" around
60–95 chained calls. DataSchema's intersection-based accumulation keeps
100 payloads + 30 targeting descriptors well within TypeScript's depth
limits and type-checks in under a second.

BREAKING CHANGE: Data.create() now requires a BuiltDataSchema argument.
The schema configuration methods (usePayload, useTargeting,
useFallThroughTargeting) have moved from Data/PromisedData to DataSchema.
The ConfigurableData interface and the DT.Assign* type helpers have been
removed from the public API.

Before:
```
  const data = await Data.create()
    .usePayload({ greeting: z.string() })
    .useTargeting({ country: targetIncludes(z.string()) })
    .addRules('greeting', [...])
```

After:
```
  const schema = DataSchema.create()
    .usePayload({ greeting: z.string() })
    .useTargeting({ country: targetIncludes(z.string()) })
    .build()

  const data = await Data.create(schema).addRules('greeting', [...])
```
Copilot AI review requested due to automatic review settings April 20, 2026 14:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Introduces a new two-phase API for @targetd/api that separates schema configuration from data operations by adding a DataSchema builder and requiring Data.create(schema).

Changes:

  • Added DataSchema / BuiltDataSchema and updated Data.create to require a built schema (breaking change).
  • Removed the old schema-configuration surface (ConfigurableData, Merge, and PromisedData.use* configuration methods) and updated call sites across packages/tests/docs.
  • Added a type-stress test to validate TypeScript depth/perf improvements with large chained schemas.

Reviewed changes

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

Show a summary per file
File Description
packages/server/test/index.test.ts Updates server tests to build a DataSchema and pass it into Data.create(schema).
packages/server/src/index.ts Updates public server JSDoc example to the new DataSchema flow.
packages/server/README.md Updates server documentation examples to the new two-phase API.
packages/json-schema/test/fixtures/data.ts Updates json-schema fixtures to use DataSchema.build() and Data.create(schema).
packages/fs/test/fixtures/data.ts Updates fs fixtures to the new DataSchema initialization pattern.
packages/fs/src/watch.ts Updates watch() JSDoc example to use DataSchema.
packages/fs/src/load.ts Updates load() JSDoc example to use DataSchema.
packages/fs/README.md Updates fs documentation examples to the new schema builder API.
packages/explode/README.md Updates explode documentation examples to construct Data via DataSchema.
packages/date-range/test/index.test.ts Updates date-range tests to create Data from a built schema.
packages/date-range/src/index.ts Updates date-range package JSDoc examples to the new API.
packages/date-range/README.md Updates date-range documentation examples to build schema separately.
packages/client/test/index.test.ts Updates client tests to use DataSchema + Data.create(schema).
packages/client/src/index.ts Updates a JSDoc snippet referencing Data.create(...) for the new API shape.
packages/client/README.md Refactors docs to define a shared DataSchema and build Data from it on both client/server.
packages/api/test/type-stress.test.ts Adds a stress test for large chained schema configuration.
packages/api/test/Data.test.ts Updates core API tests to the new schema builder flow.
packages/api/src/util.ts Removes the exported Merge type helper (no longer used).
packages/api/src/predicates/targetIncludes.ts Updates predicate documentation examples to the new DataSchema usage.
packages/api/src/predicates/equals.ts Updates predicate documentation examples to the new DataSchema usage.
packages/api/src/index.ts Exports DataSchema and BuiltDataSchema; removes exports of removed types.
packages/api/src/PromisedData.ts Removes schema-configuration methods; keeps PromisedData focused on data ops/query chaining.
packages/api/src/DataSchema.ts Adds the new builder that accumulates parsers/predicates and produces a built schema.
packages/api/src/Data.ts Makes Data.create require a built schema; removes old configuration methods and ConfigurableData implementation.
packages/api/src/ConfigurableData.ts Deletes the old configuration interface from the public API.
packages/api/README.md Updates API README usage and explanations for the new two-phase model.
deno.lock Updates lockfile metadata (marks @xmldom/xmldom as deprecated).
README.md Updates root README examples to use DataSchema + Data.create(schema).
.github/copilot-instructions.md Updates internal repo guidance to describe the new two-phase API.

Comment thread packages/api/src/DataSchema.ts
Comment thread packages/api/src/DataSchema.ts
Comment thread packages/api/src/DataSchema.ts Outdated
Copilot AI review requested due to automatic review settings April 20, 2026 14:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 1 comment.

Comment thread packages/api/src/DataSchema.ts
@johngeorgewright johngeorgewright merged commit 9f44b39 into master Apr 20, 2026
6 checks passed
@johngeorgewright johngeorgewright deleted the performance branch April 20, 2026 14:37
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