Skip to content

chore: sync the spec and regenerate response types - #21

Merged
AminChirazi merged 1 commit into
mainfrom
chore/sync-spec-response-types
Jul 29, 2026
Merged

chore: sync the spec and regenerate response types#21
AminChirazi merged 1 commit into
mainfrom
chore/sync-spec-response-types

Conversation

@AminChirazi

Copy link
Copy Markdown
Contributor

spec/openapi.json was vendored before the API's response-typing work: 209 of its 239 operations described no response body.

That is not a cosmetic gap. openapi-typescript turns a bodyless operation into responses: never, and extracting a 200 body out of that infers unknown — so most of this SDK's surface typed its return values as unknown, which is precisely the drift the 1.0 rewrite existed to end.

Copied the current spec from datamaker@next and ran pnpm generate.

What changes

before after
operations with a typed response 30 / 239 209 / 240
components["schemas"] 15 123
  • 178 operations gain a real response type.
  • GET /scenarios/jobs is new.
  • Additive only. All 15 pre-existing schemas are byte-identical, so nothing that compiles today stops compiling. Hence minor, not major.

Verification

Beyond the four CI steps, I wrote a type-level proof (scratch, not committed) and — importantly — checked it wasn't vacuous.

A naive assertion here is worthless: both unknown and never swallow a loose assignability check, so const x: Body<...> = {...} passes against the old schema too. My first attempt at this proof did exactly that and told me nothing. The real proof asserts exact type identity:

type Exact<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
type Assert<T extends true> = T;

It confirms:

  1. GET /scenarios yields exactly Scenario[].
  2. The environment-variable asymmetry survives generationGET is {key, value}[], the writes are a Record<string, string>. Had those been collapsed into one schema upstream, exactly one of these two assertions would fail.
  3. PlanRun["files"] is PlanRunFile[] | undefinedoptional, not nullable.
  4. /export/rest, still deliberately bodyless upstream, resolves to unknown — which is the mechanism this whole PR is about, demonstrated rather than asserted.

Run against the old schema, assertions 1–3 all fail. Assertion 4 passes against both, correctly, since that route is bodyless in each.

  • pnpm generate:check — generated types match the spec
  • pnpm lint (tsc) — clean
  • pnpm test — 11/11
  • pnpm build — ESM + CJS + DTS

Scope — what this does not do

It widens the exported paths and components types, which consumers can use directly. It does not add methods to the resource clients: dm.projects, dm.templates, dm.sets, dm.keymaps, dm.maskingPolicies and dm.plans still cover exactly what they covered before, because resources.ts hand-picks the schemas it exposes. There are now 108 more schemas available to build against; wiring them into ergonomic clients is a separate, larger piece of work worth its own PR.

Still unknown, on purpose

31 operations remain deliberately untyped upstream: the 22 Tosca/Jira/SAP pass-throughs, whose bodies belong to those systems rather than to DataMaker, and 9 routes that return credentials and are kept out of the published contract (automators-com/datamaker#2882, #2916, #2919). The API now has a CI ratchet (automators-com/datamaker#2922) that stops any new operation from shipping bodyless, so this gap should not reopen.

datamaker-py needs the same backfill and has not had it.

🤖 Generated with Claude Code

`spec/openapi.json` was vendored before the API's response-typing work and
had 209 of 239 operations describing no response body. openapi-typescript
turns a bodyless operation into `responses: never`, and extracting a 200
body from that infers `unknown` - so most of this SDK's surface typed its
return values as `unknown`, which is the drift the 1.0 rewrite was meant
to end.

Copied the current spec from datamaker@next and ran `pnpm generate`:

  - 178 operations gain a real response type (30 typed -> 209 of 240)
  - components.schemas grows 15 -> 123
  - GET /scenarios/jobs is new

Additive only. All 15 pre-existing schemas are byte-identical, so nothing
that compiles today stops compiling - hence a minor, not a major.

Verified with a type-level proof (not committed) asserting exact types
rather than assignability, since `unknown` and `never` both swallow a
loose assignability check and make such a test vacuous. It confirms
`GET /scenarios` yields Scenario[]; that the environment-variable
asymmetry survives generation (GET is an array of {key, value}, the
writes are a Record - collapsing them upstream would have broken exactly
one); and that PlanRun.files is optional rather than nullable. Run
against the OLD schema every one of those assertions fails, so the proof
is not vacuous.

31 operations stay untyped upstream on purpose and still resolve to
`unknown`: the Tosca/Jira/SAP pass-throughs, and the routes that return
credentials.

This does NOT extend the resource clients - dm.projects, dm.templates and
friends still cover what they covered before. The win here is in the
exported `paths` and `components` types; widening the clients is separate
work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 29, 2026 05:47

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@AminChirazi
AminChirazi merged commit 0c55fe0 into main Jul 29, 2026
2 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.

2 participants